After “select” returns, the socket is still busy – seen since iOS 13 Beta 7. Was working on prior versions

We have observed the following issue since iOS 13 Beta 7 which was not occurring in previous releases uptil and including iOS 13 Beta 6.


Consider the following steps:

Create a non-blocking socket and perform a ‘connect’ operation

Wait for the connection to be completed by performing a ‘select’ operation and check the appropriate FD_SET bits.

Once select returns with the appropriate bit set for the newly connected socket, perform operations on the socket e.g. setting the TTL option.

Results:

Until iOS 13 Beta 6 – the set TTL option operation would succeed.

Since iOS 13 Beta 7 – the set TTL option operation fails most of the time with an error code string (converted from errno): Resource busy


It would seem that the newly connected socket is still “busy” even after the ‘select’ returned. (I have checked that the select did not return due to timeout).

Note that if we retry to set the TTL again a few milliseconds later it succeeds.


Example code to illustrate the issue:


/* Set up a non-blocking socket and connect */

struct sockaddr_in server_address;

int reuse_addr = 1;

so_linger.l_onoff = 1;

so_linger.l_linger = 0;


int socket_fd;


socket_fd = socket(AF_INET, SOCK_STREAM, 0);


// Set up some properties of the socket

res = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));

res = setsockopt(socket_fd, SOL_SOCKET, SO_LINGER, (char*)&so_linger, sizeof so_linger);


// set as non-blocking

fcntl(socket_fd, F_SETFL, O_NONBLOCK);


// Set the address

server_address.sin_family = AF_INET;

server_address.port = MY_PORT;

server_address.sin_addr.s_addr = MY_ADDRESS;


res = connect(socket_fd, (struct sockaddr*)&server_address, sizeof(server_address));

/* this will return immediately because the socket is non-blocking */


/* Wait for the socket to be connected */

On some thread:


int ttl = 63;


while (s_should_run == 1)

{

//Prepare to select

FD_ZERO(p_read_fds);

FD_ZERO(p_write_fds);


FD_SET(socket_fd, &write_fds);


/* Set the timeout to 300 millisecs – we have checked that this is enough */

timeout.tv_sec = 0;

timeout.tv_usec = TIMEOUT_MILLISECOND * 1000);

/* select: block until event received from one of the sockets */

num_events = select( FD_SETSIZE, &read_fds, &write_fds, NULL, &timeout);

if (num_events <= 0) /* check if error occurred */

{

/* Check errors … */

continue;

}


if (FD_ISSET(socket_fd, &write_fds)

{

//Handle the now connected socket

// Change the TTL - // Since iOS13 Beta 7 it fails most of the time printing e.g socket=17, ttl=63 setsockopt failed. res=-1. errno=Resource busy

res = setsockopt(socket_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));


if (res < 0)

{

PRINT_ERROR( "socket=%d, ttl=%d setsockopt failed. res=%d. errno=%s\n", socket_fd, ttl, res, strerror(errno));

// Do some error handling …

}

else

{

// all OK continue normally …

}

}

}