code wiki / (root) / nx_torrent_seed.nx

nx_torrent_seed.nx

buildroot/runtime/nx_torrent_seed.nx

35150 B582 linesdepth 7pulls 13 transitivereach 6 importersview sourcekind tooltopic torrent
docsdependenciesstructsconstsfunctions

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

nx_peerwire.nx nx_mse_wire.nx nx_ipfilter.nx nx_torrent_seed.nx nx_ipfilter_seed_gate.nx nx_mse_seed_gate.nx nx_torrent_backoff_gate.nx nx_torrent_leech_probe.nx nx_torrent_seed_gate.nx nx_ts_partial_gate.nx

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

main ts_w ts_atoi ts_hex2bin ts_hexval ts_accept_loop ts_sockaddr ts_w ↻ ts_wn ipf_load sys_openat_rd sys_mmap nxa_die sys_write sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ sys_read sys_close ipf_u32le ts_max_live ts_atoi ↻ ts_backoff_ms ts_ipf_reject ts_peer_ip ipf_blocked ts_serve_peer ts_read_n mse_classify_first_byte nx_pw_parse_handshake ts_memeq

structs

none

consts

25const TS_MAGIC_2026: i64 = 2026
26const TS_MAGIC_65536: i64 = 65536
27const TS_MAGIC_1048576: i64 = 1048576
28const TS_MAGIC_1024: i64 = 1024
29const TS_MAGIC_6881: i64 = 6881
31const TS_IPF_PATH: *u8 = "/volume1/ai/torrent/data/ipfilter.bin" as *u8
32const TS_IPF_MAXP: i64 = 80000
33const TS_SA_CELL: i64 = 32 // getpeername sockaddr scratch (mmap'd + munmap'd per call -- leak-free pair)
34const TS_AL_CELL: i64 = 8 // getpeername addrlen out-cell (same leak-free pair)
55const TS_BLOCK_MAX: i64 = 32768 // cap a single served block (std request = 16384)
56const TS_MSG_CAP: i64 = 131072 // cap an inbound control message (drain if larger)
57const TS_REG_DEFAULT: *u8 = "/volume1/ai/torrent/seed_index.conf" as *u8
58const TS_PEER_TIMEOUT: i64 = 30 // per-peer socket timeout (no-hang law)
64const TS_LIMITS_PATH: *u8 = "/volume1/ai/torrent/seed_limits.conf" as *u8
65const TS_LIVE_DEFAULT: i64 = 4
472const TS_BK_TOL: i64 = 8 // real peers abort mid-handshake; tolerate a burst before slowing at all
473const TS_BK_N2: i64 = 64
474const TS_BK_N3: i64 = 512
475const TS_BK_D1: i64 = 50
476const TS_BK_D2: i64 = 250
477const TS_BK_D3: i64 = 1000 // ceiling: one attempt per second is still a live seeder, not a dead one

functions

40func ts_peer_ip(afd: i64) -> i64
called by 2: maints_ipf_reject
49func ts_ipf_reject(afd: i64, arr: *i64, cnt: i64) -> i64
67func ts_max_live() -> i64
80func 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 }
98func ts_wn(fd: i64, v: i64) -> i64
105func ts_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
106func 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 }
109func ts_sockaddr(sa: *u8, port: i64, i0: i64, i1: i64, i2: i64, i3: i64) -> i64
116func ts_read_n(fd: i64, buf: *u8, n: i64) -> i64
119func ts_write_n(fd: i64, buf: *u8, n: i64) -> i64
called by 1: main
123func ts_read_msg(fd: i64, mb: *u8, cap: i64) -> i64
called by 1: main calls 2: ts_read_n_pw_get_u32
140func ts_dh_priv(x: *i64) -> i64 { return mse_gen_priv(x) } // CSPRNG per-connection key (nx_mse_wire)
142func ts_read_msg_ctx(ctx: *MseCtx, afd: i64, mb: *u8, cap: i64) -> i64
154func 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 }
155func ts_hexval(c: i64) -> i64
called by 1: ts_hex2bin
162func ts_hex2bin(hex: *u8, out: *u8) -> i64
174func ts_build_full_bitfield(npc: i64, bf: *u8) -> i64
called by 1: ts_serve_after_hs
191func ts_load_have(srcpath: *u8, npc: i64, have: *u8) -> i64
202func ts_build_bitfield_have(npc: i64, have: *u8, bf: *u8) -> i64
210func ts_read_hs(afd: i64, out_ih: *u8, out_pid: *u8) -> i64
221func ts_serve_after_hs(ctx: *MseCtx, afd: i64, ih: *u8, my_pid: *u8, srcpath: *u8, plen: i64, total: i64, npc: i64) -> i64
280func ts_serve_peer(afd: i64, ih: *u8, my_pid: *u8, srcpath: *u8, plen: i64, total: i64, npc: i64) -> i64
303func 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 }
304func 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
305func ts_field(row: *u8, rlen: i64, idx: i64, out: *u8) -> i64
called by 2: ts_lookupts_registry_scan calls 1: ts_tab
311func ts_lookup(reg: *u8, want_ih: *u8, out_src: *u8, out_plen: *i64, out_total: *i64) -> i64
336func ts_registry_scan(reg: *u8, target: *u8, out_ih: *u8, out_src: *u8, out_plen: *i64, out_total: *i64) -> i64
361func ts_serve_peer_registry(afd: i64, my_pid: *u8, reg: *u8) -> i64
393func ts_accept_loop_registry(port: i64, my_pid: *u8, reg: *u8, max_conns: i64) -> i64
478func ts_backoff_ms(consec_fail: i64) -> i64
485func ts_backoff_ms_old(consec_fail: i64) -> i64 { return 0 }
called by 1: main
490func ts_accept_loop(port: i64, ih: *u8, my_pid: *u8, src: *u8, plen: i64, total: i64, npc: i64, max_conns: i64) -> i64
550func main(argc: i64, argv: *i64) -> i64