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