diff options
| author | Bitflash <btf01@proton.me> | 2026-08-01 21:31:33 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-01 21:31:33 -0300 |
| commit | 5358e2396ca6cb371400f685181ef420dcf12382 (patch) | |
| tree | 6e5a363deafc74d315ad60857b8617d674b763f5 /src/sockcount.h | |
| parent | ca0b6d0c4a3520a87037ba72bb1f1ee10eb504dc (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.h | 17 |
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. |
| 154 | inline void BtfSockSnapshot(long long* pOpened, long long* pClosed, long long* pFailed, long long* pUntagged) | 165 | inline 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 | } |