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