code wiki / _hdl_build / nx_mp_live_gate.nx
nx_mp_live_gate.nx source
↩ module page · 114 lines · 5716 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"
10
11func slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
12// connect a fresh TCP socket to 127.0.0.1:port; returns fd or -1
13func conn(port: i64) -> i64 {
14 let addr: *u8 = sys_mmap(16)
15 addr[0]=2 as u8; addr[1]=0 as u8
16 addr[2]=((port>>8)&0xff) as u8; addr[3]=(port&0xff) as u8
17 addr[4]=127 as u8; addr[5]=0 as u8; addr[6]=0 as u8; addr[7]=1 as u8
18 var z: i64=8; while z<16 { addr[z]=0 as u8; z=z+1 }
19 let fd: i64 = sys_socket(2,1,0)
20 if fd<0 { return 0-1 }
21 if nx_connect_bounded(fd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { sys_close(fd); return 0-1 }
22 return fd
23}
24// POST a `flen`-byte snapshot to /pstate?r=<rm>&p=<pr>
25func post_pstate(port: i64, rm: i64, pr: i64, frame: *u8, flen: i64) -> i64 {
26 let fd: i64 = conn(port)
27 if fd < 0 { return 0-1 }
28 let req: *u8 = sys_mmap(256)
29 var o: i64 = 0
30 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}
31 var m: i64=rm; let t: *u8 = sys_mmap(16); var k: i64=0
32 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} }
33 var j: i64=k-1; while j>=0 {req[o]=t[j];o=o+1;j=j-1}
34 let h2: *u8 = "&p=" as *u8; i=0; while h2[i]!=(0 as u8){req[o]=h2[i];o=o+1;i=i+1}
35 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} }
36 j=k-1; while j>=0 {req[o]=t[j];o=o+1;j=j-1}
37 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}
38 var b: i64=0; while b<flen {req[o]=frame[b];o=o+1;b=b+1}
39 sys_write(fd, req, o)
40 let rb: *u8 = sys_mmap(256); sys_read(fd, rb, 255) // drain ack
41 sys_close(fd)
42 return 0
43}
44// GET /roster?r=<rm>&p=<self> into out; returns bytes read
45func get_roster(port: i64, rm: i64, self_pr: i64, out: *u8) -> i64 {
46 let fd: i64 = conn(port)
47 if fd < 0 { return 0-1 }
48 let req: *u8 = sys_mmap(256)
49 var o: i64 = 0
50 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}
51 var m: i64=rm; let t: *u8 = sys_mmap(16); var k: i64=0
52 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} }
53 var j: i64=k-1; while j>=0 {req[o]=t[j];o=o+1;j=j-1}
54 let h2: *u8 = "&p=" as *u8; i=0; while h2[i]!=(0 as u8){req[o]=h2[i];o=o+1;i=i+1}
55 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} }
56 j=k-1; while j>=0 {req[o]=t[j];o=o+1;j=j-1}
57 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}
58 sys_write(fd, req, o)
59 let n: i64 = sys_read(fd, out, 4095)
60 sys_close(fd)
61 return n
62}
63// offset of the body (past "\r\n\r\n") in a response of length n
64func body_off(buf: *u8, n: i64) -> i64 {
65 var i: i64=0
66 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 }
67 return 0-1
68}
69// count [len][frame] records in a body
70func rec_count(body: *u8, total: i64) -> i64 {
71 var o: i64=0; var c: i64=0; var go: i64=1
72 while go==1 { if o>=total {go=0} else { let fl: i64=body[o] as i64; o=o+1+fl; c=c+1 } }
73 return c
74}
75
76func main() -> i64 {
77 g_puts("nx_mp_live gate (sovereign HTTP client vs the LIVE daemon on :7702, NO curl/node)\n" as *u8)
78 var pass: i64 = 0; var total: i64 = 0
79 let PORT: i64 = 7702
80 let RM: i64 = 99
81
82 // reachability
83 let probe: i64 = conn(PORT)
84 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 }
85 sys_close(probe)
86
87 let fa: *u8 = sys_mmap(16); var i: i64=0; while i<11 { fa[i]=(100+i) as u8; i=i+1 }
88 let fb: *u8 = sys_mmap(16); i=0; while i<11 { fb[i]=(40+i) as u8; i=i+1 }
89 post_pstate(PORT, RM, 1, fa, 11)
90 post_pstate(PORT, RM, 2, fb, 11)
91
92 let out: *u8 = sys_mmap(4096)
93 let n: i64 = get_roster(PORT, RM, 9, out)
94 let bo: i64 = body_off(out, n)
95 var r1: i64 = 1
96 var nrec: i64 = 0
97 if bo < 0 { r1 = 0 } else {
98 let body: *u8 = (out + bo) as *u8
99 let blen: i64 = n - bo
100 nrec = rec_count(body, blen)
101 if nrec != 2 { r1 = 0 }
102 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)
103 }
104 pass = pass + g_check("LIVE relay: 2 players POSTed -> roster returns both (shared-mmap across forks)" as *u8, r1); total=total+1
105
106 // isolation: an empty room returns 0 records
107 let n2: i64 = get_roster(PORT, 12345, 9, out)
108 let bo2: i64 = body_off(out, n2)
109 pass = pass + g_check("LIVE room isolation: empty room -> 0 records (neg)" as *u8, (n2 - bo2) == 0); total=total+1
110
111 g_puts("---- mp-live gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
112 if pass == total { g_puts("verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
113 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1
114}