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}