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