hermit/syscalls/
socket.rs

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