code wiki / (root) / nx_udp_tracker.nx

nx_udp_tracker.nx source

↩ module page · 105 lines · 4468 B

1// nx_udp_tracker.nx -- BitTorrent UDP tracker protocol (BEP-15), bits-up. 2// 3// module: nishi-core.torrent.udp_tracker 4// depends: nx_syscalls.nx 5// capability: CORE_COMPUTE 6// wired_status: FULLY_WIRED 7// 8// The dominant tracker transport (BEP-15, Olaf van der Spek 2008): ~618 bytes / 9// 4 packets for 50 peers vs HTTP's ~1206 / 10 -- half the bytes, no TCP setup. 10// Two-step: connect (get a connection_id) then announce (get peers). Pure 11// build/parse here (KAT'd, deterministic); the UDP socket round-trip reuses the 12// net stack + nx_net_governor pacing. Big-endian wire; magic protocol_id 13// 0x41727101980. 14 15import "nx_syscalls.nx" 16 17const NX_UDP_PROTO_ID: i64 = 0x41727101980 // BEP-15 connect magic 18const NX_UDP_ACT_CONNECT: i64 = 0 19const NX_UDP_ACT_ANNOUNCE: i64 = 1 20const NX_UDP_ACT_SCRAPE: i64 = 2 21const NX_UDP_ACT_ERROR: i64 = 3 22 23func _ut_put_u64(out: *u8, off: i64, v: i64) -> i64 { 24 out[off] = (v >> 56) & 0xff; out[off+1] = (v >> 48) & 0xff 25 out[off+2] = (v >> 40) & 0xff; out[off+3] = (v >> 32) & 0xff 26 out[off+4] = (v >> 24) & 0xff; out[off+5] = (v >> 16) & 0xff 27 out[off+6] = (v >> 8) & 0xff; out[off+7] = v & 0xff 28 return 0 29} 30func _ut_get_u64(buf: *u8, off: i64) -> i64 { 31 return ((buf[off] as i64)<<56)|((buf[off+1] as i64)<<48)|((buf[off+2] as i64)<<40)|((buf[off+3] as i64)<<32)|((buf[off+4] as i64)<<24)|((buf[off+5] as i64)<<16)|((buf[off+6] as i64)<<8)|(buf[off+7] as i64) 32} 33func _ut_put_u32(out: *u8, off: i64, v: i64) -> i64 { 34 out[off]=(v>>24)&0xff; out[off+1]=(v>>16)&0xff; out[off+2]=(v>>8)&0xff; out[off+3]=v&0xff 35 return 0 36} 37func _ut_get_u32(buf: *u8, off: i64) -> i64 { 38 return ((buf[off] as i64)<<24)|((buf[off+1] as i64)<<16)|((buf[off+2] as i64)<<8)|(buf[off+3] as i64) 39} 40func _ut_put_u16(out: *u8, off: i64, v: i64) -> i64 { out[off]=(v>>8)&0xff; out[off+1]=v&0xff; return 0 } 41 42// connect request: <magic u64><action=0 u32><transaction_id u32> = 16 bytes. 43func nx_udp_build_connect(txid: i64, out: *u8) -> i64 { 44 _ut_put_u64(out, 0, NX_UDP_PROTO_ID) 45 _ut_put_u32(out, 8, NX_UDP_ACT_CONNECT) 46 _ut_put_u32(out, 12, txid) 47 return 16 48} 49// connect response: <action=0 u32><txid u32><connection_id u64>. Validates + 50// writes connection_id to out_conn[0]. Returns 1 if valid, 0 otherwise. 51func nx_udp_parse_connect_resp(buf: *u8, n: i64, txid: i64, out_conn: *i64) -> i64 { 52 if n < 16 { return 0 } 53 if _ut_get_u32(buf, 0) != NX_UDP_ACT_CONNECT { return 0 } 54 if _ut_get_u32(buf, 4) != txid { return 0 } 55 out_conn[0] = _ut_get_u64(buf, 8) 56 return 1 57} 58 59// announce request (98 bytes, BEP-15). 60func nx_udp_build_announce(conn_id: i64, txid: i64, info_hash: *u8, peer_id: *u8, 61 downloaded: i64, left: i64, uploaded: i64, event: i64, 62 num_want: i64, port: i64, out: *u8) -> i64 { 63 _ut_put_u64(out, 0, conn_id) 64 _ut_put_u32(out, 8, NX_UDP_ACT_ANNOUNCE) 65 _ut_put_u32(out, 12, txid) 66 var i: i64 = 0 67 while i < 20 { out[16 + i] = info_hash[i]; i = i + 1 } 68 i = 0 69 while i < 20 { out[36 + i] = peer_id[i]; i = i + 1 } 70 _ut_put_u64(out, 56, downloaded) 71 _ut_put_u64(out, 64, left) 72 _ut_put_u64(out, 72, uploaded) 73 _ut_put_u32(out, 80, event) 74 _ut_put_u32(out, 84, 0) // IP = default 75 _ut_put_u32(out, 88, 0) // key 76 _ut_put_u32(out, 92, num_want) 77 _ut_put_u16(out, 96, port) 78 return 98 79} 80 81// announce response: <action=1><txid><interval><leechers><seeders><6N peers>. 82// Writes interval/seeders/leechers + compact peers. Returns peer count or -1. 83func nx_udp_parse_announce_resp(buf: *u8, n: i64, txid: i64, 84 out_interval: *i64, out_seeders: *i64, out_leechers: *i64, 85 out_ips: *i64, out_ports: *i64, max: i64) -> i64 { 86 if n < 20 { return 0 - 1 } 87 if _ut_get_u32(buf, 0) != NX_UDP_ACT_ANNOUNCE { return 0 - 1 } 88 if _ut_get_u32(buf, 4) != txid { return 0 - 1 } 89 out_interval[0] = _ut_get_u32(buf, 8) 90 out_leechers[0] = _ut_get_u32(buf, 12) 91 out_seeders[0] = _ut_get_u32(buf, 16) 92 let total: i64 = (n - 20) / 6 93 var c: i64 = 0 94 var i: i64 = 0 95 while i < total { 96 if c < max { 97 let b: i64 = 20 + i * 6 98 out_ips[c] = ((buf[b] as i64)<<24)|((buf[b+1] as i64)<<16)|((buf[b+2] as i64)<<8)|(buf[b+3] as i64) 99 out_ports[c] = ((buf[b+4] as i64)<<8)|(buf[b+5] as i64) 100 c = c + 1 101 } 102 i = i + 1 103 } 104 return c 105}