netbase: Make InterruptibleRecv return an error code instead of bool

This commit is contained in:
Wladimir J. van der Laan 2017-02-09 08:51:53 +01:00
parent 36f9d3ae6d
commit 13f608582c

View File

@ -198,6 +198,14 @@ struct timeval MillisToTimeval(int64_t nTimeout)
return timeout; return timeout;
} }
enum class IntrRecvError {
OK,
Timeout,
Disconnected,
NetworkError,
Interrupted
};
/** /**
* Read bytes from socket. This will either read the full number of bytes requested * Read bytes from socket. This will either read the full number of bytes requested
* or return False on error or timeout. * or return False on error or timeout.
@ -209,7 +217,7 @@ struct timeval MillisToTimeval(int64_t nTimeout)
* *
* @note This function requires that hSocket is in non-blocking mode. * @note This function requires that hSocket is in non-blocking mode.
*/ */
bool static 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 curTime = GetTimeMillis();
int64_t endTime = curTime + timeout; int64_t endTime = curTime + timeout;
@ -222,12 +230,12 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
len -= ret; len -= ret;
data += ret; data += ret;
} else if (ret == 0) { // Unexpected disconnection } else if (ret == 0) { // Unexpected disconnection
return false; return IntrRecvError::Disconnected;
} else { // Other error or blocking } else { // Other error or blocking
int nErr = WSAGetLastError(); int nErr = WSAGetLastError();
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) { if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
if (!IsSelectableSocket(hSocket)) { if (!IsSelectableSocket(hSocket)) {
return false; return IntrRecvError::NetworkError;
} }
struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait)); struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
fd_set fdset; fd_set fdset;
@ -235,17 +243,17 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
FD_SET(hSocket, &fdset); FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval); int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval);
if (nRet == SOCKET_ERROR) { if (nRet == SOCKET_ERROR) {
return false; return IntrRecvError::NetworkError;
} }
} else { } else {
return false; return IntrRecvError::NetworkError;
} }
} }
if (interruptSocks5Recv) if (interruptSocks5Recv)
return false; return IntrRecvError::Interrupted;
curTime = GetTimeMillis(); curTime = GetTimeMillis();
} }
return len == 0; return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
} }
struct ProxyCredentials struct ProxyCredentials
@ -272,6 +280,7 @@ std::string Socks5ErrorString(int err)
/** Connect using SOCKS5 (as described in RFC1928) */ /** Connect using SOCKS5 (as described in RFC1928) */
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket) static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
{ {
IntrRecvError recvr;
LogPrint("net", "SOCKS5 connecting %s\n", strDest); LogPrint("net", "SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255) { if (strDest.size() > 255) {
CloseSocket(hSocket); CloseSocket(hSocket);
@ -294,7 +303,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return error("Error sending to proxy"); return error("Error sending to proxy");
} }
char pchRet1[2]; char pchRet1[2];
if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port); LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
return false; return false;
@ -320,7 +329,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
} }
LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
char pchRetA[2]; char pchRetA[2];
if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
return error("Error reading proxy authentication response"); return error("Error reading proxy authentication response");
} }
@ -349,9 +358,9 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return error("Error sending to proxy"); return error("Error sending to proxy");
} }
char pchRet2[4]; char pchRet2[4];
if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) { if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
return error("Error reading proxy response"); return error("Error while reading proxy response");
} }
if (pchRet2[0] != 0x05) { if (pchRet2[0] != 0x05) {
CloseSocket(hSocket); CloseSocket(hSocket);
@ -370,26 +379,26 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
char pchRet3[256]; char pchRet3[256];
switch (pchRet2[3]) switch (pchRet2[3])
{ {
case 0x01: ret = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break; case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
case 0x04: ret = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break; case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
case 0x03: case 0x03:
{ {
ret = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket); recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
if (!ret) { if (recvr != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
return error("Error reading from proxy"); return error("Error reading from proxy");
} }
int nRecv = pchRet3[0]; int nRecv = pchRet3[0];
ret = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket); recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
break; break;
} }
default: CloseSocket(hSocket); return error("Error: malformed proxy response"); default: CloseSocket(hSocket); return error("Error: malformed proxy response");
} }
if (!ret) { if (recvr != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
return error("Error reading from proxy"); 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); CloseSocket(hSocket);
return error("Error reading from proxy"); return error("Error reading from proxy");
} }