1#![allow(dead_code)]
2#![allow(nonstandard_style)]
3
4mod addrinfo;
5
6use alloc::sync::Arc;
7use core::ffi::{c_char, c_void};
8use core::mem::size_of;
9#[allow(unused_imports)]
10use core::ops::DerefMut;
11
12use cfg_if::cfg_if;
13use num_enum::{IntoPrimitive, TryFromPrimitive};
14#[cfg(any(feature = "tcp", feature = "udp"))]
15use smoltcp::wire::{IpAddress, IpEndpoint, IpListenEndpoint};
16
17use crate::errno::Errno;
18#[cfg(any(feature = "tcp", feature = "udp"))]
19use crate::executor::network::{NIC, NetworkState};
20#[cfg(feature = "tcp")]
21use crate::fd::socket::tcp;
22#[cfg(feature = "udp")]
23use crate::fd::socket::udp;
24#[cfg(feature = "vsock")]
25use crate::fd::socket::vsock::{self, VsockEndpoint, VsockListenEndpoint};
26use crate::fd::{
27 self, Endpoint, ListenEndpoint, ObjectInterface, SocketOption, get_object, insert_object,
28};
29use crate::syscalls::block_on;
30
31#[derive(TryFromPrimitive, IntoPrimitive, PartialEq, Eq, Clone, Copy, Debug)]
32#[repr(u8)]
33pub enum Af {
34 Unspec = 0,
35 Inet = 3,
36 Inet6 = 1,
37 #[cfg(feature = "vsock")]
38 Vsock = 2,
39}
40
41#[derive(TryFromPrimitive, IntoPrimitive, PartialEq, Eq, Clone, Copy, Debug)]
42#[repr(u8)]
43pub enum Ipproto {
44 Ip = 0,
45 Ipv6 = 41,
46 Tcp = 6,
47 Udp = 17,
48}
49
50pub const IPV6_ADD_MEMBERSHIP: i32 = 12;
51pub const IPV6_DROP_MEMBERSHIP: i32 = 13;
52pub const IPV6_MULTICAST_LOOP: i32 = 19;
53pub const IPV6_V6ONLY: i32 = 27;
54pub const IP_TOS: i32 = 1;
55pub const IP_TTL: i32 = 2;
56pub const IP_MULTICAST_TTL: i32 = 5;
57pub const IP_MULTICAST_LOOP: i32 = 7;
58pub const IP_ADD_MEMBERSHIP: i32 = 3;
59pub const IP_DROP_MEMBERSHIP: i32 = 4;
60pub const SOL_SOCKET: i32 = 4095;
61pub const SO_REUSEADDR: i32 = 0x0004;
62pub const SO_KEEPALIVE: i32 = 0x0008;
63pub const SO_BROADCAST: i32 = 0x0020;
64pub const SO_LINGER: i32 = 0x0080;
65pub const SO_SNDBUF: i32 = 0x1001;
66pub const SO_RCVBUF: i32 = 0x1002;
67pub const SO_SNDTIMEO: i32 = 0x1005;
68pub const SO_RCVTIMEO: i32 = 0x1006;
69pub const SO_ERROR: i32 = 0x1007;
70pub const TCP_NODELAY: i32 = 1;
71pub const MSG_PEEK: i32 = 1;
72pub type sa_family_t = u8;
73pub type socklen_t = u32;
74pub type in_addr_t = u32;
75pub type in_port_t = u16;
76
77#[derive(TryFromPrimitive, IntoPrimitive, PartialEq, Eq, Clone, Copy, Debug)]
78#[repr(u8)]
79pub enum Sock {
80 Stream = 1,
81 Dgram = 2,
82}
83
84bitflags! {
85 #[derive(Debug, Copy, Clone)]
86 #[repr(C)]
87 pub struct SockFlags: i32 {
88 const SOCK_NONBLOCK = 0o4000;
89 const SOCK_CLOEXEC = 0o40000;
90 const _ = !0;
91 }
92}
93
94impl Sock {
95 pub fn from_bits(bits: i32) -> Option<(Self, SockFlags)> {
96 let sock = Sock::try_from(bits as u8).ok()?;
97 let flags = SockFlags::from_bits_retain(bits & !0xff);
98 Some((sock, flags))
99 }
100}
101
102#[repr(C)]
103#[derive(Debug, Default, Copy, Clone)]
104pub struct in_addr {
105 pub s_addr: in_addr_t,
106}
107
108#[repr(C, align(4))]
109#[derive(Debug, Default, Copy, Clone)]
110pub struct in6_addr {
111 pub s6_addr: [u8; 16],
112}
113
114#[repr(C)]
115#[derive(Debug, Default, Copy, Clone)]
116pub struct sockaddr {
117 pub sa_len: u8,
118 pub sa_family: sa_family_t,
119 pub sa_data: [c_char; 14],
120}
121
122#[cfg(feature = "vsock")]
123#[repr(C)]
124#[derive(Debug, Copy, Clone, Default)]
125pub struct sockaddr_vm {
126 pub svm_len: u8,
127 pub svm_family: sa_family_t,
128 pub svm_reserved1: u16,
129 pub svm_port: u32,
130 pub svm_cid: u32,
131 pub svm_zero: [u8; 4],
132}
133
134#[cfg(feature = "vsock")]
135impl From<sockaddr_vm> for VsockListenEndpoint {
136 fn from(addr: sockaddr_vm) -> VsockListenEndpoint {
137 let port = addr.svm_port;
138 let cid = if addr.svm_cid < u32::MAX {
139 Some(addr.svm_cid)
140 } else {
141 None
142 };
143
144 VsockListenEndpoint::new(port, cid)
145 }
146}
147
148#[cfg(feature = "vsock")]
149impl From<sockaddr_vm> for VsockEndpoint {
150 fn from(addr: sockaddr_vm) -> VsockEndpoint {
151 let port = addr.svm_port;
152 let cid = addr.svm_cid;
153
154 VsockEndpoint::new(port, cid)
155 }
156}
157
158#[cfg(feature = "vsock")]
159impl From<VsockEndpoint> for sockaddr_vm {
160 fn from(endpoint: VsockEndpoint) -> Self {
161 Self {
162 svm_len: core::mem::size_of::<sockaddr_vm>().try_into().unwrap(),
163 svm_family: Af::Vsock.into(),
164 svm_port: endpoint.port,
165 svm_cid: endpoint.cid,
166 ..Default::default()
167 }
168 }
169}
170
171#[repr(C)]
172#[derive(Debug, Default, Copy, Clone)]
173pub struct sockaddr_in {
174 pub sin_len: u8,
175 pub sin_family: sa_family_t,
176 pub sin_port: in_port_t,
177 pub sin_addr: in_addr,
178 pub sin_zero: [c_char; 8],
179}
180
181#[cfg(any(feature = "tcp", feature = "udp"))]
182impl From<sockaddr_in> for IpListenEndpoint {
183 fn from(addr: sockaddr_in) -> IpListenEndpoint {
184 let port = u16::from_be(addr.sin_port);
185 if addr.sin_addr.s_addr == 0 {
186 IpListenEndpoint { addr: None, port }
187 } else {
188 let s_addr = addr.sin_addr.s_addr.to_ne_bytes();
189
190 let address = IpAddress::v4(s_addr[0], s_addr[1], s_addr[2], s_addr[3]);
191
192 IpListenEndpoint::from((address, port))
193 }
194 }
195}
196
197#[cfg(any(feature = "tcp", feature = "udp"))]
198impl From<sockaddr_in> for IpEndpoint {
199 fn from(addr: sockaddr_in) -> IpEndpoint {
200 let port = u16::from_be(addr.sin_port);
201 let s_addr = addr.sin_addr.s_addr.to_ne_bytes();
202 let address = IpAddress::v4(s_addr[0], s_addr[1], s_addr[2], s_addr[3]);
203
204 IpEndpoint::from((address, port))
205 }
206}
207
208#[cfg(any(feature = "tcp", feature = "udp"))]
209impl From<IpEndpoint> for sockaddr_in {
210 fn from(endpoint: IpEndpoint) -> Self {
211 match endpoint.addr {
212 IpAddress::Ipv4(ip) => {
213 let sin_addr = in_addr {
214 s_addr: u32::from_ne_bytes(ip.octets()),
215 };
216
217 Self {
218 sin_len: core::mem::size_of::<sockaddr_in>().try_into().unwrap(),
219 sin_port: endpoint.port.to_be(),
220 sin_family: Af::Inet.into(),
221 sin_addr,
222 ..Default::default()
223 }
224 }
225 IpAddress::Ipv6(_) => panic!("Unable to convert IPv6 address to sockadd_in"),
226 }
227 }
228}
229
230#[repr(C)]
231#[derive(Debug, Default, Copy, Clone)]
232pub struct sockaddr_in6 {
233 pub sin6_len: u8,
234 pub sin6_family: sa_family_t,
235 pub sin6_port: in_port_t,
236 pub sin6_flowinfo: u32,
237 pub sin6_addr: in6_addr,
238 pub sin6_scope_id: u32,
239}
240
241#[cfg(any(feature = "tcp", feature = "udp"))]
242impl From<sockaddr_in6> for IpListenEndpoint {
243 fn from(addr: sockaddr_in6) -> IpListenEndpoint {
244 let port = u16::from_be(addr.sin6_port);
245 if addr.sin6_addr.s6_addr.into_iter().all(|b| b == 0) {
246 IpListenEndpoint { addr: None, port }
247 } else {
248 let s6_addr = addr.sin6_addr.s6_addr;
249 let a0 = (u16::from(s6_addr[0]) << 8) | u16::from(s6_addr[1]);
250 let a1 = (u16::from(s6_addr[2]) << 8) | u16::from(s6_addr[3]);
251 let a2 = (u16::from(s6_addr[4]) << 8) | u16::from(s6_addr[5]);
252 let a3 = (u16::from(s6_addr[6]) << 8) | u16::from(s6_addr[7]);
253 let a4 = (u16::from(s6_addr[8]) << 8) | u16::from(s6_addr[9]);
254 let a5 = (u16::from(s6_addr[10]) << 8) | u16::from(s6_addr[11]);
255 let a6 = (u16::from(s6_addr[12]) << 8) | u16::from(s6_addr[13]);
256 let a7 = (u16::from(s6_addr[14]) << 8) | u16::from(s6_addr[15]);
257 let address = IpAddress::v6(a0, a1, a2, a3, a4, a5, a6, a7);
258
259 IpListenEndpoint::from((address, port))
260 }
261 }
262}
263
264#[cfg(any(feature = "tcp", feature = "udp"))]
265impl From<sockaddr_in6> for IpEndpoint {
266 fn from(addr: sockaddr_in6) -> IpEndpoint {
267 let port = u16::from_be(addr.sin6_port);
268 let s6_addr = addr.sin6_addr.s6_addr;
269 let a0 = (u16::from(s6_addr[0]) << 8) | u16::from(s6_addr[1]);
270 let a1 = (u16::from(s6_addr[2]) << 8) | u16::from(s6_addr[3]);
271 let a2 = (u16::from(s6_addr[4]) << 8) | u16::from(s6_addr[5]);
272 let a3 = (u16::from(s6_addr[6]) << 8) | u16::from(s6_addr[7]);
273 let a4 = (u16::from(s6_addr[8]) << 8) | u16::from(s6_addr[9]);
274 let a5 = (u16::from(s6_addr[10]) << 8) | u16::from(s6_addr[11]);
275 let a6 = (u16::from(s6_addr[12]) << 8) | u16::from(s6_addr[13]);
276 let a7 = (u16::from(s6_addr[14]) << 8) | u16::from(s6_addr[15]);
277 let address = IpAddress::v6(a0, a1, a2, a3, a4, a5, a6, a7);
278
279 IpEndpoint::from((address, port))
280 }
281}
282
283#[cfg(any(feature = "tcp", feature = "udp"))]
284impl From<IpEndpoint> for sockaddr_in6 {
285 fn from(endpoint: IpEndpoint) -> Self {
286 match endpoint.addr {
287 IpAddress::Ipv6(ip) => {
288 let mut in6_addr = in6_addr::default();
289 in6_addr.s6_addr.copy_from_slice(&ip.octets());
290
291 Self {
292 sin6_len: core::mem::size_of::<sockaddr_in6>().try_into().unwrap(),
293 sin6_port: endpoint.port.to_be(),
294 sin6_family: Af::Inet6.into(),
295 sin6_addr: in6_addr,
296 ..Default::default()
297 }
298 }
299 IpAddress::Ipv4(_) => panic!("Unable to convert IPv4 address to sockadd_in6"),
300 }
301 }
302}
303
304#[repr(C)]
305#[derive(Debug, Copy, Clone)]
306pub struct ip_mreq {
307 pub imr_multiaddr: in_addr,
308 pub imr_interface: in_addr,
309}
310
311#[repr(C)]
312#[derive(Debug, Copy, Clone)]
313pub struct ipv6_mreq {
314 pub ipv6mr_multiaddr: in6_addr,
315 pub ipv6mr_interface: u32,
316}
317#[repr(C)]
318#[derive(Debug, Copy, Clone)]
319pub struct linger {
320 pub l_onoff: i32,
321 pub l_linger: i32,
322}
323
324#[cfg(not(feature = "dns"))]
325#[hermit_macro::system(errno)]
326#[unsafe(no_mangle)]
327pub unsafe extern "C" fn sys_getaddrbyname(
328 _name: *const c_char,
329 _inaddr: *mut u8,
330 _len: usize,
331) -> i32 {
332 error!("Please enable the feature 'dns' to determine the network ip by name.");
333 -i32::from(Errno::Nosys)
334}
335
336#[cfg(feature = "dns")]
359#[hermit_macro::system(errno)]
360#[unsafe(no_mangle)]
361pub unsafe extern "C" fn sys_getaddrbyname(
362 name: *const c_char,
363 inaddr: *mut u8,
364 len: usize,
365) -> i32 {
366 use alloc::borrow::ToOwned;
367
368 use smoltcp::wire::DnsQueryType;
369
370 use crate::executor::block_on;
371 use crate::executor::network::get_query_result;
372
373 if len != size_of::<in_addr>() && len != size_of::<in6_addr>() {
374 return -i32::from(Errno::Inval);
375 }
376
377 if inaddr.is_null() {
378 return -i32::from(Errno::Inval);
379 }
380
381 let query_type = if len == size_of::<in6_addr>() {
382 DnsQueryType::Aaaa
383 } else {
384 DnsQueryType::A
385 };
386
387 let name = unsafe { core::ffi::CStr::from_ptr(name) };
388 let name = if let Ok(name) = name.to_str() {
389 name.to_owned()
390 } else {
391 return -i32::from(Errno::Inval);
392 };
393
394 let query = {
395 let mut guard = NIC.lock();
396 let nic = guard.as_nic_mut().unwrap();
397 let query = nic.start_query(&name, query_type).unwrap();
398 nic.poll_common(crate::executor::network::now());
399
400 query
401 };
402
403 match block_on(get_query_result(query), None) {
404 Ok(addr_vec) => {
405 let slice = unsafe { core::slice::from_raw_parts_mut(inaddr, len) };
406
407 match addr_vec[0] {
408 IpAddress::Ipv4(ipv4_addr) => slice.copy_from_slice(&ipv4_addr.octets()),
409 IpAddress::Ipv6(ipv6_addr) => slice.copy_from_slice(&ipv6_addr.octets()),
410 }
411
412 0
413 }
414 Err(e) => -i32::from(e),
415 }
416}
417
418#[hermit_macro::system(errno)]
419#[unsafe(no_mangle)]
420pub extern "C" fn sys_socket(domain: i32, type_: i32, protocol: i32) -> i32 {
421 debug!("sys_socket: domain {domain}, type {type_:?}, protocol {protocol}");
422
423 let Ok(Ok(domain)) = u8::try_from(domain).map(Af::try_from) else {
424 return -i32::from(Errno::Inval);
425 };
426
427 let Some((sock, sock_flags)) = Sock::from_bits(type_) else {
428 return -i32::from(Errno::Inval);
429 };
430
431 if protocol != 0 {
432 return -i32::from(Errno::Inval);
433 }
434
435 #[cfg(feature = "vsock")]
436 if domain == Af::Vsock && sock == Sock::Stream {
437 let socket = Arc::new(async_lock::RwLock::new(vsock::Socket::new()));
438
439 if sock_flags.contains(SockFlags::SOCK_NONBLOCK) {
440 block_on(socket.set_status_flags(fd::StatusFlags::O_NONBLOCK), None).unwrap();
441 }
442
443 let fd = insert_object(socket).expect("FD is already used");
444
445 return fd;
446 }
447
448 #[cfg(any(feature = "tcp", feature = "udp"))]
449 if (domain == Af::Inet || domain == Af::Inet6) && (sock == Sock::Stream || sock == Sock::Dgram)
450 {
451 let mut guard = NIC.lock();
452
453 if let NetworkState::Initialized(nic) = &mut *guard {
454 #[cfg(feature = "udp")]
455 if sock == Sock::Dgram {
456 let handle = nic.create_udp_handle().unwrap();
457 drop(guard);
458 let socket = Arc::new(async_lock::RwLock::new(udp::Socket::new(handle, domain)));
459
460 if sock_flags.contains(SockFlags::SOCK_NONBLOCK) {
461 block_on(socket.set_status_flags(fd::StatusFlags::O_NONBLOCK), None).unwrap();
462 }
463
464 let fd = insert_object(socket).expect("FD is already used");
465
466 return fd;
467 }
468
469 #[cfg(feature = "tcp")]
470 if sock == Sock::Stream {
471 let handle = nic.create_tcp_handle().unwrap();
472 drop(guard);
473 let socket = Arc::new(async_lock::RwLock::new(tcp::Socket::new(handle, domain)));
474
475 if sock_flags.contains(SockFlags::SOCK_NONBLOCK) {
476 block_on(socket.set_status_flags(fd::StatusFlags::O_NONBLOCK), None).unwrap();
477 }
478
479 let fd = insert_object(socket).expect("FD is already used");
480
481 return fd;
482 }
483 }
484 }
485
486 -i32::from(Errno::Inval)
487}
488
489#[hermit_macro::system(errno)]
490#[unsafe(no_mangle)]
491pub unsafe extern "C" fn sys_accept(fd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> i32 {
492 let obj = get_object(fd);
493 obj.map_or_else(
494 |e| -i32::from(e),
495 |v| {
496 block_on((*v).accept(), None).map_or_else(
497 |e| -i32::from(e),
498 #[cfg_attr(not(any(feature = "tcp", feature = "udp")), expect(unused_variables))]
499 |(obj, endpoint)| match endpoint {
500 #[cfg(any(feature = "tcp", feature = "udp"))]
501 Endpoint::Ip(endpoint) => {
502 let new_fd = insert_object(obj).unwrap();
503
504 if !addr.is_null() && !addrlen.is_null() {
505 let addrlen = unsafe { &mut *addrlen };
506
507 match endpoint.addr {
508 IpAddress::Ipv4(_) => {
509 if *addrlen >= u32::try_from(size_of::<sockaddr_in>()).unwrap()
510 {
511 let addr = unsafe { &mut *addr.cast() };
512 *addr = sockaddr_in::from(endpoint);
513 *addrlen = size_of::<sockaddr_in>().try_into().unwrap();
514 }
515 }
516 IpAddress::Ipv6(_) => {
517 if *addrlen >= u32::try_from(size_of::<sockaddr_in6>()).unwrap()
518 {
519 let addr = unsafe { &mut *addr.cast() };
520 *addr = sockaddr_in6::from(endpoint);
521 *addrlen = size_of::<sockaddr_in6>().try_into().unwrap();
522 }
523 }
524 }
525 }
526
527 new_fd
528 }
529 #[cfg(feature = "vsock")]
530 Endpoint::Vsock(endpoint) => {
531 let new_fd = insert_object(v.clone()).unwrap();
532
533 if !addr.is_null() && !addrlen.is_null() {
534 let addrlen = unsafe { &mut *addrlen };
535
536 if *addrlen >= u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
537 let addr = unsafe { &mut *addr.cast() };
538 *addr = sockaddr_vm::from(endpoint);
539 *addrlen = size_of::<sockaddr_vm>().try_into().unwrap();
540 }
541 }
542
543 new_fd
544 }
545 },
546 )
547 },
548 )
549}
550
551#[hermit_macro::system(errno)]
552#[unsafe(no_mangle)]
553pub extern "C" fn sys_listen(fd: i32, backlog: i32) -> i32 {
554 let obj = get_object(fd);
555 obj.map_or_else(
556 |e| -i32::from(e),
557 |v| block_on((*v).listen(backlog), None).map_or_else(|e| -i32::from(e), |()| 0),
558 )
559}
560
561#[hermit_macro::system(errno)]
562#[unsafe(no_mangle)]
563pub unsafe extern "C" fn sys_bind(fd: i32, name: *const sockaddr, namelen: socklen_t) -> i32 {
564 if name.is_null() {
565 return -i32::from(Errno::Destaddrreq);
566 }
567
568 let Ok(family) = (unsafe { Af::try_from((*name).sa_family) }) else {
569 return -i32::from(Errno::Inval);
570 };
571
572 let obj = get_object(fd);
573 obj.map_or_else(
574 |e| -i32::from(e),
575 |v| match family {
576 #[cfg(any(feature = "tcp", feature = "udp"))]
577 Af::Inet => {
578 if namelen < u32::try_from(size_of::<sockaddr_in>()).unwrap() {
579 return -i32::from(Errno::Inval);
580 }
581 let endpoint = IpListenEndpoint::from(unsafe { *name.cast::<sockaddr_in>() });
582 block_on((*v).bind(ListenEndpoint::Ip(endpoint)), None)
583 .map_or_else(|e| -i32::from(e), |()| 0)
584 }
585 #[cfg(any(feature = "tcp", feature = "udp"))]
586 Af::Inet6 => {
587 if namelen < u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
588 return -i32::from(Errno::Inval);
589 }
590 let endpoint = IpListenEndpoint::from(unsafe { *name.cast::<sockaddr_in6>() });
591 block_on((*v).bind(ListenEndpoint::Ip(endpoint)), None)
592 .map_or_else(|e| -i32::from(e), |()| 0)
593 }
594 #[cfg(feature = "vsock")]
595 Af::Vsock => {
596 if namelen < u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
597 return -i32::from(Errno::Inval);
598 }
599 let endpoint = VsockListenEndpoint::from(unsafe { *name.cast::<sockaddr_vm>() });
600 block_on((*v).bind(ListenEndpoint::Vsock(endpoint)), None)
601 .map_or_else(|e| -i32::from(e), |()| 0)
602 }
603 _ => -i32::from(Errno::Inval),
604 },
605 )
606}
607
608#[hermit_macro::system(errno)]
609#[unsafe(no_mangle)]
610pub unsafe extern "C" fn sys_connect(fd: i32, name: *const sockaddr, namelen: socklen_t) -> i32 {
611 if name.is_null() {
612 return -i32::from(Errno::Inval);
613 }
614
615 let Ok(sa_family) = (unsafe { Af::try_from((*name).sa_family) }) else {
616 return -i32::from(Errno::Inval);
617 };
618
619 let endpoint = match sa_family {
620 #[cfg(any(feature = "tcp", feature = "udp"))]
621 Af::Inet => {
622 if namelen < u32::try_from(size_of::<sockaddr_in>()).unwrap() {
623 return -i32::from(Errno::Inval);
624 }
625 Endpoint::Ip(IpEndpoint::from(unsafe { *name.cast::<sockaddr_in>() }))
626 }
627 #[cfg(any(feature = "tcp", feature = "udp"))]
628 Af::Inet6 => {
629 if namelen < u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
630 return -i32::from(Errno::Inval);
631 }
632 Endpoint::Ip(IpEndpoint::from(unsafe { *name.cast::<sockaddr_in6>() }))
633 }
634 #[cfg(feature = "vsock")]
635 Af::Vsock => {
636 if namelen < u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
637 return -i32::from(Errno::Inval);
638 }
639 Endpoint::Vsock(VsockEndpoint::from(unsafe { *name.cast::<sockaddr_vm>() }))
640 }
641 _ => {
642 return -i32::from(Errno::Inval);
643 }
644 };
645
646 let obj = get_object(fd);
647 obj.map_or_else(
648 |e| -i32::from(e),
649 |v| block_on((*v).connect(endpoint), None).map_or_else(|e| -i32::from(e), |()| 0),
650 )
651}
652
653#[hermit_macro::system(errno)]
654#[unsafe(no_mangle)]
655pub unsafe extern "C" fn sys_getsockname(
656 fd: i32,
657 addr: *mut sockaddr,
658 addrlen: *mut socklen_t,
659) -> i32 {
660 let obj = get_object(fd);
661 obj.map_or_else(
662 |e| -i32::from(e),
663 |v| {
664 if let Ok(Some(endpoint)) = block_on((*v).getsockname(), None) {
665 if !addr.is_null() && !addrlen.is_null() {
666 let addrlen = unsafe { &mut *addrlen };
667
668 match endpoint {
669 #[cfg(any(feature = "tcp", feature = "udp"))]
670 Endpoint::Ip(endpoint) => match endpoint.addr {
671 IpAddress::Ipv4(_) => {
672 if *addrlen >= u32::try_from(size_of::<sockaddr_in>()).unwrap() {
673 let addr = unsafe { &mut *addr.cast() };
674 *addr = sockaddr_in::from(endpoint);
675 *addrlen = size_of::<sockaddr_in>().try_into().unwrap();
676
677 0
678 } else {
679 -i32::from(Errno::Inval)
680 }
681 }
682 #[cfg(any(feature = "tcp", feature = "udp"))]
683 IpAddress::Ipv6(_) => {
684 if *addrlen >= u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
685 let addr = unsafe { &mut *addr.cast() };
686 *addr = sockaddr_in6::from(endpoint);
687 *addrlen = size_of::<sockaddr_in6>().try_into().unwrap();
688
689 0
690 } else {
691 -i32::from(Errno::Inval)
692 }
693 }
694 },
695 #[cfg(feature = "vsock")]
696 Endpoint::Vsock(_) => {
697 if *addrlen >= u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
698 warn!("unsupported device");
699 0
700 } else {
701 -i32::from(Errno::Inval)
702 }
703 }
704 }
705 } else {
706 -i32::from(Errno::Inval)
707 }
708 } else {
709 -i32::from(Errno::Inval)
710 }
711 },
712 )
713}
714
715#[hermit_macro::system(errno)]
716#[unsafe(no_mangle)]
717pub unsafe extern "C" fn sys_setsockopt(
718 fd: i32,
719 level: i32,
720 optname: i32,
721 optval: *const c_void,
722 optlen: socklen_t,
723) -> i32 {
724 if level == SOL_SOCKET && optname == SO_REUSEADDR {
725 return 0;
726 }
727
728 let Ok(Ok(level)) = u8::try_from(level).map(Ipproto::try_from) else {
729 return -i32::from(Errno::Inval);
730 };
731
732 debug!("sys_setsockopt: {fd}, level {level:?}, optname {optname}");
733
734 if level == Ipproto::Tcp
735 && optname == TCP_NODELAY
736 && optlen == u32::try_from(size_of::<i32>()).unwrap()
737 {
738 if optval.is_null() {
739 return -i32::from(Errno::Inval);
740 }
741
742 let value = unsafe { *optval.cast::<i32>() };
743 let obj = get_object(fd);
744 obj.map_or_else(
745 |e| -i32::from(e),
746 |v| {
747 block_on((*v).setsockopt(SocketOption::TcpNoDelay, value != 0), None)
748 .map_or_else(|e| -i32::from(e), |()| 0)
749 },
750 )
751 } else {
752 -i32::from(Errno::Inval)
753 }
754}
755
756#[hermit_macro::system(errno)]
757#[unsafe(no_mangle)]
758pub unsafe extern "C" fn sys_getsockopt(
759 fd: i32,
760 level: i32,
761 optname: i32,
762 optval: *mut c_void,
763 optlen: *mut socklen_t,
764) -> i32 {
765 let Ok(Ok(level)) = u8::try_from(level).map(Ipproto::try_from) else {
766 return -i32::from(Errno::Inval);
767 };
768
769 debug!("sys_getsockopt: {fd}, level {level:?}, optname {optname}");
770
771 if level == Ipproto::Tcp && optname == TCP_NODELAY {
772 if optval.is_null() || optlen.is_null() {
773 return -i32::from(Errno::Inval);
774 }
775
776 let optval = unsafe { &mut *optval.cast::<i32>() };
777 let optlen = unsafe { &mut *optlen };
778 let obj = get_object(fd);
779 obj.map_or_else(
780 |e| -i32::from(e),
781 |v| {
782 block_on((*v).getsockopt(SocketOption::TcpNoDelay), None).map_or_else(
783 |e| -i32::from(e),
784 |value| {
785 if value {
786 *optval = 1;
787 } else {
788 *optval = 0;
789 }
790 *optlen = core::mem::size_of::<i32>().try_into().unwrap();
791
792 0
793 },
794 )
795 },
796 )
797 } else {
798 -i32::from(Errno::Inval)
799 }
800}
801
802#[hermit_macro::system(errno)]
803#[unsafe(no_mangle)]
804pub unsafe extern "C" fn sys_getpeername(
805 fd: i32,
806 addr: *mut sockaddr,
807 addrlen: *mut socklen_t,
808) -> i32 {
809 let obj = get_object(fd);
810 obj.map_or_else(
811 |e| -i32::from(e),
812 |v| {
813 if let Ok(Some(endpoint)) = block_on((*v).getpeername(), None) {
814 if !addr.is_null() && !addrlen.is_null() {
815 let addrlen = unsafe { &mut *addrlen };
816
817 match endpoint {
818 #[cfg(any(feature = "tcp", feature = "udp"))]
819 Endpoint::Ip(endpoint) => match endpoint.addr {
820 IpAddress::Ipv4(_) => {
821 if *addrlen >= u32::try_from(size_of::<sockaddr_in>()).unwrap() {
822 let addr = unsafe { &mut *addr.cast() };
823 *addr = sockaddr_in::from(endpoint);
824 *addrlen = size_of::<sockaddr_in>().try_into().unwrap();
825 } else {
826 return -i32::from(Errno::Inval);
827 }
828 }
829 IpAddress::Ipv6(_) => {
830 if *addrlen >= u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
831 let addr = unsafe { &mut *addr.cast() };
832 *addr = sockaddr_in6::from(endpoint);
833 *addrlen = size_of::<sockaddr_in6>().try_into().unwrap();
834 } else {
835 return -i32::from(Errno::Inval);
836 }
837 }
838 },
839 #[cfg(feature = "vsock")]
840 Endpoint::Vsock(_) => {
841 if *addrlen >= u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
842 warn!("unsupported device");
843 } else {
844 return -i32::from(Errno::Inval);
845 }
846 }
847 }
848 } else {
849 return -i32::from(Errno::Inval);
850 }
851 }
852
853 0
854 },
855 )
856}
857
858#[hermit_macro::system(errno)]
859#[unsafe(no_mangle)]
860pub unsafe extern "C" fn sys_send(s: i32, mem: *const c_void, len: usize, _flags: i32) -> isize {
861 unsafe { super::write(s, mem.cast(), len) }
862}
863
864fn shutdown(sockfd: i32, how: i32) -> i32 {
865 let obj = get_object(sockfd);
866 obj.map_or_else(
867 |e| -i32::from(e),
868 |v| block_on((*v).shutdown(how), None).map_or_else(|e| -i32::from(e), |()| 0),
869 )
870}
871
872#[hermit_macro::system(errno)]
873#[unsafe(no_mangle)]
874pub extern "C" fn sys_shutdown(sockfd: i32, how: i32) -> i32 {
875 shutdown(sockfd, how)
876}
877
878#[hermit_macro::system(errno)]
879#[unsafe(no_mangle)]
880pub extern "C" fn sys_shutdown_socket(fd: i32, how: i32) -> i32 {
881 shutdown(fd, how)
882}
883
884#[hermit_macro::system(errno)]
885#[unsafe(no_mangle)]
886pub unsafe extern "C" fn sys_recv(fd: i32, buf: *mut u8, len: usize, flags: i32) -> isize {
887 if flags == 0 {
888 let slice = unsafe { core::slice::from_raw_parts_mut(buf.cast(), len) };
889 crate::fd::read(fd, slice).map_or_else(
890 |e| isize::try_from(-i32::from(e)).unwrap(),
891 |v| v.try_into().unwrap(),
892 )
893 } else {
894 (-i32::from(Errno::Inval)).try_into().unwrap()
895 }
896}
897
898#[hermit_macro::system(errno)]
899#[unsafe(no_mangle)]
900pub unsafe extern "C" fn sys_sendto(
901 fd: i32,
902 buf: *const u8,
903 len: usize,
904 _flags: i32,
905 addr: *const sockaddr,
906 addr_len: socklen_t,
907) -> isize {
908 let endpoint;
909
910 if addr.is_null() || addr_len == 0 {
911 return (-i32::from(Errno::Inval)).try_into().unwrap();
912 }
913
914 cfg_if! {
915 if #[cfg(any(feature = "tcp", feature = "udp"))] {
916 let Ok(sa_family) = (unsafe { Af::try_from((*addr).sa_family) }) else {
917 return (-i32::from(Errno::Inval)).try_into().unwrap();
918 };
919
920 if sa_family == Af::Inet {
921 if addr_len < u32::try_from(size_of::<sockaddr_in>()).unwrap() {
922 return (-i32::from(Errno::Inval)).try_into().unwrap();
923 }
924
925 endpoint = Some(Endpoint::Ip(IpEndpoint::from(unsafe {*(addr.cast::<sockaddr_in>())})));
926 } else if sa_family == Af::Inet6 {
927 if addr_len < u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
928 return (-i32::from(Errno::Inval)).try_into().unwrap();
929 }
930
931 endpoint = Some(Endpoint::Ip(IpEndpoint::from(unsafe { *(addr.cast::<sockaddr_in6>()) })));
932 } else {
933 endpoint = None;
934 }
935 } else {
936 endpoint = None;
937 }
938 }
939
940 if let Some(endpoint) = endpoint {
941 let slice = unsafe { core::slice::from_raw_parts(buf, len) };
942 let obj = get_object(fd);
943
944 obj.map_or_else(
945 |e| isize::try_from(-i32::from(e)).unwrap(),
946 |v| {
947 block_on((*v).sendto(slice, endpoint), None).map_or_else(
948 |e| isize::try_from(-i32::from(e)).unwrap(),
949 |v| v.try_into().unwrap(),
950 )
951 },
952 )
953 } else {
954 (-i32::from(Errno::Inval)).try_into().unwrap()
955 }
956}
957
958#[hermit_macro::system(errno)]
959#[unsafe(no_mangle)]
960pub unsafe extern "C" fn sys_recvfrom(
961 fd: i32,
962 buf: *mut u8,
963 len: usize,
964 _flags: i32,
965 addr: *mut sockaddr,
966 addrlen: *mut socklen_t,
967) -> isize {
968 let slice = unsafe { core::slice::from_raw_parts_mut(buf.cast(), len) };
969 let obj = get_object(fd);
970 obj.map_or_else(
971 |e| isize::try_from(-i32::from(e)).unwrap(),
972 |v| {
973 block_on((*v).recvfrom(slice), None).map_or_else(
974 |e| isize::try_from(-i32::from(e)).unwrap(),
975 |(len, endpoint)| {
976 if !addr.is_null() && !addrlen.is_null() {
977 #[allow(unused_variables)]
978 let addrlen = unsafe { &mut *addrlen };
979
980 match endpoint {
981 #[cfg(any(feature = "tcp", feature = "udp"))]
982 Endpoint::Ip(endpoint) => match endpoint.addr {
983 IpAddress::Ipv4(_) => {
984 if *addrlen >= u32::try_from(size_of::<sockaddr_in>()).unwrap()
985 {
986 let addr = unsafe { &mut *addr.cast() };
987 *addr = sockaddr_in::from(endpoint);
988 *addrlen = size_of::<sockaddr_in>().try_into().unwrap();
989 } else {
990 return (-i32::from(Errno::Inval)).try_into().unwrap();
991 }
992 }
993 IpAddress::Ipv6(_) => {
994 if *addrlen >= u32::try_from(size_of::<sockaddr_in6>()).unwrap()
995 {
996 let addr = unsafe { &mut *addr.cast() };
997 *addr = sockaddr_in6::from(endpoint);
998 *addrlen = size_of::<sockaddr_in6>().try_into().unwrap();
999 } else {
1000 return (-i32::from(Errno::Inval)).try_into().unwrap();
1001 }
1002 }
1003 },
1004 #[cfg(feature = "vsock")]
1005 _ => {
1006 return (-i32::from(Errno::Inval)).try_into().unwrap();
1007 }
1008 }
1009 }
1010
1011 len.try_into().unwrap()
1012 },
1013 )
1014 },
1015 )
1016}