nx_torrent_seed.nx
buildroot/runtime/nx_torrent_seed.nx
about
nx_torrent_seed.nx -- SOVEREIGN BitTorrent SEEDER (the missing UPLOAD half of the stack).
Until now the Nishi torrent stack was a pure LEECHER: DNS->tracker/DHT->peers->handshake->metadata->
pieces->disk (all proven live), but it NEVER served pieces back. A pure leecher is punished by
BitTorrent tit-for-tat (seeders never optimistically-unchoke it -> it stalls -- exactly what
nx_torrent_seedeval's "IGNORING" verdict describes) and it cannot SHARE at all (only the HTTP /dist
mirror could). This organ is the symmetric other half: it ACCEPTS incoming peers and SERVES verified
blocks from a real file, so we become a real swarm member (seed-while-download + seed-after-complete).
Composes nx_peerwire (BEP-3 build/parse) + nx_syscalls (sockets/files). Content is mapped by info_hash
via a seed registry (like dist_index.conf): rows = <name>\t<ih_hex40>\t<piece_length>\t<total>\t<srcpath>.
The seeder core `ts_serve_peer` is a LIB fn (import strips main) so the gate can drive it directly.
nx_torrent_seed serve <port> [registry] -- accept-loop, serve every registered torrent
nx_torrent_seed serve1 <port> <ih_hex40> <plen> <total> <src> -- serve ONE torrent (deploy/test convenience)
NEVER-BRICK by construction: writes ZERO persistent hardware state -- only network sends + file READS.
license_tier: ORIGINAL layer: L4 (peer-wire serving) module: nishi-core.torrent.seed
depends: nishi-core.torrent.peerwire, nishi-core.syscalls, nishi-core.torrent.mse_wire
MSE/PE: inbound peers are demuxed (0x13=plaintext BT / else=encrypted MSE) so DPI can't fingerprint us,
while legacy plaintext peers still work (backward compatible). All post-handshake I/O routes through MseCtx.
dependencies 3 imports · 6 importers
imports: nx_peerwire.nxnx_mse_wire.nxnx_ipfilter.nx
imported by: nx_ipfilter_seed_gate.nxnx_mse_seed_gate.nxnx_torrent_backoff_gate.nxnx_torrent_leech_probe.nxnx_torrent_seed_gate.nxnx_ts_partial_gate.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 25 | const TS_MAGIC_2026: i64 = 2026 |
| 26 | const TS_MAGIC_65536: i64 = 65536 |
| 27 | const TS_MAGIC_1048576: i64 = 1048576 |
| 28 | const TS_MAGIC_1024: i64 = 1024 |
| 29 | const TS_MAGIC_6881: i64 = 6881 |
| 31 | const TS_IPF_PATH: *u8 = "/volume1/ai/torrent/data/ipfilter.bin" as *u8 |
| 32 | const TS_IPF_MAXP: i64 = 80000 |
| 33 | const TS_SA_CELL: i64 = 32 // getpeername sockaddr scratch (mmap'd + munmap'd per call -- leak-free pair) |
| 34 | const TS_AL_CELL: i64 = 8 // getpeername addrlen out-cell (same leak-free pair) |
| 55 | const TS_BLOCK_MAX: i64 = 32768 // cap a single served block (std request = 16384) |
| 56 | const TS_MSG_CAP: i64 = 131072 // cap an inbound control message (drain if larger) |
| 57 | const TS_REG_DEFAULT: *u8 = "/volume1/ai/torrent/seed_index.conf" as *u8 |
| 58 | const TS_PEER_TIMEOUT: i64 = 30 // per-peer socket timeout (no-hang law) |
| 64 | const TS_LIMITS_PATH: *u8 = "/volume1/ai/torrent/seed_limits.conf" as *u8 |
| 65 | const TS_LIVE_DEFAULT: i64 = 4 |
| 453 | const TS_BK_TOL: i64 = 8 // real peers abort mid-handshake; tolerate a burst before slowing at all |
| 454 | const TS_BK_N2: i64 = 64 |
| 455 | const TS_BK_N3: i64 = 512 |
| 456 | const TS_BK_D1: i64 = 50 |
| 457 | const TS_BK_D2: i64 = 250 |
| 458 | const TS_BK_D3: i64 = 1000 // ceiling: one attempt per second is still a live seeder, not a dead one |
functions
| 40 | func ts_peer_ip(afd: i64) -> i64 |
| 49 | func ts_ipf_reject(afd: i64, arr: *i64, cnt: i64) -> i64 |
| 67 | func ts_max_live() -> i64 |
| 80 | func ts_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } |
| 81 | func ts_wn(fd: i64, v: i64) -> i64 |
| 86 | func ts_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } |
| 87 | func ts_atoi(s: *u8) -> i64 { var v: i64=0; var i: i64=0; while s[i]!=(0 as u8){ let c: i64=s[i] as i64; if c<48 {return v} if c>57 {return v} v=v*10+(c-48); i=i+1 } return v } |
| 90 | func ts_sockaddr(sa: *u8, port: i64, i0: i64, i1: i64, i2: i64, i3: i64) -> i64 |
| 97 | func ts_read_n(fd: i64, buf: *u8, n: i64) -> i64 called by 6: ts_read_msgts_read_hsts_serve_after_hsts_serve_peerts_serve_peer_registrymain calls 1: sys_read |
| 100 | func ts_write_n(fd: i64, buf: *u8, n: i64) -> i64 called by 1: main |
| 104 | func ts_read_msg(fd: i64, mb: *u8, cap: i64) -> i64 |
| 121 | func ts_dh_priv(x: *i64) -> i64 { return mse_gen_priv(x) } // CSPRNG per-connection key (nx_mse_wire) |
| 123 | func ts_read_msg_ctx(ctx: *MseCtx, afd: i64, mb: *u8, cap: i64) -> i64 |
| 135 | func ts_memeq(a: *u8, b: *u8, n: i64) -> i64 { var i: i64=0; while i<n { if a[i]!=b[i] { return 0 } i=i+1 } return 1 } |
| 136 | func ts_hexval(c: i64) -> i64 called by 1: ts_hex2bin |
| 143 | func ts_hex2bin(hex: *u8, out: *u8) -> i64 |
| 155 | func ts_build_full_bitfield(npc: i64, bf: *u8) -> i64 called by 1: ts_serve_after_hs |
| 172 | func ts_load_have(srcpath: *u8, npc: i64, have: *u8) -> i64 |
| 183 | func ts_build_bitfield_have(npc: i64, have: *u8, bf: *u8) -> i64 |
| 191 | func ts_read_hs(afd: i64, out_ih: *u8, out_pid: *u8) -> i64 |
| 202 | func ts_serve_after_hs(ctx: *MseCtx, afd: i64, ih: *u8, my_pid: *u8, srcpath: *u8, plen: i64, total: i64, npc: i64) -> i64 |
| 261 | func ts_serve_peer(afd: i64, ih: *u8, my_pid: *u8, srcpath: *u8, plen: i64, total: i64, npc: i64) -> i64 |
| 284 | func ts_eol(b: *u8, from: i64, blen: i64) -> i64 { var e: i64=from; while e<blen { if b[e]==(10 as u8) { return e } e=e+1 } return blen } |
| 285 | func ts_tab(b: *u8, from: i64, limit: i64) -> i64 { var e: i64=from; while e<limit { if b[e]==(9 as u8) { return e } e=e+1 } return limit } called by 1: ts_field |
| 286 | func ts_field(row: *u8, rlen: i64, idx: i64, out: *u8) -> i64 |
| 292 | func ts_lookup(reg: *u8, want_ih: *u8, out_src: *u8, out_plen: *i64, out_total: *i64) -> i64 |
| 317 | func ts_registry_scan(reg: *u8, target: *u8, out_ih: *u8, out_src: *u8, out_plen: *i64, out_total: *i64) -> i64 called by 1: ts_serve_peer_registry calls 6: sys_readts_eolts_fieldts_hex2binmse_skey_matchests_atoi |
| 342 | func ts_serve_peer_registry(afd: i64, my_pid: *u8, reg: *u8) -> i64 |
| 374 | func ts_accept_loop_registry(port: i64, my_pid: *u8, reg: *u8, max_conns: i64) -> i64 |
| 459 | func ts_backoff_ms(consec_fail: i64) -> i64 |
| 466 | func ts_backoff_ms_old(consec_fail: i64) -> i64 { return 0 } called by 1: main |
| 471 | func ts_accept_loop(port: i64, ih: *u8, my_pid: *u8, src: *u8, plen: i64, total: i64, npc: i64, max_conns: i64) -> i64 |
| 531 | func main(argc: i64, argv: *i64) -> i64 |