upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/net.cpp15
-rw-r--r--src/net.h18
2 files changed, 32 insertions, 1 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);
diff --git a/src/net.h b/src/net.h
index 314c709..1c0c24e 100644
--- a/src/net.h
+++ b/src/net.h
@@ -638,10 +638,26 @@ public:
638 PushMessage("version", VERSION, nLocalServices, nTime, addr, nBestHeight); 638 PushMessage("version", VERSION, nLocalServices, nTime, addr, nBestHeight);
639 } 639 }
640 640
641 // Disconnect() closes the socket and sets this to INVALID_SOCKET, so by the
642 // time a node is deleted there is normally nothing left to do here. It used
643 // not to: Disconnect() closed the handle and left the number in place, and
644 // this destructor closed that same number a second time -- with a raw
645 // closesocket() that the socket accounting never saw, so neither the double
646 // close nor the stale claim showed up in any report.
647 //
648 // A double close is not a harmless no-op. Between the two, the operating
649 // system is free to hand that number to a new socket -- this node opens
650 // hundreds a minute -- and the second close then takes down a connection
651 // that belongs to somebody else, which the log can only report as a peer
652 // vanishing for no reason. `dropping node: its socket is no longer valid`
653 // is what that looks like from the outside.
641 ~CNode() 654 ~CNode()
642 { 655 {
643 if (hSocket != INVALID_SOCKET) 656 if (hSocket != INVALID_SOCKET)
644 closesocket(hSocket); 657 {
658 BtfCloseSocket(hSocket);
659 hSocket = INVALID_SOCKET;
660 }
645 } 661 }
646 662
647private: 663private: