Requirement for #11227.
We'll need to create sockets and perform the actual connect in separate steps, so break them up.
#11227 adds an RAII wrapper around connection attempts, as a belt-and-suspenders in case a CloseSocket is missed.
566 | @@ -554,8 +567,6 @@ bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int 567 | if (!Socks5(strDest, (unsigned short)port, 0, hSocket)) 568 | return false; 569 | } 570 | - 571 | - hSocketRet = hSocket;
If socks negotiation fail then hSocket will not be INVALID_SOCKET which is a different behavior than before. This also indicates that there is a leak in master because hSocket is not freed?
Nice Catch! Force-pushed the missing CloseSocket()s.
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 18763d2..4b72826 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -561,11 +561,15 @@ bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int
ProxyCredentials random_auth;
static std::atomic_int counter(0);
random_auth.username = random_auth.password = strprintf("%i", counter++);
- if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
+ if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket)) {
+ CloseSocket(hSocket);
return false;
+ }
} else {
- if (!Socks5(strDest, (unsigned short)port, 0, hSocket))
+ if (!Socks5(strDest, (unsigned short)port, 0, hSocket)) {
+ CloseSocket(hSocket);
return false;
+ }
}
return true;
}
CloseSocket sets hSocket to INVALID_SOCKET so this LGTM. I wonder if you could just return CloseSocket(hSocket)?
CloseSocket's return value indicates whether the close succeeded or not, which would be true in this case. Not what we want :)
Ahhh yeah... now I win the most stupid comment award.
Hah, no worries. We'll call it even for pointing out my mistake here
I'm not yet familiar with P2P code to ACK. In any case see my comment below.
Rebased after #10663.
Also, changed from the last version: Rather than passing in a socket reference and returning a bool, CreateSocket() now returns a socket (which may be invalid) instead. That's much more straightforward, IMO, and matches the usage of socket().
451 | @@ -452,10 +452,8 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials 452 | return true; 453 | } 454 | 455 | -bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout) 456 | +SOCKET CreateSocket(const CService &addrConnect)
You need to change the return values values of all the "return false"s in here - INVALID_SOCKET is (currently) ~0, so we will pretend the socket creation succeeded.
Thanks, don't know how I missed those.
491 | + LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString()); 492 | + return false; 493 | + } 494 | + if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) { 495 | + LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString()); 496 | + CloseSocket(hSocket);
At the risk of making you redo a bunch of work, is it possible to const-ify the socket here and make the caller do the CloseSocket instead? Shits currently a maze and it'd be nice to clean it up sooner rather than try to follow it through the libevent changes.
Yes, that makes sense. Now that we don't have chained connect functions, it's much more clear what "the caller" means. The maze was only there because we had to close at all levels to be safe.
Will do.
Rebased and fixed the check against the connect() return value, which was already wrong, but doesn't really matter because it's always detected on first use anyway.
utACK f766175ebe4400561f60b75b0ede4015003bad8c
This gives me a new warning:
/.../bitcoin/src/netbase.cpp:449:17: warning: comparison of integers of different signs: 'SOCKET' (aka 'unsigned int') and 'int' [-Wsign-compare]
if (hSocket == -1)
~~~~~~~ ^ ~~
1 warning generated.
2095 | - 2096 | - 2097 | #ifndef WIN32 2098 | -#ifdef SO_NOSIGPIPE 2099 | - // Different way of disabling SIGPIPE on BSD 2100 | - setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
NOSIGPIPE handling moved to CreateSocket(addrBind)?
Yes, I think part of the goal is to get random socket flag-fiddling things out of net and into netbase, its kinda split between both right now. @theuni ?
Yep. If it's something we require for all sockets, imo it makes sense to do it in CreateSocket.
2104 | setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); 2105 | - // Disable Nagle's algorithm 2106 | - setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&nOne, sizeof(int)); 2107 | #else 2108 | setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int)); 2109 | - setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nOne, sizeof(int));
Where did this move? The only remaining reference to TCP_NODELAY I see is in SetSocketNoDelay, which is called on accepted sockets only.
Its also called in netbase.cpp in CreateSocket, so should be set for outbound and inbound connection sockets, though not the listen socket, but that makes sense.
It's set on the listen socket as well (which should pass it down to accepted sockets anyway), since BindListenPort now uses CreateSocket().
Also, check for the correct error during socket creation
We use select in ConnectSocketDirectly, so this check needs to happen before
that.
IsSelectableSocket will not be relevant after upcoming changes to remove select.
This allows const references to be passed around, making it clear where the
socket may and may not be invalidated.
@laanwj Yes, thanks. Due to our SOCKET wrappers, we need to compare against INVALID_SOCKET rather than SOCKET_ERROR. Pushed the squashed change as it was very simple (it's actually just reverting a change from this PR, it was already correct in master).
Diff from before: git diff f766175ebe44..3830b6e06591
diff --git a/src/netbase.cpp b/src/netbase.cpp
index ba2c988..74ea6b1 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -446,7 +446,7 @@ SOCKET CreateSocket(const CService &addrConnect)
}
SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
- if (hSocket == SOCKET_ERROR)
+ if (hSocket == INVALID_SOCKET)
return INVALID_SOCKET;
if (!IsSelectableSocket(hSocket)) {
utACK 3830b6e0659106458c941029f5b2e789e3cb38a3