Skip to main content

hermit/syscalls/socket/
mod.rs

1#![allow(dead_code)]
2#![allow(nonstandard_style)]
3
4mod addrinfo;
5
6use alloc::boxed::Box;
7use alloc::sync::Arc;
8use core::ffi::{c_char, c_void};
9use core::mem::MaybeUninit;
10use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
11#[allow(unused_imports)]
12use core::ops::DerefMut;
13use core::slice;
14
15use num_enum::{IntoPrimitive, TryFromPrimitive, TryFromPrimitiveError};
16#[cfg(feature = "net")]
17use smoltcp::wire::{IpAddress, IpEndpoint, IpListenEndpoint};
18
19use crate::errno::Errno;
20#[cfg(feature = "net")]
21use crate::executor::network::{NIC, NetworkState};
22#[cfg(feature = "tcp")]
23use crate::fd::socket::tcp;
24#[cfg(feature = "udp")]
25use crate::fd::socket::udp;
26#[cfg(feature = "virtio-vsock")]
27use crate::fd::socket::vsock::{self, VsockEndpoint, VsockListenEndpoint};
28use crate::fd::{
29	self, Endpoint, ListenEndpoint, ObjectInterface, RawFd, SocketOption, 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(
677	fd: RawFd,
678	addr: *mut sockaddr,
679	addrlen: *mut socklen_t,
680) -> i32 {
681	let obj = get_object(fd);
682	obj.map_or_else(
683		|e| -i32::from(e),
684		|v| {
685			block_on(async { v.write().await.accept().await }, None).map_or_else(
686				|e| -i32::from(e),
687				#[cfg_attr(
688					not(any(feature = "net", feature = "virtio-vsock")),
689					expect(unused_variables)
690				)]
691				|(obj, endpoint)| match endpoint {
692					#[cfg(feature = "net")]
693					Endpoint::Ip(endpoint) => {
694						let new_fd = insert_object(obj).unwrap();
695
696						if !addr.is_null() && !addrlen.is_null() {
697							let addrlen = unsafe { &mut *addrlen };
698
699							match endpoint.addr {
700								IpAddress::Ipv4(_) => {
701									if *addrlen >= u32::try_from(size_of::<sockaddr_in>()).unwrap()
702									{
703										let addr = unsafe { &mut *addr.cast() };
704										*addr = sockaddr_in::from(endpoint);
705										*addrlen = size_of::<sockaddr_in>().try_into().unwrap();
706									}
707								}
708								IpAddress::Ipv6(_) => {
709									if *addrlen >= u32::try_from(size_of::<sockaddr_in6>()).unwrap()
710									{
711										let addr = unsafe { &mut *addr.cast() };
712										*addr = sockaddr_in6::from(endpoint);
713										*addrlen = size_of::<sockaddr_in6>().try_into().unwrap();
714									}
715								}
716							}
717						}
718
719						new_fd
720					}
721					#[cfg(feature = "virtio-vsock")]
722					Endpoint::Vsock(endpoint) => {
723						let new_fd = insert_object(obj).unwrap();
724
725						if !addr.is_null() && !addrlen.is_null() {
726							let addrlen = unsafe { &mut *addrlen };
727
728							if *addrlen >= u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
729								let addr = unsafe { &mut *addr.cast() };
730								*addr = sockaddr_vm::from(endpoint);
731								*addrlen = size_of::<sockaddr_vm>().try_into().unwrap();
732							}
733						}
734
735						new_fd
736					}
737				},
738			)
739		},
740	)
741}
742
743#[hermit_macro::system(errno)]
744#[unsafe(no_mangle)]
745pub extern "C" fn sys_listen(fd: RawFd, backlog: i32) -> i32 {
746	let obj = get_object(fd);
747	obj.map_or_else(
748		|e| -i32::from(e),
749		|v| {
750			block_on(async { v.write().await.listen(backlog).await }, None)
751				.map_or_else(|e| -i32::from(e), |()| 0)
752		},
753	)
754}
755
756#[hermit_macro::system(errno)]
757#[unsafe(no_mangle)]
758pub unsafe extern "C" fn sys_bind(fd: RawFd, name: *const sockaddr, namelen: socklen_t) -> i32 {
759	if name.is_null() {
760		return -i32::from(Errno::Destaddrreq);
761	}
762
763	let Ok(family) = (unsafe { Af::try_from((*name).sa_family) }) else {
764		return -i32::from(Errno::Inval);
765	};
766
767	let obj = get_object(fd);
768	obj.map_or_else(
769		|e| -i32::from(e),
770		|v| match family {
771			#[cfg(feature = "net")]
772			Af::Inet => {
773				if namelen < u32::try_from(size_of::<sockaddr_in>()).unwrap() {
774					return -i32::from(Errno::Inval);
775				}
776				let endpoint = IpListenEndpoint::from(unsafe { *name.cast::<sockaddr_in>() });
777				block_on(
778					async { v.write().await.bind(ListenEndpoint::Ip(endpoint)).await },
779					None,
780				)
781				.map_or_else(|e| -i32::from(e), |()| 0)
782			}
783			#[cfg(feature = "net")]
784			Af::Inet6 => {
785				if namelen < u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
786					return -i32::from(Errno::Inval);
787				}
788				let endpoint = IpListenEndpoint::from(unsafe { *name.cast::<sockaddr_in6>() });
789				block_on(
790					async { v.write().await.bind(ListenEndpoint::Ip(endpoint)).await },
791					None,
792				)
793				.map_or_else(|e| -i32::from(e), |()| 0)
794			}
795			#[cfg(feature = "virtio-vsock")]
796			Af::Vsock => {
797				if namelen < u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
798					return -i32::from(Errno::Inval);
799				}
800				let endpoint = VsockListenEndpoint::from(unsafe { *name.cast::<sockaddr_vm>() });
801				block_on(
802					async { v.write().await.bind(ListenEndpoint::Vsock(endpoint)).await },
803					None,
804				)
805				.map_or_else(|e| -i32::from(e), |()| 0)
806			}
807			_ => -i32::from(Errno::Inval),
808		},
809	)
810}
811
812#[hermit_macro::system(errno)]
813#[unsafe(no_mangle)]
814pub unsafe extern "C" fn sys_connect(fd: RawFd, name: *const sockaddr, namelen: socklen_t) -> i32 {
815	if name.is_null() {
816		return -i32::from(Errno::Inval);
817	}
818
819	let Ok(sa_family) = (unsafe { Af::try_from((*name).sa_family) }) else {
820		return -i32::from(Errno::Inval);
821	};
822
823	let endpoint = match sa_family {
824		#[cfg(feature = "net")]
825		Af::Inet => {
826			if namelen < u32::try_from(size_of::<sockaddr_in>()).unwrap() {
827				return -i32::from(Errno::Inval);
828			}
829			Endpoint::Ip(IpEndpoint::from(unsafe { *name.cast::<sockaddr_in>() }))
830		}
831		#[cfg(feature = "net")]
832		Af::Inet6 => {
833			if namelen < u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
834				return -i32::from(Errno::Inval);
835			}
836			Endpoint::Ip(IpEndpoint::from(unsafe { *name.cast::<sockaddr_in6>() }))
837		}
838		#[cfg(feature = "virtio-vsock")]
839		Af::Vsock => {
840			if namelen < u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
841				return -i32::from(Errno::Inval);
842			}
843			Endpoint::Vsock(VsockEndpoint::from(unsafe { *name.cast::<sockaddr_vm>() }))
844		}
845		_ => {
846			return -i32::from(Errno::Inval);
847		}
848	};
849
850	let obj = get_object(fd);
851	obj.map_or_else(
852		|e| -i32::from(e),
853		|v| {
854			block_on(async { v.write().await.connect(endpoint).await }, None)
855				.map_or_else(|e| -i32::from(e), |()| 0)
856		},
857	)
858}
859
860#[hermit_macro::system(errno)]
861#[unsafe(no_mangle)]
862pub unsafe extern "C" fn sys_getsockname(
863	fd: RawFd,
864	addr: *mut sockaddr,
865	addrlen: *mut socklen_t,
866) -> i32 {
867	let obj = get_object(fd);
868	obj.map_or_else(
869		|e| -i32::from(e),
870		|v| {
871			let Ok(Some(endpoint)) = block_on(async { v.read().await.getsockname().await }, None)
872			else {
873				return -i32::from(Errno::Inval);
874			};
875
876			if addr.is_null() || addrlen.is_null() {
877				return -i32::from(Errno::Inval);
878			}
879
880			let addrlen = unsafe { &mut *addrlen };
881
882			match endpoint {
883				#[cfg(feature = "net")]
884				Endpoint::Ip(endpoint) => match endpoint.addr {
885					IpAddress::Ipv4(_) => {
886						if *addrlen >= u32::try_from(size_of::<sockaddr_in>()).unwrap() {
887							let addr = unsafe { &mut *addr.cast() };
888							*addr = sockaddr_in::from(endpoint);
889							*addrlen = size_of::<sockaddr_in>().try_into().unwrap();
890
891							0
892						} else {
893							-i32::from(Errno::Inval)
894						}
895					}
896					#[cfg(feature = "net")]
897					IpAddress::Ipv6(_) => {
898						if *addrlen >= u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
899							let addr = unsafe { &mut *addr.cast() };
900							*addr = sockaddr_in6::from(endpoint);
901							*addrlen = size_of::<sockaddr_in6>().try_into().unwrap();
902
903							0
904						} else {
905							-i32::from(Errno::Inval)
906						}
907					}
908				},
909				#[cfg(feature = "virtio-vsock")]
910				Endpoint::Vsock(_) => {
911					if *addrlen >= u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
912						warn!("unsupported device");
913						0
914					} else {
915						-i32::from(Errno::Inval)
916					}
917				}
918			}
919		},
920	)
921}
922
923#[hermit_macro::system(errno)]
924#[unsafe(no_mangle)]
925pub unsafe extern "C" fn sys_setsockopt(
926	fd: RawFd,
927	level: i32,
928	optname: i32,
929	optval: *const c_void,
930	optlen: socklen_t,
931) -> i32 {
932	if level == SOL_SOCKET && optname == SO_REUSEADDR {
933		return 0;
934	}
935
936	let Ok(Ok(level)) = u8::try_from(level).map(Ipproto::try_from) else {
937		return -i32::from(Errno::Inval);
938	};
939
940	let Ok(optname) = SocketOption::try_from(optname) else {
941		return -i32::from(Errno::Inval);
942	};
943
944	debug!("sys_setsockopt: {fd}, level {level:?}, optname {optname:?}");
945
946	if level == Ipproto::Tcp
947		&& optname == SocketOption::TcpNodelay
948		&& optlen == u32::try_from(size_of::<i32>()).unwrap()
949	{
950		if optval.is_null() {
951			return -i32::from(Errno::Inval);
952		}
953
954		let value = unsafe { *optval.cast::<i32>() };
955		let obj = get_object(fd);
956		obj.map_or_else(
957			|e| -i32::from(e),
958			|v| {
959				block_on(
960					async { v.read().await.setsockopt(optname, value != 0).await },
961					None,
962				)
963				.map_or_else(|e| -i32::from(e), |()| 0)
964			},
965		)
966	} else {
967		-i32::from(Errno::Inval)
968	}
969}
970
971#[hermit_macro::system(errno)]
972#[unsafe(no_mangle)]
973pub unsafe extern "C" fn sys_getsockopt(
974	fd: RawFd,
975	level: i32,
976	optname: i32,
977	optval: *mut c_void,
978	optlen: *mut socklen_t,
979) -> i32 {
980	let Ok(optname) = SocketOption::try_from(optname) else {
981		return -i32::from(Errno::Inval);
982	};
983
984	debug!("sys_getsockopt: {fd}, level {level}, optname {optname:?}");
985
986	if level == Ipproto::Tcp as i32 && optname == SocketOption::TcpNodelay
987		|| level == SOL_SOCKET
988			&& (optname == SocketOption::SoSndbuf || optname == SocketOption::SoRcvbuf)
989	{
990		if optval.is_null() || optlen.is_null() {
991			return -i32::from(Errno::Inval);
992		}
993
994		let optval = unsafe { &mut *optval.cast::<i32>() };
995		let optlen = unsafe { &mut *optlen };
996		let obj = get_object(fd);
997		obj.map_or_else(
998			|e| -i32::from(e),
999			|v| {
1000				block_on(async { v.read().await.getsockopt(optname).await }, None).map_or_else(
1001					|e| -i32::from(e),
1002					|value| {
1003						*optval = value;
1004						*optlen = size_of::<i32>().try_into().unwrap();
1005
1006						0
1007					},
1008				)
1009			},
1010		)
1011	} else {
1012		-i32::from(Errno::Inval)
1013	}
1014}
1015
1016#[hermit_macro::system(errno)]
1017#[unsafe(no_mangle)]
1018pub unsafe extern "C" fn sys_getpeername(
1019	fd: RawFd,
1020	addr: *mut sockaddr,
1021	addrlen: *mut socklen_t,
1022) -> i32 {
1023	let obj = get_object(fd);
1024	obj.map_or_else(
1025		|e| -i32::from(e),
1026		|v| {
1027			let Ok(Some(endpoint)) = block_on(async { v.read().await.getpeername().await }, None)
1028			else {
1029				return 0;
1030			};
1031
1032			if addr.is_null() || addrlen.is_null() {
1033				return -i32::from(Errno::Inval);
1034			}
1035
1036			let addrlen = unsafe { &mut *addrlen };
1037
1038			match endpoint {
1039				#[cfg(feature = "net")]
1040				Endpoint::Ip(endpoint) => match endpoint.addr {
1041					IpAddress::Ipv4(_) => {
1042						if *addrlen >= u32::try_from(size_of::<sockaddr_in>()).unwrap() {
1043							let addr = unsafe { &mut *addr.cast() };
1044							*addr = sockaddr_in::from(endpoint);
1045							*addrlen = size_of::<sockaddr_in>().try_into().unwrap();
1046						} else {
1047							return -i32::from(Errno::Inval);
1048						}
1049					}
1050					IpAddress::Ipv6(_) => {
1051						if *addrlen >= u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
1052							let addr = unsafe { &mut *addr.cast() };
1053							*addr = sockaddr_in6::from(endpoint);
1054							*addrlen = size_of::<sockaddr_in6>().try_into().unwrap();
1055						} else {
1056							return -i32::from(Errno::Inval);
1057						}
1058					}
1059				},
1060				#[cfg(feature = "virtio-vsock")]
1061				Endpoint::Vsock(_) => {
1062					if *addrlen >= u32::try_from(size_of::<sockaddr_vm>()).unwrap() {
1063						warn!("unsupported device");
1064					} else {
1065						return -i32::from(Errno::Inval);
1066					}
1067				}
1068			}
1069
1070			0
1071		},
1072	)
1073}
1074
1075#[hermit_macro::system(errno)]
1076#[unsafe(no_mangle)]
1077pub unsafe extern "C" fn sys_send(s: i32, mem: *const c_void, len: usize, _flags: i32) -> isize {
1078	unsafe { super::write(s, mem.cast(), len) }
1079}
1080
1081fn shutdown(sockfd: RawFd, how: i32) -> i32 {
1082	let obj = get_object(sockfd);
1083	obj.map_or_else(
1084		|e| -i32::from(e),
1085		|v| {
1086			block_on(async { v.read().await.shutdown(how).await }, None)
1087				.map_or_else(|e| -i32::from(e), |()| 0)
1088		},
1089	)
1090}
1091
1092#[hermit_macro::system(errno)]
1093#[unsafe(no_mangle)]
1094pub extern "C" fn sys_shutdown(sockfd: RawFd, how: i32) -> i32 {
1095	shutdown(sockfd, how)
1096}
1097
1098#[hermit_macro::system(errno)]
1099#[unsafe(no_mangle)]
1100pub extern "C" fn sys_shutdown_socket(fd: RawFd, how: i32) -> i32 {
1101	shutdown(fd, how)
1102}
1103
1104#[hermit_macro::system(errno)]
1105#[unsafe(no_mangle)]
1106pub unsafe extern "C" fn sys_recv(fd: RawFd, buf: *mut u8, len: usize, flags: i32) -> isize {
1107	if flags == 0 {
1108		let slice = unsafe { slice::from_raw_parts_mut(buf.cast::<MaybeUninit<u8>>(), len) };
1109		let slice = init_buf::init_buf(slice);
1110		fd::read(fd, slice).map_or_else(
1111			|e| isize::try_from(-i32::from(e)).unwrap(),
1112			|v| v.try_into().unwrap(),
1113		)
1114	} else {
1115		(-i32::from(Errno::Inval)).try_into().unwrap()
1116	}
1117}
1118
1119#[hermit_macro::system(errno)]
1120#[unsafe(no_mangle)]
1121pub unsafe extern "C" fn sys_sendto(
1122	fd: RawFd,
1123	buf: *const u8,
1124	len: usize,
1125	_flags: i32,
1126	addr: *const sockaddr,
1127	addr_len: socklen_t,
1128) -> isize {
1129	if addr.is_null() || addr_len == 0 {
1130		return (-i32::from(Errno::Inval)).try_into().unwrap();
1131	}
1132
1133	cfg_select! {
1134		feature = "net" => {
1135			let Ok(sa_family) = (unsafe { Af::try_from((*addr).sa_family) }) else {
1136				return (-i32::from(Errno::Inval)).try_into().unwrap();
1137			};
1138
1139			let endpoint = if sa_family == Af::Inet {
1140				if addr_len < u32::try_from(size_of::<sockaddr_in>()).unwrap() {
1141					return (-i32::from(Errno::Inval)).try_into().unwrap();
1142				}
1143
1144				Some(Endpoint::Ip(IpEndpoint::from(unsafe {
1145					*(addr.cast::<sockaddr_in>())
1146				})))
1147			} else if sa_family == Af::Inet6 {
1148				if addr_len < u32::try_from(size_of::<sockaddr_in6>()).unwrap() {
1149					return (-i32::from(Errno::Inval)).try_into().unwrap();
1150				}
1151
1152				Some(Endpoint::Ip(IpEndpoint::from(unsafe {
1153					*(addr.cast::<sockaddr_in6>())
1154				})))
1155			} else {
1156				None
1157			};
1158		}
1159		_ => {
1160			let endpoint = None;
1161		}
1162	}
1163
1164	let Some(endpoint) = endpoint else {
1165		return (-i32::from(Errno::Inval)).try_into().unwrap();
1166	};
1167
1168	let slice = unsafe { slice::from_raw_parts(buf, len) };
1169	let obj = get_object(fd);
1170
1171	obj.map_or_else(
1172		|e| isize::try_from(-i32::from(e)).unwrap(),
1173		|v| {
1174			block_on(async { v.read().await.sendto(slice, endpoint).await }, None).map_or_else(
1175				|e| isize::try_from(-i32::from(e)).unwrap(),
1176				|v| v.try_into().unwrap(),
1177			)
1178		},
1179	)
1180}
1181
1182#[hermit_macro::system(errno)]
1183#[unsafe(no_mangle)]
1184pub unsafe extern "C" fn sys_recvfrom(
1185	fd: RawFd,
1186	buf: *mut u8,
1187	len: usize,
1188	_flags: i32,
1189	addr: *mut sockaddr,
1190	addrlen: *mut socklen_t,
1191) -> isize {
1192	let slice = unsafe { slice::from_raw_parts_mut(buf.cast::<MaybeUninit<u8>>(), len) };
1193	let slice = init_buf::init_buf(slice);
1194	let obj = get_object(fd);
1195	obj.map_or_else(
1196		|e| isize::try_from(-i32::from(e)).unwrap(),
1197		|v| {
1198			block_on(async { v.read().await.recvfrom(slice).await }, None).map_or_else(
1199				|e| isize::try_from(-i32::from(e)).unwrap(),
1200				|(len, endpoint)| {
1201					if !addr.is_null() && !addrlen.is_null() {
1202						#[allow(unused_variables)]
1203						let addrlen = unsafe { &mut *addrlen };
1204
1205						match endpoint {
1206							#[cfg(feature = "net")]
1207							Endpoint::Ip(endpoint) => match endpoint.addr {
1208								IpAddress::Ipv4(_) => {
1209									if *addrlen >= u32::try_from(size_of::<sockaddr_in>()).unwrap()
1210									{
1211										let addr = unsafe { &mut *addr.cast() };
1212										*addr = sockaddr_in::from(endpoint);
1213										*addrlen = size_of::<sockaddr_in>().try_into().unwrap();
1214									} else {
1215										return (-i32::from(Errno::Inval)).try_into().unwrap();
1216									}
1217								}
1218								IpAddress::Ipv6(_) => {
1219									if *addrlen >= u32::try_from(size_of::<sockaddr_in6>()).unwrap()
1220									{
1221										let addr = unsafe { &mut *addr.cast() };
1222										*addr = sockaddr_in6::from(endpoint);
1223										*addrlen = size_of::<sockaddr_in6>().try_into().unwrap();
1224									} else {
1225										return (-i32::from(Errno::Inval)).try_into().unwrap();
1226									}
1227								}
1228							},
1229							#[cfg(feature = "virtio-vsock")]
1230							_ => {
1231								return (-i32::from(Errno::Inval)).try_into().unwrap();
1232							}
1233						}
1234					}
1235
1236					len.try_into().unwrap()
1237				},
1238			)
1239		},
1240	)
1241}