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::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/// The system call `sys_getaddrbyname` determine the network host entry.
496/// It expects an array of u8 with a size of in_addr or of in6_addr.
497/// The result of the DNS request will be stored in this array.
498///
499/// # Example
500///
501/// ```
502/// use hermit_abi::in_addr;
503/// let c_string = std::ffi::CString::new("rust-lang.org").expect("CString::new failed");
504/// let name = c_string.into_raw();
505/// let mut inaddr: in_addr = Default::default();
506/// let _ = unsafe {
507///         hermit_abi::getaddrbyname(
508///                 name,
509///                 &mut inaddr as *mut _ as *mut u8,
510///                 std::size_of::<in_addr>(),
511///         )
512/// };
513///
514/// // retake pointer to free memory
515/// let _ = CString::from_raw(name);
516/// ```
517#[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	// We do not support the exec syscall, so SOCK_CLOEXEC does not need an implementation.
590	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		// The branch for any supported socket should have been entered and should have returned by now.
665		return -i32::from(Errno::Socktnosupport);
666	}
667
668	// If we still haven't returned, it means that the domain is not supported.
669	-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}