code wiki / (root) / nx_torrent_get.nx

nx_torrent_get.nx source

↩ module page · 1016 lines · 83401 B

1// nx_torrent_get.nx -- the DOWNLOAD WORKER (X-TORRENT-LIVE-001 L5): magnet -> a real file on disk + 2// a live STATUS file the daemon/UI polls. Composes the proven engine (mg_parse + cl_announce + BEP-3 3// handshake + BEP-9 metadata + BEP-3 data pieces + sha1 verify). FORK-BOUNDED per peer (parent 4// wait4(WNOHANG)+sys_sleep_ms+nx_kill so an unreachable peer can't hang ~127s). Forked children share 5// progress via on-disk files: outfile (non-trunc, write each verified piece at its offset), donefile 6// (bitmap, set [i]=1 per piece), npcfile (piece count). argv[1]=magnet argv[2]=outdir. 7// nx_sov_build_run drops args -> run the built elf directly. license_tier: ORIGINAL 8// 9// module: nishi-core.torrent.get 10// depends: nishi-core.torrent.peer_piece_live, nishi-core.torrent.magnet 11import "nx_connect.nx" // bounded connect -- SO_RCVTIMEO does NOT bound connect() 12import "nx_peer_piece_live.nx" 13import "nx_magnet.nx" 14import "nx_http_tracker.nx" 15import "nx_dht_get_peers.nx" 16import "nx_endgame.nx" // rarest-first availability map + endgame last-piece racing (Phase 2; re-exports nx_avail_map's am_*) 17import "nx_pex.nx" // BEP-11 peer-exchange: harvest MORE peers (incl. seeders) from connected peers -> finish trackerless/stuck swarms 18import "nx_tracker_list.nx" // DATA-DRIVEN HTTP/HTTPS tracker list (trackers.txt) -> tl_next_line -> wider peer discovery 19import "nx_mse_wire.nx" // MSE/PE anti-throttle: try an encrypted handshake per peer, fall back to plaintext (DPI can't fingerprint) 20import "nx_ipfilter.nx" // ip-filter: drop known-bad / anti-P2P-monitor peer IPs from the peer list (privacy while WAN-seeding) 21import "nx_poolgov.nx" // seq1402/1410/1450: pool width DERIVED from this machine + the live shared budget, never a literal 22const TG_MAGIC_1410: i64 = 1410 23const TG_MAGIC_1450: i64 = 1450 24const TG_MAGIC_1024: i64 = 1024 25const TG_MAGIC_15728640: i64 = 15728640 26const TG_MAGIC_65536: i64 = 65536 27const TG_MAGIC_262144: i64 = 262144 28const TG_MAGIC_40000: i64 = 40000 29// seq1317: ticks a peer-pool slot must rest after being FILLED before it may be refilled. The loop 30// sleeps 2s per tick, so 2 = a ~4s floor between forks into the SAME slot -- invisible to a healthy 31// peer (its slot stays occupied) and decisive against a dead one (which used to re-fork every tick). 32const TG_SLOT_COOLDOWN: i64 = 2 33// Peer connect budget. The 6s sys_set_socket_timeout beside each connect() only ever governed 34// READS -- connect() itself ran to the kernel's ~127s SYN ceiling, so one dead peer held a slot 35// for two minutes. Same 6s intent, now actually enforced on the connect. 36const TG_CONNECT_MS: i64 = 6000 37// Watchdog for the BACKGROUND ANNOUNCE (tg_announce_bg). Ticks are 2s. A tracker round that has 38// not finished in 90s is against a black-holed host -- the kernel's own SYN timeout is ~127s, so 39// this reclaims the slot BEFORE the kernel would, and well inside the 30s announce cadence's 40// tolerance for a skipped cycle. Derived from those two measured numbers, not chosen by taste. 41const TG_ANN_MAX_TICKS: i64 = 45 42const TG_MAGIC_2000000: i64 = 2000000 43const TG_MAGIC_2000000: i64 = 2000000 44const TG_MAGIC_16383: i64 = 16383 45const TG_MAGIC_16384: i64 = 16384 46const TG_MAGIC_1000000000: i64 = 1000000000 47const TG_MAGIC_65535: i64 = 65535 48const TG_MAGIC_1337: i64 = 1337 49const TG_MAGIC_262143: i64 = 262143 50const TG_MAGIC_80000: i64 = 80000 51const TG_MAGIC_2000: i64 = 2000 52 53// Endgame entry: once this many or fewer OBTAINABLE pieces remain (all already in-flight), idle 54// children race them instead of exiting, to beat the one slow holder (the dominant tail-latency 55// source). ~half the 32-child pool: above it there's fresh non-duplicated work; below it, racing 56// the tail beats leaving children idle. A heuristic lever, not a correctness value (SHA1 still guards). 57const TG_ENDGAME_THRESHOLD: i64 = 16 58// BULK unchoke-patience window (seconds). A pure-leecher must OUTLAST a seeder's optimistic-unchoke rotation 59// (~30s in mainline) to ever get served -- bailing at the 6s connect timeout or on the first CHOKE is THE 60// "holders exist but we never pulled" bug (seedeval "IGNORING", 2464 missing pieces w/ holders). We keep the 61// connection alive (keep-alives) waiting for the unchoke up to this window, then free the slot. Bounds slot 62// hold-time so the pool still turns over if every holder keeps choking us. 63const TG_UNCHOKE_WAIT: i64 = 90 64// DATA-PHASE read timeout (seconds). The 6s CONNECT timeout is far too short ONCE a seeder unchokes us: 65// a busy public seeder queues our request behind many peers, so its FIRST piece block -- and inter-block 66// gaps -- routinely exceed 6s. tg_read_msg then returns a spurious timeout and the child gives up 67// mid-request, so we pull NOTHING despite being unchoked. THIS is the residual "IGNORING" bug the pre-unchoke 68// patience window never covered: seedeval shows 23 seeders unchoke us yet have=0. Extending the read timeout 69// to a full optimistic-unchoke interval lets a slow-but-willing seeder actually feed us. Bounded: a seeder 70// truly silent this long AFTER unchoking is genuinely dead -> the read times out once, we free the slot. 71const TG_DATA_TIMEOUT: i64 = 30 72 73// per-connection DH private key for MSE (varies by wall-clock; nonzero ~128-bit). Hardening TODO: CSPRNG. 74func tg_dhpriv(x: *i64) -> i64 { return mse_gen_priv(x) } // CSPRNG per-connection key (nx_mse_wire) 75// MSE is OPT-IN (marker file) so it can't silently break real downloads before it's field-verified vs real 76// clients. Default (no marker) = plaintext-first = the known-good behavior. `touch /volume1/ai/torrent/mse.on` to enable. 77func tg_mse_on() -> i64 { let f: i64 = sys_openat_rd("/volume1/ai/torrent/mse.on" as *u8); if f>=0 { sys_close(f); return 1 } return 0 } 78// MULTI-FILE torrents have NO top-level "length" -- the REAL total is the SUM of the info-dict "files" list's 79// per-file "length". Using npc*plen (the old fallback) OVER-sizes the last piece (treats a partial last piece 80// as full plen) so it NEVER completes -> stuck at 99%/missing=1. This sums files[].length. Falls back to 81// npc*plen only if the list can't be parsed (fail-safe, same as before). 82func tg_multifile_total(meta: *u8, msize: i64, npc: i64, plen: i64) -> i64 { 83 // seq1786: the FOUR bail points below all returned npc*plen SILENTLY and were therefore 84 // INDISTINGUISHABLE -- a parse failure could not be told from a legitimate total, which is how 85 // this survived undetected. Each now returns a distinct NEGATIVE sentinel; the CALLER substitutes 86 // npc*plen so BEHAVIOUR IS UNCHANGED, and records WHICH bail fired. 87 // -1 = no "files" key -2 = "files" is not a list -3 = nx_bc_skip made no progress 88 // -4 = walked the list and summed nothing 89 // A caller MUST treat any negative return as "total unknown", never as a size. 90 let fo: i64 = nx_bc_dict_get(meta, 0, msize, "files" as *u8, 5) 91 if fo < 0 { return 0-1 } 92 if meta[fo] != (108 as u8) { return 0-2 } // 'l' = list of file dicts 93 var sum: i64 = 0; var o: i64 = fo + 1 94 while o < msize { 95 if meta[o] == (101 as u8) { if sum > 0 { return sum } return 0-4 } // 'e' ends the list 96 let lo: i64 = nx_bc_dict_get(meta, o, msize, "length" as *u8, 6) 97 if lo >= 0 { let iv: *i64 = sys_mmap(16) as *i64; if nx_bc_int(meta, lo, msize, iv) >= 0 { sum = sum + iv[0] } } 98 let nxt: i64 = nx_bc_skip(meta, o, msize) // advance past this file-dict 99 if nxt <= o { if sum > 0 { return sum } return 0-3 } // no progress -> bail 100 o = nxt 101 } 102 if sum > 0 { return sum } return 0-4 103} 104// seq1804: the grinding-tail status line used to pass npc*plen as `total` -- a FABRICATED figure, 105// indistinguishable from a measured one, that over-states the torrent by up to a full piece 106// (BANK-155: 4676648960 reported vs 4674889513 actual). It misled THREE of my own investigations 107// into believing the bencode walker had failed when it never had. The parent loop reads npc/plen from 108// download.npc and never parses metadata -- but the metadata is RIGHT THERE on disk, so read it and 109// report the truth. Falls back to npc*plen ONLY on a genuine read/parse failure, which is now a real 110// event rather than the default. 111// LAW: a derived field and a measured field must not share a name. 112func tg_meta_total_of(metapath: *u8, npc: i64, plen: i64) -> i64 { 113 let fd: i64 = sys_openat_rd(metapath); if fd < 0 { return npc*plen } 114 let mb2: *u8 = sys_mmap(TG_MAGIC_262144); let n: i64 = sys_read(fd, mb2, TG_MAGIC_262144 - 1); sys_close(fd) 115 if n <= 0 { return npc*plen } 116 let lno: i64 = nx_bc_dict_get(mb2, 0, n, "length" as *u8, 6) 117 if lno >= 0 { let iv: *i64 = sys_mmap(16) as *i64; if nx_bc_int(mb2, lno, n, iv) >= 0 { return iv[0] } } 118 let t: i64 = tg_multifile_total(mb2, n, npc, plen) 119 if t > 0 { return t } 120 return npc*plen 121} 122// SELECTIVE DOWNLOAD (operator: "if the file isnt the video and it stops the torrent, trim it"). Build a 123// per-piece WANTED mask: a piece is wanted iff it overlaps a file whose size >= min_bytes (the real content; 124// small cover/nfo/sample/txt junk is skipped). Single-file torrent (top-level "length") -> all wanted. If NO 125// file qualifies (e.g. an all-small-files torrent) -> ALL wanted (never accidentally want nothing = safe). 126// Boundary pieces that overlap ANY wanted file are wanted (needed for that file's bytes). Returns wanted_count. 127func tg_build_wanted(meta: *u8, msize: i64, npc: i64, plen: i64, wanted: *u8, min_bytes: i64) -> i64 { 128 var i: i64=0; while i<npc { wanted[i]=0 as u8; i=i+1 } 129 let lno: i64 = nx_bc_dict_get(meta, 0, msize, "length" as *u8, 6) 130 if lno >= 0 { i=0; while i<npc { wanted[i]=1 as u8; i=i+1 } return npc } 131 let fo: i64 = nx_bc_dict_get(meta, 0, msize, "files" as *u8, 5) 132 if fo < 0 { i=0; while i<npc { wanted[i]=1 as u8; i=i+1 } return npc } 133 if meta[fo] != (108 as u8) { i=0; while i<npc { wanted[i]=1 as u8; i=i+1 } return npc } 134 var off: i64=0; var o: i64=fo+1; var go2: i64=1 135 while go2==1 { 136 if o>=msize { go2=0 } else { if meta[o]==(101 as u8) { go2=0 } else { 137 let flo: i64 = nx_bc_dict_get(meta, o, msize, "length" as *u8, 6) 138 var flen: i64=0; if flo>=0 { let iv: *i64=sys_mmap(16) as *i64; if nx_bc_int(meta,flo,msize,iv)>=0 { flen=iv[0] } } 139 if flen >= min_bytes { var b: i64 = off/plen; let bend: i64 = (off+flen-1)/plen 140 while b<=bend { if b>=0 { if b<npc { wanted[b]=1 as u8 } } b=b+1 } } 141 off = off + flen 142 let nxt: i64 = nx_bc_skip(meta, o, msize); if nxt<=o { go2=0 } else { o=nxt } 143 } } 144 } 145 var wc: i64=0; i=0; while i<npc { if (wanted[i] as i64)==1 { wc=wc+1 } i=i+1 } 146 if wc==0 { i=0; while i<npc { wanted[i]=1 as u8; i=i+1 } return npc } // safety: nothing qualified -> want all 147 return wc 148} 149// the min-file-size (bytes) that marks a file as WANTED content. Data-driven: <selfdir>/torrent_wanted.conf 150// (a single integer) overrides; default 15 MB (video >> cover/nfo/sample). Config, not a magic number (rule 11). 151func tg_wanted_min() -> i64 { 152 let p: *u8 = sys_mmap(TG_MAGIC_1024); var o: i64 = pm_bstr(p, 0, tg_self_dir()); o = pm_bstr(p, o, "/torrent_wanted.conf" as *u8); p[o]=0 as u8 153 let fd: i64 = sys_openat_rd(p); if fd < 0 { return TG_MAGIC_15728640 } 154 let b: *u8 = sys_mmap(64); let n: i64 = sys_read(fd, b, 63); sys_close(fd) 155 var v: i64=0; var i: i64=0; while i<n { if b[i]>=(48 as u8) { if b[i]<=(57 as u8) { v=v*10+((b[i] as i64)-48) } } i=i+1 } 156 if v<=0 { return TG_MAGIC_15728640 } 157 return v 158} 159// pm_read_msg over an MseCtx (transparent decrypt; plaintext ctx == raw). >0 body len, 0 keep-alive, <0 error. 160func tg_read_msg(ctx: *MseCtx, fd: i64, mb: *u8, cap: i64) -> i64 { 161 if mse_read(ctx, fd, mb, 4) != 4 { return 0-1 } 162 let blen: i64 = _pw_get_u32(mb, 0) 163 if blen == 0 { return 0 } 164 if blen > cap-4 { return 0-1 } 165 if mse_read(ctx, fd, mb+4, blen) != blen { return 0-1 } 166 return blen 167} 168 169// raw open O_RDWR|O_CREAT (0x42) -- NO O_TRUNC, so children write at offsets without wiping. 170func tg_open_rw(path: *u8) -> i64 { return __syscall(SYS_OPENAT, AT_FDCWD, path as i64, 0x42, 0x1a4, 0, 0) } 171 172// PEX harvest (BEP-11): append gossiped compact peers (6B each: ip4 BE + port BE) to the shared 173// download.pex log under flock. Append-only + best-effort DISCOVERY -- never a data invariant (SHA1 174// still guards every piece), so a dropped append is harmless. The parent merges these into the peer 175// set on each re-announce. Reuses the avail-map flock idiom (sys_flock LOCK_EX) + the proven 176// O_WRONLY|O_CREAT|O_APPEND (0x441) atomic-append open. 177func tg_pex_append(pexpath: *u8, ips: *i64, ports: *i64, cnt: i64) -> i64 { 178 if cnt <= 0 { return 0 } 179 let fd: i64 = __syscall(SYS_OPENAT, AT_FDCWD, pexpath as i64, 0x441, 0x1a4, 0, 0) 180 if fd < 0 { return 0 } 181 sys_flock(fd, SYS_LOCK_EX) 182 let buf: *u8 = sys_mmap(cnt * 6 + 16) 183 var o: i64 = 0; var i: i64 = 0 184 while i < cnt { 185 let ip: i64 = ips[i]; let pt: i64 = ports[i] 186 buf[o]=((ip>>24)&0xff) as u8; buf[o+1]=((ip>>16)&0xff) as u8; buf[o+2]=((ip>>8)&0xff) as u8; buf[o+3]=(ip&0xff) as u8 187 buf[o+4]=((pt>>8)&0xff) as u8; buf[o+5]=(pt&0xff) as u8 188 o = o + 6; i = i + 1 189 } 190 cl_write_n(fd, buf, o) 191 sys_flock(fd, SYS_LOCK_UN) 192 sys_close(fd) 193 return cnt 194} 195 196// parent: merge harvested PEX peers (download.pex, 6B records) into the live peer set, deduped 197// against the current set. Returns the new count (bounded by max). Lock-free read -- a torn tail 198// record is ignored (i+6<=rn) and re-read next cycle. 199func tg_pex_merge(pexpath: *u8, ips: *i64, ports: *i64, have: i64, max: i64) -> i64 { 200 let fd: i64 = sys_openat_rd(pexpath) 201 if fd < 0 { return have } 202 let buf: *u8 = sys_mmap(6 * TG_MAGIC_65536 + 16) 203 let rn: i64 = sys_read(fd, buf, 6 * TG_MAGIC_65536); sys_close(fd) 204 if rn < 6 { return have } 205 var h: i64 = have 206 var i: i64 = 0 207 while i + 6 <= rn { 208 let ip: i64 = ((buf[i] as i64)<<24)|((buf[i+1] as i64)<<16)|((buf[i+2] as i64)<<8)|(buf[i+3] as i64) 209 let pt: i64 = ((buf[i+4] as i64)<<8)|(buf[i+5] as i64) 210 var dup: i64 = 0; var j: i64 = 0 211 while j < h { if ips[j]==ip { if ports[j]==pt { dup=1; j=h } } j=j+1 } 212 if dup == 0 { if h < max { ips[h]=ip; ports[h]=pt; h=h+1 } } 213 i = i + 6 214 } 215 return h 216} 217 218// ip-filter: compact the peer list in place, dropping any IP in a blocked range. Runs after each announce/PEX 219// merge in the PARENT -> children inherit the clean list via fork COW (no per-connect cost, no tg_from_peer 220// arg-cap change). cnt<=0 (no blocklist) -> pass-through no-op. 221func tg_ipf_filter(ips: *i64, ports: *i64, np: i64, arr: *i64, cnt: i64) -> i64 { 222 if cnt <= 0 { return np } 223 var w: i64 = 0; var i: i64 = 0 224 while i < np { if ipf_blocked(arr, cnt, ips[i]) == 0 { ips[w]=ips[i]; ports[w]=ports[i]; w=w+1 } i=i+1 } 225 return w 226} 227 228// read outdir/download.control -> 1 if the operator asked to stop (paused/removed), else 0. 229// pure file-based control (the daemon writes the file); no kill/getpid/setpgid needed. 230func tg_stop(ctlpath: *u8) -> i64 { 231 let fd: i64 = sys_openat_rd(ctlpath) 232 if fd < 0 { return 0 } 233 let b: *u8 = sys_mmap(16); let r: i64 = sys_read(fd, b, 15); sys_close(fd) 234 if r <= 0 { return 0 } 235 let c: i64 = b[0] as i64 236 if c == 112 { return 1 } // 'p' = paused 237 if c == 114 { return 1 } // 'r' = removed 238 return 0 239} 240 241func tg_status(path: *u8, name: *u8, total: i64, done: i64, have: i64, npc: i64, peers: i64, state: *u8) -> i64 { 242 let fd: i64 = sys_openat_wr(path, 0x1a4) 243 if fd < 0 { return 0 } 244 // newline-delimited key=value (value = rest of line) so a name with spaces parses cleanly 245 cl_w(fd, "total=" as *u8); cl_wn(fd, total); cl_w(fd, "\n" as *u8) 246 cl_w(fd, "done=" as *u8); cl_wn(fd, done); cl_w(fd, "\n" as *u8) 247 cl_w(fd, "have=" as *u8); cl_wn(fd, have); cl_w(fd, "\n" as *u8) 248 cl_w(fd, "pieces=" as *u8); cl_wn(fd, npc); cl_w(fd, "\n" as *u8) 249 cl_w(fd, "peers=" as *u8); cl_wn(fd, peers); cl_w(fd, "\n" as *u8) 250 cl_w(fd, "state=" as *u8); cl_w(fd, state); cl_w(fd, "\n" as *u8) 251 cl_w(fd, "name=" as *u8); cl_w(fd, name); cl_w(fd, "\n" as *u8) 252 sys_close(fd) 253 return 0 254} 255 256// CHILD: download as many NEEDED pieces as this peer serves; write each to outfile@offset + set 257// donefile bit. Returns pieces completed by this child. 258// STREAM MODE: present (the daemon writes it when a /stream request arrives) => download SEQUENTIALLY so 259// the contiguous playable prefix grows front-to-back for a <video> (rarest-first leaves holes that stall 260// playback). Absent => normal rarest-first+endgame (best for swarm health). 1 if the sidecar exists. 261func tg_stream_on(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 } 262 263// sequential pick: the LOWEST-index NEEDED piece this peer HAS. Pass 1 prefers a piece no other child is 264// downloading (in-flight==0) so the pool spreads; pass 2 allows an in-flight piece (race) so the prefix 265// always advances. -1 if the peer has nothing needed. (Relates to nx_sp_sequential, peer+in-flight aware.) 266func tg_seq_pick(donebits: *u8, peerbits: *u8, byte_len: i64, havebits: i64, inf: *i64, npc: i64) -> i64 { 267 var p: i64 = 0 268 while p < npc { 269 if (donebits[p] as i64) == 0 { var has: i64 = 1; if havebits == 1 { if nx_pw_bitfield_has(peerbits, byte_len, p) == 0 { has = 0 } } if has == 1 { if inf[p] == 0 { return p } } } 270 p = p + 1 271 } 272 p = 0 273 while p < npc { 274 if (donebits[p] as i64) == 0 { var h2: i64 = 1; if havebits == 1 { if nx_pw_bitfield_has(peerbits, byte_len, p) == 0 { h2 = 0 } } if h2 == 1 { return p } } 275 p = p + 1 276 } 277 return 0 - 1 278} 279 280// SEED what we already have (operator OK'd uploading -> s-class exceed): send our BITFIELD (peers learn 281// our pieces) + UNCHOKE (they may request). Earns RECIPROCITY -- a LEECHER that holds a piece we still 282// need (e.g. the last piece) but needs one WE have will TRADE it to us, instead of us begging a non- 283// ---- PARTIAL-PIECE PERSISTENCE (reciprocity-starvation fix) ---- 284// Saturated public seeders give a pure-leecher only BRIEF optimistic-unchoke windows -- too short to move a 285// whole 2-4MB piece. Without this a child accumulates a piece in pbuf and DISCARDS it on CHOKE -> zero progress 286// on stingy swarms (seedeval "IGNORING": 23 seeders unchoke us yet have=0). Persist the received CONTIGUOUS 287// PREFIX of the in-flight piece to a staging file (download.pstage) + its byte-count (download.ppart) so the 288// NEXT window (this or another child) RESUMES from there -> pieces complete across many brief windows. 289// download.part stays VERIFIED-ONLY (verify/extract UNCHANGED); SHA1 still gates completion, so a torn/stale 290// prefix just fails verify -> redownload = SAFE BY CONSTRUCTION. cprefix (contiguous), NOT pbytes (total), is 291// persisted so a resumed prefix can never be garbage from an out-of-order gap. The staged prefix is bounded by 292// PCAP (block receipt drops beyond PCAP) so a load can never overflow pbuf. 293func tg_ppart_get(ppath: *u8, piece: i64) -> i64 { 294 let fd: i64 = sys_openat_rd(ppath); if fd < 0 { return 0 } 295 let b: *u8 = sys_mmap(16); sys_lseek(fd, piece*8, 0); let r: i64 = sys_read(fd, b, 8); sys_close(fd) 296 if r < 8 { return 0 } 297 var v: i64 = 0; var i: i64 = 0; while i < 8 { v = v | ((b[i] as i64) << (i*8)); i = i + 1 } 298 if v < 0 { return 0 } 299 return v 300} 301func tg_ppart_set(ppath: *u8, piece: i64, val: i64) -> i64 { 302 let fd: i64 = tg_open_rw(ppath); if fd < 0 { return 0 } // O_RDWR|O_CREAT, NO truncate -> per-piece 8-byte slot, sparse 303 let b: *u8 = sys_mmap(16); var i: i64 = 0; while i < 8 { b[i] = ((val >> (i*8)) & 0xff) as u8; i = i + 1 } 304 sys_lseek(fd, piece*8, 0); cl_write_n(fd, b, 8); sys_close(fd) 305 return 0 306} 307// flush pbuf[0..cprefix] of `piece` to the staging file + record cprefix. Called on CHOKE / child exit. 308func tg_ppart_flush(spath: *u8, ppath: *u8, piece: i64, plen: i64, pbuf: *u8, cprefix: i64) -> i64 { 309 if cprefix <= 0 { return 0 } 310 let fd: i64 = tg_open_rw(spath); if fd < 0 { return 0 } 311 sys_lseek(fd, piece*plen, 0); cl_write_n(fd, pbuf, cprefix); sys_close(fd) 312 tg_ppart_set(ppath, piece, cprefix) 313 return 0 314} 315// load `piece`'s staged prefix (cprefix bytes) into pbuf. Returns bytes loaded (0 => start fresh, safe). 316func tg_ppart_load(spath: *u8, piece: i64, plen: i64, pbuf: *u8, cprefix: i64) -> i64 { 317 if cprefix <= 0 { return 0 } 318 let fd: i64 = sys_openat_rd(spath); if fd < 0 { return 0 } 319 sys_lseek(fd, piece*plen, 0); let r: i64 = sys_read(fd, pbuf, cprefix); sys_close(fd) 320 if r < cprefix { return 0 } 321 return cprefix 322} 323// reciprocating seeder for a free optimistic-unchoke. THE "IGNORING" completion fix. 324func tg_seed_hello(ctx: *MseCtx, fd: i64, lbits: *u8, npc: i64) -> i64 { 325 let nbytes: i64 = (npc + 7) / 8 326 let bf: *u8 = sys_mmap(nbytes + 16); var b: i64 = 0; while b < nbytes { bf[b] = 0 as u8; b = b + 1 } 327 var p: i64 = 0 328 while p < npc { if (lbits[p] as i64) == 1 { let by: i64 = p / 8; let bit: i64 = 7 - (p - by*8); bf[by] = ((bf[by] as i64) | (1 << bit)) as u8 } p = p + 1 } 329 let m1: *u8 = sys_mmap(nbytes + 16); mse_write(ctx, fd, m1, nx_pw_build_msg(NX_PW_BITFIELD, bf, nbytes, m1)) 330 let m2: *u8 = sys_mmap(16); mse_write(ctx, fd, m2, nx_pw_build_msg(NX_PW_UNCHOKE, 0 as *u8, 0, m2)) 331 return 0 332} 333func tg_from_peer(ipv: i64, port: i64, ih: *u8, mypid: *u8, outpath: *u8, donepath: *u8, npcpath: *u8, metapath: *u8, statpath: *u8, ctlpath: *u8, availpath: *u8, inflightpath: *u8, streampath: *u8, pexpath: *u8, peers: i64) -> i64 { 334 let dest: *u8 = sys_mmap(16); cl_sockaddr(dest, port, (ipv>>24)&0xff, (ipv>>16)&0xff, (ipv>>8)&0xff, ipv&0xff) 335 var fd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 336 if fd < 0 { return 0 } 337 sys_set_socket_timeout(fd, 6) 338 if nx_connect_bounded(fd, dest, 16, TG_CONNECT_MS) != 0 { sys_close(fd); return 0 } 339 // MSE/PE ANTI-THROTTLE (OPT-IN via /volume1/ai/torrent/mse.on): try an encrypted handshake first (DPI can't 340 // fingerprint it); on reject the socket is dead -> reconnect + plaintext. DEFAULT (no marker) = plaintext-first 341 // = the known-good download path (MSE stays off until field-verified vs real clients, so it can't stall real DLs). 342 let ctx: *MseCtx = sys_mmap(MSE_CTX_BYTES) as *MseCtx 343 if tg_mse_on() == 1 { 344 let xpriv: *i64 = sys_mmap((MSE_N+2)*8) as *i64; tg_dhpriv(xpriv) 345 if mse_connect(fd, ih, xpriv, ctx) != 1 { 346 sys_close(fd) 347 fd = sys_socket(AF_INET, SOCK_STREAM, 0); if fd < 0 { return 0 } 348 sys_set_socket_timeout(fd, 6) 349 if nx_connect_bounded(fd, dest, 16, TG_CONNECT_MS) != 0 { sys_close(fd); return 0 } 350 mse_ctx_plain(ctx) 351 } 352 } else { mse_ctx_plain(ctx) } // DEFAULT plaintext (byte-identical to pre-MSE behavior) 353 let ch: *u8 = sys_mmap(128); nx_pw_build_handshake(ih, mypid, ch); ch[25] = (ch[25] as i64 | 0x10) as u8 354 if mse_write(ctx, fd, ch, 68) != 68 { sys_close(fd); return 0 } 355 let ph: *u8 = sys_mmap(128); if mse_read(ctx, fd, ph, 68) != 68 { sys_close(fd); return 0 } 356 let gih: *u8 = sys_mmap(20); let gpid: *u8 = sys_mmap(20); if nx_pw_parse_handshake(ph, 68, gih, gpid) != 1 { sys_close(fd); return 0 } 357 let ceb: *u8 = sys_mmap(64); let cm: *u8 = sys_mmap(128); mse_write(ctx, fd, cm, pm_build_ext(0, ceb, pm_bstr(ceb, 0, "d1:md11:ut_metadatai1e6:ut_pexi3eee" as *u8), cm)) // advertise ut_metadata=1 + ut_pex=3 (PEX_OUR_ID) 358 359 let outfd: i64 = tg_open_rw(outpath); let donefd: i64 = tg_open_rw(donepath) 360 let lbits: *u8 = sys_mmap(TG_MAGIC_262144) 361 sys_lseek(donefd, 0, 0); sys_read(donefd, lbits, TG_MAGIC_262144) // load current progress 362 // SELECTIVE DOWNLOAD: download.wanted (sibling of download.done) = per-piece wanted mask; pickbits = lbits | ~wanted 363 // so the picker treats unwanted (junk-file) pieces as done -> never fetches them. Built once after metadata resolves. 364 let wantedpath: *u8 = sys_mmap(640); var wpo: i64=0; var lastsl: i64=0; var wci: i64=0 365 while donepath[wci]!=(0 as u8) { if donepath[wci]==(47 as u8) { lastsl=wci } wci=wci+1 } 366 wci=0; while wci<=lastsl { wantedpath[wpo]=donepath[wci]; wpo=wpo+1; wci=wci+1 } wpo=pm_bstr(wantedpath, wpo, "download.wanted" as *u8); wantedpath[wpo]=0 as u8 367 let wbits: *u8 = sys_mmap(TG_MAGIC_262144); let pickbits: *u8 = sys_mmap(TG_MAGIC_262144); var wbuilt: i64=0 368 // partial-prefix persistence staging (siblings of download.part; same dir-prefix idiom as download.wanted) 369 let spath: *u8 = sys_mmap(640); var spo: i64=0; var si2: i64=0; while si2<=lastsl { spath[spo]=donepath[si2]; spo=spo+1; si2=si2+1 } spo=pm_bstr(spath, spo, "download.pstage" as *u8); spath[spo]=0 as u8 370 let ppath: *u8 = sys_mmap(640); var ppo2: i64=0; var pi3: i64=0; while pi3<=lastsl { ppath[ppo2]=donepath[pi3]; ppo2=ppo2+1; pi3=pi3+1 } ppo2=pm_bstr(ppath, ppo2, "download.ppart" as *u8); ppath[ppo2]=0 as u8 371 372 let meta: *u8 = sys_mmap(TG_MAGIC_262144); var msize: i64=0; var putm: i64=0; var gmeta: i64=0; var nmeta: i64=0; var rmeta: i64=0; var mdone: i64=0 373 var plen: i64=0; var poff: i64=0; var total: i64=0; var npc: i64=0; var unchoked: i64=0 374 let name: *u8 = sys_mmap(256); name[0]=63 as u8; name[1]=0 as u8 375 let mb: *u8 = sys_mmap(TG_MAGIC_40000); let pbuf: *u8 = sys_mmap(PCAP) 376 // seq1734: counts block receipts refused for landing beyond PCAP. Must never be silent -- a 377 // truncated piece can never verify, so a non-zero value here is the difference between 378 // "this torrent is slow" and "this torrent is structurally impossible with this buffer". 379 var dropped_blocks: i64 = 0 380 let peerbits: *u8 = sys_mmap(TG_MAGIC_40000) // THIS peer's advertised pieces (from BITFIELD + HAVE), MSB-first per BEP-3 381 var have: i64=0; var cur: i64=0-1; var pbytes: i64=0; var loops: i64=0; var go: i64=1; var chmsg: i64=0; var havebits: i64=0; var patient: i64=0 // tail-patience: stay glued to a holder waiting for its unchoke (the seedeval "IGNORING" fix) 382 var cprefix: i64=0 // contiguous received prefix of the in-flight piece (persisted on choke so brief unchoke windows accumulate) 383 let t_start: i64 = sys_now_realtime_sec() // connection start -> bounds the bulk unchoke-patience window (TG_UNCHOKE_WAIT) 384 var avail_added: i64=0; var avbuf: *i64 = 0 as *i64; var effbuf: *i64 = 0 as *i64; var infbuf: *i64 = 0 as *i64 // rarest-first + endgame scratch (lazy-alloc once npc known) 385 // METADATA CACHE LOAD: if a prior peer already resolved + SHA1-verified the metadata, load it from 386 // disk and skip the ut_metadata round-trip entirely (kills the per-child refetch tax). The SHA1 387 // re-verify guards a partial/corrupt cache -> falls back to the normal ut_metadata fetch. 388 let mcfd: i64 = sys_openat_rd(metapath) 389 if mcfd >= 0 { 390 let mr: i64 = sys_read(mcfd, meta, TG_MAGIC_262144); sys_close(mcfd) 391 if mr > 0 { 392 let gc: *u8 = sys_mmap(20); sha1(meta, mr, gc); var ec: i64=1; var xc: i64=0; while xc<20 { if gc[xc]!=ih[xc] { ec=0; xc=20 } else { xc=xc+1 } } 393 if ec==1 { 394 msize=mr; mdone=1; rmeta=1 395 let plo: i64=nx_bc_dict_get(meta,0,msize,"piece length" as *u8,12); let iv5: *i64=sys_mmap(16) as *i64; if plo>=0 { nx_bc_int(meta,plo,msize,iv5); plen=iv5[0] } 396 let pco: i64=nx_bc_dict_get(meta,0,msize,"pieces" as *u8,6); let so5: *i64=sys_mmap(16) as *i64; let sl5: *i64=sys_mmap(16) as *i64; if pco>=0 { nx_bc_str(meta,pco,msize,so5,sl5); poff=so5[0]; npc=sl5[0]/20 } 397 let lno: i64=nx_bc_dict_get(meta,0,msize,"length" as *u8,6); if lno>=0 { let iv6: *i64=sys_mmap(16) as *i64; nx_bc_int(meta,lno,msize,iv6); total=iv6[0] } else { total=tg_multifile_total(meta, msize, npc, plen) } 398 // seq1786: substitute the historical npc*plen fallback so BEHAVIOUR IS UNCHANGED, but 399 // publish WHICH bail fired -- a stuck torrent now names its own parse failure in 400 // download.status instead of silently reporting an invented total. A negative total 401 // must NEVER reach the piece math: pl_i = total - cur*plen would go wildly wrong. 402 if total < 0 { 403 if total == 0-1 { tg_status(statpath,name,0,0,0,npc,0,"meta-bail-nofiles" as *u8) } 404 if total == 0-2 { tg_status(statpath,name,0,0,0,npc,0,"meta-bail-notlist" as *u8) } 405 if total == 0-3 { tg_status(statpath,name,0,0,0,npc,0,"meta-bail-noprogress" as *u8) } 406 if total == 0-4 { tg_status(statpath,name,0,0,0,npc,0,"meta-bail-empty" as *u8) } 407 total = npc*plen 408 } 409 let nmo: i64=nx_bc_dict_get(meta,0,msize,"name" as *u8,4); if nmo>=0 { let so6: *i64=sys_mmap(16) as *i64; let sl6: *i64=sys_mmap(16) as *i64; if nx_bc_str(meta,nmo,msize,so6,sl6)>=0 { var k: i64=0; var nn: i64=sl6[0]; if nn>200 {nn=200} while k<nn { name[k]=meta[so6[0]+k]; k=k+1 } name[nn]=0 as u8 } } 410 let im: *u8=sys_mmap(16); mse_write(ctx,fd,im,nx_pw_build_msg(NX_PW_INTERESTED,0 as *u8,0,im)) 411 // TAIL PATIENCE (the seedeval "IGNORING" fix): in the endgame (<= threshold pieces left) a 412 // holder is almost always a SEEDER that needs ~10-30s to optimistically-unchoke our pure- 413 // leecher. Extend this peer's read timeout so we WAIT for that unchoke instead of cycling 414 // off at the 6s connect timeout -- THE reason "76 peers HAVE the last piece but we never 415 // pull it". Only at the tail, so the bulk download keeps cycling fast off real chokers. 416 var done_n: i64=0; var dq: i64=0; while dq<npc { if (lbits[dq] as i64)==1 { done_n=done_n+1 } dq=dq+1 } 417 if npc - done_n <= TG_ENDGAME_THRESHOLD { sys_set_socket_timeout(fd, 45); patient=1 } 418 tg_seed_hello(ctx, fd, lbits, npc) // advertise what we hold + unchoke -> a leecher can TRADE us the tail piece 419 } 420 } 421 } 422 // LEAK ROOT-FIX 2026-07-30: the SEED/SERVE path (NX_PW_REQUEST, below) used to sys_mmap(rln+32) 423 // TWICE PER BLOCK SERVED and NEVER munmap -- ~40KB of leaked pages per served block, which is why 424 // long-lived children reached 1.5GB RSS (measured: 3 pids at 0.8-1.6GB, nx_leak_check CRITICAL). 425 // rln is BOUNDED (rln<=TG_MAGIC_16384 is checked at the serve guard), so these two buffers are 426 // LOOP-INVARIANT: map them ONCE here and reuse them every request. DO NOT move them back inside 427 // the loop -- that reintroduces the leak. This loop runs up to TG_MAGIC_2000000 iterations. 428 let sv_pbuf: *u8 = sys_mmap(TG_MAGIC_16384 + 64) 429 let sv_mbuf: *u8 = sys_mmap(TG_MAGIC_16384 + 64) 430 while go == 1 { 431 loops = loops + 1 432 if (loops % 512) == 0 { if tg_stop(ctlpath) == 1 { go = 0 } } 433 if loops > TG_MAGIC_2000000 { go = 0 } 434 if go == 1 { 435 let t_r0: i64 = sys_now_realtime_sec() 436 let blen: i64 = tg_read_msg(ctx, fd, mb, TG_MAGIC_40000) 437 if blen < 0 { 438 // Distinguish a recv TIMEOUT (blocked ~the socket timeout -> connection alive, peer just 439 // silent) from a real CLOSE/error (returns fast). While still waiting for a FIRST unchoke and 440 // inside the patience window, a timeout is NOT death: keep-alive and STAY so the seeder can 441 // rotate its optimistic-unchoke onto us. A fast return, or an active/expired peer -> give up. 442 var giveup: i64 = 1 443 if (sys_now_realtime_sec() - t_r0) >= 4 { if mdone==1 { if unchoked==0 { if cur<0 { 444 if (sys_now_realtime_sec() - t_start) < TG_UNCHOKE_WAIT { 445 let ka: *u8=sys_mmap(8); ka[0]=0 as u8; ka[1]=0 as u8; ka[2]=0 as u8; ka[3]=0 as u8; mse_write(ctx, fd, ka, 4); giveup=0 446 } 447 } } } } 448 if giveup == 1 { go = 0 } 449 } 450 if blen > 0 { 451 let id: i64 = nx_pw_msg_id(mb); let nt: i64 = 4 + blen 452 if id == PW_EXT { 453 let xi: i64 = mb[5] as i64 454 if xi == 0 { 455 let mo: i64 = nx_bc_dict_get(mb,6,nt,"m" as *u8,1); if mo>=0 { let uo: i64=nx_bc_dict_get(mb,mo,nt,"ut_metadata" as *u8,11); if uo>=0 { let iv: *i64=sys_mmap(16) as *i64; if nx_bc_int(mb,uo,nt,iv)>=0 { putm=iv[0] } } } 456 let so: i64 = nx_bc_dict_get(mb,6,nt,"metadata_size" as *u8,13); if so>=0 { let iv2: *i64=sys_mmap(16) as *i64; if nx_bc_int(mb,so,nt,iv2)>=0 { msize=iv2[0] } } 457 if putm>0 { if msize>0 { if rmeta==0 { nmeta=(msize+TG_MAGIC_16383)/TG_MAGIC_16384; var pi: i64=0; while pi<nmeta { let rb: *u8=sys_mmap(64); var ro: i64=pm_bstr(rb,0,"d8:msg_typei0e5:piecei" as *u8); ro=pm_bint(rb,ro,pi); ro=pm_bstr(rb,ro,"ee" as *u8); let rm: *u8=sys_mmap(128); mse_write(ctx,fd,rm,pm_build_ext(putm,rb,ro,rm)); pi=pi+1 } rmeta=1 } } } 458 } 459 if xi == 1 { if mdone==0 { 460 let pio: i64=nx_bc_dict_get(mb,6,nt,"piece" as *u8,5); var px: i64=0; if pio>=0 { let iv3: *i64=sys_mmap(16) as *i64; if nx_bc_int(mb,pio,nt,iv3)>=0 { px=iv3[0] } } 461 let raw: i64=nx_bc_skip(mb,6,nt); if raw>0 { let rl: i64=nt-raw; var c: i64=0; while c<rl { if px*TG_MAGIC_16384+c<TG_MAGIC_262144 { meta[px*TG_MAGIC_16384+c]=mb[raw+c] } c=c+1 } gmeta=gmeta+1 } 462 if gmeta>=nmeta { if nmeta>0 { 463 let gh: *u8=sys_mmap(20); sha1(meta,msize,gh); var eq: i64=1; var x: i64=0; while x<20 { if gh[x]!=ih[x] { eq=0; x=20 } else { x=x+1 } } 464 if eq==1 { mdone=1 465 let plo: i64=nx_bc_dict_get(meta,0,msize,"piece length" as *u8,12); let iv5: *i64=sys_mmap(16) as *i64; if plo>=0 { nx_bc_int(meta,plo,msize,iv5); plen=iv5[0] } 466 let pco: i64=nx_bc_dict_get(meta,0,msize,"pieces" as *u8,6); let so5: *i64=sys_mmap(16) as *i64; let sl5: *i64=sys_mmap(16) as *i64; if pco>=0 { nx_bc_str(meta,pco,msize,so5,sl5); poff=so5[0]; npc=sl5[0]/20 } 467 let lno: i64=nx_bc_dict_get(meta,0,msize,"length" as *u8,6); if lno>=0 { let iv6: *i64=sys_mmap(16) as *i64; nx_bc_int(meta,lno,msize,iv6); total=iv6[0] } else { total=tg_multifile_total(meta, msize, npc, plen) } 468 // seq1786: substitute the historical npc*plen fallback so BEHAVIOUR IS UNCHANGED, but 469 // publish WHICH bail fired -- a stuck torrent now names its own parse failure in 470 // download.status instead of silently reporting an invented total. A negative total 471 // must NEVER reach the piece math: pl_i = total - cur*plen would go wildly wrong. 472 if total < 0 { 473 if total == 0-1 { tg_status(statpath,name,0,0,0,npc,0,"meta-bail-nofiles" as *u8) } 474 if total == 0-2 { tg_status(statpath,name,0,0,0,npc,0,"meta-bail-notlist" as *u8) } 475 if total == 0-3 { tg_status(statpath,name,0,0,0,npc,0,"meta-bail-noprogress" as *u8) } 476 if total == 0-4 { tg_status(statpath,name,0,0,0,npc,0,"meta-bail-empty" as *u8) } 477 total = npc*plen 478 } 479 let nmo: i64=nx_bc_dict_get(meta,0,msize,"name" as *u8,4); if nmo>=0 { let so6: *i64=sys_mmap(16) as *i64; let sl6: *i64=sys_mmap(16) as *i64; if nx_bc_str(meta,nmo,msize,so6,sl6)>=0 { var k: i64=0; var nn: i64=sl6[0]; if nn>200 {nn=200} while k<nn { name[k]=meta[so6[0]+k]; k=k+1 } name[nn]=0 as u8 } } 480 let nf: i64=sys_openat_wr(npcpath,0x1a4); if nf>=0 { let nb: *u8=sys_mmap(16); nb[0]=(npc>>24)&0xff; nb[1]=(npc>>16)&0xff; nb[2]=(npc>>8)&0xff; nb[3]=npc&0xff; nb[4]=(plen>>24)&0xff; nb[5]=(plen>>16)&0xff; nb[6]=(plen>>8)&0xff; nb[7]=plen&0xff; cl_write_n(nf,nb,8); sys_close(nf) } 481 let mwf: i64=sys_openat_wr(metapath,0x1a4); if mwf>=0 { cl_write_n(mwf, meta, msize); sys_close(mwf) } // CACHE the verified metadata so sibling/recycled children skip the ut_metadata refetch 482 let im: *u8=sys_mmap(16); mse_write(ctx,fd,im,nx_pw_build_msg(NX_PW_INTERESTED,0 as *u8,0,im)) 483 // reflect pieces ALREADY on disk (resume) instead of hardcoding 0 -- lbits 484 // was loaded from the donefile, so this shows preserved progress immediately. 485 var dn82: i64=0; var q82: i64=0; while q82<npc { if (lbits[q82] as i64)==1 { dn82=dn82+1 } q82=q82+1 } 486 tg_status(statpath,name,total,dn82*plen,dn82,npc,peers,"downloading" as *u8) 487 tg_seed_hello(ctx, fd, lbits, npc) // advertise + unchoke from first metadata so reciprocity bootstraps the bulk + 0%-non-starters 488 } 489 } } 490 } } 491 if xi == PEX_OUR_ID { 492 let pip: *i64 = sys_mmap(8*64) as *i64; let ppo: *i64 = sys_mmap(8*64) as *i64 493 let pc: i64 = pex_parse_added(mb, 6, nt, pip, ppo, 64) 494 if pc > 0 { tg_pex_append(pexpath, pip, ppo, pc) } 495 } 496 } 497 if id == NX_PW_UNCHOKE { unchoked=1; chmsg=0; sys_set_socket_timeout(fd, TG_DATA_TIMEOUT) } // DATA PHASE: a busy seeder's first block + inter-block gaps blow past the 6s connect timeout -> extend so we actually RECEIVE the pieces we just requested instead of bailing mid-request (the seedeval "23 seeders unchoke us, have=0 = IGNORING" fix) 498 if id == NX_PW_CHOKE { unchoked=0; if cur>=0 { tg_ppart_flush(spath, ppath, cur, plen, pbuf, cprefix); eg_clear(inflightpath, cur); cur=0-1; pbytes=0; cprefix=0 } } // choked: PERSIST the contiguous prefix (so the next window resumes it) + release the in-flight piece + return to waiting. DON'T give up here -- TG_UNCHOKE_WAIT bounds the wait so we outlast the optimistic-unchoke rotation (the "IGNORING" fix). Persisting the prefix is the reciprocity-starvation completion fix. 499 if id == NX_PW_BITFIELD { let bl2: i64=blen-1; var c: i64=0; while c<bl2 { if c<TG_MAGIC_40000 { peerbits[c]=mb[5+c] } c=c+1 } havebits=1 } // record which pieces THIS peer has 500 if id == NX_PW_HAVE { let hp: i64=_pw_get_u32(mb,5); let by: i64=hp/8; if by<TG_MAGIC_40000 { peerbits[by]=((peerbits[by] as i64) | (1 << (7 - (hp - by*8)))) as u8 } havebits=1; if avail_added==1 { if mdone==1 { am_add_have(availpath, hp) } } } 501 if id == NX_PW_PIECE { 502 let pidx: i64=_pw_get_u32(mb,5); let beg: i64=_pw_get_u32(mb,9); let bl: i64=blen-9 503 if pidx==cur { if beg+bl<=PCAP { var c: i64=0; while c<bl { pbuf[beg+c]=mb[13+c]; c=c+1 } pbytes=pbytes+bl; if beg==cprefix { cprefix=cprefix+bl } } } 504 // seq1734: a block landing beyond PCAP used to vanish here with NO else branch -- 505 // silent data loss that made any plen>PCAP torrent retry forever at have=0. The cap 506 // is now 32 MiB, but the DROP MUST STAY VISIBLE: count it so a future oversized 507 // piece surfaces as a number instead of an eternal 0%. 508 if pidx==cur { if beg+bl>PCAP { dropped_blocks=dropped_blocks+1 } } // cprefix = length of the in-order prefix (what we can safely persist across a choke) 509 var pl_i: i64=plen; if cur==npc-1 { pl_i=total-cur*plen } 510 if pbytes>=pl_i { if pl_i>0 { 511 let g2: *u8=sys_mmap(20); sha1(pbuf,pl_i,g2); var ev: i64=1; var y: i64=0; while y<20 { if g2[y]!=meta[poff+cur*20+y] { ev=0; y=20 } else { y=y+1 } } 512 if ev==1 { 513 sys_lseek(outfd, cur*plen, 0); cl_write_n(outfd, pbuf, pl_i) 514 lbits[cur]=1 as u8; sys_lseek(donefd, cur, 0); let one: *u8=sys_mmap(4); one[0]=1 as u8; cl_write_n(donefd, one, 1) 515 have=have+1 516 var dn: i64=0; var q: i64=0; while q<npc { if (lbits[q] as i64)==1 { dn=dn+1 } q=q+1 } 517 tg_status(statpath,name,total,dn*plen,dn,npc,peers,"downloading" as *u8) 518 let hp2: *u8=sys_mmap(8); hp2[0]=((cur>>24)&0xff) as u8; hp2[1]=((cur>>16)&0xff) as u8; hp2[2]=((cur>>8)&0xff) as u8; hp2[3]=(cur&0xff) as u8; let hm: *u8=sys_mmap(16); mse_write(ctx,fd,hm,nx_pw_build_msg(NX_PW_HAVE,hp2,4,hm)) // advertise our NEW piece -> a peer needing it requests -> reciprocity 519 } 520 // seq1745: a SHA-1 verify failure used to be indistinguishable from success -- 521 // same cleanup, no counter, no status. Four hours of failing every piece looked 522 // exactly like four hours of idle, which is why BANK-155 (done frozen at 30/2230 523 // since 13:22 while avail+wanted kept updating at 17:31) could not be diagnosed. 524 // Surfacing it costs one status write and DECIDES between the two live 525 // hypotheses: verify-failure vs reciprocity starvation. Same class as the PCAP 526 // silent drop -- a discard with no counter is invisible data loss. 527 if ev==0 { var dnf: i64=0; var qf: i64=0; while qf<npc { if (lbits[qf] as i64)==1 { dnf=dnf+1 } qf=qf+1 } tg_status(statpath,name,total,dnf*plen,dnf,npc,peers,"verify-fail" as *u8) } 528 tg_ppart_set(ppath, cur, 0); eg_clear(inflightpath, cur); cur=0-1; pbytes=0; cprefix=0 // piece done (or verify-failed) -> clear staged partial + no longer in-flight by this child 529 } } 530 } 531 if id == NX_PW_REQUEST { let ri: i64=_pw_get_u32(mb,5); let rqb: i64=_pw_get_u32(mb,9); let rln: i64=_pw_get_u32(mb,13) 532 if rln>0 { if rln<=TG_MAGIC_16384 { if ri>=0 { if ri<npc { if (lbits[ri] as i64)==1 { // we HAVE the requested piece -> SERVE it (seed back = reciprocity) 533 let sp: *u8=sv_pbuf 534 sp[0]=((ri>>24)&0xff) as u8; sp[1]=((ri>>16)&0xff) as u8; sp[2]=((ri>>8)&0xff) as u8; sp[3]=(ri&0xff) as u8 535 sp[4]=((rqb>>24)&0xff) as u8; sp[5]=((rqb>>16)&0xff) as u8; sp[6]=((rqb>>8)&0xff) as u8; sp[7]=(rqb&0xff) as u8 536 sys_lseek(outfd, ri*plen+rqb, 0); let got: i64=sys_read(outfd, (sp as i64 + 8) as *u8, rln) 537 if got==rln { let sm: *u8=sv_mbuf; mse_write(ctx, fd, sm, nx_pw_build_msg(NX_PW_PIECE, sp, 8+rln, sm)) } 538 } } } } } } 539 if mdone==1 { if unchoked==1 { if cur<0 { 540 sys_lseek(donefd, 0, 0); sys_read(donefd, lbits, npc) // refresh: skip pieces other parallel peers already finished 541 if wbuilt==0 { tg_build_wanted(meta, msize, npc, plen, wbits, tg_wanted_min()); let wf3: i64=tg_open_rw(wantedpath); if wf3>=0 { sys_lseek(wf3,0,0); cl_write_n(wf3, wbits, npc); sys_close(wf3) } wbuilt=1 } 542 var wpk: i64=0; while wpk<npc { if (wbits[wpk] as i64)==0 { pickbits[wpk]=1 as u8 } else { pickbits[wpk]=lbits[wpk] } wpk=wpk+1 } // pickbits: unwanted treated as done 543 // SMART LAYER (Phase 2): contribute THIS peer's availability to the shared cross-peer 544 // map ONCE -- deferred to here (not BITFIELD-receipt time) because the bitfield usually 545 // arrives before we know npc, and am_add_bitfield needs npc to know how far to scan. 546 if havebits==1 { if avail_added==0 { am_add_bitfield(availpath, peerbits, TG_MAGIC_40000, npc); avail_added=1 } } 547 if avbuf == (0 as *i64) { avbuf = sys_mmap(npc*8+64) as *i64; effbuf = sys_mmap(npc*8+64) as *i64; infbuf = sys_mmap(npc*8+64) as *i64 } 548 // SMART PICK (Phase 2): phase-1 = rarest NEEDED piece this peer HAS that no other child 549 // is already downloading (clean work-split -- kills the duplicate-download waste the old 550 // done-only scan allowed); phase-2 = in the tail (<= TG_ENDGAME_THRESHOLD obtainable 551 // pieces left, all in-flight) RACE the rarest to beat the one slow holder. eg_pick is 552 // self-sufficient (handles no-bitfield seeders + the avail map), so -1 means genuinely 553 // nothing for this peer right now -> free the slot (the pool refills with another peer). 554 var np: i64 = 0 - 1 555 if tg_stream_on(streampath) == 1 { am_load(inflightpath, infbuf, npc); np = tg_seq_pick(pickbits, peerbits, TG_MAGIC_40000, havebits, infbuf, npc) } 556 else { np = eg_pick(availpath, inflightpath, pickbits, peerbits, TG_MAGIC_40000, havebits, npc, TG_ENDGAME_THRESHOLD, avbuf, effbuf, infbuf) } 557 if np<0 { go=0 } else { cur=np; eg_mark(inflightpath, cur) 558 var pl_i: i64=plen; if cur==npc-1 { pl_i=total-cur*plen } 559 var pp: i64 = tg_ppart_get(ppath, cur); if pp >= pl_i { pp = 0 } // RESUME a staged prefix (defensive: stale/full -> fresh) 560 if pp > 0 { pbytes = tg_ppart_load(spath, cur, plen, pbuf, pp); cprefix = pbytes } else { pbytes = 0; cprefix = 0 } 561 let rq: *u8=sys_mmap(32); var b: i64=cprefix; while b<pl_i { var bk: i64=TG_MAGIC_16384; if pl_i-b<bk { bk=pl_i-b } mse_write(ctx,fd,rq,nx_pw_build_request(cur,b,bk,rq)); b=b+TG_MAGIC_16384 } // request only the MISSING blocks (skip the resumed prefix); one req buffer reused 562 } 563 } } } 564 if mdone==1 { if unchoked==0 { if cur<0 { if (sys_now_realtime_sec() - t_start) >= TG_UNCHOKE_WAIT { go=0 } } } } // give up ONLY after the unchoke-patience window elapses (covers choke-spammers that keep us choked-and-idle while sending messages, so the read-timeout path never fires). Bounds slot hold-time; productive/unchoked peers never reach here. 565 } 566 } 567 } 568 if cur>=0 { tg_ppart_flush(spath, ppath, cur, plen, pbuf, cprefix); eg_clear(inflightpath, cur) } // abandoned mid-piece (choke/timeout) -> PERSIST the contiguous prefix (resumed by the next child) + release the in-flight claim 569 sys_close(outfd); sys_close(donefd); sys_close(fd) 570 return have 571} 572 573// one HTTP/TCP tracker announce, appended to the peer set (dedup later). Bypasses ISP UDP blocking. 574func tg_http_one(host: *u8, port: i64, path: *u8, ih: *u8, pid: *u8, ips: *i64, ports: *i64, have: i64, max: i64) -> i64 { 575 let ip4: *u8 = sys_mmap(4) 576 if nx_dns_a_resolve(host, ip4) != 1 { return 0 } 577 let tip: *i64 = sys_mmap(8*80) as *i64; let tpo: *i64 = sys_mmap(8*80) as *i64 578 let c: i64 = ht_announce(host, ip4, port, path, ih, pid, TG_MAGIC_1000000000, tip, tpo, 80) 579 if c <= 0 { return 0 } 580 var added: i64 = 0; var k: i64 = 0 581 while k < c { if have + added < max { ips[have+added] = tip[k]; ports[have+added] = tpo[k]; added = added + 1 } k = k + 1 } 582 return added 583} 584 585// ---- DATA-DRIVEN WIDE tracker announce (Cardinal 11) ---------------------------------------------- 586// Announce to EVERY HTTP/HTTPS tracker in <selfdir>/trackers.txt (one URL/line; '#' comments + blanks 587// skipped via tl_next_line) and append discovered peers to download.pex -- the SAME shared file BEP-11 588// PEX uses, so the parent's existing tg_pex_merge folds them into the live peer set. Widening the 589// tracker set = better odds of reaching the one seed holding a rare tail piece (the "stuck at 99%" fix 590// for poorly-seeded swarms). Absent file (e.g. dev box without trackers.txt) -> no-op; the synchronous 591// UDP + baked-HTTP + DHT discovery still runs. Returns peers appended. 592func tg_wide_to_pex(selfdir: *u8, outdir: *u8, ih: *u8, pid: *u8) -> i64 { 593 let path: *u8 = sys_mmap(640) 594 var pp: i64 = pm_bstr(path, 0, selfdir); pp = pm_bstr(path, pp, "/trackers.txt" as *u8); path[pp] = 0 as u8 595 let fd: i64 = sys_openat_rd(path) 596 if fd < 0 { return 0 } 597 let buf: *u8 = sys_mmap(TG_MAGIC_65536) 598 let n: i64 = sys_read(fd, buf, TG_MAGIC_65535); sys_close(fd) 599 if n <= 0 { return 0 } 600 let pexpath: *u8 = sys_mmap(640); var xp: i64 = pm_bstr(pexpath, 0, outdir); xp = pm_bstr(pexpath, xp, "/download.pex" as *u8); pexpath[xp] = 0 as u8 601 let tip: *i64 = sys_mmap(8*80) as *i64; let tpo: *i64 = sys_mmap(8*80) as *i64 602 let line: *u8 = sys_mmap(512) 603 var added: i64 = 0 604 var p2: i64 = tl_next_line(buf, n, 0, line) 605 while p2 >= 0 { 606 let cnt: i64 = ht_announce_url(line, ih, pid, TG_MAGIC_1000000000, tip, tpo, 80) 607 if cnt > 0 { tg_pex_append(pexpath, tip, tpo, cnt); added = added + cnt } 608 p2 = tl_next_line(buf, n, p2, line) 609 } 610 return added 611} 612// Run the wide announce in a DETACHED grandchild (double-fork -> reparents to init, no zombie) so a 613// firewalled tracker's ~127s connect() hang can NEVER stall the download (nx_http_client has no connect 614// timeout -- the very reason peers are fork-bounded). One-shot per worker run; a re-add starts a fresh 615// worker -> a fresh wide scan. The immediate child is reaped here; the grandchild is reaped by init. 616func tg_spawn_wide_announce(selfdir: *u8, outdir: *u8, ih: *u8, pid: *u8) -> i64 { 617 let p1: i64 = sys_fork() 618 if p1 == 0 { 619 let p2: i64 = sys_fork() 620 if p2 == 0 { 621 var fdx: i64 = 3; while fdx < 64 { sys_close(fdx); fdx = fdx + 1 } 622 tg_wide_to_pex(selfdir, outdir, ih, pid) 623 sys_exit(0) 624 } 625 sys_exit(0) 626 } 627 let st1: *i64 = sys_mmap(16) as *i64 628 sys_wait4(p1, st1, 0) 629 return 0 630} 631 632// MULTI-CHANNEL peer discovery -- the TEAM picks the set (UDP + HTTP/TCP); nothing external decides. 633// HTTP/TCP survives ISP UDP-tracker blocking AND a single tracker's announce rate-limit. 634func tg_announce_all(ih: *u8, pid: *u8, ips: *i64, ports: *i64, max: i64) -> i64 { 635 var have: i64 = cl_announce(ih, pid, ips, ports, max) // UDP open.stealth.si:80 (existing) 636 if have < 0 { have = 0 } 637 have = have + tg_http_one("open.stealth.si" as *u8, 80, "/announce" as *u8, ih, pid, ips, ports, have, max) // same tracker over TCP 638 have = have + tg_http_one("tracker.opentrackr.org" as *u8, TG_MAGIC_1337, "/announce" as *u8, ih, pid, ips, ports, have, max) 639 // DHT (BEP-5): trackerless peer discovery -- the ONLY source for tracker-less magnets (e.g. the 640 // operator's javdb magnets have no tr=). Append DHT peers to the set; reuses pid as the node id. 641 let dip: *i64 = sys_mmap(8*256) as *i64; let dpo: *i64 = sys_mmap(8*256) as *i64 642 let dc: i64 = dgp_find(ih, pid, dip, dpo, max) 643 var k: i64 = 0 644 while k < dc { if have < max { ips[have] = dip[k]; ports[have] = dpo[k]; have = have + 1 } k = k + 1 } 645 return have 646} 647 648// ---- BACKGROUND ANNOUNCE: THE PARENT MUST NEVER BLOCK ON THE NETWORK ------------------------------ 649// tg_announce_all does a UDP tracker round (cl_announce), two DNS lookups + TCP tracker connects 650// (tg_http_one -> ht_announce) and a DHT get_peers (dgp_find). EVERY one of those can park the caller for 651// the kernel's full SYN / datagram timeout (~127s) against a black-holed tracker, and SO_RCVTIMEO does 652// NOT bound connect() -- so the 6s sys_set_socket_timeout calls on the PEER path buy nothing here. 653// 654// MEASURED 2026-07-31: worker parents sat in __inet_stream_connect and __skb_recv_datagram holding 655// EXACTLY 32 zombie children -- 32 == MAXP, the whole peer pool. While the parent is parked, the slot 656// reaper and the refill loop below it do not run, so every peer child that exits during the stall becomes 657// a zombie AND its slot is never refilled: the pool goes fully idle for the length of one stalled 658// announce. The zombies were the SYMPTOM that made it visible; the blocked parent was the defect. 659// 660// FIX: fork the announce. The child appends its peers to download.pex -- the same file BEP-11 PEX already 661// uses, that tg_wide_to_pex already publishes to, and that the parent already merges from on this exact 662// code path -- so discovery moves off the critical path with no new plumbing. The parent's loop stays hot 663// and its existing general wait4 sweep reaps the announce child. Peers land one cycle later; that costs 664// 30s of freshness and buys back a 2-minute total pool stall per bad tracker. 665// 666// One announce in flight at a time (slot[0]); a child still alive after TG_ANN_MAX_TICKS is SIGKILLed so 667// one wedged tracker cannot permanently silence discovery. Returns 1 if a fresh announce was started. 668func tg_announce_bg(ihb: *u8, mypid: *u8, pexpath: *u8, slot: *i64, stbuf: *i64, ticks: i64) -> i64 { 669 if slot[0] > 0 { 670 let r: i64 = sys_wait4(slot[0], stbuf, WNOHANG) 671 if r == 0 { 672 // Still running. Reclaim it if it outlived the watchdog, but NEVER block waiting on it -- 673 // blocking here is the exact defect this function exists to remove. 674 if ticks - slot[1] >= TG_ANN_MAX_TICKS { nx_kill(slot[0], 9); slot[0] = 0 } 675 return 0 676 } 677 // r>0 = reaped right here; r<0 = the loop's general sweep already reaped it. Both mean FREE. 678 // Treating r<0 as "still running" would strand the slot on a dead pid and stop announcing forever. 679 slot[0] = 0 680 } 681 let p: i64 = sys_fork() 682 if p == 0 { 683 let aip: *i64 = sys_mmap(8 * 80) as *i64 684 let apo: *i64 = sys_mmap(8 * 80) as *i64 685 let c: i64 = tg_announce_all(ihb, mypid, aip, apo, 80) 686 if c > 0 { tg_pex_append(pexpath, aip, apo, c) } 687 sys_exit(0) 688 } 689 if p > 0 { slot[0] = p; slot[1] = ticks } 690 return 1 691} 692 693// on finish, split download.part into the real media files (multi-file torrents) so the operator sees a 694// playable REBDB-1026...mkv, not download.part. Best-effort: if the extractor elf is absent, exec fails 695// harmlessly (the manual extractor + .part remain). Streaming split lives in nx_torrent_extract. 696// The directory THIS worker binary lives in, read from /proc/self/cmdline argv[0] (mirrors the 697// daemon's d_self_dir). The extract + gallery-index elfs are deployed as the worker's SIBLINGS, so 698// they resolve on BOTH the dev box (/tmp) AND the NAS hub (/volume1/ai/torrent). Fallback "/tmp". 699func tg_self_dir() -> *u8 { 700 let buf: *u8 = sys_mmap(TG_MAGIC_1024) 701 let fd: i64 = sys_openat_rd("/proc/self/cmdline" as *u8) 702 var n: i64 = 0 703 if fd >= 0 { n = sys_read(fd, buf, 1023); sys_close(fd) } 704 if n <= 0 { let fb: *u8 = sys_mmap(8); fb[0]=47 as u8; fb[1]=116 as u8; fb[2]=109 as u8; fb[3]=112 as u8; fb[4]=0 as u8; return fb } 705 var z: i64 = 0; var dz: i64 = 0 706 while dz == 0 { if z >= n { dz = 1 } else { if buf[z] == (0 as u8) { dz = 1 } else { z = z + 1 } } } 707 var i: i64 = z - 1; var df: i64 = 0 708 while df == 0 { if i <= 0 { df = 1 } else { if buf[i] == (47 as u8) { buf[i] = 0 as u8; df = 1 } else { i = i - 1 } } } 709 if buf[0] == (0 as u8) { let fb: *u8 = sys_mmap(8); fb[0]=47 as u8; fb[1]=116 as u8; fb[2]=109 as u8; fb[3]=112 as u8; fb[4]=0 as u8; return fb } 710 return buf 711} 712// AUTO-SEED (the "sharing" half): on FULL completion, register this torrent in the seeder's registry so we 713// SHARE it back (download->seed reciprocity). srcpath = download.part = the EXACT concatenated payload the 714// piece hashes are computed over, so the seeder serves correct pieces for single AND multi file. total = the 715// .part file SIZE (== the exact byte total, no metadata re-parse). Idempotent (skips if the info_hash hex is 716// already registered). ONLY called on done_total>=npc -> never registers a partial (which would serve corrupt 717// zero-filled pieces to peers). regpath is a PARAM (config, not hardcoded) so it is gate-testable. 718func tg_autoseed(outdir: *u8, ih: *u8, plen: i64, name: *u8, regpath: *u8) -> i64 { 719 if plen <= 0 { return 0 } 720 let part: *u8 = sys_mmap(640); var po: i64=pm_bstr(part,0,outdir); po=pm_bstr(part,po,"/download.part" as *u8); part[po]=0 as u8 721 let pf: i64 = sys_openat_rd(part); if pf<0 { return 0 } 722 let total: i64 = sys_lseek(pf, 0, 2); sys_close(pf) // SEEK_END -> exact byte total 723 if total <= 0 { return 0 } 724 // ONLY seed a FULLY-complete torrent: a selective/complete-on-wanted download lacks the junk pieces, but the 725 // seeder advertises a FULL bitfield -> seeding a partial would serve corrupt (zero) junk pieces + get us banned. 726 let npcp: *u8=sys_mmap(640); var npo: i64=pm_bstr(npcp,0,outdir); npo=pm_bstr(npcp,npo,"/download.npc" as *u8); npcp[npo]=0 as u8 727 let nfd: i64=sys_openat_rd(npcp); if nfd<0 { return 0 } let nb: *u8=sys_mmap(16); let nn: i64=sys_read(nfd,nb,16); sys_close(nfd) 728 if nn<4 { return 0 } let npc_a: i64=((nb[0] as i64)<<24)|((nb[1] as i64)<<16)|((nb[2] as i64)<<8)|(nb[3] as i64) 729 let donp: *u8=sys_mmap(640); var dpo: i64=pm_bstr(donp,0,outdir); dpo=pm_bstr(donp,dpo,"/download.done" as *u8); donp[dpo]=0 as u8 730 let dfd: i64=sys_openat_rd(donp); if dfd<0 { return 0 } let dbf: *u8=sys_mmap(TG_MAGIC_262144); let dnn: i64=sys_read(dfd,dbf,TG_MAGIC_262144); sys_close(dfd) 731 var dc: i64=0; var di: i64=0; while di<dnn { if (dbf[di] as i64)==1 { dc=dc+1 } di=di+1 } 732 if dc <= 0 { return 0 } // nothing downloaded -> nothing to share (else OK: the seeder advertises+serves ONLY download.done pieces, so a selective/complete-on-wanted torrent seeds honestly) 733 let hd: *u8 = "0123456789abcdef" as *u8; let hx: *u8 = sys_mmap(48) 734 var i: i64=0; while i<20 { hx[i*2]=hd[((ih[i] as i64)>>4)&15]; hx[i*2+1]=hd[(ih[i] as i64)&15]; i=i+1 } hx[40]=0 as u8 735 let rf: i64 = sys_openat_rd(regpath) 736 if rf>=0 { let rb: *u8=sys_mmap(TG_MAGIC_262144); let rn: i64=sys_read(rf,rb,TG_MAGIC_262143); sys_close(rf) 737 var s: i64=0; while s+40<=rn { var m: i64=1; var k: i64=0; while k<40 { if rb[s+k]!=hx[k] { m=0; k=40 } else { k=k+1 } } if m==1 { return 0 } s=s+1 } } // already registered -> idempotent 738 let row: *u8=sys_mmap(TG_MAGIC_1024); var o: i64=0 739 o=pm_bstr(row,o,name); row[o]=9 as u8; o=o+1 // name \t 740 var j: i64=0; while j<40 { row[o]=hx[j]; o=o+1; j=j+1 } row[o]=9 as u8; o=o+1 // ih_hex40 \t 741 o=pm_bint(row,o,plen); row[o]=9 as u8; o=o+1 // piece_length \t 742 o=pm_bint(row,o,total); row[o]=9 as u8; o=o+1 // total \t 743 o=pm_bstr(row,o,part); row[o]=10 as u8; o=o+1 // srcpath \n 744 let wf: i64 = __syscall(SYS_OPENAT, AT_FDCWD, regpath as i64, 0x441, 0x1a4, 0, 0) // O_WRONLY|O_CREAT|O_APPEND 745 if wf>=0 { cl_write_n(wf, row, o); sys_close(wf) } 746 return 0 747} 748func tg_run_extract(outdir: *u8) -> i64 { 749 // CRITICAL (NAS): /tmp is mounted NOEXEC on the hub -- the old hardcoded "/tmp/...elf" execve here 750 // FAILED silently, so completed downloads stayed as download.part and never became playable media 751 // (and the gallery never refreshed). Resolve the SELF-DIR sibling FIRST (the deployed bundle path, 752 // /volume1/ai/torrent), then fall back to /tmp (dev box). In the child, the first execve replaces 753 // the process on success; it only returns on failure, so the second execve is the fallback. This is 754 // strictly safer than before on BOTH hosts. The extract elf being absent is still harmless (-> 127). 755 let sd: *u8 = tg_self_dir() 756 let exself: *u8 = sys_mmap(TG_MAGIC_1024); var eo: i64 = pm_bstr(exself,0,sd); eo=pm_bstr(exself,eo,"/nx_torrent_extract.sov.elf" as *u8); exself[eo]=0 as u8 757 let extmp: *u8 = "/tmp/nx_torrent_extract.sov.elf" as *u8 758 let exargv: *i64 = sys_mmap(32) as *i64; exargv[0]=exself as i64; exargv[1]=outdir as i64; exargv[2]=0 759 let exenvp: *i64 = sys_mmap(16) as *i64; exenvp[0]=0 760 let pid: i64 = sys_fork() 761 if pid==0 { sys_execve(exself, exargv, exenvp); sys_execve(extmp, exargv, exenvp); sys_exit(127) } 762 let stx: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, stx, 0) 763 // GALLERY REFRESH: re-index the recordings/torrent video roots so the just-extracted media 764 // shows up + streams in the Nishi gallery. nx_galx_vidindex writes an ABSOLUTE index path so 765 // this is CWD-independent; exec failing (elf absent) is harmless (gallery just isn't refreshed). 766 let gself: *u8 = sys_mmap(TG_MAGIC_1024); var go: i64 = pm_bstr(gself,0,sd); go=pm_bstr(gself,go,"/nx_galx_vidindex.sov.elf" as *u8); gself[go]=0 as u8 767 let gtmp: *u8 = "/tmp/nx_galx_vidindex.sov.elf" as *u8 768 let gargv: *i64 = sys_mmap(16) as *i64; gargv[0]=gself as i64; gargv[1]=0 769 let genvp: *i64 = sys_mmap(16) as *i64; genvp[0]=0 770 let gpid: i64 = sys_fork() 771 if gpid==0 { sys_execve(gself, gargv, genvp); sys_execve(gtmp, gargv, genvp); sys_exit(127) } 772 let gstx: *i64 = sys_mmap(16) as *i64; sys_wait4(gpid, gstx, 0) 773 // ANALYSIS-ON-INGEST 2026-07-14: after re-indexing, trigger the derivation pipeline (thumbnail prewarm + NXVI 774 // duration/keyframe/markers) for the just-extracted media via the GUARDED galxpipeline hostctl sub 775 // (single-instance -> no stacking across concurrent torrents; it spawns the pipeline detached). Harmless if 776 // nx_hostctl is absent on this host (-> 127), matching the vidindex fork above. 777 let hcself: *u8 = "/volume1/homes/elderwesto/nishihost/nx_hostctl" as *u8 778 let pargv: *i64 = sys_mmap(16) as *i64; pargv[0]=hcself as i64; pargv[1]="galxpipeline" as *u8 as i64; pargv[2]=0 779 let penvp: *i64 = sys_mmap(16) as *i64; penvp[0]="PATH=/usr/bin:/bin" as *u8 as i64; penvp[1]=0 780 let ppid: i64 = sys_fork() 781 if ppid==0 { sys_execve(hcself, pargv, penvp); sys_exit(127) } 782 let pstx: *i64 = sys_mmap(16) as *i64; sys_wait4(ppid, pstx, 0) 783 return 0 784} 785 786func main(argc: i64, argv: *i64) -> i64 { 787 var magnet: *u8 = "magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c&dn=Big+Buck+Bunny" as *u8 788 if argc >= 2 { magnet = argv[1] as *u8 } 789 var outdir: *u8 = "/mnt/c/Users/elder/Downloads/nishi-torrents" as *u8 790 if argc >= 3 { outdir = argv[2] as *u8 } 791 sys_mkdir(outdir, 0x1ff) 792 // SINGLE WORKER PER TORRENT (s-class robustness, the hardware rung): take a NON-BLOCKING exclusive 793 // flock on download.lock. If another worker for THIS torrent already holds it (a duplicate from a 794 // re-add / startup autoresume / the retry-sweep / a racing daemon restart), exit NOW instead of 795 // thrashing the swarm with redundant peer connections + DHT bootstraps -- the "lots of stalls / 796 // non-starters under load" failure mode. The kernel releases the lock when this process dies, so a 797 // dead worker's torrent is instantly re-spawnable. lockfd is intentionally kept open for our lifetime. 798 let lockp: *u8 = sys_mmap(640); var lkp: i64 = pm_bstr(lockp, 0, outdir); lkp = pm_bstr(lockp, lkp, "/download.lock" as *u8); lockp[lkp] = 0 as u8 799 let lockfd: i64 = sys_openat_wr(lockp, 0x1a4) 800 if lockfd >= 0 { if sys_flock(lockfd, SYS_LOCK_EX | SYS_LOCK_NB) != 0 { cl_w(1, "TGET already-running (download.lock held) -> exit clean\n" as *u8); sys_exit(0); return 0 } } 801 802 let ihb: *u8 = sys_mmap(20); let trk: *i64 = sys_mmap(8*32) as *i64; let ntrk: *i64 = sys_mmap(16) as *i64; let nm: *u8 = sys_mmap(512) 803 if mg_parse(magnet, ihb, trk, 32, ntrk, nm) != 1 { cl_w(1, "TGET verdict=RED reason=bad-magnet\n" as *u8); sys_exit(1); return 1 } 804 let mypid: *u8 = sys_mmap(20); let ps: *u8 = "-NX0001-000000000000" as *u8; var z: i64=0; while z<20 { mypid[z]=ps[z]; z=z+1 } 805 806 // emit a status BEFORE the (slow ~15-20s) DHT/tracker discovery so the UI shows "discovering peers" 807 // instead of looking dead/failed. Fresh add only -- a resume keeps its preserved have-count status. 808 if argc < 4 { 809 let estat: *u8 = sys_mmap(512); var es: i64=pm_bstr(estat,0,outdir); es=pm_bstr(estat,es,"/download.status" as *u8); estat[es]=0 as u8 810 tg_status(estat, nm, 0, 0, 0, 0, 0, "discovering peers" as *u8) 811 } 812 let ips: *i64 = sys_mmap(8*80) as *i64; let ports: *i64 = sys_mmap(8*80) as *i64 813 var np: i64 = tg_announce_all(ihb, mypid, ips, ports, 80) 814 cl_w(1, "TGET peers=" as *u8); cl_wn(1, np); cl_w(1, "\n" as *u8) 815 // ip-filter: load the blocklist ONCE (children inherit via fork COW); absent file -> ipf_n=0 -> no-op. 816 let ipf_arr: *i64 = sys_mmap(TG_MAGIC_80000*16 + 64) as *i64 817 let ipf_n: i64 = ipf_load("/volume1/ai/torrent/data/ipfilter.bin" as *u8, ipf_arr, TG_MAGIC_80000) 818 if ipf_n > 0 { let ipfb: i64 = np; np = tg_ipf_filter(ips, ports, np, ipf_arr, ipf_n); cl_w(1, "TGET ipfilter ranges=" as *u8); cl_wn(1, ipf_n); cl_w(1, " peers " as *u8); cl_wn(1, ipfb); cl_w(1, "->" as *u8); cl_wn(1, np); cl_w(1, "\n" as *u8) } 819 if np < 1 { 820 let sp2: *u8 = sys_mmap(512); var s2: i64=pm_bstr(sp2,0,outdir); s2=pm_bstr(sp2,s2,"/download.status" as *u8); sp2[s2]=0 as u8 821 tg_status(sp2, "no seeders found" as *u8, 0, 0, 0, 0, 0, "stalled" as *u8) 822 cl_w(1, "TGET verdict=RED reason=no-peers (tracker rate-limit? re-run)\n" as *u8); sys_exit(1); return 1 823 } 824 825 let outpath: *u8 = sys_mmap(512); var o: i64=pm_bstr(outpath,0,outdir); o=pm_bstr(outpath,o,"/download.part" as *u8); outpath[o]=0 as u8 826 let donepath: *u8 = sys_mmap(512); var d: i64=pm_bstr(donepath,0,outdir); d=pm_bstr(donepath,d,"/download.done" as *u8); donepath[d]=0 as u8 827 let npcpath: *u8 = sys_mmap(512); var nn2: i64=pm_bstr(npcpath,0,outdir); nn2=pm_bstr(npcpath,nn2,"/download.npc" as *u8); npcpath[nn2]=0 as u8 828 let metapath: *u8 = sys_mmap(512); var mpp: i64=pm_bstr(metapath,0,outdir); mpp=pm_bstr(metapath,mpp,"/download.meta" as *u8); metapath[mpp]=0 as u8 // shared metadata cache (fetch once, not per-child) 829 let statpath: *u8 = sys_mmap(512); var s: i64=pm_bstr(statpath,0,outdir); s=pm_bstr(statpath,s,"/download.status" as *u8); statpath[s]=0 as u8 830 let ctlpath: *u8 = sys_mmap(512); var cc: i64=pm_bstr(ctlpath,0,outdir); cc=pm_bstr(ctlpath,cc,"/download.control" as *u8); ctlpath[cc]=0 as u8 831 let availpath: *u8 = sys_mmap(512); var ap: i64=pm_bstr(availpath,0,outdir); ap=pm_bstr(availpath,ap,"/download.avail" as *u8); availpath[ap]=0 as u8 // shared cross-peer rarity map 832 let inflightpath: *u8 = sys_mmap(512); var ip2: i64=pm_bstr(inflightpath,0,outdir); ip2=pm_bstr(inflightpath,ip2,"/download.inflight" as *u8); inflightpath[ip2]=0 as u8 // shared in-flight refcount (endgame) 833 let streampath: *u8 = sys_mmap(512); var sp3: i64=pm_bstr(streampath,0,outdir); sp3=pm_bstr(streampath,sp3,"/download.stream" as *u8); streampath[sp3]=0 as u8 // stream-mode flag (sequential) when present 834 let pexpath: *u8 = sys_mmap(512); var pxp: i64=pm_bstr(pexpath,0,outdir); pxp=pm_bstr(pexpath,pxp,"/download.pex" as *u8); pexpath[pxp]=0 as u8 // shared PEX-harvested peer log (BEP-11) 835 // fresh add (argc<4) truncates done/npc/part for a clean run; RESUME (argv[3] present) keeps the 836 // partial so the worker continues from the donefile bitmap instead of re-downloading from zero. 837 if argc < 4 { 838 let z1: i64=sys_openat_wr(donepath,0x1a4); if z1>=0 { sys_close(z1) } 839 let z2: i64=sys_openat_wr(npcpath,0x1a4); if z2>=0 { sys_close(z2) } 840 let z3: i64=sys_openat_wr(outpath,0x1a4); if z3>=0 { sys_close(z3) } 841 let z5: i64=sys_openat_wr(pexpath,0x1a4); if z5>=0 { sys_close(z5) } // fresh add: drop stale harvested peers 842 } 843 // DATA-DRIVEN WIDE tracker scan (one-shot, detached -> download.pex; off the parent's critical path 844 // so a hung tracker can't stall the grind). Fires for fresh AND resume, so a re-added stuck torrent 845 // re-scans the wider tracker set for the seed holding its missing tail piece. Runs AFTER the pex 846 // truncate above so a fresh add never wipes the peers it appends. 847 tg_spawn_wide_announce(tg_self_dir(), outdir, ihb, mypid) 848 // fresh add: show "resolving/started". RESUME: leave the pre-pause status intact (preserved 849 // have-count stays visible) so the UI doesn't flash back to 0% while metadata re-resolves. 850 if argc < 4 { tg_status(statpath,"resolving" as *u8,0,0,0,0,np,"started" as *u8) } 851 852 // SMART LAYER: zero the shared availability + in-flight maps ONCE before any child runs (both fresh 853 // + resume -- both are per-session, rebuilt from THIS run's live swarm). 262144 = the donefile ceiling. 854 am_init(availpath, TG_MAGIC_262144) 855 eg_init(inflightpath, TG_MAGIC_262144) 856 857 let st: *i64 = sys_mmap(16) as *i64 858 var done_total: i64 = 0; var npc: i64 = 0 859 var fin: i64 = 0 860 // S-CLASS THROUGHPUT: a self-refilling pool of MAXP download children. Each child connects to ONE 861 // peer (ring round-robin over the discovered set), downloads the pieces that peer serves, and EXITS 862 // the instant it is choked/idle (see tg_from_peer) -- so a choking peer can never freeze a slot. 863 // Every 2s the parent reaps dead children and IMMEDIATELY refills every free slot from the peer ring 864 // (no gate). The pool stays full and constantly cycles connections => continuous optimistic-unchokes 865 // => sustained throughput instead of "fast burst then freeze". Re-announce every ~30s for fresh peers. 866 // seq1402/seq1410 -- POOL WIDTH IS DERIVED, NOT DECLARED. This was `let MAXP: i64 = 32`, a hardcoded 867 // literal (rule-11) that made every machine behave identically: the NAS (4c/8t), the west server, the 868 // laptop and any future box all ran 32 slots, sized for hardware nobody measured. Worse, 32 was 869 // PER-INSTANCE, and nx_procchurn measured 143 forks/sec = ~9 concurrent instances = ~288 concurrent 870 // slots against a box with 8 threads. NOBODY CHOSE 143; it was 32 x N. 871 // LAW: A PER-INSTANCE LIMIT IS NOT A LIMIT -- N instances multiply it and nobody ever picks N. 872 // What is NOT changed: the aggressive refill/cycling below. Constant connection cycling IS the 873 // BitTorrent throughput strategy (continuous optimistic-unchokes); throttling it would attack the 874 // feature to flatten a graph (rule 25). Only the WIDTH is governed; inside the budget the pool stays 875 // exactly as aggressive as it ever was. 876 // slots_per_cpu=4 reproduces the historical 32 on this 8-thread NAS => BEHAVIOUR-PRESERVING HERE, 877 // and correctly scales up on a bigger box / down inside a cgroup. Governor gate: 18/18 GREEN. 878 // ⚠LANDING BLOCKED BY LAYERING, NOT BY DESIGN: nx_poolwidth_lib lives in _hdl_build/ and a runtime/ 879 // organ CANNOT import from there (`nx_compile_x86: expand_imports failed`). The governor is built and 880 // gate-proven 18/18; it must MOVE to runtime/ (the primitive layer, beside nx_hw.nx) before this line 881 // can become `pw_width(pw_budget_from_hw(4,8), pw_count_procs("nx_torrent_get"), pw_load_centi(), 800, 2, 32)`. 882 // Moving it needs care: a second copy under the same basename would SHADOW (seq207/284 dual-copy). 883 // REVERTED 2026-07-30 (seq1666/seq1681). The pg_* governor that stood here was on the WRONG AXIS 884 // and cost real downloads. A peer slot is a socket plus a piece buffer on a NETWORK-BLOCKED child: 885 // it consumes almost no CPU, so budgeting slots as cpus x 4 spent capability to relieve a resource 886 // peer slots never consumed. MEASURED HARM: nx_torstat returned VERDICT=IGNORING on BANK-155 887 // (2200/2200 missing pieces that DO have holders among connected peers) and ajvr-166 (468/1069) 888 // = 2668 fetchable pieces never pulled -- the exact signature of too few slots, because a pure 889 // leecher never wins optimistic-unchoke before its child times out. 890 // The block above claimed slots_per_cpu=4 was BEHAVIOUR-PRESERVING (4 x 8 = the historical 32). 891 // IT WAS NOT: 32 became the AGGREGATE budget SPLIT across instances. nx_poolgov_gate measures it 892 // directly -- T1 = 3 slots each across 9 instances, T6 = 2 under real load. 288 -> 27 aggregate, 893 // shipped believing it was a no-op, and the gate recorded the squeeze as a PASS. 894 // LAW: A GATE PROVES THE MECHANISM IS ARITHMETICALLY SOUND, NEVER THAT THE POLICY IS RIGHT. 895 // The per-instance-multiplication insight above IS STILL CORRECT and must not be lost: 32 x N 896 // instances is a width nobody chose. But the aggregate cap has to be derived from the resource 897 // slots ACTUALLY consume -- fd/socket budget (RLIMIT_NOFILE), or measured network saturation -- 898 // never from CPU count, and never squeezed by a loadavg that on this host is dominated by 899 // D-state disk wait (measured: load 16.58 with only 4 runnable on 8 cores). 900 // Restoring the proven constant until that governor exists (rule 3: stop patching, rewrite). 901 let MAXP: i64 = 32 902 let cpids: *i64 = sys_mmap(8 * 64) as *i64 // child pid per slot (0/neg = free) 903 // seq1317 PER-SLOT COOLDOWN. This pool refilled EVERY free slot on EVERY tick with a fresh fork and 904 // no backoff whatsoever, so a peer that fails instantly frees its slot and is re-forked ~2s later, 905 // forever -- a self-inflicted fork treadmill (the perf lane measured bursts of 179 forks/s against an 906 // 85/s since-boot average). A slot is now ineligible for TG_SLOT_COOLDOWN ticks after it is FILLED, 907 // which bounds the refill rate structurally without needing to classify why a child died: a healthy 908 // long-lived peer is unaffected (its slot is occupied anyway), while a dead-peer slot stops spinning. 909 let cnext: *i64 = sys_mmap(8 * 64) as *i64 // earliest tick this slot may be refilled 910 var ci: i64 = 0 911 while ci < 64 { cnext[ci] = 0; ci = ci + 1 } 912 // Background-announce state: [0] = announce child pid (0 = idle), [1] = the tick it was forked. 913 // Allocated ONCE rather than per call so a multi-hour download does not leak a page per announce. 914 let annslot: *i64 = sys_mmap(16) as *i64 915 annslot[0] = 0; annslot[1] = 0 916 let annst: *i64 = sys_mmap(8) as *i64 917 var ring: i64 = 0 // round-robin index over the peer set 918 var s0: i64 = 0 919 while s0 < MAXP { 920 let pid: i64 = sys_fork() 921 if pid == 0 { tg_from_peer(ips[ring % np], ports[ring % np], ihb, mypid, outpath, donepath, npcpath, metapath, statpath, ctlpath, availpath, inflightpath, streampath, pexpath, np); sys_exit(0) } 922 cpids[s0] = pid; ring = ring + 1; s0 = s0 + 1 923 } 924 let nslots: i64 = MAXP 925 var last_done: i64 = 0 - 1; var stall_ticks: i64 = 0; var ticks: i64 = 0; var plen_p: i64 = 0 926 let lbp: *u8 = sys_mmap(TG_MAGIC_262144); let avp: *i64 = sys_mmap(TG_MAGIC_262144 * 8) as *i64; var done_rn: i64 = 0; var finalized: i64 = 0 // auto-finalize tail (reuse donefile + avail map) 927 // SELECTIVE DOWNLOAD completion: DONE when the WANTED pieces (not all npc) are complete -> a junk/sample file 928 // whose pieces are unavailable no longer blocks the torrent. wbp=download.wanted mask (sibling of donepath); 929 // effdone = have|unwanted (so the tail/finalize logic ignores skipped junk). No download.wanted -> all-npc. 930 let wbp: *u8 = sys_mmap(TG_MAGIC_262144); let effdone: *u8 = sys_mmap(TG_MAGIC_262144) 931 let wantedpath_p: *u8 = sys_mmap(640); var wpp: i64=0; var lsl: i64=0; var wpi: i64=0 932 while donepath[wpi]!=(0 as u8) { if donepath[wpi]==(47 as u8) { lsl=wpi } wpi=wpi+1 } 933 wpi=0; while wpi<=lsl { wantedpath_p[wpp]=donepath[wpi]; wpp=wpp+1; wpi=wpi+1 } wpp=pm_bstr(wantedpath_p, wpp, "download.wanted" as *u8); wantedpath_p[wpp]=0 as u8 934 var wanted_count: i64=0; var wanted_done: i64=0 935 while fin == 0 { 936 sys_sleep_ms(TG_MAGIC_2000); ticks = ticks + 1 937 if tg_stop(ctlpath) == 1 { fin = 1 } else { 938 var s: i64 = 0 939 while s < nslots { if cpids[s] > 0 { let r: i64 = sys_wait4(cpids[s], st, WNOHANG); if r > 0 { cpids[s] = 0 } } s = s + 1 } 940 while sys_wait4(0 - 1, st, WNOHANG) > 0 { } // reap ANY other exited child (untracked bounded-connect/announce forks) -- nx_zombie_audit flagged these leaking 941 let df: i64=sys_openat_rd(donepath); if df>=0 { let rn: i64=sys_read(df, lbp, TG_MAGIC_262144); sys_close(df); done_rn=rn; var dn: i64=0; var q: i64=0; while q<rn { if (lbp[q] as i64)==1 { dn=dn+1 } q=q+1 } done_total=dn } 942 let nf: i64=sys_openat_rd(npcpath); if nf>=0 { let nb: *u8=sys_mmap(16); let rn2: i64=sys_read(nf,nb,16); sys_close(nf); if rn2>=4 { npc=((nb[0] as i64)<<24)|((nb[1] as i64)<<16)|((nb[2] as i64)<<8)|(nb[3] as i64) } if rn2>=8 { plen_p=((nb[4] as i64)<<24)|((nb[5] as i64)<<16)|((nb[6] as i64)<<8)|(nb[7] as i64) } } 943 // SELECTIVE: recompute wanted_count/wanted_done + effdone(have|unwanted) from fresh lbp + download.wanted 944 wanted_count=0; wanted_done=0; var wloaded: i64=0 945 if npc > 0 { let wf: i64=sys_openat_rd(wantedpath_p); if wf>=0 { let wn: i64=sys_read(wf, wbp, TG_MAGIC_262144); sys_close(wf); if wn>=npc { wloaded=1 } } 946 var eq: i64=0 947 while eq<npc { var hv: i64=0; if eq<done_rn { if (lbp[eq] as i64)==1 { hv=1 } } 948 if wloaded==1 { if (wbp[eq] as i64)==1 { wanted_count=wanted_count+1; if hv==1 { wanted_done=wanted_done+1; effdone[eq]=1 as u8 } else { effdone[eq]=0 as u8 } } else { effdone[eq]=1 as u8 } } 949 else { effdone[eq]=lbp[eq]; if hv==1 { wanted_done=wanted_done+1 } } 950 eq=eq+1 } 951 if wloaded==0 { wanted_count=npc } } 952 if wanted_count > 0 { if wanted_done >= wanted_count { fin = 1 } } // WANTED-complete (junk pieces ignored) 953 if fin == 0 { if (ticks % 15) == 0 { tg_announce_bg(ihb, mypid, pexpath, annslot, annst, ticks); np = tg_pex_merge(pexpath, ips, ports, np, 80); np = tg_ipf_filter(ips, ports, np, ipf_arr, ipf_n) } } // fresh peers every ~30s (tracker+DHT+harvested PEX); ip-filter the refreshed list 954 if fin == 0 { 955 var s2: i64 = 0 956 while s2 < MAXP { if cpids[s2] <= 0 { if ticks >= cnext[s2] { 957 let pid2: i64 = sys_fork() 958 if pid2 == 0 { tg_from_peer(ips[ring % np], ports[ring % np], ihb, mypid, outpath, donepath, npcpath, metapath, statpath, ctlpath, availpath, inflightpath, streampath, pexpath, np); sys_exit(0) } 959 cpids[s2] = pid2; cnext[s2] = ticks + TG_SLOT_COOLDOWN; ring = ring + 1 960 } } s2 = s2 + 1 } 961 } 962 if done_total == last_done { stall_ticks = stall_ticks + 1 } else { stall_ticks = 0 } 963 last_done = done_total 964 // KEEP GRINDING THE TAIL: never abandon a partial download while peers exist. On a plateau 965 // (no new piece for ~16s) re-announce HARD every ~16s for fresh peers/seeders + keep cycling 966 // the pool, and publish an HONEST status that PRESERVES the have-count (name=nm, real bytes) 967 // instead of flashing "done=0 stalled". Real S-class clients grind the tail, they don't quit. 968 if fin == 0 { if stall_ticks >= 8 { 969 if (stall_ticks % 8) == 0 { tg_announce_bg(ihb, mypid, pexpath, annslot, annst, ticks); np = tg_pex_merge(pexpath, ips, ports, np, 80); np = tg_ipf_filter(ips, ports, np, ipf_arr, ipf_n) } 970 tg_status(statpath, nm, tg_meta_total_of(metapath, npc, plen_p), done_total*plen_p, done_total, npc, np, "downloading (grinding tail)" as *u8) 971 } } 972 if npc == 0 { if ticks > 90 { fin = 1 } } // never resolved metadata in ~180s -> give up 973 // AUTO-FINALIZE the tail: don't grind a hopeless last piece for 20 min or leave a 99%-done 974 // .part the operator can't open. On a sustained plateau, EXTRACT what we have NOW (a playable 975 // file, "most of a film") and stop -- (a) >=90% held + 60s plateau, or (b) the pieces we still 976 // need are provably UNOBTAINABLE here (no connected peer has them -> avail 0) after a 2-min 977 // plateau. This is the no-seeder-last-piece recovery (the 300MIUM-class fix). 978 // TAIL POLICY: at >=90% + plateau, EXTRACT a playable file ONCE (operator watches the "most of a 979 // film" now) but KEEP GRINDING while the missing pieces are OBTAINABLE (a connected peer has them). 980 // Only STOP when the tail is genuinely UNOBTAINABLE (avail 0) or the 20-min ultimate giveup below. 981 // BUG FIXED 2026-07-04: the old code STOPPED (fin=1) at 90%+60s UNCONDITIONALLY -> abandoned an 982 // obtainable last piece forever whenever the holders took >60s to optimistically-unchoke our 983 // leecher ("stuck at 99% with 177 holders"). Now an obtainable tail is ground until it lands. 984 if fin == 0 { if npc > 0 { if done_total > 0 { if done_rn >= npc { 985 am_load(availpath, avp, npc); let obt: i64 = eg_obtainable_remaining(effdone, avp, npc) // effdone ignores unwanted junk 986 if finalized == 0 { if stall_ticks >= 30 { if wanted_done * 100 >= wanted_count * 90 { 987 tg_run_extract(outdir); finalized = 1 988 tg_status(statpath, nm, npc*plen_p, done_total*plen_p, done_total, npc, np, "playable extracted - still grinding the last piece(s)" as *u8) 989 } } } 990 if stall_ticks >= 60 { if obt == 0 { 991 tg_run_extract(outdir) 992 tg_status(statpath, nm, npc*plen_p, done_total*plen_p, done_total, npc, np, "finalized - swarm has no more (tail unobtainable)" as *u8) 993 fin = 1 994 } } 995 } } } } 996 if npc > 0 { if stall_ticks > 600 { fin = 1 } } // ultimate giveup: ~20 min of zero new pieces -> exit (re-add resumes) 997 } 998 } 999 var k: i64 = 0; while k < nslots { if cpids[k] > 0 { nx_kill(cpids[k], 9); sys_wait4(cpids[k], st, 0) } k = k + 1 } 1000 cl_w(1, "TGET done_pieces=" as *u8); cl_wn(1, done_total); cl_w(1, "/" as *u8); cl_wn(1, npc); cl_w(1, " ticks=" as *u8); cl_wn(1, ticks); cl_w(1, " stall=" as *u8); cl_wn(1, stall_ticks); cl_w(1, " np=" as *u8); cl_wn(1, np); cl_w(1, " stop=" as *u8); cl_wn(1, tg_stop(ctlpath)); cl_w(1, " -> " as *u8); cl_w(1, outpath); cl_w(1, "\n" as *u8) 1001 if wanted_count > 0 { if wanted_done >= wanted_count { cl_w(1, "TGET verdict=GREEN COMPLETE (wanted="); cl_wn(1, wanted_done); cl_w(1, "/"); cl_wn(1, wanted_count); cl_w(1, ")\n" as *u8) 1002 let asreg: *u8=sys_mmap(TG_MAGIC_1024); var aso: i64=pm_bstr(asreg,0,tg_self_dir()); aso=pm_bstr(asreg,aso,"/seed_index.conf" as *u8); asreg[aso]=0 as u8 1003 tg_autoseed(outdir, ihb, plen_p, nm, asreg) // SHARE it back (skips partials internally: only FULL npc seeds) 1004 tg_run_extract(outdir); sys_exit(0); return 0 } } 1005 if done_total > 0 { 1006 if finalized == 0 { // not already extracted by the in-loop auto-finalize 1007 tg_status(statpath, nm, npc*plen_p, done_total*plen_p, done_total, npc, np, "partial - re-add to resume" as *u8) 1008 if npc > 0 { if done_total * 100 >= npc * 90 { tg_run_extract(outdir) } } // near-complete (>=90%) -> auto-extract playable media 1009 } 1010 cl_w(1, "TGET verdict=PARTIAL\n" as *u8); sys_exit(0); return 0 1011 } 1012 cl_w(1, "TGET verdict=RED reason=no-pieces\n" as *u8) 1013 tg_status(statpath, nm, 0, 0, done_total, npc, np, "stalled - no seeder served data" as *u8) 1014 sys_exit(1) 1015 return 1 1016}