upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/test_btftunnel.cpp
diff options
context:
space:
mode:
authorbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
committerbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
commit5ce650382352c1503f40abf08129ada69402af55 (patch)
tree6a18198901f1e2c4933f1ac53c9365eec512bf63 /src/test_btftunnel.cpp
parentf34113291da7e5e3dc7d2468d4f9c212c05c584b (diff)
public commit
Diffstat (limited to 'src/test_btftunnel.cpp')
-rw-r--r--src/test_btftunnel.cpp97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/test_btftunnel.cpp b/src/test_btftunnel.cpp
new file mode 100644
index 0000000..df01da8
--- /dev/null
+++ b/src/test_btftunnel.cpp
@@ -0,0 +1,97 @@
1// Full-stack loopback test of the anonymous tunnel: relay + service + client in
2// one process on 127.0.0.1 (unit test of the logic, NOT a LAN/network test).
3// The app-facing sockets are plain TCP; the wire between them is echan over the
4// rendezvous relay. Proves CNode can use a .btf peer as an ordinary socket.
5//
6// Build (UCRT64):
7// g++ -std=gnu++14 test_btftunnel.cpp btftunnel.cpp btfrv.cpp btfchan.cpp -lsodium -lws2_32 -o test_btftunnel.exe
8
9#include "btftunnel.h"
10#include "btfrv.h"
11#include "btfchan.h"
12#include <winsock2.h>
13#include <cstdio>
14#include <cstring>
15#include <string>
16#include <vector>
17#include <thread>
18#include <chrono>
19
20using namespace btf;
21static int g_fail = 0;
22#define CHECK(cond, name) do { \
23 if (cond) { printf(" ok %s\n", name); } \
24 else { printf(" FAIL %s\n", name); g_fail++; } } while(0)
25
26static const unsigned short PORT = 18444;
27
28static bool RecvN(btf_socket_t s, void* buf, int n)
29{
30 char* p = (char*)buf; int off = 0;
31 while (off < n) { int r = recv((SOCKET)s, p + off, n - off, 0); if (r <= 0) return false; off += r; }
32 return true;
33}
34static bool SendN(btf_socket_t s, const void* buf, int n)
35{
36 const char* p = (const char*)buf; int off = 0;
37 while (off < n) { int r = send((SOCKET)s, p + off, n - off, 0); if (r <= 0) return false; off += r; }
38 return true;
39}
40
41static bool g_svcOk = false;
42static std::string g_svcGot;
43
44static void ServiceThread(std::vector<unsigned char> pairing_id, std::vector<unsigned char> enc_sk, int msglen)
45{
46 RvSocket rv = RvServiceRegister("127.0.0.1", PORT, pairing_id.data());
47 if (rv == RV_INVALID) return;
48 btf_socket_t app = BtfServiceWrap(rv, enc_sk.data());
49 if (app == INVALID_SOCKET) return;
50 // Read the client's plaintext message and echo it back (as a normal socket).
51 std::vector<char> buf(msglen);
52 if (!RecvN(app, buf.data(), msglen)) { closesocket((SOCKET)app); return; }
53 g_svcGot.assign(buf.data(), msglen);
54 g_svcOk = SendN(app, buf.data(), msglen);
55 closesocket((SOCKET)app);
56}
57
58int main()
59{
60 if (!TunnelInit()) { printf("init failed\n"); return 2; }
61
62 unsigned char svc_enc_pk[32], svc_enc_sk[32];
63 ChanKeypair(svc_enc_pk, svc_enc_sk);
64 std::vector<unsigned char> pairing_id(32);
65 for (int i = 0; i < 32; i++) pairing_id[i] = (unsigned char)(i * 3 + 5);
66
67 std::string msg = "hello one-cpu-one-vote via anonymous .btf tunnel";
68 int msglen = (int)msg.size();
69
70 printf("anonymous_tunnel_full_stack\n");
71
72 std::thread relay([]{ RvRelayRun(PORT); });
73 std::this_thread::sleep_for(std::chrono::milliseconds(300));
74 std::thread svc(ServiceThread, pairing_id,
75 std::vector<unsigned char>(svc_enc_sk, svc_enc_sk+32), msglen);
76 std::this_thread::sleep_for(std::chrono::milliseconds(300));
77
78 btf_socket_t app = BtfClientTunnel("127.0.0.1", PORT, pairing_id.data(), svc_enc_pk);
79 CHECK(app != INVALID_SOCKET, "client built anonymous tunnel to service");
80 if (app != INVALID_SOCKET)
81 {
82 CHECK(SendN(app, msg.data(), msglen), "app writes plaintext to the tunnel socket");
83 std::vector<char> echo(msglen);
84 CHECK(RecvN(app, echo.data(), msglen), "app reads echo from the tunnel socket");
85 CHECK(std::string(echo.data(), msglen) == msg, "plaintext round-trips end-to-end through the relay");
86 closesocket((SOCKET)app);
87 }
88
89 svc.join();
90 CHECK(g_svcOk && g_svcGot == msg, "service saw the correct decrypted plaintext");
91
92 RvRelayStop();
93 relay.join();
94
95 printf("\n%s (%d failures)\n", g_fail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED", g_fail);
96 return g_fail == 0 ? 0 : 1;
97}