upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-08-01 21:31:58 -0300
committerGitHub <noreply@github.com>2026-08-01 21:31:58 -0300
commitfc071066c9de259795a210e449b364ac126416ad (patch)
treee9f9b98f12f9eae51ed7f91b82036bf53207429b /src/net.cpp
parent5358e2396ca6cb371400f685181ef420dcf12382 (diff)
net: stop closing a peer's socket twice (#103)
CNode::Disconnect() closed the socket and left the handle number in the object; ~CNode() then closed it again with a raw closesocket() the accounting never saw. There is no assignment of INVALID_SOCKET to CNode::hSocket anywhere in this tree, so the destructor's guard never fired. Between the two closes the OS can reissue that number, and the second close then takes down somebody else's connection. The same omission left a closed handle in the select() set, which fails every iteration and drives the recovery path that prints 'dropping node: its socket is no longer valid'. Measured A/B on the real network at matched socket volume: unpatched 552 sockets, 4 closes failing with 10038, 741 invalid-socket drops (all one peer), 11 peers held; patched 547 sockets, 0, 0, and 21 peers held. No protocol change.
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp15
1 files changed, 15 insertions, 0 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 3af0189..7091981 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1030,7 +1030,12 @@ void CNode::Disconnect()
1030{ 1030{
1031 LogPrint("net", "disconnecting node %s\n", addr.ToString().c_str()); 1031 LogPrint("net", "disconnecting node %s\n", addr.ToString().c_str());
1032 1032
1033 // Invalidate before anything else can look at it. This used to close the
1034 // socket and leave the handle number sitting in the object, so ~CNode
1035 // closed it a second time and the select loop kept arming it in the
1036 // meantime. See the note on ~CNode in net.h.
1033 BtfCloseSocket(hSocket); 1037 BtfCloseSocket(hSocket);
1038 hSocket = INVALID_SOCKET;
1034 1039
1035 // All of a nodes broadcasts and subscriptions are automatically torn down 1040 // All of a nodes broadcasts and subscriptions are automatically torn down
1036 // when it goes down, so a node has to stay up to keep its broadcast going. 1041 // when it goes down, so a node has to stay up to keep its broadcast going.
@@ -1210,6 +1215,11 @@ void ThreadSocketHandler2(void* parg)
1210 { 1215 {
1211 if (nWatched >= FD_SETSIZE) 1216 if (nWatched >= FD_SETSIZE)
1212 break; 1217 break;
1218 // A disconnected node stays in vNodes until its references go.
1219 // Arming its closed handle asks select() to watch a number the
1220 // operating system may already have given to somebody else.
1221 if (pnode->hSocket == INVALID_SOCKET)
1222 continue;
1213 FD_SET(pnode->hSocket, &fdsetRecv); 1223 FD_SET(pnode->hSocket, &fdsetRecv);
1214 nWatched++; 1224 nWatched++;
1215 hSocketMax = max(hSocketMax, pnode->hSocket); 1225 hSocketMax = max(hSocketMax, pnode->hSocket);
@@ -1272,6 +1282,11 @@ void ThreadSocketHandler2(void* parg)
1272 { 1282 {
1273 foreach(CNode* pnode, vNodes) 1283 foreach(CNode* pnode, vNodes)
1274 { 1284 {
1285 // Already disconnected: its handle is gone on purpose, and
1286 // reporting it here would name the wrong node for a select()
1287 // failure it did not cause.
1288 if (pnode->hSocket == INVALID_SOCKET)
1289 continue;
1275 int nType = 0; 1290 int nType = 0;
1276#ifdef _WIN32 1291#ifdef _WIN32
1277 int nTypeLen = sizeof(nType); 1292 int nTypeLen = sizeof(nType);