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>
This commit is contained in:
ookami125 2026-06-15 12:12:00 -04:00
commit 2178d6a70c
121 changed files with 12644 additions and 0 deletions

98
tests/unit/test_dht.c Normal file
View file

@ -0,0 +1,98 @@
#include "naut/bencode.h"
#include "naut/dht.h"
#include "test.h"
#include <stdlib.h>
#include <string.h>
static void check_get_peers_query(void) {
uint8_t tx[2] = { 0x12, 0x34 };
uint8_t id[20], hash[20];
for (size_t i = 0; i < 20; i++) {
id[i] = (uint8_t)i;
hash[i] = (uint8_t)(0x80 + i);
}
uint8_t *query = NULL;
size_t query_len = 0;
CHECK(naut_dht_build_get_peers(tx, sizeof tx, id, hash,
&query, &query_len) == NAUT_OK);
naut_bc_doc *doc = NULL;
CHECK(naut_bc_parse(query, query_len, &doc) == NAUT_OK);
const naut_bc *root = naut_bc_root(doc);
CHECK(naut_bc_str_eq(naut_bc_dict_get(root, "y"), "q"));
CHECK(naut_bc_str_eq(naut_bc_dict_get(root, "q"), "get_peers"));
const naut_bc *args = naut_bc_dict_get(root, "a");
const uint8_t *p = NULL;
size_t n = 0;
CHECK(naut_bc_get_str(naut_bc_dict_get(args, "id"), &p, &n));
CHECK(n == 20 && memcmp(p, id, 20) == 0);
CHECK(naut_bc_get_str(naut_bc_dict_get(args, "info_hash"), &p, &n));
CHECK(n == 20 && memcmp(p, hash, 20) == 0);
naut_bc_free(doc);
free(query);
}
static void check_response(void) {
uint8_t packet[256];
size_t len = 0;
const char *prefix = "d1:rd2:id20:";
memcpy(packet + len, prefix, strlen(prefix));
len += strlen(prefix);
for (size_t i = 0; i < 20; i++) packet[len++] = (uint8_t)(0x20 + i);
const char *nodes = "5:nodes26:";
memcpy(packet + len, nodes, strlen(nodes));
len += strlen(nodes);
for (size_t i = 0; i < 20; i++) packet[len++] = (uint8_t)(0x40 + i);
packet[len++] = 192; packet[len++] = 0; packet[len++] = 2; packet[len++] = 9;
packet[len++] = 0x1a; packet[len++] = 0xe1;
const char *suffix = "5:token3:abc6:valuesl6:";
memcpy(packet + len, suffix, strlen(suffix));
len += strlen(suffix);
packet[len++] = 203; packet[len++] = 0; packet[len++] = 113; packet[len++] = 7;
packet[len++] = 0xc8; packet[len++] = 0xd5;
const char *tail = "ee1:t2:aa1:y1:re";
memcpy(packet + len, tail, strlen(tail));
len += strlen(tail);
naut_dht_response response;
CHECK(naut_dht_parse_response(packet, len, &response) == NAUT_OK);
CHECK(response.type == NAUT_DHT_RESPONSE);
CHECK(response.transaction_len == 2 &&
memcmp(response.transaction, "aa", 2) == 0);
CHECK(response.has_id && response.id[0] == 0x20);
CHECK(response.token_len == 3 &&
memcmp(response.token, "abc", 3) == 0);
CHECK(response.num_nodes == 1);
CHECK(response.nodes[0].ip[0] == 192 &&
response.nodes[0].port == 6881);
CHECK(response.num_peers == 1);
CHECK(response.peers[0].ip[0] == 203 &&
response.peers[0].port == 51413);
naut_dht_response_free(&response);
}
int main(void) {
check_get_peers_query();
check_response();
const char error[] = "d1:eli203e12:Server errore1:t2:zz1:y1:ee";
naut_dht_response response;
CHECK(naut_dht_parse_response((const uint8_t *)error, sizeof error - 1,
&response) == NAUT_OK);
CHECK(response.type == NAUT_DHT_ERROR && response.error_code == 203);
naut_dht_response_free(&response);
const char malformed[] =
"d1:rd2:id20:abcdefghijklmnopqrst5:nodes1:xe1:t1:a1:y1:re";
CHECK(naut_dht_parse_response((const uint8_t *)malformed,
sizeof malformed - 1,
&response) == NAUT_ERR_PROTO);
TEST_MAIN_END();
}