aboutsummaryrefslogtreecommitdiff
path: root/src/netbase.cpp
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@protonmail.com>2021-03-30 17:27:07 +0200
committerWladimir J. van der Laan <laanwj@protonmail.com>2021-03-30 17:41:13 +0200
commitf9e86d89660002d3dd17211d8b030a47b95d2fa2 (patch)
treecb02dd5555388535322436bb12e6b33f52076214 /src/netbase.cpp
parentdede9eb9247363aacc3816c7352494a3609fa28b (diff)
parent40316a37cb02cf8a9a8b2cbd4d7153ffa57e7ec5 (diff)
Merge #21387: p2p: Refactor sock to add I2P fuzz and unit tests
40316a37cb02cf8a9a8b2cbd4d7153ffa57e7ec5 test: add I2P test for a runaway SAM proxy (Vasil Dimov) 2d8ac779708322e1235e823edfc9c8f6e2dd65e4 fuzz: add tests for the I2P Session public interface (Vasil Dimov) 9947e44de0cbd79e99d883443a9ac441d8c69713 i2p: use pointers to Sock to accommodate mocking (Vasil Dimov) 82d360b5a88d9057b6c09b61cd69e426c7a2412d net: change ConnectSocketDirectly() to take a Sock argument (Vasil Dimov) b5861100f85fef77b00f55dcdf01ffb4a2a112d8 net: add connect() and getsockopt() wrappers to Sock (Vasil Dimov) 5a887d49b2b39e59d7cce8e9d5b89c21ad694f8b fuzz: avoid FuzzedSock::Recv() repeated errors with EAGAIN (Vasil Dimov) 3088f83d016e7ebb6e6aa559e6326fa0ef0d6282 fuzz: extend FuzzedSock::Recv() to support MSG_PEEK (Vasil Dimov) 9b05c49ade729311a0f4388a109530ff8d0ed1f9 fuzz: implement unimplemented FuzzedSock methods (Vasil Dimov) Pull request description: Change the networking code and the I2P code to be fully mockable and use `FuzzedSocket` to fuzz the I2P methods `Listen()`, `Accept()` and `Connect()`. Add a mocked `Sock` implementation that returns a predefined data on reads and use it for a regression unit test for the bug fixed in https://github.com/bitcoin/bitcoin/pull/21407. ACKs for top commit: practicalswift: Tested ACK 40316a37cb02cf8a9a8b2cbd4d7153ffa57e7ec5 MarcoFalke: Concept ACK 40316a37cb jonatack: re-ACK 40316a37cb02cf8a9a8b2cbd4d7153ffa57e7ec5 reviewed `git range-diff 01bb3afb 23c861d 40316a3` and the new unit test commit, debug built, ran unit tests, ran bitcoind with an I2P service and network operation with seven I2P peers (2 in, 5 out) is looking nominal laanwj: Code review ACK 40316a37cb02cf8a9a8b2cbd4d7153ffa57e7ec5 Tree-SHA512: 7fc4f129849e16e0c7e16662d9f4d35dfcc369bb31450ee369a2b97bdca95285533bee7787983e881e5a3d248f912afb42b4a2299d5860ace7129b0b19623cc8
Diffstat (limited to 'src/netbase.cpp')
-rw-r--r--src/netbase.cpp59
1 files changed, 23 insertions, 36 deletions
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 49e455aa84..2980bdf459 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -537,12 +537,12 @@ static void LogConnectFailure(bool manual_connection, const char* fmt, const Arg
}
}
-bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection)
+bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nTimeout, bool manual_connection)
{
// Create a sockaddr from the specified service.
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
- if (hSocket == INVALID_SOCKET) {
+ if (sock.Get() == INVALID_SOCKET) {
LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
return false;
}
@@ -552,8 +552,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
}
// Connect to the addrConnect service on the hSocket socket.
- if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
- {
+ if (sock.Connect(reinterpret_cast<struct sockaddr*>(&sockaddr), len) == SOCKET_ERROR) {
int nErr = WSAGetLastError();
// WSAEINVAL is here because some legacy version of winsock uses it
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)
@@ -561,46 +560,34 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
// Connection didn't actually fail, but is being established
// asynchronously. Thus, use async I/O api (select/poll)
// synchronously to check for successful connection with a timeout.
-#ifdef USE_POLL
- struct pollfd pollfd = {};
- pollfd.fd = hSocket;
- pollfd.events = POLLIN | POLLOUT;
- int nRet = poll(&pollfd, 1, nTimeout);
-#else
- struct timeval timeout = MillisToTimeval(nTimeout);
- fd_set fdset;
- FD_ZERO(&fdset);
- FD_SET(hSocket, &fdset);
- int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
-#endif
- // Upon successful completion, both select and poll return the total
- // number of file descriptors that have been selected. A value of 0
- // indicates that the call timed out and no file descriptors have
- // been selected.
- if (nRet == 0)
- {
- LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
+ const Sock::Event requested = Sock::RECV | Sock::SEND;
+ Sock::Event occurred;
+ if (!sock.Wait(std::chrono::milliseconds{nTimeout}, requested, &occurred)) {
+ LogPrintf("wait for connect to %s failed: %s\n",
+ addrConnect.ToString(),
+ NetworkErrorString(WSAGetLastError()));
return false;
- }
- if (nRet == SOCKET_ERROR)
- {
- LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
+ } else if (occurred == 0) {
+ LogPrint(BCLog::NET, "connection attempt to %s timed out\n", addrConnect.ToString());
return false;
}
- // Even if the select/poll was successful, the connect might not
+ // Even if the wait was successful, the connect might not
// have been successful. The reason for this failure is hidden away
// in the SO_ERROR for the socket in modern systems. We read it into
- // nRet here.
- socklen_t nRetSize = sizeof(nRet);
- if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR)
- {
+ // sockerr here.
+ int sockerr;
+ socklen_t sockerr_len = sizeof(sockerr);
+ if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&sockerr, &sockerr_len) ==
+ SOCKET_ERROR) {
LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
return false;
}
- if (nRet != 0)
- {
- LogConnectFailure(manual_connection, "connect() to %s failed after select(): %s", addrConnect.ToString(), NetworkErrorString(nRet));
+ if (sockerr != 0) {
+ LogConnectFailure(manual_connection,
+ "connect() to %s failed after wait: %s",
+ addrConnect.ToString(),
+ NetworkErrorString(sockerr));
return false;
}
}
@@ -668,7 +655,7 @@ bool IsProxy(const CNetAddr &addr) {
bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed)
{
// first connect to proxy server
- if (!ConnectSocketDirectly(proxy.proxy, sock.Get(), nTimeout, true)) {
+ if (!ConnectSocketDirectly(proxy.proxy, sock, nTimeout, true)) {
outProxyConnectionFailed = true;
return false;
}