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