hermit/syscalls/socket/
mod.rs

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