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>
88 lines
3.5 KiB
C
88 lines
3.5 KiB
C
/* mse.h - BitTorrent Message Stream Encryption (MSE/PE) transport. */
|
|
#ifndef NAUT_MSE_H
|
|
#define NAUT_MSE_H
|
|
|
|
#include "naut/common.h"
|
|
#include "naut/peer.h"
|
|
#include "naut/rc4.h"
|
|
|
|
#include <sys/types.h>
|
|
|
|
#define NAUT_MSE_DH_LEN 96
|
|
|
|
typedef struct {
|
|
naut_rc4 send;
|
|
naut_rc4 recv;
|
|
bool active;
|
|
} naut_mse_stream;
|
|
|
|
/* ---- sans-IO handshake state machine ------------------------------------- *
|
|
* The outgoing MSE/PE handshake as a pure state machine over byte buffers — no
|
|
* sockets — so the same logic drives the blocking apps and the io_uring reactor
|
|
* (where blocking in a handshake would stall a whole core's worth of peers).
|
|
*
|
|
* Drive it like a codec: pump NEED_WRITE bytes out, feed NEED_READ bytes in,
|
|
* repeat until DONE or ERROR, then call _finish().
|
|
*
|
|
* h = naut_mse_handshake_begin(info_hash, peer_id, reserved);
|
|
* for (;;) switch (naut_mse_handshake_status(h)) {
|
|
* case NAUT_MSE_HS_NEED_WRITE: pull bytes, write them to the peer; break;
|
|
* case NAUT_MSE_HS_NEED_READ: read bytes from the peer, feed them; break;
|
|
* case NAUT_MSE_HS_DONE: naut_mse_handshake_finish(h, ...); goto ok;
|
|
* case NAUT_MSE_HS_ERROR: ... ; goto err;
|
|
* }
|
|
*/
|
|
typedef enum {
|
|
NAUT_MSE_HS_NEED_READ,
|
|
NAUT_MSE_HS_NEED_WRITE,
|
|
NAUT_MSE_HS_DONE,
|
|
NAUT_MSE_HS_ERROR,
|
|
} naut_mse_hs_status;
|
|
|
|
typedef struct naut_mse_handshake naut_mse_handshake;
|
|
|
|
naut_mse_handshake *naut_mse_handshake_begin(
|
|
const uint8_t info_hash[20],
|
|
const uint8_t peer_id[NAUT_PEERID_LEN],
|
|
uint64_t reserved);
|
|
void naut_mse_handshake_free(naut_mse_handshake *h);
|
|
|
|
naut_mse_hs_status naut_mse_handshake_status(const naut_mse_handshake *h);
|
|
|
|
/* Copy pending outgoing bytes into buf (up to cap); returns the count, 0 when
|
|
* nothing is queued. Call repeatedly until it returns 0. */
|
|
size_t naut_mse_handshake_pull(naut_mse_handshake *h, uint8_t *buf, size_t cap);
|
|
|
|
/* Feed received bytes; *consumed reports how many were absorbed (the rest, if
|
|
* any, must be re-fed — after DONE that remainder is the start of the encrypted
|
|
* payload stream). Returns the new status. */
|
|
naut_mse_hs_status naut_mse_handshake_feed(naut_mse_handshake *h,
|
|
const uint8_t *data, size_t len,
|
|
size_t *consumed);
|
|
|
|
/* Valid once status is DONE: hand out the negotiated stream and the peer's
|
|
* decrypted BitTorrent handshake. */
|
|
naut_err naut_mse_handshake_finish(naut_mse_handshake *h,
|
|
naut_mse_stream *stream,
|
|
uint8_t remote_handshake[NAUT_HANDSHAKE_LEN]);
|
|
|
|
/* Blocking convenience wrapper over the state machine: perform the whole
|
|
* outgoing handshake on a blocking socket, offering RC4 only. The BitTorrent
|
|
* handshake is carried as IA; the peer's decrypted handshake is returned in
|
|
* remote_handshake. */
|
|
naut_err naut_mse_client_handshake(
|
|
int fd,
|
|
const uint8_t info_hash[20],
|
|
const uint8_t peer_id[NAUT_PEERID_LEN],
|
|
uint64_t reserved,
|
|
naut_mse_stream *stream,
|
|
uint8_t remote_handshake[NAUT_HANDSHAKE_LEN]);
|
|
|
|
/* Stream I/O after a successful handshake. Encryption/decryption is in-place
|
|
* with connection-owned RC4 state. send_all preserves the caller's buffer. */
|
|
bool naut_mse_send_all(int fd, naut_mse_stream *stream,
|
|
const void *data, size_t len);
|
|
ssize_t naut_mse_recv(int fd, naut_mse_stream *stream,
|
|
void *data, size_t len);
|
|
|
|
#endif /* NAUT_MSE_H */
|