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