/* 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 */