code wiki / _hdl_build / nx_vroom.nx

nx_vroom.nx source

↩ module page · 216 lines · 9270 B

1// nx_vroom.nx -- the sovereign video-room request HANDLER (the daemon's brain), 2// kept separate from sockets/TLS so it is unit-gateable. Composes nx_room_relay 3// (per-room peer frames) into HTTP responses for the relay routes: 4// POST /video/post?room=R&id=N body=frame -> rr_post, "200 ok" 5// GET /video/frames?room=R&id=N -> octet body of OTHER peers' 6// frames as length-prefixed records: [id u64 LE][len u32 LE][frame bytes]* 7// GET /video/roster?room=R&id=N -> JSON [id,id,...] 8// Returns response length in `out`, or 0 if the route isn't a relay route (the 9// TLS/fork shell then serves the static page / client.wasm / 404). 10// Server-relay = ZERO WebRTC/STUN/TURN. All flag-style loops (no break/continue 11// in nested ifs -- that miscompiles and hangs, per the sites-daemon note). 12// license_tier: ORIGINAL 13import "nx_room_relay.nx" 14const K_MAGIC_2166136261: i64 = 2166136261 15const K_MAGIC_16777619: i64 = 16777619 16 17func vr_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 18func vr_lower(c: u8) -> u8 { if c >= (65 as u8) { if c <= (90 as u8) { return c + (32 as u8) } } return c } 19 20func vr_contains(hay: *u8, hlen: i64, needle: *u8, nlen: i64) -> i64 { 21 if nlen <= 0 { return 0 } 22 if hlen < nlen { return 0 } 23 var i: i64 = 0 24 let last: i64 = hlen - nlen 25 while i <= last { 26 var j: i64 = 0; var ok: i64 = 1 27 while j < nlen { if hay[i+j] != needle[j] { ok = 0; j = nlen } else { j = j + 1 } } 28 if ok == 1 { return 1 } 29 i = i + 1 30 } 31 return 0 32} 33 34// body offset after CRLFCRLF, or hlen if absent 35func vr_body_start(hay: *u8, hlen: i64) -> i64 { 36 var i: i64 = 0 37 while i + 4 <= hlen { 38 if hay[i]==(13 as u8) { if hay[i+1]==(10 as u8) { if hay[i+2]==(13 as u8) { if hay[i+3]==(10 as u8) { return i + 4 } } } } 39 i = i + 1 40 } 41 return hlen 42} 43 44func vr_content_length(req: *u8, reqn: i64) -> i64 { 45 let key: *u8 = "content-length:" as *u8 46 var i: i64 = 0 47 while i + 15 <= reqn { 48 var j: i64 = 0; var ok: i64 = 1 49 while j < 15 { if vr_lower(req[i+j]) != key[j] { ok = 0; j = 15 } else { j = j + 1 } } 50 if ok == 1 { 51 var k: i64 = i + 15 52 var sk: i64 = 1 53 while sk == 1 { if k < reqn { if req[k]==(32 as u8) { k = k + 1 } else { sk = 0 } } else { sk = 0 } } 54 var v: i64 = 0; var got: i64 = 0; var run: i64 = 1 55 while run == 1 { 56 if k >= reqn { run = 0 } else { 57 let c: i64 = req[k] as i64 58 var dig: i64 = 0 59 if c >= 48 { if c <= 57 { dig = 1 } } 60 if dig == 1 { v = v*10 + (c-48); got = 1; k = k + 1 } else { run = 0 } 61 } 62 } 63 if got == 1 { return v } 64 return 0 - 1 65 } 66 i = i + 1 67 } 68 return 0 - 1 69} 70 71// FNV-1a over the request-line value of key (e.g. "room="); 0 if absent. 72// Hash keeps rooms isolated without storing names. Always nonzero-ized (|1). 73func vr_room_hash(req: *u8, reqn: i64) -> i64 { 74 let key: *u8 = "room=" as *u8 75 // limit to request line 76 var lim: i64 = 0; var sc: i64 = 1 77 while sc == 1 { if lim < reqn { if req[lim]==(13 as u8) { sc = 0 } else { lim = lim + 1 } } else { sc = 0 } } 78 var found: i64 = 0 - 1; var i: i64 = 0 79 while i + 5 <= lim { 80 if found < 0 { 81 var j: i64 = 0; var ok: i64 = 1 82 while j < 5 { if req[i+j] != key[j] { ok = 0; j = 5 } else { j = j + 1 } } 83 if ok == 1 { found = i + 5 } 84 } 85 i = i + 1 86 } 87 if found < 0 { return 0 } 88 var h: i64 = K_MAGIC_2166136261 89 var k: i64 = found; var run: i64 = 1 90 while run == 1 { 91 if k >= lim { run = 0 } else { 92 let c: u8 = vr_lower(req[k]) 93 var keepc: i64 = 0 94 if c >= (97 as u8) { if c <= (122 as u8) { keepc = 1 } } 95 if c >= (48 as u8) { if c <= (57 as u8) { keepc = 1 } } 96 if c == (45 as u8) { keepc = 1 } 97 if keepc == 0 { run = 0 } else { h = (h ^ (c as i64)) * K_MAGIC_16777619; h = h & 0xffffffff; k = k + 1 } 98 } 99 } 100 return h | 1 101} 102 103// integer value of the request-line value of "id=" (digits only), or -1 104func vr_id(req: *u8, reqn: i64) -> i64 { 105 let key: *u8 = "id=" as *u8 106 var lim: i64 = 0; var sc: i64 = 1 107 while sc == 1 { if lim < reqn { if req[lim]==(13 as u8) { sc = 0 } else { lim = lim + 1 } } else { sc = 0 } } 108 var found: i64 = 0 - 1; var i: i64 = 0 109 while i + 3 <= lim { 110 if found < 0 { 111 var j: i64 = 0; var ok: i64 = 1 112 while j < 3 { if req[i+j] != key[j] { ok = 0; j = 3 } else { j = j + 1 } } 113 if ok == 1 { found = i + 3 } 114 } 115 i = i + 1 116 } 117 if found < 0 { return 0 - 1 } 118 var v: i64 = 0; var got: i64 = 0; var k: i64 = found; var run: i64 = 1 119 while run == 1 { 120 if k >= lim { run = 0 } else { 121 let c: i64 = req[k] as i64 122 var dig: i64 = 0 123 if c >= 48 { if c <= 57 { dig = 1 } } 124 if dig == 1 { v = v*10 + (c-48); got = 1; k = k + 1 } else { run = 0 } 125 } 126 } 127 if got == 0 { return 0 - 1 } 128 return v 129} 130 131func vr_app(dst: *u8, off: i64, src: *u8, n: i64) -> i64 { var i: i64=0; while i<n { dst[off+i]=src[i]; i=i+1 } return off+n } 132func vr_apps(dst: *u8, off: i64, s: *u8) -> i64 { return vr_app(dst, off, s, vr_strlen(s)) } 133func vr_wu64(dst: *u8, off: i64, v: i64) -> i64 { var i: i64=0; while i<8 { dst[off+i]=((v >> (i*8)) & 0xff) as u8; i=i+1 } return off+8 } 134func vr_wu32(dst: *u8, off: i64, v: i64) -> i64 { var i: i64=0; while i<4 { dst[off+i]=((v >> (i*8)) & 0xff) as u8; i=i+1 } return off+4 } 135func vr_wdec(dst: *u8, off: i64, v: i64) -> i64 { 136 if v == 0 { dst[off]=48; return off+1 } 137 var d: i64=0; var y: i64=v 138 while y>0 { d=d+1; y=y/10 } 139 var i: i64=d-1; y=v 140 while i>=0 { dst[off+i]=(48+(y%10)) as u8; y=y/10; i=i-1 } 141 return off+d 142} 143 144// Handle a relay route. Returns response bytes written to out, or 0 if not a relay route. 145func vr_handle(plain: *u8, plain_n: i64, rr_st: *i64, rr_arena: *u8, now: i64, ttl: i64, 146 out: *u8, out_cap: i64, ids: *i64) -> i64 { 147 let slotb: i64 = rr_st[1] 148 149 if vr_contains(plain, plain_n, "/post" as *u8, 5) == 1 { 150 let rm: i64 = vr_room_hash(plain, plain_n) 151 let pr: i64 = vr_id(plain, plain_n) 152 if rm == 0 { return vr_apps(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\nConnection: keep-alive\r\n\r\n" as *u8) } 153 if pr < 0 { return vr_apps(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\nConnection: keep-alive\r\n\r\n" as *u8) } 154 let bs: i64 = vr_body_start(plain, plain_n) 155 var fl: i64 = plain_n - bs 156 let cl: i64 = vr_content_length(plain, plain_n) 157 if cl >= 0 { if cl < fl { fl = cl } } 158 if fl < 0 { fl = 0 } 159 rr_post(rr_st, rr_arena, rm, pr, now, now, (plain as i64 + bs) as *u8, fl) 160 return vr_apps(out, 0, "HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: keep-alive\r\n\r\nok" as *u8) 161 } 162 163 if vr_contains(plain, plain_n, "/frames" as *u8, 7) == 1 { 164 let rm: i64 = vr_room_hash(plain, plain_n) 165 let pr: i64 = vr_id(plain, plain_n) 166 let cnt: i64 = rr_roster(rr_st, rm, pr, now, ttl, ids) 167 // pass 1: body length 168 var blen: i64 = 0; var a: i64 = 0 169 while a < cnt { 170 let s: i64 = rr_live(rr_st, rm, ids[a], now, ttl) 171 if s >= 0 { blen = blen + 12 + rr_flen(rr_st, s) } 172 a = a + 1 173 } 174 var o: i64 = vr_apps(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: " as *u8) 175 o = vr_wdec(out, o, blen) 176 o = vr_apps(out, o, "\r\nConnection: keep-alive\r\n\r\n" as *u8) 177 // pass 2: body records [id u64][len u32][frame] 178 var b: i64 = 0 179 while b < cnt { 180 let s: i64 = rr_live(rr_st, rm, ids[b], now, ttl) 181 if s >= 0 { 182 let fl: i64 = rr_flen(rr_st, s) 183 o = vr_wu64(out, o, ids[b]) 184 o = vr_wu32(out, o, fl) 185 o = vr_app(out, o, (rr_arena as i64 + s*slotb) as *u8, fl) 186 } 187 b = b + 1 188 } 189 return o 190 } 191 192 if vr_contains(plain, plain_n, "/roster" as *u8, 7) == 1 { 193 let rm: i64 = vr_room_hash(plain, plain_n) 194 let pr: i64 = vr_id(plain, plain_n) 195 let cnt: i64 = rr_roster(rr_st, rm, pr, now, ttl, ids) 196 // build JSON body in the tail of out, then header (Content-Length) 197 let bodycap: i64 = out_cap - 256 198 var jb: i64 = bodycap 199 jb = vr_app(out, jb, "[" as *u8, 1) 200 var a: i64 = 0 201 while a < cnt { 202 if a > 0 { jb = vr_app(out, jb, "," as *u8, 1) } 203 jb = vr_wdec(out, jb, ids[a]) 204 a = a + 1 205 } 206 jb = vr_app(out, jb, "]" as *u8, 1) 207 let blen: i64 = jb - bodycap 208 var o: i64 = vr_apps(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: " as *u8) 209 o = vr_wdec(out, o, blen) 210 o = vr_apps(out, o, "\r\nConnection: keep-alive\r\n\r\n" as *u8) 211 o = vr_app(out, o, (out as i64 + bodycap) as *u8, blen) 212 return o 213 } 214 215 return 0 216}