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