nx_net_chan_blob_test.nx source
↩ module page · 152 lines · 5484 B
1// nx_net_chan_blob_test.nx -- variable-length frames over TCP.
2//
3// Round-trips three blobs of varying length (8B, 64B, 1024B) over
4// loopback and verifies bytes intact end-to-end. Builds on
5// [[nx_net_chan_tcp_i64]] with length-prefix framing.
6
7import "nx_kernel_v2.nx"
8import "nx_log.nx"
9import "nx_atom.nx"
10import "nx_thread.nx"
11import "nx_socket.nx"
12import "nx_net_chan.nx"
13
14const NX_PORT: i64 = 38923
15
16struct BlobState {
17 done_flag: i64,
18 diag: i64,
19}
20
21func _sleep_ms(ms: i64) -> i64 {
22 let ts_raw: *u8 = sys_mmap(16)
23 let ts: *i64 = ts_raw as *i64
24 ts[0] = ms / 1000
25 ts[1] = (ms % 1000) * 1000000
26 return __syscall(SYS_CLOCK_NANOSLEEP, 1, 0, ts as i64, 0, 0, 0)
27}
28
29func _fill(buf: *u8, n: i64, seed: i64) -> i64 {
30 var i: i64 = 0
31 while i < n {
32 buf[i] = ((seed + i) & 0xFF) as u8
33 i = i + 1
34 }
35 return 0
36}
37
38func _check(buf: *u8, n: i64, seed: i64) -> i64 {
39 var i: i64 = 0
40 while i < n {
41 let expected: i64 = (seed + i) & 0xFF
42 if buf[i] != expected { return i + 1 }
43 i = i + 1
44 }
45 return 0
46}
47
48// Client: send 3 blobs (8B seed 10, 64B seed 20, 1024B seed 30) +
49// recv 3 echo blobs that should match.
50func client_main(arg: *u8) -> i64 {
51 let s: *BlobState = arg as *BlobState
52 let done_addr: *i64 = (arg as *i64)
53
54 _sleep_ms(150)
55 let fd: i64 = nx_sock_socket(NX_AF_INET, NX_SOCK_STREAM, NX_IPPROTO_TCP)
56 if fd < 0 { s.diag = 10; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0 }
57 let addr: *u8 = sys_mmap(16)
58 nx_sock_sin_init(addr, 0x0100007F, NX_PORT)
59 if nx_sock_connect(fd, addr, 16) < 0 {
60 s.diag = 20; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0
61 }
62 let nc: *NxNetChan = nx_net_chan_from_fd(fd)
63
64 // Send 8-byte blob.
65 let b8: *u8 = sys_mmap(16); _fill(b8, 8, 10)
66 if nx_net_chan_send_blob(nc, b8, 8) != 0 {
67 s.diag = 30; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0
68 }
69 // Send 64-byte blob.
70 let b64: *u8 = sys_mmap(128); _fill(b64, 64, 20)
71 if nx_net_chan_send_blob(nc, b64, 64) != 0 {
72 s.diag = 31; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0
73 }
74 // Send 1024-byte blob.
75 let b1k: *u8 = sys_mmap(2048); _fill(b1k, 1024, 30)
76 if nx_net_chan_send_blob(nc, b1k, 1024) != 0 {
77 s.diag = 32; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0
78 }
79
80 // Recv 3 echoed blobs + verify each.
81 let r1: *u8 = sys_mmap(4096)
82 let n1: i64 = nx_net_chan_recv_blob(nc, r1, 4096)
83 if n1 != 8 { s.diag = 40; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0 }
84 if _check(r1, 8, 10) != 0 { s.diag = 41; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0 }
85
86 let r2: *u8 = sys_mmap(4096)
87 let n2: i64 = nx_net_chan_recv_blob(nc, r2, 4096)
88 if n2 != 64 { s.diag = 42; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0 }
89 if _check(r2, 64, 20) != 0 { s.diag = 43; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0 }
90
91 let r3: *u8 = sys_mmap(4096)
92 let n3: i64 = nx_net_chan_recv_blob(nc, r3, 4096)
93 if n3 != 1024 { s.diag = 44; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0 }
94 if _check(r3, 1024, 30) != 0 { s.diag = 45; nx_atom_store_i64(done_addr, -1, NX_MO_SEQ_CST); return 0 }
95
96 nx_net_chan_close(nc)
97 s.diag = 1
98 nx_atom_store_i64(done_addr, 1, NX_MO_SEQ_CST)
99 return 0
100}
101
102func main() -> nx_exit {
103 println("=== nx_net_chan_blob round-trip (8B, 64B, 1024B) ===" as *u8)
104
105 let state_raw: *u8 = sys_mmap(64)
106 let s: *BlobState = state_raw as *BlobState
107 s.done_flag = 0
108 s.diag = 0
109
110 let lfd: i64 = nx_sock_socket(NX_AF_INET, NX_SOCK_STREAM, NX_IPPROTO_TCP)
111 if lfd < 0 { println("FAIL: socket" as *u8); return 1 }
112 nx_sock_reuseaddr(lfd)
113 let laddr: *u8 = sys_mmap(16)
114 nx_sock_sin_init(laddr, 0, NX_PORT)
115 if nx_sock_bind(lfd, laddr, 16) < 0 { println("FAIL: bind" as *u8); return 2 }
116 if nx_sock_listen(lfd, 1) < 0 { println("FAIL: listen" as *u8); return 3 }
117
118 let tid: i64 = nx_thread_spawn_fn(client_main, state_raw, 65536)
119 if tid <= 0 { println("FAIL: spawn" as *u8); return 4 }
120
121 let cfd: i64 = nx_sock_accept(lfd, 0 as *u8, 0 as *i64)
122 if cfd < 0 { println("FAIL: accept" as *u8); return 5 }
123 let server_nc: *NxNetChan = nx_net_chan_from_fd(cfd)
124
125 // Echo 3 blobs back to client.
126 var i: i64 = 0
127 while i < 3 {
128 let recv_buf: *u8 = sys_mmap(4096)
129 let n: i64 = nx_net_chan_recv_blob(server_nc, recv_buf, 4096)
130 if n < 0 { println("FAIL: server recv blob" as *u8); print_i64(n); println("" as *u8); return 6 }
131 if nx_net_chan_send_blob(server_nc, recv_buf, n) != 0 {
132 println("FAIL: server send blob" as *u8); return 7
133 }
134 i = i + 1
135 }
136 nx_net_chan_close(server_nc)
137 sys_close(lfd)
138
139 let done_addr: *i64 = (state_raw as *i64)
140 var spins: i64 = 0
141 while nx_atom_load_i64(done_addr, NX_MO_SEQ_CST) == 0 {
142 nx_thread_yield()
143 spins = spins + 1
144 if spins > 100000000 { println("FAIL: client timeout" as *u8); return 8 }
145 }
146 if nx_atom_load_i64(done_addr, NX_MO_SEQ_CST) != 1 {
147 println("FAIL: client diag=" as *u8); print_i64(s.diag); println("" as *u8); return 9
148 }
149 println("PASS: 3 variable-length blobs (8B+64B+1024B) round-tripped over TCP." as *u8)
150 println("Length-prefix framing works; foundation for typed-struct RPC + bulk transfer." as *u8)
151 return 0
152}