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