a00457f03b2d7150e9684a5ebfac2cfc4ac8dad6 galt Tue Mar 22 23:47:07 2011 -0700 adding non-blocking tcp connect to deal with long several minutes default delay diff --git src/lib/net.c src/lib/net.c index 01c1926..0b6de68 100644 --- src/lib/net.c +++ src/lib/net.c @@ -23,53 +23,142 @@ /* Brought errno in to get more useful error messages */ extern int errno; static int netStreamSocket() /* Create a TCP/IP streaming socket. Complain and return something * negative if can't */ { int sd = socket(AF_INET, SOCK_STREAM, 0); if (sd < 0) warn("Couldn't make AF_INET socket."); return sd; } - -int netConnect(char *hostName, int port) -/* Start connection with a server. */ +static int netConnectWithTimeout(char *hostName, int port, long msTimeout) +/* In order to avoid a very long default timeout (several minutes) for hosts that will + * not answer the port, we are forced to connect non-blocking. + * After the connection has been established, we return to blocking mode. */ { -int sd, err; +int sd; struct sockaddr_in sai; /* Some system socket info. */ +int res; +fd_set mySet; +struct timeval lTime; +long fcntlFlags; if (hostName == NULL) { warn("NULL hostName in netConnect"); return -1; } if (!internetFillInAddress(hostName, port, &sai)) return -1; if ((sd = netStreamSocket()) < 0) return sd; -if ((err = connect(sd, (struct sockaddr*)&sai, sizeof(sai))) < 0) + +// Set non-blocking +if ((fcntlFlags = fcntl(sd, F_GETFL, NULL)) < 0) + { + warn("Error fcntl(..., F_GETFL) (%s)\n", strerror(errno)); + close(sd); + return -1; + } +fcntlFlags |= O_NONBLOCK; +if (fcntl(sd, F_SETFL, fcntlFlags) < 0) + { + warn("Error fcntl(..., F_SETFL) (%s)\n", strerror(errno)); + close(sd); + return -1; + } + +// Trying to connect with timeout +res = connect(sd, (struct sockaddr*) &sai, sizeof(sai)); +if (res < 0) + { + if (errno == EINPROGRESS) + { + while (1) + { + lTime.tv_sec = (long) (msTimeout/1000); + lTime.tv_usec = (long) (((msTimeout/1000)-lTime.tv_sec)*1000000); + FD_ZERO(&mySet); + FD_SET(sd, &mySet); + res = select(sd+1, NULL, &mySet, &mySet, &lTime); + if (res < 0) + { + if (errno != EINTR) + { + warn("Error in select() during TCP non-blocking connect %d - %s\n", errno, strerror(errno)); + close(sd); + return -1; + } + } + else if (res > 0) + { + // Socket selected for write when it is ready + // We simply re-do the connect call and get the result + res = connect(sd, (struct sockaddr*) &sai, sizeof(sai)); + if (res < 0) + { + warn("Error in TCP non-blocking connect() %d - %s\n", errno, strerror(errno)); + close(sd); + return -1; + } + break; + } + else { - errnoWarn("Couldn't connect to %s %d", hostName, port); + warn("TCP non-blocking connect() timed-out in select() after %ld milliseconds - Cancelling!\n", msTimeout); close(sd); - return err; + return -1; } + } + } + else + { + warn("TCP non-blocking connect() error %d - %s\n", errno, strerror(errno)); + close(sd); + return -1; + } + } + +// Set to blocking mode again +if ((fcntlFlags = fcntl(sd, F_GETFL, NULL)) < 0) + { + warn("Error fcntl(..., F_GETFL) (%s)\n", strerror(errno)); + close(sd); + return -1; + } +fcntlFlags &= (~O_NONBLOCK); +if (fcntl(sd, F_SETFL, fcntlFlags) < 0) + { + warn("Error fcntl(..., F_SETFL) (%s)\n", strerror(errno)); + close(sd); + return -1; + } + return sd; + +} + + +int netConnect(char *hostName, int port) +/* Start connection with a server. */ +{ +return netConnectWithTimeout(hostName, port, 10000); // 10 seconds connect timeout } int netMustConnect(char *hostName, int port) /* Start connection with server or die. */ { int sd = netConnect(hostName, port); if (sd < 0) noWarnAbort(); return sd; } int netMustConnectTo(char *hostName, char *portName) /* Start connection with a server and a port that needs to be converted to integer */ { if (!isdigit(portName[0]))