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