code wiki / (root) / nx_peer_meta_live.nx

nx_peer_meta_live.nx source

↩ module page · 177 lines · 10439 B

1// nx_peer_meta_live.nx -- fetch the REAL torrent metadata from a REAL peer (X-TORRENT-LIVE-001 L3b): 2// connect a real peer -> BEP-3 handshake -> BEP-10 ext handshake -> BEP-9 ut_metadata fetch (multi- 3// piece) -> sha1(info-dict)==info_hash -> parse name/piece_length/length. Uses a DISPATCH LOOP (real 4// peers interleave bitfield/have/choke -- not lockstep). Bounded connect via fork+parent-kill (L3a). 5// Reuses cl_announce/cl_read_n/cl_write_n/cl_sockaddr (nx_peer_connect_live) + nx_bencode + nx_sha1. 6// GATE = LIVE: any real peer yields a sha1-verified info-dict for Big Buck Bunny. license_tier: ORIGINAL 7// 8// module: nishi-core.torrent.peer_meta_live 9// depends: nishi-core.torrent.peer_connect_live, nishi-core.torrent.bencode, nishi-core.crypto.sha1 10import "nx_peer_connect_live.nx" 11import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 12import "nx_bencode.nx" 13import "nx_sha1.nx" 14const PW_MAGIC_65536: i64 = 65536 15const PW_MAGIC_262144: i64 = 262144 16const PW_MAGIC_40000: i64 = 40000 17const PW_MAGIC_16383: i64 = 16383 18const PW_MAGIC_16384: i64 = 16384 19const PW_MAGIC_12000: i64 = 12000 20 21const PW_EXT: i64 = 20 22 23func pm_bstr(buf: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8) { buf[off+i]=s[i]; i=i+1 } return off+i } 24func pm_bint(buf: *u8, off: i64, v: i64) -> i64 { 25 let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0 {t[0]=48 as u8;k=1}; while m>0 {t[k]=(48+(m%10)) as u8; m=m/10; k=k+1} 26 var o: i64=off; var j: i64=0; while j<k { buf[o]=t[k-1-j]; o=o+1; j=j+1 } return o 27} 28func pm_build_ext(ext_id: i64, data: *u8, dlen: i64, out: *u8) -> i64 { 29 let pl: *u8 = sys_mmap(PW_MAGIC_65536); pl[0] = ext_id as u8 30 var i: i64 = 0; while i < dlen { pl[1+i] = data[i]; i = i + 1 } 31 return nx_pw_build_msg(PW_EXT, pl, 1 + dlen, out) 32} 33func pm_read_msg(fd: i64, mb: *u8, cap: i64) -> i64 { 34 if cl_read_n(fd, mb, 4) != 4 { return 0 - 1 } 35 let blen: i64 = _pw_get_u32(mb, 0) 36 if blen == 0 { return 0 } // keep-alive 37 if blen > cap - 4 { return 0 - 1 } 38 if cl_read_n(fd, mb + 4, blen) != blen { return 0 - 1 } 39 return blen 40} 41 42// connect+handshake+ext+metadata from one real peer; on success write [1][4 total][1 namelen][name] to res. 43func pm_child(ipv: i64, port: i64, ih: *u8, mypid: *u8, res: *u8) -> i64 { 44 let fd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 45 if fd < 0 { return 0 } 46 sys_set_socket_timeout(fd, 5) 47 let dest: *u8 = sys_mmap(16); cl_sockaddr(dest, port, (ipv>>24)&0xff, (ipv>>16)&0xff, (ipv>>8)&0xff, ipv&0xff) 48 if nx_connect_bounded(fd, dest, 16, NX_CONN_DEFAULT_MS) != 0 { sys_close(fd); return 0 } 49 let ch: *u8 = sys_mmap(128); nx_pw_build_handshake(ih, mypid, ch); ch[25] = (ch[25] as i64 | 0x10) as u8 50 if cl_write_n(fd, ch, 68) != 68 { sys_close(fd); return 0 } 51 let ph: *u8 = sys_mmap(128) 52 if cl_read_n(fd, ph, 68) != 68 { sys_close(fd); return 0 } 53 let gih: *u8 = sys_mmap(20); let gpid: *u8 = sys_mmap(20) 54 if nx_pw_parse_handshake(ph, 68, gih, gpid) != 1 { sys_close(fd); return 0 } 55 // send our ext handshake 56 let ceb: *u8 = sys_mmap(64); let cm: *u8 = sys_mmap(128) 57 cl_write_n(fd, cm, pm_build_ext(0, ceb, pm_bstr(ceb, 0, "d1:md11:ut_metadatai1eee" as *u8), cm)) 58 59 let meta: *u8 = sys_mmap(PW_MAGIC_262144) // assembled info-dict (up to 256KiB) 60 var meta_size: i64 = 0; var peer_utm: i64 = 0; var got: i64 = 0; var npieces: i64 = 0; var requested: i64 = 0 61 let mb: *u8 = sys_mmap(PW_MAGIC_40000) 62 var loops: i64 = 0 63 var done: i64 = 0 64 while done == 0 { 65 if loops >= 200 { done = 0 - 9 } // safety bound 66 if done == 0 { 67 let blen: i64 = pm_read_msg(fd, mb, PW_MAGIC_40000) 68 if blen < 0 { done = 0 - 1 } // read error/timeout 69 if blen == 0 { loops = loops + 1 } // keep-alive 70 if blen > 0 { 71 loops = loops + 1 72 let id: i64 = nx_pw_msg_id(mb) 73 if id == PW_EXT { 74 let nt: i64 = 4 + blen 75 let ext_id: i64 = mb[5] as i64 76 if ext_id == 0 { 77 // peer ext handshake: learn ut_metadata id + metadata_size 78 let mo: i64 = nx_bc_dict_get(mb, 6, nt, "m" as *u8, 1) 79 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 { peer_utm = iv[0] } } } 80 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 { meta_size = iv2[0] } } 81 if peer_utm > 0 { if meta_size > 0 { if requested == 0 { 82 npieces = (meta_size + PW_MAGIC_16383) / PW_MAGIC_16384 83 var pi: i64 = 0 84 while pi < npieces { 85 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) 86 let rm: *u8 = sys_mmap(128); cl_write_n(fd, rm, pm_build_ext(peer_utm, rb, ro, rm)) 87 pi = pi + 1 88 } 89 requested = 1 90 } } } 91 } 92 if ext_id == 1 { 93 // ut_metadata data: header bencode + raw 94 let pio: i64 = nx_bc_dict_get(mb, 6, nt, "piece" as *u8, 5) 95 var pidx: i64 = 0; if pio >= 0 { let iv3: *i64 = sys_mmap(16) as *i64; if nx_bc_int(mb, pio, nt, iv3) >= 0 { pidx = iv3[0] } } 96 let raw: i64 = nx_bc_skip(mb, 6, nt) 97 if raw > 0 { let rawlen: i64 = nt - raw 98 var c: i64 = 0; while c < rawlen { if pidx*PW_MAGIC_16384 + c < PW_MAGIC_262144 { meta[pidx*PW_MAGIC_16384 + c] = mb[raw + c] } c = c + 1 } 99 got = got + 1 100 if got >= npieces { if npieces > 0 { 101 // assemble done -> verify 102 let gh: *u8 = sys_mmap(20); sha1(meta, meta_size, gh) 103 var eqv: i64 = 1; var x: i64 = 0; while x < 20 { if gh[x] != ih[x] { eqv = 0; x = 20 } else { x = x + 1 } } 104 if eqv == 1 { done = 1 } else { done = 0 - 2 } 105 } } 106 } 107 } 108 } 109 } 110 } 111 } 112 if done == 1 { 113 // parse name/length/piece length, write result 114 let nmo: i64 = nx_bc_dict_get(meta, 0, meta_size, "name" as *u8, 4) 115 let so2: *i64 = sys_mmap(16) as *i64; let sl2: *i64 = sys_mmap(16) as *i64; var nl: i64 = 0 116 if nmo >= 0 { if nx_bc_str(meta, nmo, meta_size, so2, sl2) >= 0 { nl = sl2[0] } } 117 let lno: i64 = nx_bc_dict_get(meta, 0, meta_size, "length" as *u8, 6); var tot: i64 = 0 118 if lno >= 0 { let iv4: *i64 = sys_mmap(16) as *i64; if nx_bc_int(meta, lno, meta_size, iv4) >= 0 { tot = iv4[0] } } 119 let rf: i64 = sys_openat_wr(res, 0x1a4) 120 if rf >= 0 { 121 let ob: *u8 = sys_mmap(512); ob[0]=1 as u8 122 ob[1]=(tot>>24)&0xff; ob[2]=(tot>>16)&0xff; ob[3]=(tot>>8)&0xff; ob[4]=tot&0xff 123 var wn: i64 = nl; if wn > 200 { wn = 200 } 124 ob[5]=wn as u8 125 var k: i64 = 0; while k < wn { ob[6+k]=meta[so2[0]+k]; k=k+1 } 126 cl_write_n(rf, ob, 6 + wn); sys_close(rf) 127 } 128 } 129 sys_close(fd) 130 return 0 131} 132 133func main() -> i64 { 134 let ih: *u8 = sys_mmap(20) 135 ih[0]=221 as u8; ih[1]=130 as u8; ih[2]=85 as u8; ih[3]=236 as u8; ih[4]=220 as u8 136 ih[5]=124 as u8; ih[6]=165 as u8; ih[7]=95 as u8; ih[8]=176 as u8; ih[9]=187 as u8 137 ih[10]=248 as u8; ih[11]=19 as u8; ih[12]=35 as u8; ih[13]=216 as u8; ih[14]=112 as u8 138 ih[15]=98 as u8; ih[16]=219 as u8; ih[17]=31 as u8; ih[18]=109 as u8; ih[19]=28 as u8 139 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 } 140 141 let ips: *i64 = sys_mmap(8*80) as *i64; let ports: *i64 = sys_mmap(8*80) as *i64 142 let np: i64 = cl_announce(ih, mypid, ips, ports, 80) 143 cl_w(1, "PEERMETALIVE peers=" as *u8); cl_wn(1, np); cl_w(1, "\n" as *u8) 144 if np < 1 { cl_w(1, "PEERMETALIVE verdict=RED reason=no-peers\n" as *u8); sys_exit(1); return 1 } 145 146 let res: *u8 = "/tmp/_nx_meta_live.bin" as *u8 147 let st: *i64 = sys_mmap(16) as *i64 148 var tries: i64 = np; if tries > 30 { tries = 30 } 149 var ok: i64 = 0; var attempted: i64 = 0 150 var i: i64 = 0 151 while i < tries { 152 if ok == 0 { 153 let cf: i64 = sys_openat_wr(res, 0x1a4); if cf >= 0 { let zb: *u8 = sys_mmap(4); zb[0]=0 as u8; cl_write_n(cf, zb, 1); sys_close(cf) } 154 attempted = attempted + 1 155 let pid: i64 = sys_fork() 156 if pid == 0 { pm_child(ips[i], ports[i], ih, mypid, res); sys_exit(0) } 157 var el: i64 = 0; var go: i64 = 1 158 while go == 1 { let r: i64 = sys_wait4(pid, st, WNOHANG); if r > 0 { go = 0 } else { if el >= PW_MAGIC_12000 { go = 0 } else { sys_sleep_ms(200); el = el + 200 } } } 159 if sys_wait4(pid, st, WNOHANG) <= 0 { nx_kill(pid, 9); sys_wait4(pid, st, 0) } 160 let rf: i64 = sys_openat_rd(res) 161 if rf >= 0 { let rb: *u8 = sys_mmap(512); let rn: i64 = sys_read(rf, rb, 512); sys_close(rf) 162 if rn >= 6 { if (rb[0] as i64) == 1 { 163 ok = 1 164 let tot: i64 = ((rb[1] as i64)<<24)|((rb[2] as i64)<<16)|((rb[3] as i64)<<8)|(rb[4] as i64) 165 let nl: i64 = rb[5] as i64 166 cl_w(1, "PEERMETALIVE METADATA OK name=" as *u8); var k: i64 = 0; while k < nl { sys_write(1, (rb as i64 + 6 + k) as *u8, 1); k = k + 1 } 167 cl_w(1, " total_bytes=" as *u8); cl_wn(1, tot); cl_w(1, "\n" as *u8) 168 } } 169 } 170 } 171 i = i + 1 172 } 173 cl_w(1, "PEERMETALIVE attempted=" as *u8); cl_wn(1, attempted) 174 if ok == 1 { cl_w(1, " verdict=GREEN (real sha1-verified metadata from a real peer)\n" as *u8); sys_exit(0); return 0 } 175 cl_w(1, " verdict=RED reason=no-peer-served-metadata\n" as *u8); sys_exit(1) 176 return 1 177}