code wiki / (root) / nx_torrent_seed.nx

nx_torrent_seed.nx

buildroot/runtime/nx_torrent_seed.nx

33552 B563 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 sys_socket ts_w ↻ sys_setsockopt sys_bind ts_wn sys_listen ipf_load sys_openat_rd sys_mmap sys_read sys_close ipf_u32le ts_max_live sys_read ↻ ts_atoi ↻ sys_wait4 ts_backoff_ms sys_sleep_ms sys_mmap ↻ sys_munmap sys_accept ts_ipf_reject ts_peer_ip sys_munmap ↻ ipf_blocked sys_fork ts_serve_peer sys_set_socket_timeout sys_mmap ↻ sys_setsockopt ↻ sys_munmap ↻ ts_read_n sys_read ↻

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
453const TS_BK_TOL: i64 = 8 // real peers abort mid-handshake; tolerate a burst before slowing at all
454const TS_BK_N2: i64 = 64
455const TS_BK_N3: i64 = 512
456const TS_BK_D1: i64 = 50
457const TS_BK_D2: i64 = 250
458const 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 calls 1: sys_munmap
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 }
81func ts_wn(fd: i64, v: i64) -> i64
86func ts_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
87func 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 }
90func ts_sockaddr(sa: *u8, port: i64, i0: i64, i1: i64, i2: i64, i3: i64) -> i64
97func ts_read_n(fd: i64, buf: *u8, n: i64) -> i64
100func ts_write_n(fd: i64, buf: *u8, n: i64) -> i64
called by 1: main
104func ts_read_msg(fd: i64, mb: *u8, cap: i64) -> i64
called by 1: main calls 2: ts_read_n_pw_get_u32
121func ts_dh_priv(x: *i64) -> i64 { return mse_gen_priv(x) } // CSPRNG per-connection key (nx_mse_wire)
123func ts_read_msg_ctx(ctx: *MseCtx, afd: i64, mb: *u8, cap: i64) -> i64
135func 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 }
136func ts_hexval(c: i64) -> i64
called by 1: ts_hex2bin
143func ts_hex2bin(hex: *u8, out: *u8) -> i64
155func ts_build_full_bitfield(npc: i64, bf: *u8) -> i64
called by 1: ts_serve_after_hs
172func ts_load_have(srcpath: *u8, npc: i64, have: *u8) -> i64
called by 2: ts_serve_after_hsmain calls 1: sys_read
183func ts_build_bitfield_have(npc: i64, have: *u8, bf: *u8) -> i64
191func ts_read_hs(afd: i64, out_ih: *u8, out_pid: *u8) -> i64
202func ts_serve_after_hs(ctx: *MseCtx, afd: i64, ih: *u8, my_pid: *u8, srcpath: *u8, plen: i64, total: i64, npc: i64) -> i64
261func ts_serve_peer(afd: i64, ih: *u8, my_pid: *u8, srcpath: *u8, plen: i64, total: i64, npc: i64) -> i64
284func 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 }
285func 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
286func ts_field(row: *u8, rlen: i64, idx: i64, out: *u8) -> i64
called by 2: ts_lookupts_registry_scan calls 1: ts_tab
292func ts_lookup(reg: *u8, want_ih: *u8, out_src: *u8, out_plen: *i64, out_total: *i64) -> i64
317func ts_registry_scan(reg: *u8, target: *u8, out_ih: *u8, out_src: *u8, out_plen: *i64, out_total: *i64) -> i64
342func ts_serve_peer_registry(afd: i64, my_pid: *u8, reg: *u8) -> i64
374func ts_accept_loop_registry(port: i64, my_pid: *u8, reg: *u8, max_conns: i64) -> i64
459func ts_backoff_ms(consec_fail: i64) -> i64
466func ts_backoff_ms_old(consec_fail: i64) -> i64 { return 0 }
called by 1: main
471func ts_accept_loop(port: i64, ih: *u8, my_pid: *u8, src: *u8, plen: i64, total: i64, npc: i64, max_conns: i64) -> i64
531func main(argc: i64, argv: *i64) -> i64