diff --git a/platform/socket/sckt-0.5/sckt.cpp b/platform/socket/sckt-0.5/sckt.cpp index 173999e0c36efe708dc25f0e8887aa24eb0791cf..daa4e93be34637282a5e2e90da1f0d5157a814fa 100644 --- a/platform/socket/sckt-0.5/sckt.cpp +++ b/platform/socket/sckt-0.5/sckt.cpp @@ -447,6 +447,74 @@ void TCPServerSocket::Open(const IPAddress& ip, bool disableNaggle){ #endif }; +/* + Connect with timeout. +*/ +int ConnectWait (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; +} + /* Open a TCP network socket. A TCP connection to the remote host and port is attempted. */ @@ -484,19 +552,19 @@ void TCPSocket::Open(const IPAddress& ip, Options *options, bool disableNaggle){ if (CONFIG_SOCKET_CONNECT_TIMEOUT) { struct timeval tv; - + tv.tv_sec = CONFIG_SOCKET_CONNECT_TIMEOUT / 1000; tv.tv_usec = (CONFIG_SOCKET_CONNECT_TIMEOUT % 1000) * 1000; - if (setsockopt (CastToSocket(this->socket), SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, - sizeof(tv)) < 0) - - { - throw sckt::Exc("TCPServerSocket::Open(): unable to set connect timeout"); + + if( ConnectWait(CastToSocket(this->socket), reinterpret_cast(&sockAddr), sizeof(sockAddr),&tv) == M_SOCKET_ERROR ){ + this->Close(); + throw sckt::Exc("TCPSocket::Open(): Couldn't connect to remote host"); + } + } else { + if( connect(CastToSocket(this->socket), reinterpret_cast(&sockAddr), sizeof(sockAddr)) == M_SOCKET_ERROR ){ + this->Close(); + throw sckt::Exc("TCPSocket::Open(): Couldn't connect to remote host"); } - } - if( connect(CastToSocket(this->socket), reinterpret_cast(&sockAddr), sizeof(sockAddr)) == M_SOCKET_ERROR ){ - this->Close(); - throw sckt::Exc("TCPSocket::Open(): Couldn't connect to remote host"); } #ifndef __WIN32__ }