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