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>
72 lines
3.4 KiB
C
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 */
|