1use super::netc;
2use crate::Error;
3use crate::ErrorCode;
4use crate::Result;
5use crate::RtFd;
6use crate::RtVdsoVtable;
7use crate::into_result;
8use core::sync::atomic::Ordering;
9use core::time::Duration;
10
11#[cfg(not(feature = "rustc-dep-of-std"))]
12extern crate alloc;
13
14pub const MAX_UDP_PAYLOAD: usize = 65493;
28
29pub const SHUTDOWN_READ: u8 = 1;
30pub const SHUTDOWN_WRITE: u8 = 2;
31
32pub const PROTO_TCP: u8 = 1;
33pub const PROTO_UDP: u8 = 2;
34
35pub const SO_RCVTIMEO: u64 = 1;
36pub const SO_SNDTIMEO: u64 = 2;
37pub const SO_SHUTDOWN: u64 = 3;
38pub const SO_NODELAY: u64 = 4;
39pub const SO_TTL: u64 = 5;
40pub const SO_NONBLOCKING: u64 = 6;
41pub const SO_ERROR: u64 = 7;
42pub const SO_ONLY_IPV6: u64 = 8;
43pub const SO_LINGER: u64 = 9;
44pub const SO_BROADCAST: u64 = 10;
45pub const SO_MULTICAST_LOOP_V4: u64 = 11;
46pub const SO_MULTICAST_LOOP_V6: u64 = 12;
47pub const SO_MULTICAST_TTL_V4: u64 = 13;
48
49fn setsockopt(rt_fd: RtFd, opt: u64, ptr: usize, len: usize) -> Result<()> {
50 let vdso_setsockopt: extern "C" fn(RtFd, u64, usize, usize) -> ErrorCode = unsafe {
51 core::mem::transmute(
52 RtVdsoVtable::get().net_setsockopt.load(Ordering::Relaxed) as usize as *const (),
53 )
54 };
55
56 into_result(vdso_setsockopt(rt_fd, opt, ptr, len))
57}
58
59fn getsockopt(rt_fd: RtFd, opt: u64, ptr: usize, len: usize) -> Result<()> {
60 let vdso_getsockopt: extern "C" fn(RtFd, u64, usize, usize) -> ErrorCode = unsafe {
61 core::mem::transmute(
62 RtVdsoVtable::get().net_getsockopt.load(Ordering::Relaxed) as usize as *const (),
63 )
64 };
65
66 into_result(vdso_getsockopt(rt_fd, opt, ptr, len))
67}
68
69fn setsockopt_bool(rt_fd: RtFd, val: bool, opt: u64) -> Result<()> {
70 let val: u8 = if val { 1 } else { 0 };
71 setsockopt(rt_fd, opt, &val as *const _ as usize, 1)
72}
73
74fn getsockopt_bool(rt_fd: RtFd, opt: u64) -> Result<bool> {
75 let mut val = 0_u8;
76 getsockopt(rt_fd, opt, &mut val as *mut _ as usize, 1)?;
77 match val {
78 0 => Ok(false),
79 1 => Ok(true),
80 _ => panic!("bad bool opt val {val} for opt {opt}"),
81 }
82}
83
84pub fn bind(proto: u8, addr: &netc::sockaddr) -> Result<RtFd> {
85 let vdso_bind: extern "C" fn(u8, *const netc::sockaddr) -> RtFd = unsafe {
86 core::mem::transmute(
87 RtVdsoVtable::get().net_bind.load(Ordering::Relaxed) as usize as *const (),
88 )
89 };
90
91 to_result!(vdso_bind(proto, addr))
92}
93
94pub fn listen(rt_fd: RtFd, max_backlog: u32) -> Result<()> {
95 let vdso_listen: extern "C" fn(RtFd, u32) -> ErrorCode = unsafe {
96 core::mem::transmute(
97 RtVdsoVtable::get().net_listen.load(Ordering::Relaxed) as usize as *const (),
98 )
99 };
100
101 into_result(vdso_listen(rt_fd, max_backlog))
102}
103
104pub fn accept(rt_fd: RtFd) -> Result<(RtFd, netc::sockaddr)> {
105 let vdso_accept: extern "C" fn(RtFd, *mut netc::sockaddr) -> RtFd = unsafe {
106 core::mem::transmute(
107 RtVdsoVtable::get().net_accept.load(Ordering::Relaxed) as usize as *const (),
108 )
109 };
110
111 let mut addr: netc::sockaddr = unsafe { core::mem::zeroed() };
112 let res = vdso_accept(rt_fd, &mut addr);
113 if res < 0 {
114 return Err((-res as ErrorCode).into());
115 }
116
117 Ok((res, addr))
118}
119
120pub fn tcp_connect(addr: &netc::sockaddr, timeout: Duration, nonblocking: bool) -> Result<RtFd> {
122 let vdso_tcp_connect: extern "C" fn(*const netc::sockaddr, u64, bool) -> RtFd = unsafe {
123 core::mem::transmute(
124 RtVdsoVtable::get().net_tcp_connect.load(Ordering::Relaxed) as usize as *const (),
125 )
126 };
127
128 let timeout = timeout.as_nanos().try_into().unwrap_or(u64::MAX);
129 to_result!(vdso_tcp_connect(addr, timeout, nonblocking))
130}
131
132pub fn udp_connect(rt_fd: RtFd, addr: &netc::sockaddr) -> Result<()> {
133 let vdso_udp_connect: extern "C" fn(RtFd, *const netc::sockaddr) -> ErrorCode = unsafe {
134 core::mem::transmute(
135 RtVdsoVtable::get().net_udp_connect.load(Ordering::Relaxed) as usize as *const (),
136 )
137 };
138
139 into_result(vdso_udp_connect(rt_fd, addr))
140}
141
142pub fn socket_addr(rt_fd: RtFd) -> Result<netc::sockaddr> {
143 let vdso_socket_addr: extern "C" fn(RtFd, *mut netc::sockaddr) -> ErrorCode = unsafe {
144 core::mem::transmute(
145 RtVdsoVtable::get().net_socket_addr.load(Ordering::Relaxed) as usize as *const (),
146 )
147 };
148
149 let mut addr: netc::sockaddr = unsafe { core::mem::zeroed() };
150 into_result(vdso_socket_addr(rt_fd, &mut addr))?;
151 Ok(addr)
152}
153
154pub fn peer_addr(rt_fd: RtFd) -> Result<netc::sockaddr> {
155 let vdso_peer_addr: extern "C" fn(RtFd, *mut netc::sockaddr) -> ErrorCode = unsafe {
156 core::mem::transmute(
157 RtVdsoVtable::get().net_peer_addr.load(Ordering::Relaxed) as usize as *const (),
158 )
159 };
160
161 let mut addr: netc::sockaddr = unsafe { core::mem::zeroed() };
162 into_result(vdso_peer_addr(rt_fd, &mut addr))?;
163 Ok(addr)
164}
165
166pub fn set_ttl(rt_fd: RtFd, ttl: u32) -> Result<()> {
167 setsockopt(rt_fd, SO_TTL, &ttl as *const _ as usize, 4)
168}
169
170pub fn ttl(rt_fd: RtFd) -> Result<u32> {
171 let mut ttl = 0_u32;
172 getsockopt(rt_fd, SO_TTL, &mut ttl as *mut _ as usize, 4)?;
173 Ok(ttl)
174}
175
176pub fn set_only_v6(rt_fd: RtFd, only_v6: bool) -> Result<()> {
177 setsockopt_bool(rt_fd, only_v6, SO_ONLY_IPV6)
178}
179
180pub fn only_v6(rt_fd: RtFd) -> Result<bool> {
181 getsockopt_bool(rt_fd, SO_ONLY_IPV6)
182}
183
184pub fn take_error(rt_fd: RtFd) -> Result<Option<Error>> {
185 let mut error = 0_u16;
186 getsockopt(rt_fd, SO_ERROR, &mut error as *mut _ as usize, 2)?;
187 if error == Error::Ok.into() {
188 Ok(None)
189 } else {
190 Ok(Some(error.into()))
191 }
192}
193
194pub fn set_nonblocking(rt_fd: RtFd, nonblocking: bool) -> Result<()> {
195 setsockopt_bool(rt_fd, nonblocking, SO_NONBLOCKING)
196}
197
198pub fn peek(rt_fd: RtFd, buf: &mut [u8]) -> Result<usize> {
199 let vdso_peek: extern "C" fn(i32, *mut u8, usize) -> i64 = unsafe {
200 core::mem::transmute(
201 RtVdsoVtable::get().net_peek.load(Ordering::Relaxed) as usize as *const (),
202 )
203 };
204
205 to_result!(vdso_peek(rt_fd, buf.as_mut_ptr(), buf.len()))
206}
207
208pub fn set_read_timeout(rt_fd: RtFd, timeout: Option<Duration>) -> Result<()> {
209 let timeout: u64 = match timeout {
210 Some(dur) => dur.as_nanos().try_into().unwrap_or(u64::MAX),
211 None => u64::MAX,
212 };
213
214 if timeout == 0 {
215 return Err(Error::InvalidArgument);
217 }
218
219 setsockopt(
220 rt_fd,
221 SO_RCVTIMEO,
222 &timeout as *const _ as usize,
223 core::mem::size_of::<u64>(),
224 )
225}
226
227pub fn read_timeout(rt_fd: RtFd) -> Result<Option<Duration>> {
228 let mut timeout_ns = 0_u64;
229
230 getsockopt(
231 rt_fd,
232 SO_RCVTIMEO,
233 &mut timeout_ns as *mut _ as usize,
234 core::mem::size_of::<u64>(),
235 )?;
236
237 if timeout_ns == u64::MAX {
238 Ok(None)
239 } else {
240 Ok(Some(Duration::from_nanos(timeout_ns)))
241 }
242}
243
244pub fn set_write_timeout(rt_fd: RtFd, timeout: Option<Duration>) -> Result<()> {
245 let timeout: u64 = match timeout {
246 Some(dur) => dur.as_nanos().try_into().unwrap_or(u64::MAX),
247 None => u64::MAX,
248 };
249
250 if timeout == 0 {
251 return Err(Error::InvalidArgument);
253 }
254
255 setsockopt(
256 rt_fd,
257 SO_SNDTIMEO,
258 &timeout as *const _ as usize,
259 core::mem::size_of::<u64>(),
260 )
261}
262
263pub fn write_timeout(rt_fd: RtFd) -> Result<Option<Duration>> {
264 let mut timeout_ns = 0_u64;
265
266 getsockopt(
267 rt_fd,
268 SO_SNDTIMEO,
269 &mut timeout_ns as *mut _ as usize,
270 core::mem::size_of::<u64>(),
271 )?;
272
273 if timeout_ns == u64::MAX {
274 Ok(None)
275 } else {
276 Ok(Some(Duration::from_nanos(timeout_ns)))
277 }
278}
279
280pub fn shutdown(rt_fd: RtFd, shutdown: u8) -> Result<()> {
281 if 0 != ((shutdown & !SHUTDOWN_READ) & !SHUTDOWN_WRITE) {
282 return Err(Error::InvalidArgument);
283 }
284
285 setsockopt(rt_fd, SO_SHUTDOWN, &shutdown as *const _ as usize, 1)
286}
287
288const MAX_LINGER_MS: u64 = 60_000; pub fn set_linger(rt_fd: RtFd, timeout: Option<Duration>) -> Result<()> {
290 let linger_millis: u64 = if let Some(timo) = timeout {
291 let millis = timo.as_millis();
292 if millis > (MAX_LINGER_MS as u128) {
293 MAX_LINGER_MS
294 } else {
295 millis as u64
296 }
297 } else {
298 u64::MAX
299 };
300 setsockopt(rt_fd, SO_LINGER, &linger_millis as *const u64 as usize, 8)
301}
302
303pub fn linger(rt_fd: RtFd) -> Result<Option<Duration>> {
304 let mut linger_millis = 0_u64;
305 getsockopt(rt_fd, SO_LINGER, &mut linger_millis as *mut _ as usize, 8)?;
306 match linger_millis {
307 val if val <= MAX_LINGER_MS => Ok(Some(Duration::from_millis(val))),
308 u64::MAX => Ok(None),
309 _ => panic!("bad linger {linger_millis}"),
310 }
311}
312
313pub fn set_nodelay(rt_fd: RtFd, nodelay: bool) -> Result<()> {
314 setsockopt_bool(rt_fd, nodelay, SO_NODELAY)
315}
316
317pub fn nodelay(rt_fd: RtFd) -> Result<bool> {
318 getsockopt_bool(rt_fd, SO_NODELAY)
319}
320
321pub fn set_udp_broadcast(rt_fd: RtFd, val: bool) -> Result<()> {
322 setsockopt_bool(rt_fd, val, SO_BROADCAST)
323}
324
325pub fn udp_broadcast(rt_fd: RtFd) -> Result<bool> {
326 getsockopt_bool(rt_fd, SO_BROADCAST)
327}
328
329pub fn udp_recv_from(rt_fd: RtFd, buf: &mut [u8]) -> Result<(usize, netc::sockaddr)> {
330 let mut addr: netc::sockaddr = unsafe { core::mem::zeroed() };
331
332 let vdso_udp_recv_from: extern "C" fn(i32, *mut u8, usize, *mut netc::sockaddr) -> i64 = unsafe {
333 core::mem::transmute(
334 RtVdsoVtable::get()
335 .net_udp_recv_from
336 .load(Ordering::Relaxed) as usize as *const (),
337 )
338 };
339
340 let res = vdso_udp_recv_from(rt_fd, buf.as_mut_ptr(), buf.len(), &mut addr as *mut _);
341 if res < 0 {
342 Err(((-res) as ErrorCode).into())
343 } else {
344 Ok(((res as usize), addr))
345 }
346}
347
348pub fn udp_peek_from(rt_fd: RtFd, buf: &mut [u8]) -> Result<(usize, netc::sockaddr)> {
349 let mut addr: netc::sockaddr = unsafe { core::mem::zeroed() };
350
351 let vdso_udp_peek_from: extern "C" fn(i32, *mut u8, usize, *mut netc::sockaddr) -> i64 = unsafe {
352 core::mem::transmute(
353 RtVdsoVtable::get()
354 .net_udp_peek_from
355 .load(Ordering::Relaxed) as usize as *const (),
356 )
357 };
358
359 let res = vdso_udp_peek_from(rt_fd, buf.as_mut_ptr(), buf.len(), &mut addr as *mut _);
360 if res < 0 {
361 Err(((-res) as ErrorCode).into())
362 } else {
363 Ok(((res as usize), addr))
364 }
365}
366
367pub fn udp_send_to(rt_fd: RtFd, buf: &[u8], addr: &netc::sockaddr) -> Result<usize> {
368 let vdso_udp_send_to: extern "C" fn(i32, *const u8, usize, *const netc::sockaddr) -> i64 = unsafe {
369 core::mem::transmute(
370 RtVdsoVtable::get().net_udp_send_to.load(Ordering::Relaxed) as usize as *const (),
371 )
372 };
373
374 to_result!(vdso_udp_send_to(
375 rt_fd,
376 buf.as_ptr(),
377 buf.len(),
378 addr as *const _
379 ))
380}
381
382pub fn set_udp_multicast_loop_v4(rt_fd: RtFd, val: bool) -> Result<()> {
383 setsockopt_bool(rt_fd, val, SO_MULTICAST_LOOP_V4)
384}
385
386pub fn udp_multicast_loop_v4(rt_fd: RtFd) -> Result<bool> {
387 getsockopt_bool(rt_fd, SO_MULTICAST_LOOP_V4)
388}
389
390pub fn set_udp_multicast_ttl_v4(rt_fd: RtFd, val: u32) -> Result<()> {
391 setsockopt(rt_fd, SO_MULTICAST_TTL_V4, &val as *const _ as usize, 4)
392}
393
394pub fn udp_multicast_ttl_v4(rt_fd: RtFd) -> Result<u32> {
395 let mut ttl = 0_u32;
396 getsockopt(rt_fd, SO_MULTICAST_TTL_V4, &mut ttl as *mut _ as usize, 4)?;
397 Ok(ttl)
398}
399
400pub fn set_udp_multicast_loop_v6(rt_fd: RtFd, val: bool) -> Result<()> {
401 setsockopt_bool(rt_fd, val, SO_MULTICAST_LOOP_V6)
402}
403
404pub fn udp_multicast_loop_v6(rt_fd: RtFd) -> Result<bool> {
405 getsockopt_bool(rt_fd, SO_MULTICAST_LOOP_V6)
406}
407
408pub const JOIN_MULTICAST_OP: u64 = 1;
409pub const LEAVE_MULTICAST_OP: u64 = 2;
410
411pub fn join_udp_multicast_v4(
412 rt_fd: RtFd,
413 addr: &netc::in_addr,
414 iface: &netc::in_addr,
415) -> Result<()> {
416 let vdso_multicast_op_v4: extern "C" fn(
417 i32,
418 u64,
419 *const netc::in_addr,
420 *const netc::in_addr,
421 ) -> ErrorCode = unsafe {
422 core::mem::transmute(
423 RtVdsoVtable::get()
424 .net_udp_multicast_op_v4
425 .load(Ordering::Relaxed) as usize as *const (),
426 )
427 };
428
429 into_result(vdso_multicast_op_v4(
430 rt_fd,
431 JOIN_MULTICAST_OP,
432 addr as *const _,
433 iface as *const _,
434 ))
435}
436
437pub fn leave_udp_multicast_v4(
438 rt_fd: RtFd,
439 addr: &netc::in_addr,
440 iface: &netc::in_addr,
441) -> Result<()> {
442 let vdso_multicast_op_v4: extern "C" fn(
443 i32,
444 u64,
445 *const netc::in_addr,
446 *const netc::in_addr,
447 ) -> ErrorCode = unsafe {
448 core::mem::transmute(
449 RtVdsoVtable::get()
450 .net_udp_multicast_op_v4
451 .load(Ordering::Relaxed) as usize as *const (),
452 )
453 };
454
455 into_result(vdso_multicast_op_v4(
456 rt_fd,
457 LEAVE_MULTICAST_OP,
458 addr as *const _,
459 iface as *const _,
460 ))
461}
462
463pub fn join_udp_multicast_v6(rt_fd: RtFd, addr: &netc::in6_addr, iface: u32) -> Result<()> {
464 let vdso_multicast_op_v6: extern "C" fn(i32, u64, *const netc::in6_addr, u32) -> ErrorCode = unsafe {
465 core::mem::transmute(
466 RtVdsoVtable::get()
467 .net_udp_multicast_op_v6
468 .load(Ordering::Relaxed) as usize as *const (),
469 )
470 };
471
472 into_result(vdso_multicast_op_v6(
473 rt_fd,
474 JOIN_MULTICAST_OP,
475 addr as *const _,
476 iface,
477 ))
478}
479
480pub fn leave_udp_multicast_v6(rt_fd: RtFd, addr: &netc::in6_addr, iface: u32) -> Result<()> {
481 let vdso_multicast_op_v6: extern "C" fn(i32, u64, *const netc::in6_addr, u32) -> ErrorCode = unsafe {
482 core::mem::transmute(
483 RtVdsoVtable::get()
484 .net_udp_multicast_op_v6
485 .load(Ordering::Relaxed) as usize as *const (),
486 )
487 };
488
489 into_result(vdso_multicast_op_v6(
490 rt_fd,
491 LEAVE_MULTICAST_OP,
492 addr as *const _,
493 iface,
494 ))
495}
496
497pub fn lookup_host(
498 host: &str,
499 port: u16,
500) -> Result<(u16, alloc::collections::VecDeque<netc::sockaddr>)> {
501 let vdso_lookup: extern "C" fn(
502 *const u8,
503 usize,
504 u16,
505 *mut usize,
506 *mut usize,
507 ) -> ErrorCode = unsafe {
508 core::mem::transmute(
509 RtVdsoVtable::get().dns_lookup.load(Ordering::Relaxed) as usize as *const (),
510 )
511 };
512
513 let mut result_addr: usize = 0;
514 let mut result_num: usize = 0;
515
516 into_result(vdso_lookup(
517 host.as_bytes().as_ptr(),
518 host.len(),
519 port,
520 &mut result_addr,
521 &mut result_num,
522 ))?;
523
524 let addresses: &[netc::sockaddr] =
525 unsafe { core::slice::from_raw_parts(result_addr as *const netc::sockaddr, result_num) };
526
527 let mut vecdec = alloc::collections::VecDeque::new();
528 for addr in addresses {
529 vecdec.push_back(*addr);
530 }
531
532 let layout = core::alloc::Layout::from_size_align(
533 core::mem::size_of::<netc::sockaddr>() * result_num,
534 16,
535 )
536 .unwrap();
537 unsafe { crate::alloc::dealloc(result_addr as *mut u8, layout) };
538
539 Ok((port, vecdec))
540}