code wiki / (root) / nx_research_ka.nx

nx_research_ka.nx source

↩ module page · 211 lines · 12732 B

1// nx_research_ka.nx -- R4 FULL: per-host connection POOL + keep-alive fetch, with a PROVEN-path fallback. 2// Operator 2026-07-01 chose R4. nx_https_get_complete has 30 callers (untouchable) so this is a SELF-CONTAINED module: 3// * caches ONE (host, fd, session) across calls (module static globals) -> a researcher hitting ONE host repeatedly 4// pays the ~300ms cert-verify (certloop) ONCE, then reuses the TLS session for every subsequent GET. 5// * SAFE by construction: only the clean case (fresh/reused -> HTTP 200, Content-Length body) uses the fast path; 6// ANYTHING else (redirect/non-200/stale/parse-miss) closes the pooled conn and FALLS BACK to the proven 7// nx_https_fetch_follow (fresh connect, full redirect+chunk handling). Worst case == today's behavior. 8// Proven mechanism: nx_https_ka_probe (2 GETs / 1 handshake, GREEN). license_tier: ORIGINAL expect_exit: 0 9import "nx_syscalls.nx" 10import "nx_tls13.nx" 11import "nx_tls13_record.nx" 12import "nx_tls13_read_record_from_fd.nx" 13import "nx_tls13_client_session.nx" 14import "nx_x509_trust_store.nx" 15import "nx_trust_store_load_from_certdata.nx" 16import "nx_tls13_client_validate_certificate.nx" 17import "nx_tls13_client_session_run.nx" 18import "nx_url.nx" 19import "nx_https_url_for_fetch.nx" 20import "nx_https_url_connect.nx" 21import "nx_http_response_parse.nx" 22import "nx_https_fetch_follow.nx" 23const K_MAGIC_4096: i64 = 4096 24const K_MAGIC_16645: i64 = 16645 25const K_MAGIC_2048: i64 = 2048 26const K_MAGIC_4194304: i64 = 4194304 27 28// ---- single-entry per-host connection pool (module state) ---- 29static G_KA_HOSTBUF: i64 // ptr to a persistent 512B host buffer (0 = uninit) 30static G_KA_HLEN: i64 31static G_KA_FD: i64 // 0 = no pooled connection 32static G_KA_SESS: i64 // *Tls13ClientSession 33static G_KA_HANDSHAKES:i64 // count of fresh handshakes (test/telemetry) 34static G_KA_REUSES: i64 // count of reused fetches 35 36func rka_handshakes() -> i64 { return G_KA_HANDSHAKES } 37func rka_reuses() -> i64 { return G_KA_REUSES } 38 39func rp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 40func rn(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 41func rka_write_n(fd: i64, buf: *u8, n: i64) -> i64 { var off: i64=0; while off<n { let w: i64=sys_write(fd,(buf as i64+off) as *u8,n-off); if w<=0 {return 0-1} off=off+w } return 0 } 42func rka_cat(out: *u8, o: i64, s: *u8) -> i64 { var j: i64=0; while s[j]!=(0 as u8) { out[o]=s[j]; o=o+1; j=j+1 } return o } 43 44func rka_build_req(path: *u8, path_len: i64, host: *u8, host_len: i64, out: *u8) -> i64 { 45 var o: i64 = 0 46 o = rka_cat(out, o, "GET " as *u8) 47 var pi: i64=0; while pi<path_len { out[o]=path[pi]; o=o+1; pi=pi+1 } 48 o = rka_cat(out, o, " HTTP/1.1\r\nHost: " as *u8) 49 var hi: i64=0; while hi<host_len { out[o]=host[hi]; o=o+1; hi=hi+1 } 50 o = rka_cat(out, o, "\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.5\r\nAccept-Encoding: identity\r\nConnection: keep-alive\r\n\r\n" as *u8) 51 return o 52} 53func rka_hdr_end(buf: *u8, n: i64) -> i64 { var i: i64=0; while i+4<=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}}}} i=i+1 } return 0-1 } 54func rka_lc(c: i64) -> i64 { if c>=65 { if c<=90 { return c+32 } } return c } 55func rka_clen(buf: *u8, hdr_end: i64) -> i64 { 56 let pat: *u8 = "content-length:" as *u8 57 var i: i64=0 58 while i<hdr_end { 59 var atline: i64=0 60 if i==0 { atline=1 } else { if buf[i-1]==(10 as u8) { atline=1 } } 61 if atline==1 { 62 var mm: i64=1; var j: i64=0 63 while j<15 { if rka_lc(buf[i+j] as i64)!=rka_lc(pat[j] as i64) { mm=0; j=15 } else { j=j+1 } } 64 if mm==1 { 65 var p: i64=i+15 66 var d: i64=0 67 while d==0 { if p>=hdr_end { d=1 } else { if buf[p]==(32 as u8) { p=p+1 } else { d=1 } } } 68 var v: i64=0; var any: i64=0; var go: i64=1 69 while go==1 { if p>=hdr_end { go=0 } else { let c: i64=buf[p] as i64; if c>=48 { if c<=57 { v=v*10+(c-48); any=1; p=p+1 } else { go=0 } } else { go=0 } } } 70 if any==1 { return v } 71 return 0-1 72 } 73 } 74 i=i+1 75 } 76 return 0-1 77} 78// send ONE keep-alive GET over an OPEN session+fd, drain Content-Length body, LEAVE fd open. (mirrors get_complete's cl-stop) 79func rka_get(s: *Tls13ClientSession, fd: i64, path: *u8, path_len: i64, host: *u8, host_len: i64, out_buf: *u8, out_cap: i64) -> i64 { 80 if s.state != NX_TLS13_CSESSION_STATE_CONNECTED { return 0-1 } 81 let req: *u8 = sys_mmap(K_MAGIC_4096) 82 let req_len: i64 = rka_build_req(path, path_len, host, host_len, req) 83 let rec_buf: *u8 = sys_mmap(req_len + 64) 84 let ct_out: *u8 = rec_buf + NX_TLS13_RECORD_HEADER_LEN 85 let tag_out: *u8 = rec_buf + NX_TLS13_RECORD_HEADER_LEN + req_len + 1 86 let enc_v: i64 = nx_tls13_record_encrypt_v2(s.cipher_suite, s.client_app_traffic_key, s.client_app_iv, s.client_app_seq, req, req_len, NX_TLS13_CT_APPLICATION_DATA, 0, rec_buf, ct_out, tag_out) 87 s.client_app_seq = s.client_app_seq + 1 88 if enc_v != NX_TLS13_REC_VERDICT_OK { return 0-1 } 89 let total_rec_len: i64 = NX_TLS13_RECORD_HEADER_LEN + req_len + 1 + NX_TLS13_RECORD_TAG_LEN 90 if rka_write_n(fd, rec_buf, total_rec_len) < 0 { return 0-1 } 91 var accumulated: i64 = 0 92 var body_target: i64 = 0 93 var hdr_parsed: i64 = 0 94 let rec_in: *u8 = sys_mmap(K_MAGIC_16645) 95 let plaintext: *u8 = sys_mmap(K_MAGIC_16645) 96 let pct: *i64 = sys_mmap(16) as *i64 97 let plen: *i64 = sys_mmap(16) as *i64 98 while accumulated < out_cap { 99 let rt: i64 = nx_tls13_read_record_from_fd(fd, rec_in, K_MAGIC_16645) 100 if rt < 0 { return accumulated } 101 let rec_ct: *u8 = rec_in + NX_TLS13_RECORD_HEADER_LEN 102 let rec_ct_len: i64 = rt - NX_TLS13_RECORD_HEADER_LEN - NX_TLS13_RECORD_TAG_LEN 103 let rec_tag: *u8 = rec_in + rt - NX_TLS13_RECORD_TAG_LEN 104 let dv: i64 = nx_tls13_record_decrypt_v2(s.cipher_suite, s.server_app_traffic_key, s.server_app_iv, s.server_app_seq, rec_in, rec_ct, rec_ct_len, rec_tag, plaintext, pct, plen) 105 s.server_app_seq = s.server_app_seq + 1 106 if dv != NX_TLS13_REC_VERDICT_OK { return 0-1 } 107 if *pct == NX_TLS13_CT_ALERT { return accumulated } 108 if *pct == NX_TLS13_CT_APPLICATION_DATA { 109 let to_copy: i64 = *plen 110 if to_copy > out_cap - accumulated { return accumulated } 111 var i: i64=0; while i<to_copy { out_buf[accumulated+i]=plaintext[i]; i=i+1 } 112 accumulated = accumulated + to_copy 113 if hdr_parsed==0 { let he: i64=rka_hdr_end(out_buf, accumulated); if he>=0 { hdr_parsed=1; let cl: i64=rka_clen(out_buf, he); if cl>=0 { body_target=he+4+cl } } } 114 if body_target>0 { if accumulated>=body_target { return accumulated } } 115 } 116 } 117 return accumulated 118} 119 120func rka_path(urlbuf: *u8, target: *NxHttpsTarget, path_out: *u8) -> i64 { 121 var p: i64 = target.url.host_off + target.url.host_len 122 if urlbuf[p] == 0x3A as u8 { 123 p = p + 1 124 while urlbuf[p] >= 0x30 as u8 { if urlbuf[p] <= 0x39 as u8 { p = p + 1 } else { break } } 125 } 126 if urlbuf[p] != 0x2F as u8 { path_out[0] = 0x2F as u8; path_out[1] = 0 as u8; return 1 } 127 var k: i64 = 0 128 while urlbuf[p] != 0 as u8 { path_out[k] = urlbuf[p]; p = p + 1; k = k + 1 } 129 path_out[k] = 0 as u8 130 return k 131} 132func rka_host_match(host: *u8, hlen: i64) -> i64 { 133 if G_KA_FD == 0 { return 0 } 134 if G_KA_HOSTBUF == 0 { return 0 } 135 if G_KA_HLEN != hlen { return 0 } 136 let hb: *u8 = G_KA_HOSTBUF as *u8 137 var i: i64 = 0 138 while i < hlen { if hb[i] != host[i] { return 0 } i = i + 1 } 139 return 1 140} 141func rka_host_cache(host: *u8, hlen: i64) -> i64 { 142 if G_KA_HOSTBUF == 0 { G_KA_HOSTBUF = sys_mmap(512) as i64 } 143 let hb: *u8 = G_KA_HOSTBUF as *u8 144 var i: i64 = 0 145 while i < hlen { hb[i] = host[i]; i = i + 1 } 146 G_KA_HLEN = hlen 147 return 0 148} 149 150// THE pooled keep-alive fetch. Drop-in for nx_https_fetch_follow (same signature); falls back to it on any non-clean case. 151func rf_fetch_ka(url0: *u8, store: *TrustStore, out: *u8, out_cap: i64, out_status: *i64) -> i64 { 152 out_status[0] = 0 153 let urlbuf: *u8 = sys_mmap(K_MAGIC_4096) 154 var ui: i64=0; while url0[ui]!=(0 as u8) { urlbuf[ui]=url0[ui]; ui=ui+1 } urlbuf[ui]=0 as u8 155 let target_raw: *u8 = sys_mmap(64); let target: *NxHttpsTarget = target_raw as *NxHttpsTarget 156 target.url = nx_url_new(); target.port = 0 157 if nx_https_url_for_fetch(urlbuf, target) != NX_HTTPS_URL_OK { return nx_https_fetch_follow(url0, store, out, out_cap, 6, out_status) } 158 let host: *u8 = urlbuf + target.url.host_off 159 let hlen: i64 = target.url.host_len 160 let path: *u8 = sys_mmap(K_MAGIC_2048) 161 let plen: i64 = rka_path(urlbuf, target, path) 162 let rr: *i64 = sys_mmap(128) as *i64 163 // ---- POOL REUSE (no handshake) ---- 164 if rka_host_match(host, hlen) == 1 { 165 let session: *Tls13ClientSession = G_KA_SESS as *Tls13ClientSession 166 let n: i64 = rka_get(session, G_KA_FD, path, plen, host, hlen, out, out_cap) 167 if n > 0 { if nx_http_response_parse(out, n, rr) == 0 { if rr[1] == 200 { G_KA_REUSES = G_KA_REUSES + 1; out_status[0]=200; return n } } } 168 sys_close(G_KA_FD); G_KA_FD = 0 // stale/non-200 -> drop pooled conn, fall through to fresh 169 } 170 // ---- FRESH connect + handshake (pays certloop ONCE, then cache) ---- 171 let fd_p: *i64 = sys_mmap(16) as *i64 172 if nx_https_url_connect(target, urlbuf, sys_now_realtime_sec(), fd_p) != NX_HTTPS_CONNECT_OK { return nx_https_fetch_follow(url0, store, out, out_cap, 6, out_status) } 173 let fd: i64 = fd_p[0] 174 let cr: *u8 = sys_mmap(32); let pv: *u8 = sys_mmap(32) 175 var i: i64=0; while i<32 { cr[i]=(0xC0+i) as u8; pv[i]=(0xA0+i) as u8; i=i+1 } 176 let vc_raw: *u8 = sys_mmap(64); let vc: *TlsValidationContext = vc_raw as *TlsValidationContext 177 vc.store = store; vc.sni_host = host; vc.sni_host_len = hlen; vc.now_epoch = sys_now_realtime_sec() 178 G_KA_HANDSHAKES = G_KA_HANDSHAKES + 1 179 let sr: i64 = nx_tls13_client_session_run(fd, host, hlen, cr, pv, vc) 180 if sr <= 0 { sys_close(fd); return nx_https_fetch_follow(url0, store, out, out_cap, 6, out_status) } 181 let session2: *Tls13ClientSession = sr as *Tls13ClientSession 182 let n2: i64 = rka_get(session2, fd, path, plen, host, hlen, out, out_cap) 183 if n2 > 0 { if nx_http_response_parse(out, n2, rr) == 0 { if rr[1] == 200 { 184 rka_host_cache(host, hlen); G_KA_FD = fd; G_KA_SESS = sr // CACHE for reuse 185 out_status[0]=200; return n2 186 } } } 187 sys_close(fd) // non-200 (redirect/chunked/etc) -> proven fallback (fresh, full handling) 188 return nx_https_fetch_follow(url0, store, out, out_cap, 6, out_status) 189} 190 191// self-test: fetch the SAME host 3x -> expect 1 handshake + 2 reuses, all 200. 192func main() -> i64 { 193 let sres: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, K_MAGIC_4194304) 194 if sres <= 0 { rp("trust load FAIL\n" as *u8); return 1 } 195 let store: *TrustStore = sres as *TrustStore 196 let cap: i64 = K_MAGIC_4194304 197 let out: *u8 = sys_mmap(cap) 198 let status: *i64 = sys_mmap(16) as *i64 199 rp("=== nx_research_ka -- R4 per-host connection POOL (3 GETs to 1 host -> 1 handshake) ===\n" as *u8) 200 let a: i64 = rf_fetch_ka("https://en.wikipedia.org/wiki/WebGL" as *u8, store, out, cap, status) 201 rp(" GET1 bytes="); rn(a); rp(" status="); rn(status[0]); rp("\n" as *u8) 202 let b: i64 = rf_fetch_ka("https://en.wikipedia.org/wiki/WebGL" as *u8, store, out, cap, status) 203 rp(" GET2 bytes="); rn(b); rp(" status="); rn(status[0]); rp("\n" as *u8) 204 let c: i64 = rf_fetch_ka("https://en.wikipedia.org/wiki/WebGL" as *u8, store, out, cap, status) 205 rp(" GET3 bytes="); rn(c); rp(" status="); rn(status[0]); rp("\n" as *u8) 206 rp(" handshakes="); rn(rka_handshakes()); rp(" reuses="); rn(rka_reuses()); rp("\n" as *u8) 207 var green: i64=0; if a>0 { if b>0 { if c>0 { if rka_handshakes()==1 { if rka_reuses()==2 { green=1 } } } } } 208 if green==1 { rp("verdict=GREEN -- R4 FULL: 3 fetches to 1 host used 1 handshake + 2 connection reuses (cert tax amortized).\n" as *u8); return 0 } 209 rp("verdict=RED (handshakes="); rn(rka_handshakes()); rp(" reuses="); rn(rka_reuses()); rp(")\n" as *u8) 210 return 1 211}