Naut/tests/unit/test_peer.c
ookami125 2178d6a70c Initial commit: Naut-Torrent — from-scratch 10 GbE BitTorrent client
A maintainable, extensible BitTorrent client (C11, Linux/io_uring) targeting
10 GbE saturation. All torrent functionality is built from scratch; liburing
is the only linked third-party dependency on the data path.

Implements Phases 1-7 of the roadmap:
- core: page-aligned buffer pool, MPMC/Treiber queues, bitfields, worker pool
- crypto: SHA-1/256 (SHA-NI + scalar), Merkle (BEP-52), RC4 (MSE)
- bencode/metainfo: zero-copy parser, v1/v2/hybrid .torrent + magnet
- peer: sans-IO wire codec, MSE/PE handshake state machine, BEP-10, ut_metadata, PEX
- piece/storage: block-level multi-peer engine, rarest-first + endgame,
  per-file completion events + single-file relocate (move-as-you-finish)
- tracker/dht: HTTP + UDP (BEP-15) trackers, BEP-5 KRPC iterative lookup
- platform: io_uring reactor (SQPOLL, registered buffers, SEND_ZC)
- surface: versioned RPC, native plugin ABI, sandboxed Lua scripting, nautd/nautctl

Verified against libtorrent (single/multi/hybrid, MSE, magnet-via-DHT, swarm);
unit + interop tests green; ASan/UBSan/TSan clean. Scripting reference in
docs/scripting.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:12:00 -04:00

80 lines
3.1 KiB
C

#include "naut/peer.h"
#include "test.h"
#include <string.h>
int main(void) {
uint8_t ih[20], pid[20], ih2[20], pid2[20];
for (int i = 0; i < 20; i++) { ih[i] = (uint8_t)(i + 1); pid[i] = (uint8_t)(100 + i); }
/* handshake round-trip, with the BEP-10 extension reserved bit set */
uint8_t hs[NAUT_HANDSHAKE_LEN];
uint64_t reserved = 0x0000000000100000ULL; /* ext protocol bit */
naut_peer_handshake_build(hs, ih, pid, reserved);
CHECK_EQ(hs[0], 19);
CHECK(memcmp(hs + 1, "BitTorrent protocol", 19) == 0);
uint64_t got_res = 0;
CHECK(naut_peer_handshake_parse(hs, ih2, pid2, &got_res));
CHECK(memcmp(ih, ih2, 20) == 0 && memcmp(pid, pid2, 20) == 0);
CHECK_EQ((long long)got_res, (long long)reserved);
hs[3] = 'X'; /* corrupt protocol string */
CHECK(!naut_peer_handshake_parse(hs, ih2, pid2, &got_res));
naut_msg m;
uint8_t b[64];
/* simple messages */
size_t n = naut_peer_msg_simple(b, NAUT_MSG_INTERESTED);
CHECK_EQ(n, 5);
CHECK_EQ(naut_peer_msg_parse(b, n, &m), 5);
CHECK_EQ(m.type, NAUT_MSG_INTERESTED);
/* keep-alive */
n = naut_peer_keepalive(b);
CHECK_EQ(naut_peer_msg_parse(b, n, &m), 4);
CHECK_EQ(m.type, NAUT_MSG_KEEPALIVE);
/* have */
n = naut_peer_msg_have(b, 0x01020304);
CHECK_EQ(naut_peer_msg_parse(b, n, &m), 9);
CHECK(m.type == NAUT_MSG_HAVE && m.index == 0x01020304);
/* request */
n = naut_peer_msg_request(b, 7, 16384, 16384);
CHECK_EQ(naut_peer_msg_parse(b, n, &m), 17);
CHECK(m.type == NAUT_MSG_REQUEST && m.index == 7 && m.begin == 16384 && m.length == 16384);
/* piece: header + block, payload aliases input */
{
uint8_t blk[16384];
for (int i = 0; i < 16384; i++) blk[i] = (uint8_t)(i & 0xff);
uint8_t frame[13 + 16384];
naut_peer_msg_piece_header(frame, 3, 32768, 16384);
memcpy(frame + 13, blk, 16384);
int c = naut_peer_msg_parse(frame, sizeof frame, &m);
CHECK_EQ(c, (int)sizeof frame);
CHECK(m.type == NAUT_MSG_PIECE && m.index == 3 && m.begin == 32768);
CHECK_EQ(m.payload_len, 16384);
CHECK(m.payload == frame + 13 && memcmp(m.payload, blk, 16384) == 0);
}
/* streaming: partial frame returns 0 (need more), completes when filled */
n = naut_peer_msg_have(b, 42);
CHECK_EQ(naut_peer_msg_parse(b, 3, &m), 0); /* < 4 length bytes */
CHECK_EQ(naut_peer_msg_parse(b, 7, &m), 0); /* length known, body short */
CHECK_EQ(naut_peer_msg_parse(b, 9, &m), 9);
/* bitfield */
uint8_t bf[4] = { 0xff, 0x80, 0x00, 0x01 };
n = naut_peer_msg_bitfield(b, bf, 4);
CHECK_EQ(naut_peer_msg_parse(b, n, &m), (int)n);
CHECK(m.type == NAUT_MSG_BITFIELD && m.payload_len == 4 && memcmp(m.payload, bf, 4) == 0);
/* malformed: oversized length prefix rejected */
uint8_t bad[4] = { 0xff, 0xff, 0xff, 0xff };
CHECK(naut_peer_msg_parse(bad, 4, &m) < 0);
/* malformed: HAVE whose body length (5) != required 4 */
uint8_t badhave[10] = { 0,0,0,6, NAUT_MSG_HAVE, 0,0,0,1, 0 };
CHECK(naut_peer_msg_parse(badhave, 10, &m) < 0);
TEST_MAIN_END();
}