upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/sockcount.h
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-08-01 21:31:33 -0300
committerGitHub <noreply@github.com>2026-08-01 21:31:33 -0300
commit5358e2396ca6cb371400f685181ef420dcf12382 (patch)
tree6e5a363deafc74d315ad60857b8617d674b763f5 /src/sockcount.h
parentca0b6d0c4a3520a87037ba72bb1f1ee10eb504dc (diff)
diag: catch a handle handed out while a site still claims it (#101)
A live node reported one close failing with 10038 (WSAENOTSOCK) at the tunnel's pump end. It leaks nothing; what it says is that a site's bookkeeping and its sockets disagree about ownership -- and Windows reissues a handle number only after its last close, so a site whose bookkeeping outlives its socket will eventually close a number that belongs to a live connection. BtfSocketTag now counts a handle arriving while another site still claims it, which names the site to go and read.
Diffstat (limited to 'src/sockcount.h')
-rw-r--r--src/sockcount.h17
1 files changed, 15 insertions, 2 deletions
diff --git a/src/sockcount.h b/src/sockcount.h
index ef99414..96b6efb 100644
--- a/src/sockcount.h
+++ b/src/sockcount.h
@@ -79,10 +79,18 @@ struct BtfSockAccount
79 // leak -- see the note at the top of this file -- but it is the one number 79 // leak -- see the note at the top of this file -- but it is the one number
80 // that would say so if it ever became the leak. 80 // that would say so if it ever became the leak.
81 std::map<int, long long> mapCloseErr[SOCK_SITES]; 81 std::map<int, long long> mapCloseErr[SOCK_SITES];
82 // A handle number arriving from socket()/accept() while some site still
83 // claims it. The operating system only hands a number back out after the
84 // last close of it, so a collision means somebody's bookkeeping outlived
85 // its socket -- and whoever still believes they own that number will
86 // eventually close it, taking down a connection that now belongs to
87 // someone else. Counted against the site that was still holding it, which
88 // is the one to go and read.
89 long long nCollided[SOCK_SITES];
82 long long nClosedUntagged; 90 long long nClosedUntagged;
83 BtfSockAccount() : nClosedUntagged(0) 91 BtfSockAccount() : nClosedUntagged(0)
84 { 92 {
85 for (int i = 0; i < SOCK_SITES; i++) { nOpened[i] = 0; nClosed[i] = 0; nCloseFailed[i] = 0; } 93 for (int i = 0; i < SOCK_SITES; i++) { nOpened[i] = 0; nClosed[i] = 0; nCloseFailed[i] = 0; nCollided[i] = 0; }
86 } 94 }
87}; 95};
88 96
@@ -102,6 +110,9 @@ inline SOCKET BtfSocketTag(SOCKET hSocket, int nSite)
102 return hSocket; 110 return hSocket;
103 BtfSockAccount& a = BtfSockAccounting(); 111 BtfSockAccount& a = BtfSockAccounting();
104 std::lock_guard<std::mutex> lock(a.mtx); 112 std::lock_guard<std::mutex> lock(a.mtx);
113 std::map<SOCKET, int>::iterator mi = a.mapSite.find(hSocket);
114 if (mi != a.mapSite.end())
115 a.nCollided[mi->second]++;
105 a.mapSite[hSocket] = nSite; 116 a.mapSite[hSocket] = nSite;
106 a.nOpened[nSite]++; 117 a.nOpened[nSite]++;
107 return hSocket; 118 return hSocket;
@@ -151,7 +162,8 @@ inline int BtfCloseSocket(SOCKET hSocket)
151 162
152// Copy the counters out. Formatting lives in net.cpp, which has strprintf -- 163// Copy the counters out. Formatting lives in net.cpp, which has strprintf --
153// and which the relay build does not compile. 164// and which the relay build does not compile.
154inline void BtfSockSnapshot(long long* pOpened, long long* pClosed, long long* pFailed, long long* pUntagged) 165inline void BtfSockSnapshot(long long* pOpened, long long* pClosed, long long* pFailed,
166 long long* pCollided, long long* pUntagged)
155{ 167{
156 BtfSockAccount& a = BtfSockAccounting(); 168 BtfSockAccount& a = BtfSockAccounting();
157 std::lock_guard<std::mutex> lock(a.mtx); 169 std::lock_guard<std::mutex> lock(a.mtx);
@@ -160,6 +172,7 @@ inline void BtfSockSnapshot(long long* pOpened, long long* pClosed, long long* p
160 pOpened[i] = a.nOpened[i]; 172 pOpened[i] = a.nOpened[i];
161 pClosed[i] = a.nClosed[i]; 173 pClosed[i] = a.nClosed[i];
162 pFailed[i] = a.nCloseFailed[i]; 174 pFailed[i] = a.nCloseFailed[i];
175 pCollided[i] = a.nCollided[i];
163 } 176 }
164 *pUntagged = a.nClosedUntagged; 177 *pUntagged = a.nClosedUntagged;
165} 178}