- commit: cleanup use of CloseSocket() -- call CloseSocket() before printing any text (ensure consistent usage in the code), exception is when using NetworkErrorString()
- commit: add CSocket (RAII class that provides access to a SOCKET)
SOCKET changes (CSocket RAII etc.) #4348
pull Diapolo wants to merge 2 commits into bitcoin:master from Diapolo:net_cleanup_1 changing 4 files +125 −45-
Diapolo commented at 2:19 PM on June 16, 2014: none
-
in src/net.cpp:None in baea8b9aa3 outdated
509 | @@ -510,13 +510,10 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) 510 | 511 | void CNode::CloseSocketDisconnect() 512 | { 513 | + LogPrint("net", "disconnecting node %s\n", addrName); 514 | + 515 | fDisconnect = true; 516 | - if (hSocket != INVALID_SOCKET)
laanwj commented at 2:18 PM on June 17, 2014:Don't remove this check! hSocket can be INVALID_SOCKET if there is currently no connection open, in which case no closing needs to be done either.
Diapolo commented at 2:22 PM on June 17, 2014:That check could then perhaps be rewritten to?
<pre> if (closesocket(hSocket) != WSAENOTSOCK) LogPrint("net", "disconnecting node %s\n", addrName); </pre>
laanwj commented at 2:31 PM on June 17, 2014:That would work. But I like the previous, explicit check better. It's just more clear "close the socket when we're connected" versus "try closing and log a message if it fails".
in src/net.cpp:None in baea8b9aa3 outdated
515 | fDisconnect = true; 516 | - if (hSocket != INVALID_SOCKET) 517 | - { 518 | - LogPrint("net", "disconnecting node %s\n", addrName); 519 | - closesocket(hSocket); 520 | - hSocket = INVALID_SOCKET;
laanwj commented at 2:19 PM on June 17, 2014:This hSocket = INVALID_SOCKET is used to mark the connection as closed, don't remove it.
Diapolo commented at 2:20 PM on June 17, 2014:closesocket(hSocket);does exactly that...
laanwj commented at 2:29 PM on June 17, 2014:WTF?!? closesocket(x) changes the value of x? That's terribly unexpected. I don't like that at all.
Diapolo commented at 2:32 PM on June 17, 2014:If you like or not, that IS the case for all calls to the function currently... we use closesocket() as a wrapper for the os specific ones and added some things. What would you suggest doing? IMHO it's a lot of duplication if we want to check everytime if a socket has state INVALID_SOCKET before calling our closesocket() function, no?
laanwj commented at 2:50 PM on June 17, 2014:I prefer a bit of duplication over a closesocket() call that does something else than the WIN32 API specifies.
Diapolo commented at 2:53 PM on June 17, 2014:I'm convinced, but AFAIK there are only the 2 lines in CNode that check for INVALID_SOCKET before closing, is this still correct after cleaning up closesocket() (which I'll gladly do)?
laanwj commented at 4:22 PM on June 17, 2014:I think the goal should be to make closesocket() emulate the WIN32 closesocket on Linux, and don't redefine it when WIN32 at all. As we don't define the function on WIN32 anymore we can rename the function from
myclosesockettoclosesocket.According to http://msdn.microsoft.com/en-us/library/windows/desktop/ms737582%28v=vs.85%29.aspx this behavior is to return WSAENOTSOCK when an invalid socket handle is passed. So we can keep the check for INVALID_SOCKET inside the function, to emulate that behavior on Linux.
Also removie the assignment of the output parameter
hSocket = INVALID_SOCKETfrom the function - and make sure it happens everywhere where needed outside the function.in src/net.h:None in baea8b9aa3 outdated
338 | @@ -340,11 +339,7 @@ class CNode 339 | 340 | ~CNode() 341 | { 342 | - if (hSocket != INVALID_SOCKET)
laanwj commented at 2:24 PM on June 17, 2014:Again, keep this check. hSocket can be INVALID_SOCKET, in which case closesocket should not be called on it.
Diapolo commented at 2:29 PM on June 17, 2014:See my comment above, that check IS done in
closesocket(hSocket);we did a redefinition of that function and added some nice checks to it (IMHO).
in src/net.cpp:None in baea8b9aa3 outdated
1628 | @@ -1632,6 +1629,7 @@ bool BindListenPort(const CService &addrBind, string& strError) 1629 | 1630 | if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) 1631 | { 1632 | + closesocket(hListenSocket);
laanwj commented at 2:26 PM on June 17, 2014:Good catch, this was a potential (one-time) socket leak.
laanwj commented at 2:37 PM on June 17, 2014: memberIMHO we should get rid of myclosesocket and the crazy construction in compat.h and make it a pure compatibility wrapper (only defined on unix), without extra functionality and checks. Redefining an existing API function with unexpected behavior in the guise of a compatibility wrapper is just too crazy.
in src/compat.h:None in 651cd771c7 outdated
58 | @@ -59,19 +59,17 @@ typedef u_int SOCKET; 59 | #define SOCKET_ERROR -1 60 | #endif 61 | 62 | -inline int myclosesocket(SOCKET& hSocket) 63 | +#ifndef WIN32 64 | +// Emulate WIN32 closesocket() behaviour for other OSes 65 | +inline int closesocket(SOCKET& hSocket)
laanwj commented at 1:14 PM on June 18, 2014:this can be just
SOCKET hSocketnow like a normal parameter, no need for it to be a reference anymore :)
Diapolo commented at 1:20 PM on June 18, 2014:Isn't a reference better because we then use no extra copy?
laanwj commented at 1:30 PM on June 18, 2014:For large types such as structures and objects that can be true (but then we'd use a const reference). For small types like integers and handles it's only overhead. On 64-bit architectures a pointer to an integer is larger than the integer itself.
Diapolo commented at 1:09 AM on June 22, 2014:Understood and will be changed :).
laanwj commented at 1:16 PM on June 18, 2014: memberThe hard part now will be checking all existing closesocket() calls and determining if they should be followed by
hSocket = INVALID_SOCKET.Diapolo commented at 1:19 PM on June 18, 2014: noneIf you mind looking at #3461 and we can get that merged, it would remove quite a few of them ;). Also the closesocket() during network init for listen sockets should be easy, which is also true for socks5(). Not sure if there are that many left then...
laanwj commented at 10:37 AM on June 21, 2014: memberHmm, thinking further about this, another way would be to define a CSocket class with move semantics (and a method
Close(), at least, to force closing), and use that instead of passing raw file handles around. This could avoid socket leaks completely by using RAII. It's somewhat more complex and involved, but as we have to change every call site of closesocket() anyway it may be something to think about.sipa commented at 8:25 PM on June 21, 2014: memberI like the idea of a RAII wrapper for sockets.
Diapolo commented at 1:08 AM on June 22, 2014: none@sipa @laanwj I started implementing CSocket, can you give me some feedback and help to see if I'm on the right track please :). See: https://github.com/Diapolo/bitcoin/commit/1c5873e0ba4cc466c11e5a0dbc779d78b5662075
Edit: The new class is currently only used for listening sockets to show the current implementation state. Edit 2: Also it seems that code is currently not working ^^... seems to be too late... a look from some experienced dev would be great anyway.
Diapolo commented at 11:23 AM on June 22, 2014: none@laanwj @sipa Alright, I was able to fix the problems from last night. During BOOST_FOREACH processing existing sockets were copied/used and got closed by the destructor after the loop ^^. This is now fixed by a new flag
fCloseOnDestructin the CSocket class. I need some initial feedback now :).Commit is at: https://github.com/Diapolo/bitcoin/commit/079dab40b8e2d88786d2fd0bef9025afa5719b9d
Diapolo commented at 7:21 AM on June 24, 2014: noneDid anyone take a look at the RAII class yet? I don't want to continue, if it's bugged or it's implementation is not correct.
jgarzik commented at 2:35 PM on June 26, 2014: contributorIf we are going to have an RAII CSocket, we might as well add classes Connection, SocketServer, IOEngine.
Then we can ditch boost::asio for the RPC server, and use that instead.
laanwj commented at 2:48 PM on June 26, 2014: member@diapolo No, haven't got around to it. @jgarzik I disagree we should be spending time writing and maintaining our own asynchronous I/O library. It's not like we're innovating anything here. If we want to ditch boost::asio we should switch to something which is well-known to be robust and high-performance like libevent (or derivatives).
jgarzik commented at 2:53 PM on June 26, 2014: contributorIf we don't want our own async I/O lib, then adding RAII CSocket is moving in the wrong direction. boost::asio already has portable socket classes and much much more.
laanwj commented at 3:07 PM on June 26, 2014: memberWell - in principle I agree that using the same network library everywhere would be a good thing. But I know at least @gmaxwell doesn't like boost::asio and doesn't want to switch the P2P code to it.
So at some point we have to make a decision about what async networking library to use. Not necessarily now.
The point here was to get rid of the strange compat.h behavior - a compatibility wrapper should provide compatibility not add functionality. I then thought, if we're changing socket closing behavior we might as well make it RAII. But if that's a stap too far, fair enough...
Diapolo commented at 8:11 AM on July 1, 2014: none@laanwj Thinking about
always call closesocket() before printing any text (ensure consistent usage in the code)... closesocket() can fail, which would likely interact with ourLogPrint()... so I guess it's a good idea to first log and close the socket afterwards... but then everywhere in our code.laanwj referenced this in commit ca67fc7d95 on Jul 10, 2014laanwj referenced this in commit 48e40f2492 on Jul 14, 2014Diapolo commented at 3:52 PM on July 15, 2014: noneDid anyone look at the RAII wrapper yet or is this considered unhelpful in the end? Edit: I know this needs a rebase now...
laanwj commented at 9:38 AM on July 16, 2014: member@Diapolo I've looked at it and it looks okay, but as @jgarzik says it may be too much if we intend to move to some other async networking library for P2P. Although it is clearly the way forward - from another async networking library we'd expect nothing less - right now it may brings subtle new bugs that have to be debugged. So I prefer the more trivial change in #4504 for now.
laanwj referenced this in commit 43f510d37d on Jul 17, 201456e2dc2cfecleanup use of CloseSocket()
- call CloseSocket() before printing any text (ensure consistent usage in the code), exception is when using NetworkErrorString()
Diapolo renamed this:extend and cleanup use of closesocket()
SOCKET changes (CSocket RAII etc.)
on Jul 21, 2014Diapolo commented at 12:58 PM on July 21, 2014: none@laanwj I reworked and rethought this, there is no need to try to emulate WIN32
closesocket()behaviour for non-WIN32, asclose()gives errorEBADF - fd isn't a valid open file descriptor., which we typedef asWSAENOTSOCKin compat.h anyway ;). So they behave the same already.add CSocket (RAII class that provides access to a SOCKET) 684bec2f41jgarzik commented at 1:01 PM on July 21, 2014: contributorCSocket seems to add never-used methods and flags.
Diapolo commented at 1:11 PM on July 21, 2014: none@jgarzik Right, the ones who are unused are
void SetCloseOnDestruct(bool fFlag);andvoid SetWhitelisted(bool fFlag);and I mentioned that in a comment in the source. Also CSocket is currently ONLY used for listen sockets, because I didn't want to change the whole source, before anyone gave some feedback to my implementation.BitcoinPullTester commented at 1:31 PM on July 21, 2014: noneAutomatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/p4348_684bec2f41d0963fe24cf55cd397b962a25529cf/ for binaries and test log. This test script verifies pulls every time they are updated. It, however, dies sometimes and fails to test properly. If you are waiting on a test, please check timestamps to verify that the test.log is moving at http://jenkins.bluematt.me/pull-tester/current/ Contact BlueMatt on freenode if something looks broken.
kazcw commented at 5:17 PM on July 21, 2014: contributorThe move semantics seem important. Right now you can copy or assign a socket and have two sockets using the same handle; then if one goes out of scope or is
Close()ed the other will have its underlying socket closed withoutCloseSocketsettinghSockettoINVALID_SOCKET, so it still returnsIsValid()==true. With cloning disallowed,fCloseOnDestructshouldn't be necessary.Putting the "whitelisted" flag in what would otherwise be a general RAII socket wrapper seems odd. Why not keep the
ListenSocketstruct, and just change it from using a handle to a CSocket?Having the
Get()method is no different from just making thehSocketa public member. I suggest either adding wrappers for the functions that take sockets (non-memberfriendfunctions could do theFD_SEToperations), or if CSocket is to be a struct with a destructor, making it look like a struct with a destructor.kazcw commented at 5:12 PM on July 25, 2014: contributorTo prevent copying, you can declare a private copy constructor with no implementation.
vhListenSocket would need to be a vector of pointers.
laanwj added the label P2P on Jul 31, 2014laanwj commented at 3:40 PM on August 4, 2014: memberAs said before, I deem the RAII changes too risky for what it would bring and am not going to merge it, sorry.
This would make sense as part of a change that wraps all networking behavior in proper classes, but if we make such a high-impact change to networking we should consider switching to an existing high-performance async networking library instead of mucking about with our own.
Something to consider in the future, but right now there are much more pressing things.
laanwj closed this on Aug 4, 2014Diapolo deleted the branch on Aug 5, 2014MathyV referenced this in commit 05ea249faa on Nov 24, 2014reddink referenced this in commit b5a0c6bf9d on May 27, 2020MarcoFalke locked this on Sep 8, 2021
github-metadata-mirror
This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-13 18:15 UTC
This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me