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#[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}