diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/net.cpp | 15 | ||||
| -rw-r--r-- | src/net.h | 18 |
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); |
| @@ -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 | ||
| 647 | private: | 663 | private: |