diff options
Diffstat (limited to 'src/rpc.cpp')
| -rw-r--r-- | src/rpc.cpp | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/rpc.cpp b/src/rpc.cpp index 23e25ef..df7ca05 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp | |||
| @@ -2596,6 +2596,18 @@ static void LocalAcceptFn(void*) | |||
| 2596 | break; | 2596 | break; |
| 2597 | continue; | 2597 | continue; |
| 2598 | } | 2598 | } |
| 2599 | // #6: let the OS probe a peer that has gone silent, so a half-open | ||
| 2600 | // session eventually errors out of recv and lands in the event | ||
| 2601 | // loop's existing reap path instead of sitting in gMiners forever. | ||
| 2602 | // This is a backstop, not the mechanism: the default cadence before | ||
| 2603 | // the first probe is hours on most stacks, so the idle timeout in | ||
| 2604 | // PoolEventLoop fires long before keepalive does. Miners arriving | ||
| 2605 | // via a relay ride a loopback socket pair whose remote transport is | ||
| 2606 | // the rendezvous socket owned by the tunnel pump threads; keepalive | ||
| 2607 | // cannot reach across that, which is part of why the idle timeout | ||
| 2608 | // exists. | ||
| 2609 | int keepalive = 1; | ||
| 2610 | setsockopt(c, SOL_SOCKET, SO_KEEPALIVE, (char*)&keepalive, sizeof(keepalive)); | ||
| 2599 | LogPrint("pool", "[pool] miner arrived via loopback -- pushing to event loop\n"); | 2611 | LogPrint("pool", "[pool] miner arrived via loopback -- pushing to event loop\n"); |
| 2600 | PushReady((btf_socket_t)c); | 2612 | PushReady((btf_socket_t)c); |
| 2601 | } | 2613 | } |
| @@ -2639,6 +2651,16 @@ static const int64 POOL_ACTIVE_WINDOW = 300; // a miner is "active" if it | |||
| 2639 | static const int64 POOL_UNAUTH_GRACE_SECS = 60; // a connection still not | 2651 | static const int64 POOL_UNAUTH_GRACE_SECS = 60; // a connection still not |
| 2640 | // authorized after this long is | 2652 | // authorized after this long is |
| 2641 | // idle, not merely starting up | 2653 | // idle, not merely starting up |
| 2654 | // #6: a Miner used to leave gMiners only when RecvLine reported a clean | ||
| 2655 | // disconnect. A half-open session (miner host died, NAT state expired, | ||
| 2656 | // cable pulled) sends no FIN and reports no error, so it sat in the table | ||
| 2657 | // forever -- authorize outpaced disconnect 2:1 on the live pool, and the | ||
| 2658 | // table grew toward MAX_POOL_MINERS, past which real miners are refused. | ||
| 2659 | // lastSeen is stamped on every complete line received; a miner that has | ||
| 2660 | // said nothing for this long is gone in every way that matters. Ten | ||
| 2661 | // minutes is far beyond the vardiff target (a share every 15s) and the | ||
| 2662 | // stall watchdog (45s), so no miner that is actually hashing comes close. | ||
| 2663 | static const int64 POOL_IDLE_TIMEOUT_SECS = 600; | ||
| 2642 | 2664 | ||
| 2643 | // Non-blocking recv: pull whatever bytes are available now into buf, then | 2665 | // Non-blocking recv: pull whatever bytes are available now into buf, then |
| 2644 | // return one complete line if one is ready. Three outcomes: | 2666 | // return one complete line if one is ready. Three outcomes: |
| @@ -4940,6 +4962,35 @@ static void PoolEventLoop() | |||
| 4940 | m->hashRate *= pow(0.5, (silent - grace) / expected); | 4962 | m->hashRate *= pow(0.5, (silent - grace) / expected); |
| 4941 | } | 4963 | } |
| 4942 | 4964 | ||
| 4965 | // 3.7. Idle reap (#6). Mirror the clean-disconnect path exactly -- | ||
| 4966 | // log, close, erase from gMiners via std::find, delete -- just with | ||
| 4967 | // a different reason. Shares the miner already earned stay in | ||
| 4968 | // roundShareCount, exactly as they do when a miner cleanly | ||
| 4969 | // disconnects mid-round. connectTime stands in for lastSeen on a | ||
| 4970 | // connection that never completed a line. Erasing inside the loop | ||
| 4971 | // above would invalidate the iteration, so collect then reap. | ||
| 4972 | { | ||
| 4973 | int64 now = GetTime(); | ||
| 4974 | std::vector<Miner*> idle; | ||
| 4975 | for (Miner* m : gMiners) { | ||
| 4976 | int64 last = (m->lastSeen > 0) ? m->lastSeen : m->connectTime; | ||
| 4977 | if (now - last > POOL_IDLE_TIMEOUT_SECS) | ||
| 4978 | idle.push_back(m); | ||
| 4979 | } | ||
| 4980 | for (Miner* m : idle) { | ||
| 4981 | LogPrint("worker", "[pool] dropping idle miner %s -- nothing" | ||
| 4982 | " received in over %llds (session shares: %llu," | ||
| 4983 | " round shares: %llu)\n", | ||
| 4984 | m->worker.empty() ? "(never authorized)" : m->worker.c_str(), | ||
| 4985 | (long long)POOL_IDLE_TIMEOUT_SECS, | ||
| 4986 | (unsigned long long)m->sessionShares, | ||
| 4987 | (unsigned long long)m->roundShares); | ||
| 4988 | sock_close(m->fd); | ||
| 4989 | gMiners.erase(std::find(gMiners.begin(), gMiners.end(), m)); | ||
| 4990 | delete m; | ||
| 4991 | } | ||
| 4992 | } | ||
| 4993 | |||
| 4943 | // 4. Select over miner sockets | 4994 | // 4. Select over miner sockets |
| 4944 | if (!gMiners.empty()) { | 4995 | if (!gMiners.empty()) { |
| 4945 | fd_set fds; FD_ZERO(&fds); | 4996 | fd_set fds; FD_ZERO(&fds); |
| @@ -4962,6 +5013,11 @@ static void PoolEventLoop() | |||
| 4962 | // terminate the whole node -- not just the pool. Every | 5013 | // terminate the whole node -- not just the pool. Every |
| 4963 | // line arrives from an unauthenticated socket. | 5014 | // line arrives from an unauthenticated socket. |
| 4964 | while (RecvLine(m->fd, m->readBuf, line, disc)) { | 5015 | while (RecvLine(m->fd, m->readBuf, line, disc)) { |
| 5016 | // Any complete line is proof of life (#6): authorize | ||
| 5017 | // and valid shares already stamp lastSeen themselves, | ||
| 5018 | // but a miner that only ever subscribes (or sends | ||
| 5019 | // unrecognised methods) must count as alive too. | ||
| 5020 | m->lastSeen = GetTime(); | ||
| 4965 | try { | 5021 | try { |
| 4966 | HandleLine(m, line, roundShareCount, | 5022 | HandleLine(m, line, roundShareCount, |
| 4967 | roundShareTotal, blocksFoundThisSession); | 5023 | roundShareTotal, blocksFoundThisSession); |