net: use Sock in InterruptibleRecv() and Socks5()

Use the `Sock` class instead of `SOCKET` for `InterruptibleRecv()` and
`Socks5()`.

This way the `Socks5()` function can be tested by giving it a mocked
instance of a socket.

Co-authored-by: practicalswift <practicalswift@users.noreply.github.com>
This commit is contained in:
Vasil Dimov 2020-12-28 16:57:10 +01:00
parent ba9d73268f
commit 04ae846904
No known key found for this signature in database
GPG Key ID: 54DF06F64B55CBBF
3 changed files with 12 additions and 27 deletions

View File

@ -440,7 +440,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
return nullptr; return nullptr;
} }
connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(),
sock->Get(), nConnectTimeout, proxyConnectionFailed); *sock, nConnectTimeout, proxyConnectionFailed);
} else { } else {
// no proxy needed (none set for target network) // no proxy needed (none set for target network)
sock = CreateSock(addrConnect); sock = CreateSock(addrConnect);
@ -464,7 +464,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
int port = default_port; int port = default_port;
SplitHostPort(std::string(pszDest), port, host); SplitHostPort(std::string(pszDest), port, host);
bool proxyConnectionFailed; bool proxyConnectionFailed;
connected = ConnectThroughProxy(proxy, host, port, sock->Get(), nConnectTimeout, connected = ConnectThroughProxy(proxy, host, port, *sock, nConnectTimeout,
proxyConnectionFailed); proxyConnectionFailed);
} }
if (!connected) { if (!connected) {

View File

@ -343,7 +343,7 @@ enum class IntrRecvError {
* Sockets can be made non-blocking with SetSocketNonBlocking(const * Sockets can be made non-blocking with SetSocketNonBlocking(const
* SOCKET&, bool). * SOCKET&, bool).
*/ */
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket) static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& hSocket)
{ {
int64_t curTime = GetTimeMillis(); int64_t curTime = GetTimeMillis();
int64_t endTime = curTime + timeout; int64_t endTime = curTime + timeout;
@ -351,7 +351,7 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
// (in millis) to break off in case of an interruption. // (in millis) to break off in case of an interruption.
const int64_t maxWait = 1000; const int64_t maxWait = 1000;
while (len > 0 && curTime < endTime) { while (len > 0 && curTime < endTime) {
ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first ssize_t ret = hSocket.Recv(data, len, 0); // Optimistically try the recv first
if (ret > 0) { if (ret > 0) {
len -= ret; len -= ret;
data += ret; data += ret;
@ -360,25 +360,10 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
} 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)) {
return IntrRecvError::NetworkError;
}
// Only wait at most maxWait milliseconds at a time, unless // Only wait at most maxWait milliseconds at a time, unless
// we're approaching the end of the specified total timeout // we're approaching the end of the specified total timeout
int timeout_ms = std::min(endTime - curTime, maxWait); int timeout_ms = std::min(endTime - curTime, maxWait);
#ifdef USE_POLL if (!hSocket.Wait(std::chrono::milliseconds{timeout_ms}, Sock::RECV)) {
struct pollfd pollfd = {};
pollfd.fd = hSocket;
pollfd.events = POLLIN;
int nRet = poll(&pollfd, 1, timeout_ms);
#else
struct timeval tval = MillisToTimeval(timeout_ms);
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
#endif
if (nRet == SOCKET_ERROR) {
return IntrRecvError::NetworkError; return IntrRecvError::NetworkError;
} }
} else { } else {
@ -442,7 +427,7 @@ static std::string Socks5ErrorString(uint8_t err)
* @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol * @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
* Version 5</a> * Version 5</a>
*/ */
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, const SOCKET& hSocket) static bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, const Sock& hSocket)
{ {
IntrRecvError recvr; IntrRecvError recvr;
LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest); LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
@ -460,7 +445,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vSocks5Init.push_back(0x01); // 1 method identifier follows... vSocks5Init.push_back(0x01); // 1 method identifier follows...
vSocks5Init.push_back(SOCKS5Method::NOAUTH); vSocks5Init.push_back(SOCKS5Method::NOAUTH);
} }
ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL); ssize_t ret = hSocket.Send(vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5Init.size()) { if (ret != (ssize_t)vSocks5Init.size()) {
return error("Error sending to proxy"); return error("Error sending to proxy");
} }
@ -482,7 +467,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end()); vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
vAuth.push_back(auth->password.size()); vAuth.push_back(auth->password.size());
vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL); ret = hSocket.Send(vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vAuth.size()) { if (ret != (ssize_t)vAuth.size()) {
return error("Error sending authentication to proxy"); return error("Error sending authentication to proxy");
} }
@ -508,7 +493,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end()); vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
vSocks5.push_back((port >> 8) & 0xFF); vSocks5.push_back((port >> 8) & 0xFF);
vSocks5.push_back((port >> 0) & 0xFF); vSocks5.push_back((port >> 0) & 0xFF);
ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL); ret = hSocket.Send(vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5.size()) { if (ret != (ssize_t)vSocks5.size()) {
return error("Error sending to proxy"); return error("Error sending to proxy");
} }
@ -787,10 +772,10 @@ bool IsProxy(const CNetAddr &addr) {
* *
* @returns Whether or not the operation succeeded. * @returns Whether or not the operation succeeded.
*/ */
bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool& outProxyConnectionFailed) bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& hSocket, int nTimeout, bool& outProxyConnectionFailed)
{ {
// first connect to proxy server // first connect to proxy server
if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout, true)) { if (!ConnectSocketDirectly(proxy.proxy, hSocket.Get(), nTimeout, true)) {
outProxyConnectionFailed = true; outProxyConnectionFailed = true;
return false; return false;
} }

View File

@ -68,7 +68,7 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family);
extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock; extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock;
bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout, bool manual_connection); bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout, bool manual_connection);
bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocketRet, int nTimeout, bool& outProxyConnectionFailed); bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& hSocketRet, int nTimeout, bool& outProxyConnectionFailed);
/** Disable or enable blocking-mode for a socket */ /** Disable or enable blocking-mode for a socket */
bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking); bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking);
/** Set the TCP_NODELAY flag on a socket */ /** Set the TCP_NODELAY flag on a socket */