Skip to content

Commit e82e609

Browse files
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 <[email protected]>
1 parent 806a6c1 commit e82e609

File tree

3 files changed

+39
-42
lines changed

3 files changed

+39
-42
lines changed

src/net.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
439439
return nullptr;
440440
}
441441
connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(),
442-
sock->Get(), nConnectTimeout, proxyConnectionFailed);
442+
*sock, nConnectTimeout, proxyConnectionFailed);
443443
} else {
444444
// no proxy needed (none set for target network)
445445
sock = CreateSock(addrConnect);
@@ -463,8 +463,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
463463
int port = default_port;
464464
SplitHostPort(std::string(pszDest), port, host);
465465
bool proxyConnectionFailed;
466-
connected = ConnectThroughProxy(proxy, host, port, sock->Get(), nConnectTimeout,
467-
proxyConnectionFailed);
466+
connected =
467+
ConnectThroughProxy(proxy, host, port, *sock, nConnectTimeout, proxyConnectionFailed);
468468
}
469469
if (!connected) {
470470
return nullptr;

src/netbase.cpp

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,7 @@ enum class IntrRecvError {
331331
* @param data The buffer where the read bytes should be stored.
332332
* @param len The number of bytes to read into the specified buffer.
333333
* @param timeout The total timeout in milliseconds for this read.
334-
* @param hSocket The socket (has to be in non-blocking mode) from which to read
335-
* bytes.
334+
* @param sock The socket (has to be in non-blocking mode) from which to read bytes.
336335
*
337336
* @returns An IntrRecvError indicating the resulting status of this read.
338337
* IntrRecvError::OK only if all of the specified number of bytes were
@@ -342,15 +341,15 @@ enum class IntrRecvError {
342341
* Sockets can be made non-blocking with SetSocketNonBlocking(const
343342
* SOCKET&, bool).
344343
*/
345-
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
344+
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& sock)
346345
{
347346
int64_t curTime = GetTimeMillis();
348347
int64_t endTime = curTime + timeout;
349348
// Maximum time to wait for I/O readiness. It will take up until this time
350349
// (in millis) to break off in case of an interruption.
351350
const int64_t maxWait = 1000;
352351
while (len > 0 && curTime < endTime) {
353-
ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
352+
ssize_t ret = sock.Recv(data, len, 0); // Optimistically try the recv first
354353
if (ret > 0) {
355354
len -= ret;
356355
data += ret;
@@ -359,25 +358,10 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
359358
} else { // Other error or blocking
360359
int nErr = WSAGetLastError();
361360
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
362-
if (!IsSelectableSocket(hSocket)) {
363-
return IntrRecvError::NetworkError;
364-
}
365361
// Only wait at most maxWait milliseconds at a time, unless
366362
// we're approaching the end of the specified total timeout
367363
int timeout_ms = std::min(endTime - curTime, maxWait);
368-
#ifdef USE_POLL
369-
struct pollfd pollfd = {};
370-
pollfd.fd = hSocket;
371-
pollfd.events = POLLIN;
372-
int nRet = poll(&pollfd, 1, timeout_ms);
373-
#else
374-
struct timeval tval = MillisToTimeval(timeout_ms);
375-
fd_set fdset;
376-
FD_ZERO(&fdset);
377-
FD_SET(hSocket, &fdset);
378-
int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
379-
#endif
380-
if (nRet == SOCKET_ERROR) {
364+
if (!sock.Wait(std::chrono::milliseconds{timeout_ms}, Sock::RECV)) {
381365
return IntrRecvError::NetworkError;
382366
}
383367
} else {
@@ -431,7 +415,7 @@ static std::string Socks5ErrorString(uint8_t err)
431415
* @param port The destination port.
432416
* @param auth The credentials with which to authenticate with the specified
433417
* SOCKS5 proxy.
434-
* @param hSocket The SOCKS5 proxy socket.
418+
* @param sock The SOCKS5 proxy socket.
435419
*
436420
* @returns Whether or not the operation succeeded.
437421
*
@@ -441,7 +425,10 @@ static std::string Socks5ErrorString(uint8_t err)
441425
* @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
442426
* Version 5</a>
443427
*/
444-
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, const SOCKET& hSocket)
428+
static bool Socks5(const std::string& strDest,
429+
int port,
430+
const ProxyCredentials* auth,
431+
const Sock& sock)
445432
{
446433
IntrRecvError recvr;
447434
LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
@@ -459,12 +446,12 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
459446
vSocks5Init.push_back(0x01); // 1 method identifier follows...
460447
vSocks5Init.push_back(SOCKS5Method::NOAUTH);
461448
}
462-
ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
449+
ssize_t ret = sock.Send(vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
463450
if (ret != (ssize_t)vSocks5Init.size()) {
464451
return error("Error sending to proxy");
465452
}
466453
uint8_t pchRet1[2];
467-
if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
454+
if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) {
468455
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
469456
return false;
470457
}
@@ -481,13 +468,13 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
481468
vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
482469
vAuth.push_back(auth->password.size());
483470
vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
484-
ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
471+
ret = sock.Send(vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
485472
if (ret != (ssize_t)vAuth.size()) {
486473
return error("Error sending authentication to proxy");
487474
}
488475
LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
489476
uint8_t pchRetA[2];
490-
if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
477+
if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) {
491478
return error("Error reading proxy authentication response");
492479
}
493480
if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
@@ -507,12 +494,12 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
507494
vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
508495
vSocks5.push_back((port >> 8) & 0xFF);
509496
vSocks5.push_back((port >> 0) & 0xFF);
510-
ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
497+
ret = sock.Send(vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
511498
if (ret != (ssize_t)vSocks5.size()) {
512499
return error("Error sending to proxy");
513500
}
514501
uint8_t pchRet2[4];
515-
if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
502+
if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) {
516503
if (recvr == IntrRecvError::Timeout) {
517504
/* If a timeout happens here, this effectively means we timed out while connecting
518505
* to the remote node. This is very common for Tor, so do not print an
@@ -536,24 +523,24 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
536523
uint8_t pchRet3[256];
537524
switch (pchRet2[3])
538525
{
539-
case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
540-
case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
526+
case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, sock); break;
527+
case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, sock); break;
541528
case SOCKS5Atyp::DOMAINNAME:
542529
{
543-
recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
530+
recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, sock);
544531
if (recvr != IntrRecvError::OK) {
545532
return error("Error reading from proxy");
546533
}
547534
int nRecv = pchRet3[0];
548-
recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
535+
recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, sock);
549536
break;
550537
}
551538
default: return error("Error: malformed proxy response");
552539
}
553540
if (recvr != IntrRecvError::OK) {
554541
return error("Error reading from proxy");
555542
}
556-
if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
543+
if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) {
557544
return error("Error reading from proxy");
558545
}
559546
LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
@@ -778,18 +765,23 @@ bool IsProxy(const CNetAddr &addr) {
778765
* @param proxy The SOCKS5 proxy.
779766
* @param strDest The destination service to which to connect.
780767
* @param port The destination port.
781-
* @param hSocket The socket on which to connect to the SOCKS5 proxy.
768+
* @param sock The socket on which to connect to the SOCKS5 proxy.
782769
* @param nTimeout Wait this many milliseconds for the connection to the SOCKS5
783770
* proxy to be established.
784771
* @param[out] outProxyConnectionFailed Whether or not the connection to the
785772
* SOCKS5 proxy failed.
786773
*
787774
* @returns Whether or not the operation succeeded.
788775
*/
789-
bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool& outProxyConnectionFailed)
776+
bool ConnectThroughProxy(const proxyType& proxy,
777+
const std::string& strDest,
778+
int port,
779+
const Sock& sock,
780+
int nTimeout,
781+
bool& outProxyConnectionFailed)
790782
{
791783
// first connect to proxy server
792-
if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout, true)) {
784+
if (!ConnectSocketDirectly(proxy.proxy, sock.Get(), nTimeout, true)) {
793785
outProxyConnectionFailed = true;
794786
return false;
795787
}
@@ -798,11 +790,11 @@ bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int
798790
ProxyCredentials random_auth;
799791
static std::atomic_int counter(0);
800792
random_auth.username = random_auth.password = strprintf("%i", counter++);
801-
if (!Socks5(strDest, (uint16_t)port, &random_auth, hSocket)) {
793+
if (!Socks5(strDest, (uint16_t)port, &random_auth, sock)) {
802794
return false;
803795
}
804796
} else {
805-
if (!Socks5(strDest, (uint16_t)port, 0, hSocket)) {
797+
if (!Socks5(strDest, (uint16_t)port, 0, sock)) {
806798
return false;
807799
}
808800
}

src/netbase.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family);
6868
extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock;
6969

7070
bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout, bool manual_connection);
71-
bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocketRet, int nTimeout, bool& outProxyConnectionFailed);
71+
bool ConnectThroughProxy(const proxyType& proxy,
72+
const std::string& strDest,
73+
int port,
74+
const Sock& sock,
75+
int nTimeout,
76+
bool& outProxyConnectionFailed);
7277
/** Disable or enable blocking-mode for a socket */
7378
bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking);
7479
/** Set the TCP_NODELAY flag on a socket */

0 commit comments

Comments
 (0)