Nothing to see here, move along
1#![no_std]
2#![no_main]
3
4use lancer_user::io::write_bytes;
5use lancer_user::net;
6use lancer_user::syscall;
7
8const DEFAULT_TIMEOUT_S: i64 = 10;
9const MAX_TIMEOUT_S: i64 = 60;
10
11#[unsafe(no_mangle)]
12pub extern "C" fn lancer_main() -> ! {
13 let (rx, tx) = match net::init() {
14 Some(pair) => pair,
15 None => {
16 lancer_user::show!(net, error, "netsock init failed");
17 syscall::exit();
18 }
19 };
20
21 if !net::has_relay() {
22 write_bytes(b"networking not available (use SSH)\n");
23 syscall::exit();
24 }
25
26 let mut args_buf = [0u8; 128];
27 let args_len = net::recv_args(&rx, &mut args_buf);
28 let args = &args_buf[..args_len];
29
30 let (_cmd_tok, rest) = net::next_token(args);
31 let (sub, remainder) = net::next_token(rest);
32
33 match sub {
34 _ if net::bytes_eq(sub, b"send") => cmd_send(&tx, remainder),
35 _ if net::bytes_eq(sub, b"listen") => cmd_listen(&rx, &tx, remainder),
36 _ if net::bytes_eq(sub, b"close") => cmd_close(&tx),
37 _ => {
38 write_bytes(b"usage: udp send <ip> <port> <data>\n udp listen <port> [timeout]\n udp close\n");
39 }
40 }
41
42 syscall::exit()
43}
44
45fn cmd_send(tx: &lancer_core::packet_ring::PacketRingWriter, args: &[u8]) {
46 let (ip_tok, r1) = net::next_token(args);
47 let ip = match net::parse_ip(ip_tok) {
48 Some(ip) => ip,
49 None => {
50 write_bytes(b"invalid IP\n");
51 return;
52 }
53 };
54
55 let (port_tok, r2) = net::next_token(r1);
56 let port = match net::parse_decimal_u16(port_tok) {
57 Some(p) => p,
58 None => {
59 write_bytes(b"invalid port\n");
60 return;
61 }
62 };
63
64 let data = net::skip_spaces(r2);
65 match data.is_empty() {
66 true => {
67 write_bytes(b"no data\n");
68 }
69 false => {
70 let mut msg = [0u8; 62];
71 let payload_len = data.len().min(54);
72 msg[0] = net::MSG_UDP_SEND;
73 msg[1] = ip[0];
74 msg[2] = ip[1];
75 msg[3] = ip[2];
76 msg[4] = ip[3];
77 msg[5] = (port >> 8) as u8;
78 msg[6] = port as u8;
79 msg[7..7 + payload_len].copy_from_slice(&data[..payload_len]);
80 net::send_request(tx, &msg[..7 + payload_len]);
81 write_bytes(b"sent\n");
82 }
83 }
84}
85
86fn cmd_listen(
87 rx: &lancer_core::packet_ring::PacketRingReader,
88 tx: &lancer_core::packet_ring::PacketRingWriter,
89 args: &[u8],
90) {
91 let (port_tok, remainder) = net::next_token(args);
92 let port = match net::parse_decimal_u16(port_tok) {
93 Some(p) => p,
94 None => {
95 write_bytes(b"invalid port\n");
96 return;
97 }
98 };
99
100 let (timeout_tok, _) = net::next_token(remainder);
101 let timeout_s = match timeout_tok.is_empty() {
102 true => DEFAULT_TIMEOUT_S,
103 false => match net::parse_decimal_u16(timeout_tok) {
104 Some(t) => (t as i64).clamp(1, MAX_TIMEOUT_S),
105 None => DEFAULT_TIMEOUT_S,
106 },
107 };
108
109 let bind_msg = [net::MSG_UDP_BIND, (port >> 8) as u8, port as u8];
110 net::send_request(tx, &bind_msg);
111
112 let mut resp_buf = [0u8; 64];
113 let n = net::recv_response_blocking(rx, &mut resp_buf);
114 match n >= 2 && resp_buf[0] == net::MSG_UDP_BOUND {
115 true => match resp_buf[1] {
116 0 => write_bytes(b"bound, listening...\n"),
117 _ => {
118 write_bytes(b"bind failed\n");
119 return;
120 }
121 },
122 false => {
123 write_bytes(b"bind failed\n");
124 return;
125 }
126 }
127
128 let start_ms = syscall::clock_monotonic_ms();
129 let deadline_ms = start_ms + timeout_s * 1000;
130
131 let mut running = true;
132 core::iter::from_fn(|| match running {
133 false => None,
134 true => {
135 let now = syscall::clock_monotonic_ms();
136 match now >= deadline_ms {
137 true => {
138 running = false;
139 None
140 }
141 false => match net::recv_response(rx, &mut resp_buf) {
142 Some(rn) if rn >= 2 && resp_buf[0] == net::MSG_UDP_RECV && rn >= 7 => {
143 let mut out = [0u8; 128];
144 let mut pos = 0usize;
145 let prefix = b"from ";
146 out[..prefix.len()].copy_from_slice(prefix);
147 pos += prefix.len();
148 pos += net::write_ip_decimal(&mut out[pos..], &resp_buf[1..5]);
149 out[pos] = b':';
150 pos += 1;
151 let src_port = ((resp_buf[5] as u16) << 8) | resp_buf[6] as u16;
152 pos += net::write_u16_decimal(&mut out[pos..], src_port);
153 let mid = b": ";
154 out[pos..pos + mid.len()].copy_from_slice(mid);
155 pos += mid.len();
156 write_bytes(&out[..pos]);
157 if rn > 7 {
158 write_bytes(&resp_buf[7..rn]);
159 }
160 write_bytes(b"\n");
161 Some(())
162 }
163 _ => {
164 syscall::notify_wait(net::NETSOCK_NOTIF_SLOT);
165 Some(())
166 }
167 },
168 }
169 }
170 })
171 .take(10_000)
172 .count();
173
174 let close_msg = [net::MSG_UDP_CLOSE];
175 net::send_request(tx, &close_msg);
176 write_bytes(b"closed\n");
177}
178
179fn cmd_close(tx: &lancer_core::packet_ring::PacketRingWriter) {
180 let close_msg = [net::MSG_UDP_CLOSE];
181 net::send_request(tx, &close_msg);
182 write_bytes(b"closed\n");
183}