diff --git a/src/netbase.cpp b/src/netbase.cpp --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -180,6 +180,14 @@ return timeout; } +enum class IntrRecvError { + OK, + Timeout, + Disconnected, + NetworkError, + Interrupted +}; + /** * Read bytes from socket. This will either read the full number of bytes * requested or return False on error or timeout. @@ -191,8 +199,8 @@ * * @note This function requires that hSocket is in non-blocking mode. */ -static bool InterruptibleRecv(char *data, size_t len, int timeout, - SOCKET &hSocket) { +static IntrRecvError InterruptibleRecv(char *data, size_t len, int timeout, + SOCKET &hSocket) { int64_t curTime = GetTimeMillis(); int64_t endTime = curTime + timeout; // Maximum time to wait in one select call. It will take up until this time @@ -206,14 +214,14 @@ data += ret; } else if (ret == 0) { // Unexpected disconnection - return false; + return IntrRecvError::Disconnected; } else { // Other error or blocking int nErr = WSAGetLastError(); if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) { if (!IsSelectableSocket(hSocket)) { - return false; + return IntrRecvError::NetworkError; } struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait)); @@ -222,16 +230,18 @@ FD_SET(hSocket, &fdset); int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval); if (nRet == SOCKET_ERROR) { - return false; + return IntrRecvError::NetworkError; } } else { - return false; + return IntrRecvError::NetworkError; } } - if (interruptSocks5Recv) return false; + if (interruptSocks5Recv) { + return IntrRecvError::Interrupted; + } curTime = GetTimeMillis(); } - return len == 0; + return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout; } struct ProxyCredentials { @@ -265,6 +275,7 @@ /** Connect using SOCKS5 (as described in RFC1928) */ static bool Socks5(const std::string &strDest, int port, const ProxyCredentials *auth, SOCKET &hSocket) { + IntrRecvError recvr; LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest); if (strDest.size() > 255) { CloseSocket(hSocket); @@ -293,7 +304,8 @@ return error("Error sending to proxy"); } char pchRet1[2]; - if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { + if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != + IntrRecvError::OK) { CloseSocket(hSocket); LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() " "timeout or other failure\n", @@ -323,7 +335,8 @@ LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); char pchRetA[2]; - if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { + if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, + hSocket)) != IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading proxy authentication response"); } @@ -359,9 +372,19 @@ return error("Error sending to proxy"); } char pchRet2[4]; - if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) { + if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != + IntrRecvError::OK) { CloseSocket(hSocket); - return error("Error reading proxy response"); + if (recvr == IntrRecvError::Timeout) { + /** + * If a timeout happens here, this effectively means we timed out + * while connecting to the remote node. This is very common for Tor, + * so do not print an error message. + */ + return false; + } else { + return error("Error while reading proxy response"); + } } if (pchRet2[0] != 0x05) { CloseSocket(hSocket); @@ -381,19 +404,20 @@ char pchRet3[256]; switch (pchRet2[3]) { case 0x01: - ret = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); + recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break; case 0x04: - ret = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); + recvr = + InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break; case 0x03: { - ret = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket); - if (!ret) { + recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket); + if (recvr != IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading from proxy"); } int nRecv = pchRet3[0]; - ret = + recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket); break; } @@ -401,11 +425,12 @@ CloseSocket(hSocket); return error("Error: malformed proxy response"); } - if (!ret) { + if (recvr != IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading from proxy"); } - if (!InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { + if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != + IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading from proxy"); }