diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-02 09:03:01 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-02 09:03:01 +0000 |
| commit | 7c70eb4498e88725241493033edfe89554ff1b18 (patch) | |
| tree | a053678bf029d17c3a0b193fbaaf1abaf3778aff /src | |
| parent | e4f898c4a6b9900553c64b9804889b5fdae3e55f (diff) | |
tunnel: report which stage failed instead of guessing the cause
Diffstat (limited to 'src')
| -rw-r--r-- | src/btfrv.cpp | 16 | ||||
| -rw-r--r-- | src/btfrv.h | 19 | ||||
| -rw-r--r-- | src/btftunnel.cpp | 37 | ||||
| -rw-r--r-- | src/btftunnel.h | 25 | ||||
| -rw-r--r-- | src/main.cpp | 11 |
5 files changed, 93 insertions, 15 deletions
diff --git a/src/btfrv.cpp b/src/btfrv.cpp index 133eb89..864fe3d 100644 --- a/src/btfrv.cpp +++ b/src/btfrv.cpp | |||
| @@ -334,17 +334,29 @@ bool RvServiceWaitPaired(RvSocket s, int nTimeoutSecs) | |||
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | RvSocket RvClientConnect(const char* relay_host, unsigned short port, | 336 | RvSocket RvClientConnect(const char* relay_host, unsigned short port, |
| 337 | const unsigned char target_pubkey[32]) | 337 | const unsigned char target_pubkey[32], |
| 338 | RvClientFail* pFail) | ||
| 338 | { | 339 | { |
| 340 | if (pFail) *pFail = RVC_FAIL_DIAL; | ||
| 339 | if (!RvInit()) return RV_INVALID; | 341 | if (!RvInit()) return RV_INVALID; |
| 340 | SOCKET s = ConnectTo(relay_host, port); | 342 | SOCKET s = ConnectTo(relay_host, port); |
| 341 | if (s == INVALID_SOCKET) return RV_INVALID; | 343 | if (s == INVALID_SOCKET) return RV_INVALID; |
| 344 | if (pFail) *pFail = RVC_FAIL_PAIR; | ||
| 342 | unsigned char hdr[33]; | 345 | unsigned char hdr[33]; |
| 343 | hdr[0] = (unsigned char)'C'; | 346 | hdr[0] = (unsigned char)'C'; |
| 344 | memcpy(hdr + 1, target_pubkey, 32); | 347 | memcpy(hdr + 1, target_pubkey, 32); |
| 345 | if (!WriteN(s, hdr, 33)) { CLOSESOCK(s); return RV_INVALID; } | 348 | if (!WriteN(s, hdr, 33)) { CLOSESOCK(s); return RV_INVALID; } |
| 346 | unsigned char paired = 0; | 349 | unsigned char paired = 0; |
| 347 | if (!ReadN(s, &paired, 1) || paired != 0x01) { CLOSESOCK(s); return RV_INVALID; } | 350 | if (!ReadN(s, &paired, 1)) { CLOSESOCK(s); return RV_INVALID; } |
| 351 | if (paired != 0x01) | ||
| 352 | { | ||
| 353 | // The relay answered and declined: HandleIncoming writes 0x00 and | ||
| 354 | // closes when no service is parked under this pubkey right now. | ||
| 355 | if (pFail) *pFail = RVC_FAIL_REFUSED; | ||
| 356 | CLOSESOCK(s); | ||
| 357 | return RV_INVALID; | ||
| 358 | } | ||
| 359 | if (pFail) *pFail = RVC_FAIL_NONE; | ||
| 348 | return (RvSocket)s; | 360 | return (RvSocket)s; |
| 349 | } | 361 | } |
| 350 | 362 | ||
diff --git a/src/btfrv.h b/src/btfrv.h index 9cd7476..1e85cb0 100644 --- a/src/btfrv.h +++ b/src/btfrv.h | |||
| @@ -57,10 +57,25 @@ RvSocket RvServiceRegister(const char* relay_host, unsigned short port, | |||
| 57 | bool RvServiceWaitPaired(RvSocket s, int nTimeoutSecs = 0); | 57 | bool RvServiceWaitPaired(RvSocket s, int nTimeoutSecs = 0); |
| 58 | 58 | ||
| 59 | // ---- client side (the node dialing a .btf address) ---- | 59 | // ---- client side (the node dialing a .btf address) ---- |
| 60 | // Where a failed RvClientConnect stopped. RV_INVALID alone collapses three | ||
| 61 | // different situations -- relay unreachable, relay reachable but nobody | ||
| 62 | // registered, connection died mid-pairing -- and they point at different | ||
| 63 | // components. The caller can only report the right one if this side says | ||
| 64 | // which it saw. | ||
| 65 | enum RvClientFail | ||
| 66 | { | ||
| 67 | RVC_FAIL_NONE = 0, | ||
| 68 | RVC_FAIL_DIAL, // TCP connect to the relay itself failed | ||
| 69 | RVC_FAIL_REFUSED, // relay answered 0x00: no service registered under this pubkey | ||
| 70 | RVC_FAIL_PAIR, // relay connection died before pairing completed | ||
| 71 | }; | ||
| 72 | |||
| 60 | // Connect through the relay to the service registered under `target_pubkey`. | 73 | // Connect through the relay to the service registered under `target_pubkey`. |
| 61 | // Returns the paired socket, or RV_INVALID on error. | 74 | // Returns the paired socket, or RV_INVALID on error -- with `pFail`, if |
| 75 | // given, naming the stage that failed. | ||
| 62 | RvSocket RvClientConnect(const char* relay_host, unsigned short port, | 76 | RvSocket RvClientConnect(const char* relay_host, unsigned short port, |
| 63 | const unsigned char target_pubkey[32]); | 77 | const unsigned char target_pubkey[32], |
| 78 | RvClientFail* pFail = 0); | ||
| 64 | 79 | ||
| 65 | // Blocking read/write of exactly n bytes over a rendezvous socket. Return false | 80 | // Blocking read/write of exactly n bytes over a rendezvous socket. Return false |
| 66 | // on error/EOF. | 81 | // on error/EOF. |
diff --git a/src/btftunnel.cpp b/src/btftunnel.cpp index 63d178b..408476e 100644 --- a/src/btftunnel.cpp +++ b/src/btftunnel.cpp | |||
| @@ -136,18 +136,47 @@ static btf_socket_t StartTunnel(RvSocket rv, const unsigned char shared[32]) | |||
| 136 | return appEnd; | 136 | return appEnd; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | const char* TunnelFailText(TunnelFail f) | ||
| 140 | { | ||
| 141 | switch (f) | ||
| 142 | { | ||
| 143 | case TUNNEL_FAIL_NONE: return "no failure"; | ||
| 144 | case TUNNEL_FAIL_INIT: return "local socket/crypto init failed"; | ||
| 145 | case TUNNEL_FAIL_DIAL: return "meeting node unreachable (tcp dial failed)"; | ||
| 146 | case TUNNEL_FAIL_REFUSED: return "relay reachable, but no service registered there for this address"; | ||
| 147 | case TUNNEL_FAIL_PAIR: return "relay connection died before pairing completed"; | ||
| 148 | case TUNNEL_FAIL_HANDSHAKE: return "end-to-end handshake failed"; | ||
| 149 | case TUNNEL_FAIL_LOCAL: return "local tunnel setup failed"; | ||
| 150 | } | ||
| 151 | return "unknown failure"; | ||
| 152 | } | ||
| 153 | |||
| 139 | btf_socket_t BtfClientTunnel(const char* meeting_host, unsigned short port, | 154 | btf_socket_t BtfClientTunnel(const char* meeting_host, unsigned short port, |
| 140 | const unsigned char target_pubkey[32], | 155 | const unsigned char target_pubkey[32], |
| 141 | const unsigned char service_enc_pub[32]) | 156 | const unsigned char service_enc_pub[32], |
| 157 | TunnelFail* pFail) | ||
| 142 | { | 158 | { |
| 159 | if (pFail) *pFail = TUNNEL_FAIL_INIT; | ||
| 143 | if (!TunnelInit()) return INVALID_SOCKET; | 160 | if (!TunnelInit()) return INVALID_SOCKET; |
| 144 | RvSocket rv = RvClientConnect(meeting_host, port, target_pubkey); | 161 | RvClientFail rvFail = RVC_FAIL_NONE; |
| 145 | if (rv == RV_INVALID) return INVALID_SOCKET; | 162 | RvSocket rv = RvClientConnect(meeting_host, port, target_pubkey, &rvFail); |
| 163 | if (rv == RV_INVALID) | ||
| 164 | { | ||
| 165 | if (pFail) | ||
| 166 | *pFail = rvFail == RVC_FAIL_DIAL ? TUNNEL_FAIL_DIAL | ||
| 167 | : rvFail == RVC_FAIL_REFUSED ? TUNNEL_FAIL_REFUSED | ||
| 168 | : TUNNEL_FAIL_PAIR; | ||
| 169 | return INVALID_SOCKET; | ||
| 170 | } | ||
| 146 | 171 | ||
| 147 | unsigned char eph_pub[32], shared[32]; | 172 | unsigned char eph_pub[32], shared[32]; |
| 173 | if (pFail) *pFail = TUNNEL_FAIL_HANDSHAKE; | ||
| 148 | if (!ChanClientHandshake(service_enc_pub, eph_pub, shared)) { RvClose(rv); return INVALID_SOCKET; } | 174 | if (!ChanClientHandshake(service_enc_pub, eph_pub, shared)) { RvClose(rv); return INVALID_SOCKET; } |
| 149 | if (!RvWriteN(rv, eph_pub, 32)) { RvClose(rv); return INVALID_SOCKET; } | 175 | if (!RvWriteN(rv, eph_pub, 32)) { RvClose(rv); return INVALID_SOCKET; } |
| 150 | return StartTunnel(rv, shared); | 176 | if (pFail) *pFail = TUNNEL_FAIL_LOCAL; |
| 177 | btf_socket_t app = StartTunnel(rv, shared); | ||
| 178 | if (app != INVALID_SOCKET && pFail) *pFail = TUNNEL_FAIL_NONE; | ||
| 179 | return app; | ||
| 151 | } | 180 | } |
| 152 | 181 | ||
| 153 | btf_socket_t BtfServiceWrap(RvSocket rv, const unsigned char my_enc_sk[32]) | 182 | btf_socket_t BtfServiceWrap(RvSocket rv, const unsigned char my_enc_sk[32]) |
diff --git a/src/btftunnel.h b/src/btftunnel.h index 24a7509..3cc87cd 100644 --- a/src/btftunnel.h +++ b/src/btftunnel.h | |||
| @@ -36,12 +36,33 @@ namespace btf | |||
| 36 | // Initialize (sockets + libsodium). Idempotent. | 36 | // Initialize (sockets + libsodium). Idempotent. |
| 37 | bool TunnelInit(); | 37 | bool TunnelInit(); |
| 38 | 38 | ||
| 39 | // Which stage of BtfClientTunnel failed. INVALID_SOCKET alone says only "no | ||
| 40 | // tunnel"; a caller that then guesses at causes in its log line sends whoever | ||
| 41 | // reads it to the wrong component (issue #17: "relay unreachable or pool not | ||
| 42 | // listening" blamed two healthy parts). The stage is what this side actually | ||
| 43 | // knows -- report that. | ||
| 44 | enum TunnelFail | ||
| 45 | { | ||
| 46 | TUNNEL_FAIL_NONE = 0, | ||
| 47 | TUNNEL_FAIL_INIT, // local socket/crypto init failed | ||
| 48 | TUNNEL_FAIL_DIAL, // TCP connect to the meeting node failed | ||
| 49 | TUNNEL_FAIL_REFUSED, // relay reachable, but no service registered under the pubkey | ||
| 50 | TUNNEL_FAIL_PAIR, // relay connection died before pairing completed | ||
| 51 | TUNNEL_FAIL_HANDSHAKE, // end-to-end channel handshake failed | ||
| 52 | TUNNEL_FAIL_LOCAL, // local pump plumbing (socket pair / threads) failed | ||
| 53 | }; | ||
| 54 | |||
| 55 | // Short description of a TunnelFail for log lines. | ||
| 56 | const char* TunnelFailText(TunnelFail f); | ||
| 57 | |||
| 39 | // Client: dial the service registered under `target_pubkey` at the meeting node | 58 | // Client: dial the service registered under `target_pubkey` at the meeting node |
| 40 | // (host:port), box to its static x25519 `service_enc_pub`, and return a local | 59 | // (host:port), box to its static x25519 `service_enc_pub`, and return a local |
| 41 | // plaintext SOCKET tunneled end-to-end to the service. INVALID_SOCKET on error. | 60 | // plaintext SOCKET tunneled end-to-end to the service. INVALID_SOCKET on error |
| 61 | // -- with `pFail`, if given, naming the stage that failed. | ||
| 42 | btf_socket_t BtfClientTunnel(const char* meeting_host, unsigned short port, | 62 | btf_socket_t BtfClientTunnel(const char* meeting_host, unsigned short port, |
| 43 | const unsigned char target_pubkey[32], | 63 | const unsigned char target_pubkey[32], |
| 44 | const unsigned char service_enc_pub[32]); | 64 | const unsigned char service_enc_pub[32], |
| 65 | TunnelFail* pFail = 0); | ||
| 45 | 66 | ||
| 46 | // Service: wrap an already-paired rendezvous socket (RvServiceRegister followed | 67 | // Service: wrap an already-paired rendezvous socket (RvServiceRegister followed |
| 47 | // by RvServiceWaitPaired -- the pairing byte MUST already be consumed) with | 68 | // by RvServiceWaitPaired -- the pairing byte MUST already be consumed) with |
diff --git a/src/main.cpp b/src/main.cpp index 7b3e555..c0a8825 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -3758,13 +3758,14 @@ static bool PoolParticipantMiner() | |||
| 3758 | // Step 2b: open encrypted tunnel to pool | 3758 | // Step 2b: open encrypted tunnel to pool |
| 3759 | // ------------------------------------------------------------------ | 3759 | // ------------------------------------------------------------------ |
| 3760 | SetParticipantMiningStatus("opening tunnel"); | 3760 | SetParticipantMiningStatus("opening tunnel"); |
| 3761 | btf::TunnelFail tunnelFail = btf::TUNNEL_FAIL_NONE; | ||
| 3761 | s = btf::BtfClientTunnel(host.c_str(), (unsigned short)port, | 3762 | s = btf::BtfClientTunnel(host.c_str(), (unsigned short)port, |
| 3762 | target_pubkey, service_enc_pub); | 3763 | target_pubkey, service_enc_pub, &tunnelFail); |
| 3763 | if (s == INVALID_SOCKET) { | 3764 | if (s == INVALID_SOCKET) { |
| 3764 | LogPrint("worker", "[worker] tunnel connect FAILED via %s" | 3765 | LogPrint("worker", "[worker] tunnel connect FAILED via %s: %s\n", |
| 3765 | " (relay unreachable or pool not listening)\n", | 3766 | meetingHostPort.c_str(), btf::TunnelFailText(tunnelFail)); |
| 3766 | meetingHostPort.c_str()); | 3767 | SetParticipantMiningStatus(std::string("tunnel connect failed: ") |
| 3767 | SetParticipantMiningStatus("tunnel connect failed"); | 3768 | + btf::TunnelFailText(tunnelFail)); |
| 3768 | return false; | 3769 | return false; |
| 3769 | } | 3770 | } |
| 3770 | LogPrint("worker", "[worker] tunnel open via %s\n", meetingHostPort.c_str()); | 3771 | LogPrint("worker", "[worker] tunnel open via %s\n", meetingHostPort.c_str()); |