0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-03-05 14:06:27 -05:00

net: change ConnectSocketDirectly() to take a Sock argument

Change `ConnectSocketDirectly()` to take a `Sock` argument instead of a
bare `SOCKET`. With this, use the `Sock`'s (possibly mocked) methods
`Connect()`, `Wait()` and `GetSockOpt()` instead of calling the OS
functions directly.
This commit is contained in:
Vasil Dimov 2021-03-05 17:01:59 +01:00
parent b5861100f8
commit 82d360b5a8
No known key found for this signature in database
GPG key ID: 54DF06F64B55CBBF
4 changed files with 27 additions and 40 deletions

View file

@ -279,7 +279,7 @@ Sock Session::Hello() const
throw std::runtime_error("Cannot create socket"); throw std::runtime_error("Cannot create socket");
} }
if (!ConnectSocketDirectly(m_control_host, sock->Get(), nConnectTimeout, true)) { if (!ConnectSocketDirectly(m_control_host, *sock, nConnectTimeout, true)) {
throw std::runtime_error(strprintf("Cannot connect to %s", m_control_host.ToString())); throw std::runtime_error(strprintf("Cannot connect to %s", m_control_host.ToString()));
} }

View file

@ -448,7 +448,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (!sock) { if (!sock) {
return nullptr; return nullptr;
} }
connected = ConnectSocketDirectly(addrConnect, sock->Get(), nConnectTimeout, connected = ConnectSocketDirectly(addrConnect, *sock, nConnectTimeout,
conn_type == ConnectionType::MANUAL); conn_type == ConnectionType::MANUAL);
} }
if (!proxyConnectionFailed) { if (!proxyConnectionFailed) {

View file

@ -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. // Create a sockaddr from the specified service.
struct sockaddr_storage sockaddr; struct sockaddr_storage sockaddr;
socklen_t len = sizeof(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()); LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
return false; return false;
} }
@ -552,8 +552,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
} }
// Connect to the addrConnect service on the hSocket socket. // 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(); int nErr = WSAGetLastError();
// WSAEINVAL is here because some legacy version of winsock uses it // WSAEINVAL is here because some legacy version of winsock uses it
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) 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 // Connection didn't actually fail, but is being established
// asynchronously. Thus, use async I/O api (select/poll) // asynchronously. Thus, use async I/O api (select/poll)
// synchronously to check for successful connection with a timeout. // synchronously to check for successful connection with a timeout.
#ifdef USE_POLL const Sock::Event requested = Sock::RECV | Sock::SEND;
struct pollfd pollfd = {}; Sock::Event occurred;
pollfd.fd = hSocket; if (!sock.Wait(std::chrono::milliseconds{nTimeout}, requested, &occurred)) {
pollfd.events = POLLIN | POLLOUT; LogPrintf("wait for connect to %s failed: %s\n",
int nRet = poll(&pollfd, 1, nTimeout); addrConnect.ToString(),
#else NetworkErrorString(WSAGetLastError()));
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());
return false; return false;
} } else if (occurred == 0) {
if (nRet == SOCKET_ERROR) LogPrint(BCLog::NET, "connection attempt to %s timed out\n", addrConnect.ToString());
{
LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
return false; 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 // 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 // in the SO_ERROR for the socket in modern systems. We read it into
// nRet here. // sockerr here.
socklen_t nRetSize = sizeof(nRet); int sockerr;
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR) 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())); LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
return false; return false;
} }
if (nRet != 0) if (sockerr != 0) {
{ LogConnectFailure(manual_connection,
LogConnectFailure(manual_connection, "connect() to %s failed after select(): %s", addrConnect.ToString(), NetworkErrorString(nRet)); "connect() to %s failed after wait: %s",
addrConnect.ToString(),
NetworkErrorString(sockerr));
return false; return false;
} }
} }
@ -668,7 +655,7 @@ bool IsProxy(const CNetAddr &addr) {
bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed) bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed)
{ {
// first connect to proxy server // first connect to proxy server
if (!ConnectSocketDirectly(proxy.proxy, sock.Get(), nTimeout, true)) { if (!ConnectSocketDirectly(proxy.proxy, sock, nTimeout, true)) {
outProxyConnectionFailed = true; outProxyConnectionFailed = true;
return false; return false;
} }

View file

@ -194,7 +194,7 @@ extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock;
* Try to connect to the specified service on the specified socket. * Try to connect to the specified service on the specified socket.
* *
* @param addrConnect The service to which to connect. * @param addrConnect The service to which to connect.
* @param hSocket The socket on which to connect. * @param sock The socket on which to connect.
* @param nTimeout Wait this many milliseconds for the connection to be * @param nTimeout Wait this many milliseconds for the connection to be
* established. * established.
* @param manual_connection Whether or not the connection was manually requested * @param manual_connection Whether or not the connection was manually requested
@ -202,7 +202,7 @@ extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock;
* *
* @returns Whether or not a connection was successfully made. * @returns Whether or not a connection was successfully made.
*/ */
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);
/** /**
* Connect to a specified destination service through a SOCKS5 proxy by first * Connect to a specified destination service through a SOCKS5 proxy by first