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