Skip to main content

hermit/syscalls/socket/
mod.rs

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