Implement a timeout for C socket connections
To prevent the connect
function from blocking forever, a timeout can be implemented with select
.
The function below takes the same arguments as connect
and in addition a timeout
argument, which sets the maximum time to wait to connect. The function returns 0 if the connection could be established within the given time. It returns 1 if the connection timed out and -1 if an error occured. Additionally, errno
is set to ETIMEDOUT
if the connection timed out.
Source: connect_wait.c
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/socket.h>
int connect_wait (
int sockno,
struct sockaddr * addr,
size_t addrlen,
struct timeval * timeout)
{
int res, opt;
// get socket flags
if ((opt = fcntl (sockno, F_GETFL, NULL)) < 0) {
return -1;
}
// set socket non-blocking
if (fcntl (sockno, F_SETFL, opt | O_NONBLOCK) < 0) {
return -1;
}
// try to connect
if ((res = connect (sockno, addr, addrlen)) < 0) {
if (errno == EINPROGRESS) {
fd_set wait_set;
// make file descriptor set with socket
FD_ZERO (&wait_set);
FD_SET (sockno, &wait_set);
// wait for socket to be writable; return after given timeout
res = select (sockno + 1, NULL, &wait_set, NULL, timeout);
}
}
// connection was successful immediately
else {
res = 1;
}
// reset socket flags
if (fcntl (sockno, F_SETFL, opt) < 0) {
return -1;
}
// an error occured in connect or select
if (res < 0) {
return -1;
}
// select timed out
else if (res == 0) {
errno = ETIMEDOUT;
return 1;
}
// almost finished...
else {
socklen_t len = sizeof (opt);
// check for errors in socket layer
if (getsockopt (sockno, SOL_SOCKET, SO_ERROR, &opt, &len) < 0) {
return -1;
}
// there was an error
if (opt) {
errno = opt;
return -1;
}
}
return 0;
}