code wiki / (root) / nx_quic_hdr.nx

nx_quic_hdr.nx source

↩ module page · 67 lines · 3355 B

1// nx_quic_hdr.nx -- RUNG 3 of the sovereign QUIC transport: long + short packet headers 2// (RFC 9000 sec 17.2 / 17.3). Long header carries the handshake (Initial/0-RTT/Handshake/Retry) with 3// version + connection IDs; short header is the 1-RTT data path that carries DATAGRAM frames. Parsing 4// these exactly (form bit, fixed bit, type, CIDs, packet-number length) is the frame around everything 5// the relay and client exchange. No float. license_tier: ORIGINAL 6import "nx_quic_wire.nx" 7 8// ---- Long header (RFC 9000 sec 17.2). info out: 9// info[0]=long packet type (0=Initial,1=0RTT,2=Handshake,3=Retry) 10// info[1]=version info[2]=dcid off info[3]=dcid len info[4]=scid off info[5]=scid len 11// info[6]=offset just past SCID (start of type-specific bytes) info[7]=pn_len (from low 2 bits, +1) 12// returns 0 ok, -1 malformed. 13func quic_lhdr_parse(buf: *u8, n: i64, info: *i64) -> i64 { 14 if n < 7 { return 0 - 1 } 15 let b0: i64 = buf[0] as i64 16 if (b0 & 0x80) == 0 { return 0 - 1 } // header form must be 1 (long) 17 if (b0 & 0x40) == 0 { return 0 - 1 } // fixed bit must be 1 18 info[0] = (b0 >> 4) & 3 19 info[7] = (b0 & 3) + 1 20 info[1] = ((buf[1] as i64) << 24) | ((buf[2] as i64) << 16) | ((buf[3] as i64) << 8) | (buf[4] as i64) 21 var off: i64 = 5 22 let dcil: i64 = buf[off] as i64; off = off + 1 23 if off + dcil > n { return 0 - 1 } 24 info[2] = off; info[3] = dcil; off = off + dcil 25 if off >= n { return 0 - 1 } 26 let scil: i64 = buf[off] as i64; off = off + 1 27 if off + scil > n { return 0 - 1 } 28 info[4] = off; info[5] = scil; off = off + scil 29 info[6] = off 30 return 0 31} 32 33// encode the long header through the SCID (first byte + version + dcid + scid). pn_len 1..4 -> low 2 bits. 34func quic_lhdr_encode(out: *u8, ptype: i64, version: i64, dcid: *u8, dcil: i64, scid: *u8, scil: i64, pn_len: i64) -> i64 { 35 out[0] = (0x80 | 0x40 | ((ptype & 3) << 4) | ((pn_len - 1) & 3)) as u8 36 out[1] = ((version >> 24) & 0xff) as u8 37 out[2] = ((version >> 16) & 0xff) as u8 38 out[3] = ((version >> 8) & 0xff) as u8 39 out[4] = (version & 0xff) as u8 40 var off: i64 = 5 41 out[off] = dcil as u8; off = off + 1 42 var i: i64 = 0; while i < dcil { out[off + i] = dcid[i]; i = i + 1 } off = off + dcil 43 out[off] = scil as u8; off = off + 1 44 i = 0; while i < scil { out[off + i] = scid[i]; i = i + 1 } off = off + scil 45 return off 46} 47 48// ---- Short header (RFC 9000 sec 17.3), 1-RTT. The DCID length is known from connection state. 49// first byte: 0(form) 1(fixed) spin 0 0 keyphase pnlen[2] 50func quic_shdr_encode(out: *u8, spin: i64, keyphase: i64, pn_len: i64, dcid: *u8, dcil: i64) -> i64 { 51 out[0] = (0x40 | ((spin & 1) << 5) | ((keyphase & 1) << 2) | ((pn_len - 1) & 3)) as u8 52 var i: i64 = 0; while i < dcil { out[1 + i] = dcid[i]; i = i + 1 } 53 return 1 + dcil 54} 55// parse short header given the known DCID length. info[0]=keyphase info[1]=pn_len info[2]=pn offset. 56func quic_shdr_parse(buf: *u8, n: i64, dcil: i64, info: *i64) -> i64 { 57 if n < 1 + dcil { return 0 - 1 } 58 let b0: i64 = buf[0] as i64 59 if (b0 & 0x80) != 0 { return 0 - 1 } // must be short (form bit 0) 60 if (b0 & 0x40) == 0 { return 0 - 1 } // fixed bit 1 61 info[0] = (b0 >> 2) & 1 62 info[1] = (b0 & 3) + 1 63 info[2] = 1 + dcil 64 return 0 65} 66 67func main() -> i64 { return 0 }