code wiki / _hdl_build / nx_route_table.nx
nx_route_table.nx source
↩ module page · 128 lines · 5351 B
1// nx_route_table.nx -- the S-CLASS DATA-DRIVEN ROUTE MATCHER (the LOGIC core that RETIRES the hardcoded
2// if-cascade). PURE: a route TABLE (data) + a request (host, path) -> the matched (backend port, mode). NO
3// hardcoded routes, NO IO, NO sockets. Semantics match the SOTA (nginx/Envoy/HAProxy/ingress, banked in
4// knowledge/library/route_*): EXACT host beats wildcard '*'; LONGEST path-prefix wins; BOUNDARY-SAFE (`/gen`
5// matches `/gen` and `/gen/*` but NEVER `/generated`); per-route MODE. Operator: "fix all this hardcoding and
6// tight coupling especially on routing ... get it to s class exceed, not the garbage f-level stuff."
7// Table row format (one per line, space-delimited; '#'=comment): <host|*> <path-prefix> <port> <mode>
8// modes: buffered|stream|gated. license_tier: ORIGINAL
9import "nx_syscalls.nx"
10const RT_MAGIC_1000000: i64 = 1000000
11
12const RT_BUFFERED: i64 = 0
13const RT_STREAM: i64 = 1
14const RT_GATED: i64 = 2
15
16func rt_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
17
18func rt_eol(b: *u8, n: i64, st: i64) -> i64 {
19 var i: i64 = st
20 var f: i64 = 0
21 while f == 0 { if i >= n { f = 1 } else { if (b[i] as i64) == 10 { f = 1 } else { i = i + 1 } } }
22 return i
23}
24
25// split b[ls..le) on spaces into up-to-maxf (offs,lens) absolute slices. returns field count.
26func rt_split(b: *u8, ls: i64, le: i64, offs: *i64, lens: *i64, maxf: i64) -> i64 {
27 var nf: i64 = 0
28 var i: i64 = ls
29 while i < le {
30 var sk: i64 = 1
31 while sk == 1 { if i >= le { sk = 0 } else { if (b[i] as i64) == 32 { i = i + 1 } else { sk = 0 } } }
32 if i < le {
33 let st: i64 = i
34 var sc: i64 = 1
35 while sc == 1 { if i >= le { sc = 0 } else { if (b[i] as i64) == 32 { sc = 0 } else { i = i + 1 } } }
36 if nf < maxf { offs[nf] = st; lens[nf] = i - st; nf = nf + 1 }
37 }
38 }
39 return nf
40}
41
42func rt_slice_atoi(src: *u8, off: i64, len: i64) -> i64 {
43 var v: i64 = 0
44 var i: i64 = 0
45 while i < len {
46 let c: i64 = src[off + i] as i64
47 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } }
48 i = i + 1
49 }
50 return v
51}
52
53// slice == null-terminated tok?
54func rt_tok_eq(src: *u8, off: i64, len: i64, tok: *u8) -> i64 {
55 let tl: i64 = rt_slen(tok)
56 if tl != len { return 0 }
57 var i: i64 = 0
58 while i < len { if (src[off + i] as i64) != (tok[i] as i64) { return 0 } i = i + 1 }
59 return 1
60}
61
62// slice a[ao..ao+al) == slice b[bo..bo+bl)?
63func rt_slice_eq(a: *u8, ao: i64, al: i64, b: *u8, bo: i64, bl: i64) -> i64 {
64 if al != bl { return 0 }
65 var i: i64 = 0
66 while i < al { if (a[ao + i] as i64) != (b[bo + i] as i64) { return 0 } i = i + 1 }
67 return 1
68}
69
70// BOUNDARY-SAFE prefix: does path[0..pn) start with pre[po..po+prel) AT A PATH BOUNDARY?
71// true iff pre is a char-prefix AND (path==pre OR the next path char is '/'). So "/gen" matches "/gen" and
72// "/gen/x" but NOT "/generated". (route prefixes are authored WITHOUT a trailing slash.)
73func rt_prefix_boundary(path: *u8, pn: i64, pre: *u8, po: i64, prel: i64) -> i64 {
74 if prel > pn { return 0 }
75 var i: i64 = 0
76 while i < prel { if (path[i] as i64) != (pre[po + i] as i64) { return 0 } i = i + 1 }
77 if pn == prel { return 1 }
78 if (path[prel] as i64) == 47 { return 1 }
79 return 0
80}
81
82func rt_mode_code(rt: *u8, off: i64, len: i64) -> i64 {
83 if rt_tok_eq(rt, off, len, "stream" as *u8) == 1 { return RT_STREAM }
84 if rt_tok_eq(rt, off, len, "gated" as *u8) == 1 { return RT_GATED }
85 return RT_BUFFERED
86}
87
88// THE MATCHER: best route for (host,path) over the table rt[0..n). EXACT host beats '*'; among those, LONGEST
89// path-prefix wins (boundary-safe). Sets port_out/mode_out, returns 1 if matched / 0 if none.
90func rt_match(rt: *u8, n: i64, host: *u8, hn: i64, path: *u8, pn: i64, port_out: *i64, mode_out: *i64) -> i64 {
91 let offs: *i64 = sys_mmap(64) as *i64
92 let lens: *i64 = sys_mmap(64) as *i64
93 var best_score: i64 = 0 - 1
94 var best_port: i64 = 0
95 var best_mode: i64 = 0
96 var cur: i64 = 0
97 while cur < n {
98 let le: i64 = rt_eol(rt, n, cur)
99 var ok_line: i64 = 1
100 if le <= cur { ok_line = 0 }
101 if ok_line == 1 { if (rt[cur] as i64) == 35 { ok_line = 0 } }
102 if ok_line == 1 {
103 let nf: i64 = rt_split(rt, cur, le, offs, lens, 8)
104 if nf >= 4 {
105 var hmatch: i64 = 0
106 var exact: i64 = 0
107 if rt_tok_eq(rt, offs[0], lens[0], "*" as *u8) == 1 { hmatch = 1 }
108 if hmatch == 0 { if rt_slice_eq(rt, offs[0], lens[0], host, 0, hn) == 1 { hmatch = 1; exact = 1 } }
109 if hmatch == 1 {
110 if rt_prefix_boundary(path, pn, rt, offs[1], lens[1]) == 1 {
111 var score: i64 = lens[1]
112 if exact == 1 { score = score + RT_MAGIC_1000000 }
113 if score > best_score {
114 best_score = score
115 best_port = rt_slice_atoi(rt, offs[2], lens[2])
116 best_mode = rt_mode_code(rt, offs[3], lens[3])
117 }
118 }
119 }
120 }
121 }
122 cur = le + 1
123 }
124 if best_score < 0 { return 0 }
125 port_out[0] = best_port
126 mode_out[0] = best_mode
127 return 1
128}