code wiki / _hdl_build / nx_mp_live_gate.nx

nx_mp_live_gate.nx source

↩ module page · 122 lines · 6157 B

1// nx_mp_live_gate.nx -- SOVEREIGN end-to-end LIVE proof of the running multiplayer daemon (no curl, no node): 2// a pure-syscall HTTP client POSTs two players' snapshots to the LIVE nx_mp_serve on 127.0.0.1:7702, then GETs 3// the roster and confirms the response body carries BOTH players' [len][frame] records. Proves the live relay 4// works (shared-mmap rr_post across forked handlers), not just that a page serves. 5// Run AFTER `nx_mp_up`: ./_offc/nx_sov_build_run.elf nx_mp_live_gate 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 9import "nx_gate_emit_lib.nx" 10import "nx_gate_verdict.nx" 11 12func slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 13// connect a fresh TCP socket to 127.0.0.1:port; returns fd or -1 14func conn(port: i64) -> i64 { 15 let addr: *u8 = sys_mmap(16) 16 addr[0]=2 as u8; addr[1]=0 as u8 17 addr[2]=((port>>8)&0xff) as u8; addr[3]=(port&0xff) as u8 18 addr[4]=127 as u8; addr[5]=0 as u8; addr[6]=0 as u8; addr[7]=1 as u8 19 var z: i64=8; while z<16 { addr[z]=0 as u8; z=z+1 } 20 let fd: i64 = sys_socket(2,1,0) 21 if fd<0 { return 0-1 } 22 if nx_connect_bounded(fd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { sys_close(fd); return 0-1 } 23 return fd 24} 25// POST a `flen`-byte snapshot to /pstate?r=<rm>&p=<pr> 26func post_pstate(port: i64, rm: i64, pr: i64, frame: *u8, flen: i64) -> i64 { 27 let fd: i64 = conn(port) 28 if fd < 0 { return 0-1 } 29 let req: *u8 = sys_mmap(256) 30 var o: i64 = 0 31 let h1: *u8 = "POST /pstate?r=" as *u8; var i: i64=0; while h1[i]!=(0 as u8){req[o]=h1[i];o=o+1;i=i+1} 32 var m: i64=rm; let t: *u8 = sys_mmap(16); var k: i64=0 33 if m==0 {t[0]=48 as u8;k=1} else { while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} } 34 var j: i64=k-1; while j>=0 {req[o]=t[j];o=o+1;j=j-1} 35 let h2: *u8 = "&p=" as *u8; i=0; while h2[i]!=(0 as u8){req[o]=h2[i];o=o+1;i=i+1} 36 m=pr;k=0; if m==0 {t[0]=48 as u8;k=1} else { while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} } 37 j=k-1; while j>=0 {req[o]=t[j];o=o+1;j=j-1} 38 let h3: *u8 = " HTTP/1.0\r\nContent-Length: 11\r\n\r\n" as *u8; i=0; while h3[i]!=(0 as u8){req[o]=h3[i];o=o+1;i=i+1} 39 var b: i64=0; while b<flen {req[o]=frame[b];o=o+1;b=b+1} 40 sys_write(fd, req, o) 41 let rb: *u8 = sys_mmap(256); sys_read(fd, rb, 255) // drain ack 42 sys_close(fd) 43 return 0 44} 45// GET /roster?r=<rm>&p=<self> into out; returns bytes read 46func get_roster(port: i64, rm: i64, self_pr: i64, out: *u8) -> i64 { 47 let fd: i64 = conn(port) 48 if fd < 0 { return 0-1 } 49 let req: *u8 = sys_mmap(256) 50 var o: i64 = 0 51 let h1: *u8 = "GET /roster?r=" as *u8; var i: i64=0; while h1[i]!=(0 as u8){req[o]=h1[i];o=o+1;i=i+1} 52 var m: i64=rm; let t: *u8 = sys_mmap(16); var k: i64=0 53 if m==0 {t[0]=48 as u8;k=1} else { while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} } 54 var j: i64=k-1; while j>=0 {req[o]=t[j];o=o+1;j=j-1} 55 let h2: *u8 = "&p=" as *u8; i=0; while h2[i]!=(0 as u8){req[o]=h2[i];o=o+1;i=i+1} 56 m=self_pr;k=0; if m==0 {t[0]=48 as u8;k=1} else { while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} } 57 j=k-1; while j>=0 {req[o]=t[j];o=o+1;j=j-1} 58 let h3: *u8 = " HTTP/1.0\r\nHost: x\r\n\r\n" as *u8; i=0; while h3[i]!=(0 as u8){req[o]=h3[i];o=o+1;i=i+1} 59 sys_write(fd, req, o) 60 let n: i64 = sys_read(fd, out, 4095) 61 sys_close(fd) 62 return n 63} 64// offset of the body (past "\r\n\r\n") in a response of length n 65func body_off(buf: *u8, n: i64) -> i64 { 66 var i: i64=0 67 while i+3 < n { if buf[i]==(13 as u8){if buf[i+1]==(10 as u8){if buf[i+2]==(13 as u8){if buf[i+3]==(10 as u8){return i+4}}}} i=i+1 } 68 return 0-1 69} 70// count [len][frame] records in a body 71func rec_count(body: *u8, total: i64) -> i64 { 72 var o: i64=0; var c: i64=0; var go: i64=1 73 while go==1 { if o>=total {go=0} else { let fl: i64=body[o] as i64; o=o+1+fl; c=c+1 } } 74 return c 75} 76 77func main() -> i64 { 78 g_puts("nx_mp_live gate (sovereign HTTP client vs the LIVE daemon on :7702, NO curl/node)\n" as *u8) 79 var pass: i64 = 0; var total: i64 = 0 80 let PORT: i64 = 7702 81 let RM: i64 = 99 82 83 // reachability 84 let probe: i64 = conn(PORT) 85 if probe < 0 { g_puts(" FAIL daemon not reachable on :7702 -- run nx_mp_up first\n" as *u8); g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1 } 86 sys_close(probe) 87 88 let fa: *u8 = sys_mmap(16); var i: i64=0; while i<11 { fa[i]=(100+i) as u8; i=i+1 } 89 let fb: *u8 = sys_mmap(16); i=0; while i<11 { fb[i]=(40+i) as u8; i=i+1 } 90 post_pstate(PORT, RM, 1, fa, 11) 91 post_pstate(PORT, RM, 2, fb, 11) 92 93 let out: *u8 = sys_mmap(4096) 94 let n: i64 = get_roster(PORT, RM, 9, out) 95 let bo: i64 = body_off(out, n) 96 var r1: i64 = 1 97 var nrec: i64 = 0 98 if bo < 0 { r1 = 0 } else { 99 let body: *u8 = (out + bo) as *u8 100 let blen: i64 = n - bo 101 nrec = rec_count(body, blen) 102 if nrec != 2 { r1 = 0 } 103 g_puts(" [measure] LIVE /roster body = " as *u8); g_pn(blen); g_puts(" bytes, " as *u8); g_pn(nrec); g_puts(" player records\n" as *u8) 104 } 105 pass = pass + g_check("LIVE relay: 2 players POSTed -> roster returns both (shared-mmap across forks)" as *u8, r1); total=total+1 106 107 // isolation: an empty room returns 0 records 108 let n2: i64 = get_roster(PORT, 12345, 9, out) 109 let bo2: i64 = body_off(out, n2) 110 pass = pass + g_check("LIVE room isolation: empty room -> 0 records (neg)" as *u8, (n2 - bo2) == 0); total=total+1 111 112 g_puts("---- mp-live gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 113 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 114 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 115 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 116 let ctr__dry: *i64 = gv_ctr() 117 ctr__dry[0] = pass 118 ctr__dry[1] = total 119 let rc__dry: i64 = gv_verdict("MP-LIVE-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 120 sys_exit(rc__dry) 121 return rc__dry 122}