Naut/include/naut/peer.h
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

72 lines
3.4 KiB
C

/* peer.h — BitTorrent peer wire protocol (BEP-3), sans-IO.
*
* This is a pure codec: it never touches a socket. You feed it bytes and it
* yields parsed messages; you ask it to build a message and it writes bytes.
* That keeps the protocol unit-testable in isolation and lets the SAME codec be
* driven by the simple blocking leecher (Phase 3) and by the io_uring reactor
* (Phase 6) without change — the I/O strategy is somebody else's problem.
*/
#ifndef NAUT_PEER_H
#define NAUT_PEER_H
#include "naut/common.h"
#define NAUT_HANDSHAKE_LEN 68
#define NAUT_PEERID_LEN 20
/* Reject absurd length prefixes early: largest legitimate message is a PIECE,
* 9 + block. Allow generous slack over the 16 KiB default block. */
#define NAUT_MSG_MAX (1u << 20)
typedef enum {
NAUT_MSG_CHOKE = 0,
NAUT_MSG_UNCHOKE = 1,
NAUT_MSG_INTERESTED = 2,
NAUT_MSG_NOT_INTERESTED = 3,
NAUT_MSG_HAVE = 4,
NAUT_MSG_BITFIELD = 5,
NAUT_MSG_REQUEST = 6,
NAUT_MSG_PIECE = 7,
NAUT_MSG_CANCEL = 8,
NAUT_MSG_PORT = 9,
NAUT_MSG_EXTENDED = 20, /* BEP-10 extension payload */
NAUT_MSG_KEEPALIVE = 255, /* synthetic: length-prefix of 0 */
} naut_msg_type;
typedef struct {
naut_msg_type type;
uint32_t index; /* HAVE/REQUEST/PIECE/CANCEL */
uint32_t begin; /* REQUEST/PIECE/CANCEL */
uint32_t length; /* REQUEST/CANCEL; PIECE: block length */
const uint8_t *payload; /* PIECE: block bytes; BITFIELD: bytes */
size_t payload_len;
} naut_msg;
/* --- handshake ----------------------------------------------------------- */
void naut_peer_handshake_build(uint8_t out[NAUT_HANDSHAKE_LEN],
const uint8_t infohash[20],
const uint8_t peerid[NAUT_PEERID_LEN],
uint64_t reserved);
/* Returns true on a well-formed handshake with the expected protocol string. */
bool naut_peer_handshake_parse(const uint8_t in[NAUT_HANDSHAKE_LEN],
uint8_t infohash[20],
uint8_t peerid[NAUT_PEERID_LEN],
uint64_t *reserved);
/* --- decode -------------------------------------------------------------- */
/* Parse one message from buf[0..len). Returns bytes consumed (>0) with *out
* filled (payload pointers alias into buf), 0 if more bytes are needed, or
* NAUT_ERR_PROTO (<0) on a malformed/oversized frame. */
int naut_peer_msg_parse(const uint8_t *buf, size_t len, naut_msg *out);
/* --- encode (all return bytes written) ----------------------------------- */
size_t naut_peer_keepalive(uint8_t out[4]);
size_t naut_peer_msg_simple(uint8_t out[5], naut_msg_type t); /* choke..not_interested */
size_t naut_peer_msg_have(uint8_t out[9], uint32_t index);
size_t naut_peer_msg_request(uint8_t out[17], uint32_t index, uint32_t begin, uint32_t length);
size_t naut_peer_msg_cancel(uint8_t out[17], uint32_t index, uint32_t begin, uint32_t length);
/* PIECE header (13 bytes); the block bytes follow separately on the wire. */
size_t naut_peer_msg_piece_header(uint8_t out[13], uint32_t index, uint32_t begin, uint32_t block_len);
/* BITFIELD into out (must hold 5 + nbytes); returns total length. */
size_t naut_peer_msg_bitfield(uint8_t *out, const uint8_t *bf, size_t nbytes);
#endif /* NAUT_PEER_H */