Skip to main content

hermit/syscalls/socket/
mod.rs

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