nx_peer_download.nx source
↩ module page · 166 lines · 8401 B
1// nx_peer_download.nx -- DOWNLOAD a multi-block piece off a peer + WRITE it to a LOCAL FILE,
2// read-back verified (X-TORRENT-LIVE-001 R5): the literal "download locally" step. Builds on R4-b:
3// handshake -> interested -> unchoke -> request each 16-byte block -> PIECE -> assemble the 32-byte
4// piece -> sha1-verify -> sys_openat_wr the piece to a local file at its offset -> read it back ->
5// assert on-disk bytes + sha1 match. Reuses nx_peerwire (BEP-3) + nx_sha1. GATE = SOVEREIGN LOOPBACK:
6// a mock peer serves the two known blocks in request order; the client downloads, assembles, writes,
7// and re-reads from disk. Deterministic; no external net; no-hang (timeouts). license_tier: ORIGINAL
8//
9// module: nishi-core.torrent.peer_download
10// depends: nishi-core.torrent.peerwire, nishi-core.crypto.sha1
11import "nx_peerwire.nx"
12import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
13import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
14import "nx_sha1.nx"
15const K_MAGIC_53401: i64 = 53401
16
17func pd_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
18// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
19// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
20// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
21// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
22func pd_wn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 }
23func pd_sockaddr(sa: *u8, port: i64, i0: i64, i1: i64, i2: i64, i3: i64) -> i64 {
24 sa[0]=2 as u8; sa[1]=0 as u8
25 sa[2]=((port>>8)&0xff) as u8; sa[3]=(port&0xff) as u8
26 sa[4]=i0 as u8; sa[5]=i1 as u8; sa[6]=i2 as u8; sa[7]=i3 as u8
27 var k: i64=8; while k<16 { sa[k]=0 as u8; k=k+1 }
28 return 0
29}
30func pd_read_n(fd: i64, buf: *u8, n: i64) -> i64 {
31 var got: i64 = 0
32 while got < n { let r: i64 = sys_read(fd, buf + got, n - got); if r <= 0 { return 0 - 1 } got = got + r }
33 return got
34}
35func pd_write_n(fd: i64, buf: *u8, n: i64) -> i64 {
36 var off: i64 = 0
37 while off < n { let w: i64 = sys_write(fd, buf + off, n - off); if w <= 0 { return 0 - 1 } off = off + w }
38 return n
39}
40func pd_read_msg(fd: i64, mb: *u8, cap: i64) -> i64 {
41 if pd_read_n(fd, mb, 4) != 4 { return 0 - 1 }
42 let blen: i64 = _pw_get_u32(mb, 0)
43 if blen == 0 { return 0 }
44 if blen > cap - 4 { return 0 - 1 }
45 if pd_read_n(fd, mb + 4, blen) != blen { return 0 - 1 }
46 return blen
47}
48
49const BLK: i64 = 16
50const NBLK: i64 = 2
51const PIECE: i64 = 32 // BLK*NBLK
52
53func main() -> i64 {
54 let PORT: i64 = K_MAGIC_53401
55 let ih: *u8 = sys_mmap(20); var z: i64 = 0; while z < 20 { ih[z] = (z+1) as u8; z = z + 1 }
56 let pidb: *u8 = sys_mmap(20); z = 0; while z < 20 { pidb[z] = 80 as u8; z = z + 1 }
57 // expected piece = block0 ++ block1
58 let expect: *u8 = sys_mmap(PIECE)
59 let b0: *u8 = "TORRENTBLOCK0123" as *u8
60 let b1: *u8 = "ABCDEFGHIJKLMNOP" as *u8
61 z = 0; while z < BLK { expect[z] = b0[z]; z = z + 1 }
62 z = 0; while z < BLK { expect[BLK + z] = b1[z]; z = z + 1 }
63 let sa: *u8 = sys_mmap(16); pd_sockaddr(sa, PORT, 127, 0, 0, 1)
64 let dlpath: *u8 = "/tmp/_nx_dl_test.bin" as *u8
65
66 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
67 var bound: i64 = 0
68 if lfd >= 0 {
69 let one: *u8 = sys_mmap(4); one[0]=1 as u8; one[1]=0 as u8; one[2]=0 as u8; one[3]=0 as u8
70 sys_setsockopt(lfd, SOL_SOCKET, 2, one, 4)
71 sys_set_socket_timeout(lfd, 3)
72 if sys_bind(lfd, sa, 16) >= 0 { if sys_listen(lfd, 1) >= 0 { bound = 1 } }
73 }
74 if bound == 0 { pd_w(1, "PEERDL-GATE authored=organ bound=0 verdict=RED\n" as *u8); sys_exit(1); return 1 }
75
76 let pid: i64 = sys_fork()
77 if pid == 0 {
78 // MOCK PEER: serve the 2 blocks in request order.
79 let afd: i64 = sys_accept(lfd)
80 if afd >= 0 {
81 sys_set_socket_timeout(afd, 3)
82 let hb: *u8 = sys_mmap(128); pd_read_n(afd, hb, 68)
83 let oh: *u8 = sys_mmap(128); nx_pw_build_handshake(ih, pidb, oh); pd_write_n(afd, oh, 68)
84 let mb: *u8 = sys_mmap(256); pd_read_msg(afd, mb, 256) // INTERESTED
85 let un: *u8 = sys_mmap(16); let ul: i64 = nx_pw_build_msg(NX_PW_UNCHOKE, 0 as *u8, 0, un); pd_write_n(afd, un, ul)
86 var bi: i64 = 0
87 while bi < NBLK {
88 pd_read_msg(afd, mb, 256) // REQUEST
89 let begin: i64 = _pw_get_u32(mb, 9)
90 let pl: *u8 = sys_mmap(64); _pw_put_u32(pl, 0, 0); _pw_put_u32(pl, 4, begin)
91 var i: i64 = 0; while i < BLK { pl[8 + i] = expect[begin + i]; i = i + 1 }
92 let pm: *u8 = sys_mmap(128); let pml: i64 = nx_pw_build_msg(NX_PW_PIECE, pl, 8 + BLK, pm)
93 pd_write_n(afd, pm, pml)
94 bi = bi + 1
95 }
96 sys_close(afd)
97 }
98 sys_close(lfd)
99 sys_exit(0)
100 }
101
102 // CLIENT
103 let cfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
104 sys_set_socket_timeout(cfd, 3)
105 var conn_ok: i64 = 0
106 if nx_connect_bounded(cfd, sa, 16, NX_CONN_DEFAULT_MS) >= 0 { conn_ok = 1 }
107 var hs_ok: i64 = 0; var blocks_ok: i64 = 0; var sha_eq: i64 = 0; var disk_eq: i64 = 0
108 let piece: *u8 = sys_mmap(PIECE)
109 if conn_ok == 1 {
110 let ch: *u8 = sys_mmap(128); nx_pw_build_handshake(ih, pidb, ch); pd_write_n(cfd, ch, 68)
111 let ph2: *u8 = sys_mmap(128)
112 if pd_read_n(cfd, ph2, 68) == 68 {
113 let gih: *u8 = sys_mmap(20); let gpid: *u8 = sys_mmap(20)
114 if nx_pw_parse_handshake(ph2, 68, gih, gpid) == 1 { hs_ok = 1 }
115 }
116 if hs_ok == 1 {
117 let im: *u8 = sys_mmap(16); let il: i64 = nx_pw_build_msg(NX_PW_INTERESTED, 0 as *u8, 0, im); pd_write_n(cfd, im, il)
118 let mb: *u8 = sys_mmap(256); pd_read_msg(cfd, mb, 256) // UNCHOKE
119 var got_all: i64 = 1
120 var bi: i64 = 0
121 while bi < NBLK {
122 let rq: *u8 = sys_mmap(32); let rl: i64 = nx_pw_build_request(0, bi*BLK, BLK, rq); pd_write_n(cfd, rq, rl)
123 let pb: *u8 = sys_mmap(256); let plen: i64 = pd_read_msg(cfd, pb, 256)
124 if plen >= 9 { if nx_pw_msg_id(pb) == NX_PW_PIECE {
125 let begin: i64 = _pw_get_u32(pb, 9)
126 var i: i64 = 0; while i < BLK { piece[begin + i] = pb[13 + i]; i = i + 1 }
127 } else { got_all = 0 } } else { got_all = 0 }
128 bi = bi + 1
129 }
130 blocks_ok = got_all
131 if blocks_ok == 1 {
132 let gh: *u8 = sys_mmap(20); let eh: *u8 = sys_mmap(20)
133 sha1(piece, PIECE, gh); sha1(expect, PIECE, eh)
134 var se: i64 = 1; var i: i64 = 0
135 while i < 20 { if gh[i] != eh[i] { se = 0; i = 20 } else { i = i + 1 } }
136 sha_eq = se
137 // WRITE the verified piece to a LOCAL FILE, then read it back
138 let wf: i64 = sys_openat_wr(dlpath, 0x1a4)
139 if wf >= 0 { pd_write_n(wf, piece, PIECE); sys_close(wf) }
140 let rf: i64 = sys_openat_rd(dlpath)
141 if rf >= 0 {
142 let disk: *u8 = sys_mmap(PIECE)
143 let dn: i64 = pd_read_n(rf, disk, PIECE)
144 sys_close(rf)
145 if dn == PIECE {
146 var de: i64 = 1; i = 0
147 while i < PIECE { if disk[i] != expect[i] { de = 0; i = PIECE } else { i = i + 1 } }
148 disk_eq = de
149 }
150 }
151 }
152 }
153 }
154 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0); sys_close(cfd); sys_close(lfd)
155
156 pd_w(1, "PEERDL-GATE authored=organ conn_ok=" as *u8); pd_wn(1, conn_ok)
157 pd_w(1, " handshake_ok=" as *u8); pd_wn(1, hs_ok)
158 pd_w(1, " blocks_ok=" as *u8); pd_wn(1, blocks_ok)
159 pd_w(1, " sha1_verify=" as *u8); pd_wn(1, sha_eq)
160 pd_w(1, " disk_readback=" as *u8); pd_wn(1, disk_eq)
161 var allok: i64 = 0
162 if conn_ok==1 { if hs_ok==1 { if blocks_ok==1 { if sha_eq==1 { if disk_eq==1 { allok = 1 } } } } }
163 if allok == 1 { pd_w(1, " verdict=GREEN file=/tmp/_nx_dl_test.bin\n" as *u8); sys_exit(0); return 0 }
164 pd_w(1, " verdict=RED\n" as *u8); sys_exit(1)
165 return 1
166}