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