diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2011-06-06 20:35:01 +0200 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2011-06-12 00:29:05 +0200 |
commit | 76d660ebd336d3dd47dd555ebbaa721a4cc978b2 (patch) | |
tree | ce40033b63b17ee2527795781885a76310d5fe0d /src/net.cpp | |
parent | e051f1b510c2a8da51c099c73d5750b9c8c9422b (diff) |
Faster timeout when connecting
Use non-blocking connects, and a select() call to wait a predefined
time (5s by default, but configurable with -timeout) for either
success or failure. This allows much more connections to be tried
per time unit.
Based on a patch by phantomcircuit.
Diffstat (limited to 'src/net.cpp')
-rw-r--r-- | src/net.cpp | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/src/net.cpp b/src/net.cpp index c884e8d5e7..ca6380fc76 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -51,6 +51,7 @@ map<CInv, int64> mapAlreadyAskedFor; // Settings int fUseProxy = false; +int nConnectTimeout = 5000; CAddress addrProxy("127.0.0.1",9050); @@ -76,7 +77,7 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) -bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet) +bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout) { hSocketRet = INVALID_SOCKET; @@ -91,8 +92,87 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet) bool fProxy = (fUseProxy && addrConnect.IsRoutable()); struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr()); +#ifdef __WXMSW__ + u_long fNonblock = 1; + if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) +#else + int fFlags = fcntl(hSocket, F_GETFL, 0); + if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1) +#endif + { + closesocket(hSocket); + return false; + } + + if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) { + // WSAEINVAL is here because some legacy version of winsock uses it + if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL) + { + struct timeval timeout; + timeout.tv_sec = nTimeout / 1000; + timeout.tv_usec = (nTimeout % 1000) * 1000; + + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(hSocket, &fdset); + int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout); + if (nRet == 0) + { + printf("connection timeout\n"); + closesocket(hSocket); + return false; + } + if (nRet == SOCKET_ERROR) + { + printf("select() for connection failed: %i\n",WSAGetLastError()); + closesocket(hSocket); + return false; + } + socklen_t nRetSize = sizeof(nRet); +#ifdef __WXMSW__ + if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR) +#else + if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) +#endif + { + printf("getsockopt() for connection failed: %i\n",WSAGetLastError()); + closesocket(hSocket); + return false; + } + if (nRet != 0) + { + printf("connect() failed after select(): %i\n",nRet); + closesocket(hSocket); + return false; + } + } +#ifdef __WXMSW__ + else if (WSAGetLastError() != WSAEISCONN) +#else + else +#endif + { + printf("connect() failed: %s\n",WSAGetLastError()); + closesocket(hSocket); + return false; + } + } + + /* + this isn't even strictly necessary + CNode::ConnectNode immediately turns the socket back to non-blocking + but we'll turn it back to blocking just in case + */ +#ifdef __WXMSW__ + fNonblock = 0; + if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) +#else + fFlags = fcntl(hSocket, F_GETFL, 0); + if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR) +#endif + { closesocket(hSocket); return false; } |