nx_metainfo.nx source
↩ module page · 65 lines · 2450 B
1// nx_metainfo.nx -- .torrent metainfo loader (bits-up), reuses bencode + sha1.
2//
3// module: nishi-core.torrent.metainfo
4// depends: nx_syscalls.nx, nx_bencode.nx, nx_sha1.nx
5// capability: CORE_COMPUTE
6// wired_status: FULLY_WIRED
7//
8// Parse a .torrent: announce URL, info dict (name, piece length, total length),
9// and the INFO-HASH = SHA-1 over the raw bencoded `info` dict bytes (BEP-3) --
10// the identity used in tracker announces + peer handshakes. Reuses nx_bencode
11// (parse) + sha1 (hash); zero new crypto. The info-dict byte bounds come from
12// nx_bc_skip so the hash is over the exact on-wire bytes.
13
14import "nx_syscalls.nx"
15import "nx_bencode.nx"
16import "nx_sha1.nx"
17
18struct NxMetainfo {
19 announce_off: i64,
20 announce_len: i64,
21 name_off: i64,
22 name_len: i64,
23 piece_length: i64,
24 total_length: i64,
25 info_off: i64,
26 info_len: i64,
27}
28const NX_METAINFO_BYTES: i64 = 64 // 8 * 8
29const NX_MI_OK: i64 = 1
30const NX_MI_BAD: i64 = 0
31
32// Parse metainfo buf[0..n) into mi; write the 20-byte info-hash to ih_out.
33func nx_metainfo_parse(buf: *u8, n: i64, mi: *NxMetainfo, ih_out: *u8) -> i64 {
34 if nx_bc_type(buf, 0, n) != NX_BC_DICT { return NX_MI_BAD }
35 let so: *i64 = sys_mmap(8) as *i64
36 let sl: *i64 = sys_mmap(8) as *i64
37 let iv: *i64 = sys_mmap(8) as *i64
38
39 let ann: i64 = nx_bc_dict_get(buf, 0, n, "announce", 8)
40 if ann < 0 { return NX_MI_BAD }
41 if nx_bc_str(buf, ann, n, so, sl) < 0 { return NX_MI_BAD }
42 mi.announce_off = so[0]
43 mi.announce_len = sl[0]
44
45 let info: i64 = nx_bc_dict_get(buf, 0, n, "info", 4)
46 if info < 0 { return NX_MI_BAD }
47 let info_end: i64 = nx_bc_skip(buf, info, n)
48 if info_end < 0 { return NX_MI_BAD }
49 mi.info_off = info
50 mi.info_len = info_end - info
51 // info-hash = SHA-1 of the raw info-dict bytes
52 sha1(((buf as i64) + info) as *u8, mi.info_len, ih_out)
53
54 let nm: i64 = nx_bc_dict_get(buf, info, n, "name", 4)
55 if nm >= 0 { nx_bc_str(buf, nm, n, so, sl); mi.name_off = so[0]; mi.name_len = sl[0] }
56 else { mi.name_off = 0 - 1; mi.name_len = 0 }
57
58 let pl: i64 = nx_bc_dict_get(buf, info, n, "piece length", 12)
59 if pl >= 0 { nx_bc_int(buf, pl, n, iv); mi.piece_length = iv[0] } else { mi.piece_length = 0 }
60
61 let ln: i64 = nx_bc_dict_get(buf, info, n, "length", 6)
62 if ln >= 0 { nx_bc_int(buf, ln, n, iv); mi.total_length = iv[0] } else { mi.total_length = 0 }
63
64 return NX_MI_OK
65}