upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/rpc.cpp
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-09-01 14:41:33 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-09-01 14:41:33 +0000
commit12752bc0f9441ef9f929ee652eeb5d92b9dda4a5 (patch)
tree8d37b2cd119078c9e1e84327211b213a6b4b0af6 /src/rpc.cpp
parent8e0d97f7957e570c2e26d79e66efe0cc064cee4b (diff)
pool: refuse a miner the select() loop cannot represent
The operator event loop still builds an fd_set by hand (#26), and FD_SET on a descriptor the set cannot represent is undefined -- it writes past the bitmap. MAX_POOL_MINERS caps the miner list at 1000, but that is a count, and a count does not bound descriptor values: a Miner is removed only on clean disconnect, so half-open sessions hold their fds while the OS keeps issuing higher ones. Refuse the connection instead, and refuse on the limit that actually applies. On POSIX that is the descriptor value against FD_SETSIZE. On Windows an fd_set is a counted array of SOCKET handles whose values are arbitrary -- often large from the first accept -- so comparing a handle against FD_SETSIZE there would reject nearly every miner; the bound is how many sockets are held. This is a behaviour change: a pool at the limit now turns miners away with a log line rather than corrupting memory quietly. The real fix is poll/epoll, which #26 tracks.
Diffstat (limited to 'src/rpc.cpp')
-rw-r--r--src/rpc.cpp25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/rpc.cpp b/src/rpc.cpp
index 4ff09b9..a4b53ca 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -4697,6 +4697,31 @@ static void PoolEventLoop()
4697 sock_close(fd); 4697 sock_close(fd);
4698 continue; 4698 continue;
4699 } 4699 }
4700 // #26: select() + FD_SET goes undefined once we exceed what an
4701 // fd_set can carry, and MAX_POOL_MINERS (1000) alone does not
4702 // prevent it -- a Miner is only removed on clean disconnect, so
4703 // half-open zombies accumulate and the OS can hand out fds past
4704 // the limit long before the count reaches 1000. Refuse rather
4705 // than corrupt the fd_set. Which limit applies is platform
4706 // specific: POSIX bounds the descriptor value, Windows the
4707 // number of SOCKET handles an fd_set can hold.
4708#ifndef _WIN32
4709 if ((int)fd >= (int)FD_SETSIZE) {
4710 LogPrint("worker", "[pool] refusing miner fd=%d -- at/over"
4711 " FD_SETSIZE=%d, select() would be undefined (#26)\n",
4712 (int)fd, (int)FD_SETSIZE);
4713 sock_close(fd);
4714 continue;
4715 }
4716#else
4717 if (gMiners.size() >= (size_t)FD_SETSIZE) {
4718 LogPrint("worker", "[pool] refusing miner -- %zu sockets held,"
4719 " an fd_set carries at most FD_SETSIZE=%d (#26)\n",
4720 gMiners.size(), (int)FD_SETSIZE);
4721 sock_close(fd);
4722 continue;
4723 }
4724#endif
4700 gMiners.push_back(new Miner(fd)); 4725 gMiners.push_back(new Miner(fd));
4701 LogPrint("worker", "[pool] miner fd=%d entered event loop" 4726 LogPrint("worker", "[pool] miner fd=%d entered event loop"
4702 " -- awaiting subscribe/authorize\n", (int)fd); 4727 " -- awaiting subscribe/authorize\n", (int)fd);