code wiki / _hdl_build / nx_ws_client_session.nx

nx_ws_client_session.nx source

↩ module page · 139 lines · 7556 B

1// nx_ws_client_session.nx -- shared sovereign WSS-over-TLS1.3 CLIENT SESSION helpers. Extracted from 2// nx_video_2party_probe so the mobile-native room client and the probe share ONE implementation instead of 3// copy-pasting the TLS-record + RFC-6455 framing glue (rule #15 DRY / the operator's SSOT direction). 4// No main -- import this and call wscs_connect / wscs_send / wscs_ws_recv. These are the transport a 5// ZERO-JS, ZERO-browser NishiLang client (mobile-native) uses to join a live room. 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_x509_trust_store.nx" 9import "nx_trust_store_load_from_certdata.nx" 10import "nx_tls13_client_validate_certificate.nx" 11import "nx_tls13_client_session_run.nx" 12import "nx_https_url_for_fetch.nx" 13import "nx_https_url_connect.nx" 14import "nx_https_get_complete.nx" // record constants + session struct + record encrypt/decrypt (transitive) 15import "nx_websocket_client_upgrade.nx" // nx_ws_client_build_request / nx_ws_client_validate_response 16import "nx_websocket_frame.nx" // ws_build_header / ws_apply_mask / ws_parse_frame / WS_OP_BINARY / WsFrame 17const WSCS_MAGIC_16645: i64 = 16645 18const WSCS_MAGIC_131072: i64 = 131072 19const WSCS_MAGIC_4096: i64 = 4096 20const WSCS_MAGIC_65536: i64 = 65536 21 22const WSCS_TMO_S: i64 = 12 23 24// TLS-encrypt `bytes` as ONE application_data record (client-app keys) and write it. 0 ok / -1 fail. 25func wscs_send(s: *Tls13ClientSession, fd: i64, bytes: *u8, blen: i64) -> i64 { 26 let rec_buf: *u8 = sys_mmap(blen + 64) 27 let header_out: *u8 = rec_buf 28 let ct_out: *u8 = ((rec_buf as i64) + NX_TLS13_RECORD_HEADER_LEN) as *u8 29 let tag_out: *u8 = ((rec_buf as i64) + NX_TLS13_RECORD_HEADER_LEN + blen + 1) as *u8 30 let ev: i64 = nx_tls13_record_encrypt_v2(s.cipher_suite, s.client_app_traffic_key, s.client_app_iv, s.client_app_seq, bytes, blen, NX_TLS13_CT_APPLICATION_DATA, 0, header_out, ct_out, tag_out) 31 s.client_app_seq = s.client_app_seq + 1 32 if ev != NX_TLS13_REC_VERDICT_OK { return 0 - 1 } 33 let total: i64 = NX_TLS13_RECORD_HEADER_LEN + blen + 1 + NX_TLS13_RECORD_TAG_LEN 34 var wo: i64 = 0 35 while wo < total { let w: i64 = sys_write(fd, ((rec_buf as i64) + wo) as *u8, total - wo); if w <= 0 { return 0 - 1 } wo = wo + w } 36 return 0 37} 38 39// read+decrypt records into out until CRLFCRLF (the 101 headers) present. returns bytes accumulated, or -1. 40func wscs_recv_headers(s: *Tls13ClientSession, fd: i64, out: *u8, cap: i64) -> i64 { 41 var acc: i64 = 0 42 let rec_in: *u8 = sys_mmap(WSCS_MAGIC_16645) 43 let pt: *u8 = sys_mmap(WSCS_MAGIC_16645) 44 let ctp: *i64 = sys_mmap(16) as *i64 45 let lenp: *i64 = sys_mmap(16) as *i64 46 var go: i64 = 1 47 while go == 1 { 48 let rt: i64 = nx_tls13_read_record_from_fd(fd, rec_in, WSCS_MAGIC_16645) 49 if rt < 0 { return 0 - 1 } 50 let ct_len: i64 = rt - NX_TLS13_RECORD_HEADER_LEN - NX_TLS13_RECORD_TAG_LEN 51 let tag: *u8 = ((rec_in as i64) + rt - NX_TLS13_RECORD_TAG_LEN) as *u8 52 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_in as i64) + NX_TLS13_RECORD_HEADER_LEN) as *u8, ct_len, tag, pt, ctp, lenp) 53 s.server_app_seq = s.server_app_seq + 1 54 if dv != NX_TLS13_REC_VERDICT_OK { return 0 - 1 } 55 if ctp[0] == NX_TLS13_CT_APPLICATION_DATA { 56 var i: i64 = 0 57 while i < lenp[0] { if acc < cap { out[i + acc] = pt[i] } i = i + 1 } 58 acc = acc + lenp[0] 59 if _wscu_find_header_end(out, acc) >= 0 { go = 0 } 60 } 61 if ctp[0] == NX_TLS13_CT_ALERT { return 0 - 1 } 62 } 63 return acc 64} 65 66// read+decrypt records, parse ONE WS data frame, copy its payload into out. returns payload_len, or -1. 67func wscs_ws_recv(s: *Tls13ClientSession, fd: i64, out: *u8, cap: i64) -> i64 { 68 let plain: *u8 = sys_mmap(WSCS_MAGIC_131072) 69 var acc: i64 = 0 70 let rec_in: *u8 = sys_mmap(WSCS_MAGIC_16645) 71 let pt: *u8 = sys_mmap(WSCS_MAGIC_16645) 72 let ctp: *i64 = sys_mmap(16) as *i64 73 let lenp: *i64 = sys_mmap(16) as *i64 74 let f_raw: *u8 = sys_mmap(128) 75 let f: *WsFrame = f_raw as *WsFrame 76 var go: i64 = 1 77 while go == 1 { 78 let rt: i64 = nx_tls13_read_record_from_fd(fd, rec_in, WSCS_MAGIC_16645) 79 if rt < 0 { return 0 - 1 } 80 let ct_len: i64 = rt - NX_TLS13_RECORD_HEADER_LEN - NX_TLS13_RECORD_TAG_LEN 81 let tag: *u8 = ((rec_in as i64) + rt - NX_TLS13_RECORD_TAG_LEN) as *u8 82 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_in as i64) + NX_TLS13_RECORD_HEADER_LEN) as *u8, ct_len, tag, pt, ctp, lenp) 83 s.server_app_seq = s.server_app_seq + 1 84 if dv != NX_TLS13_REC_VERDICT_OK { return 0 - 1 } 85 if ctp[0] == NX_TLS13_CT_ALERT { return 0 - 1 } 86 if ctp[0] == NX_TLS13_CT_APPLICATION_DATA { 87 var i: i64 = 0 88 while i < lenp[0] { if acc < WSCS_MAGIC_131072 { plain[acc] = pt[i]; acc = acc + 1 } i = i + 1 } 89 if ws_parse_frame(plain, acc, 0, f) == 0 { 90 if f.opcode == WS_OP_BINARY { 91 var pl: i64 = f.payload_len 92 if pl > cap { pl = cap } 93 var c: i64 = 0 94 while c < pl { out[c] = plain[f.payload_off + c]; c = c + 1 } 95 if f.masked == 1 { ws_apply_mask(out, 0, pl, f.mask_key) } 96 return pl 97 } 98 } 99 } 100 } 101 return 0 - 1 102} 103 104// connect + TLS-1.3 + WS upgrade to https://<host>/signal/<room>. sess_out[0]=session ptr, fd_out[0]=fd. 1 ok. 105func wscs_connect(store: *TrustStore, url: *u8, kseed: i64, sess_out: *i64, fd_out: *i64) -> i64 { 106 let cr: *u8 = sys_mmap(32); var i: i64=0; while i<32{cr[i]=((kseed+i)&0xff) as u8;i=i+1} 107 let priv: *u8 = sys_mmap(32); i=0; while i<32{priv[i]=((kseed+64+i)&0xff) as u8;i=i+1} 108 let url_p: *NxUrl = nx_url_new() 109 let target_raw: *u8 = sys_mmap(32) 110 let target: *NxHttpsTarget = target_raw as *NxHttpsTarget 111 target.url = url_p; target.port = 0 112 if nx_https_url_for_fetch(url, target) != NX_HTTPS_URL_OK { return 0 } 113 let fd_p: *i64 = sys_mmap(16) as *i64 114 if nx_https_url_connect(target, url, sys_now_realtime_sec(), fd_p) != NX_HTTPS_CONNECT_OK { return 0 } 115 let fd: i64 = *fd_p 116 sys_set_socket_timeout(fd, WSCS_TMO_S) 117 let host: *u8 = url + target.url.host_off 118 let hlen: i64 = target.url.host_len 119 let path: *u8 = url + target.url.path_off 120 let plen: i64 = target.url.path_len 121 let vc_raw: *u8 = sys_mmap(128) 122 let vc: *TlsValidationContext = vc_raw as *TlsValidationContext 123 vc.store = store; vc.sni_host = host; vc.sni_host_len = hlen; vc.now_epoch = sys_now_realtime_sec() 124 let sr: i64 = nx_tls13_client_session_run(fd, host, hlen, cr, priv, vc) 125 if sr <= 0 { sys_close(fd); return 0 } 126 let s: *Tls13ClientSession = sr as *Tls13ClientSession 127 let req: *u8 = sys_mmap(WSCS_MAGIC_4096) 128 let key24: *u8 = sys_mmap(32) 129 let rn: i64 = nx_ws_client_build_request(req, WSCS_MAGIC_4096, host, hlen, path, plen, 443, 0, key24) 130 if rn < 0 { sys_close(fd); return 0 } 131 if wscs_send(s, fd, req, rn) != 0 { sys_close(fd); return 0 } 132 let resp: *u8 = sys_mmap(WSCS_MAGIC_65536) 133 let hn: i64 = wscs_recv_headers(s, fd, resp, WSCS_MAGIC_65536) 134 if hn < 0 { sys_close(fd); return 0 } 135 if nx_ws_client_validate_response(resp, hn, key24) != NX_WSCU_OK { sys_close(fd); return 0 } 136 sess_out[0] = sr 137 fd_out[0] = fd 138 return 1 139}