So here I am setting up a TCP connection to the server and is invoked from an application in a loop and sometimes I end up seeing the following error
select() timed out after 4 seconds - Operation now in progress
which means select
did return 0
which means it timed out in 5 seconds without observing any activity on the file descriptor.
My understanding is nonblocking mode is set after connect()
in case it doesn't connect right away with getsockopt()
indicating whether connect()
call did establish but for some reason, select
seems to be returning 0. Does it have to with delay being too small?
int InitializeSocket(int sockType, int protocol, long timeout)
{
int socketFd = socket(AF_INET, sockType, protocol);
if (socketFd < 0)
{
perror ("Failed to create a client socket of type %d", sockType);
return -1;
}
if (timeout > 0)
{
struct timeval sockTimeout = {.tv_sec = timeout, .tv_usec = 0};
// setting the receive timeout
if (setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, &sockTimeout, sizeof(sockTimeout)) < 0)
{
perror ("Failed to set the RX timeout");
return -1;
}
// setting the send timeout
if (setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, &sockTimeout, sizeof(sockTimeout)) < 0)
{
perror ("Failed to set the TX timeout");
return -1;
}
}
return socketFd;
}
void OpenTcpConnection(int serverTimeout, int port, const char *ipAddr)
{
struct sockaddr_in *address
int socketFd = InitializeSocket(SOCK_STREAM, 0, serverTimeout);
if (socketFd == -1)
{
return -1;
}
address->sin_family = AF_INET;
address->sin_port = htons(port);
address->sin_addr.s_addr = inet_addr(ipAddr);
memset(address->sin_zero, '\0', sizeof(address->sin_zero));
// get the existing file flags
long arg = 0;
if( (arg = fcntl(socketFd, F_GETFL, NULL)) < 0)
{
perror ("Failed to get file status flags");
exit(0);
}
// set the socket to nonblocking mode
arg |= O_NONBLOCK;
if( fcntl(socketFd, F_SETFL, arg) < 0)
{
perror ("Failed to set to nonblocking mode");
return -1;
}
// connect to the server
int res = connect(socketFd, (struct sockaddr *) &address, sizeof(address));
fd_set fdset;
struct timeval tv;
long selectTimeout = 4; // connect() timeout
if (res < 0)
{
// the socket is nonblocking & the connection cannot be completed immediately
if (errno == EINPROGRESS)
{
do
{
tv.tv_sec = selectTimeout;
tv.tv_usec = 0;
FD_ZERO(&fdset);
FD_SET(socketFd, &fdset);
res = select(socketFd+1, NULL, &fdset, NULL, &tv);
if (res < 0 && errno != EINTR)
{
perror ("Failed to monitor socket FD %d", socketFd);
return -1;
}
else if (res > 0)
{
int so_error;
socklen_t len = sizeof so_error;
int valopt;
// check whether connect() completed successfully
if (getsockopt(socketFd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &len) < 0)
{
perror ("Error in getsockopt");
return -1;
}
if (valopt)
{
perror ("Error in delayed connection");
return -1;
}
break;
}
else
{
perror ("select() timed out after %ld seconds", selectTimeout); // ERROR HERE !!!
return -1;
}
} while(1);
}
}
}