1#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
14compile_error!("air-sys-syscall::net supporte uniquement x86_64 et aarch64 (ADR-014).");
15
16use air_sys_types::fd::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
17use alloc::ffi::CString;
18use alloc::vec::Vec;
19use core::ffi::CStr;
20use core::num::NonZeroI32;
21
22use air_sys_types::net::{
23 AcceptFlags, AcceptResult, IoSlice, IoSliceMut, IpMembershipV4, IpMembershipV6, Ipv4SocketAddr,
24 Ipv6SocketAddr, LingerOption, MessageFlags, ReceiveMessageRequest, ReceiveMessageResult,
25 SendMessageRequest, SendMessageResult, ShutdownMode, SocketAddr, SocketDomain, SocketType,
26 UnixCredentials, UnixSocketAddr,
27};
28use air_sys_types::process::Pid;
29use air_sys_types::{Errno, OwnedFd as AirOwnedFd, Timeval};
30
31fn errno_from_negative_syscall_ret(ret: i64) -> Errno {
36 debug_assert!(ret < 0 && ret > -4096);
37 #[allow(clippy::cast_possible_truncation)]
38 let raw = ret.wrapping_neg() as i32;
39 let nz = NonZeroI32::new(raw).expect("errno strictement positif par construction");
40 Errno::from_nonzero(nz)
41}
42
43const SOCK_CLOEXEC: i32 = 0x0008_0000;
49
50const MSG_NOSIGNAL: i32 = 0x4000;
52
53const SOL_SOCKET: i32 = 1;
58const SO_KEEPALIVE: i32 = 9;
59const SO_REUSEADDR: i32 = 2;
60const SO_REUSEPORT: i32 = 15;
61const SO_SNDBUF: i32 = 7;
62const SO_RCVBUF: i32 = 8;
63const SO_ERROR: i32 = 4;
64const SO_LINGER: i32 = 13;
65const SO_PEERCRED: i32 = 17;
66const SO_BINDTODEVICE: i32 = 25;
67const SO_RCVTIMEO: i32 = 20;
71const SO_SNDTIMEO: i32 = 21;
72
73const IPPROTO_TCP: i32 = 6;
74const TCP_NODELAY: i32 = 1;
75const TCP_KEEPIDLE: i32 = 4;
76const TCP_KEEPINTVL: i32 = 5;
77const TCP_KEEPCNT: i32 = 6;
78
79const IPPROTO_IP: i32 = 0;
80const IP_TTL: i32 = 2;
81const IP_ADD_MEMBERSHIP: i32 = 35;
82const IP_DROP_MEMBERSHIP: i32 = 36;
83
84const IPPROTO_IPV6: i32 = 41;
85const IPV6_V6ONLY: i32 = 26;
86const IPV6_ADD_MEMBERSHIP: i32 = 20;
88const IPV6_DROP_MEMBERSHIP: i32 = 21;
89
90const TIMEVAL_LEN: u32 = 16;
92const IP_MREQ_LEN: u32 = 8;
94const IPV6_MREQ_LEN: u32 = 20;
96
97const _: () = assert!(core::mem::size_of::<Timeval>() == TIMEVAL_LEN as usize);
100const _: () = assert!(core::mem::size_of::<IpMembershipV4>() == IP_MREQ_LEN as usize);
101const _: () = assert!(core::mem::size_of::<IpMembershipV6>() == IPV6_MREQ_LEN as usize);
102
103pub(crate) const MAX_SOCKADDR_LEN: usize = 128;
108
109#[repr(C, align(8))]
111#[derive(Debug)]
112pub(crate) struct RawSockaddrStorage {
113 pub(crate) bytes: [u8; MAX_SOCKADDR_LEN],
114}
115
116pub(crate) fn socket_addr_to_raw(address: &SocketAddr) -> (RawSockaddrStorage, u32) {
119 let mut storage = RawSockaddrStorage {
120 bytes: [0u8; MAX_SOCKADDR_LEN],
121 };
122 match address {
123 SocketAddr::Unix(unix) => {
124 storage.bytes[0..2].copy_from_slice(&1u16.to_ne_bytes());
126 match unix {
127 UnixSocketAddr::Path(path) => {
128 let bytes = path.as_bytes();
129 let length = bytes.len().min(107);
130 storage.bytes[2..2_usize.saturating_add(length)]
131 .copy_from_slice(&bytes[..length]);
132 storage.bytes[2_usize.saturating_add(length)] = 0; #[allow(clippy::cast_possible_truncation)]
135 let addrlen = (2_usize.saturating_add(length).saturating_add(1)) as u32;
136 (storage, addrlen)
137 }
138 UnixSocketAddr::Abstract(name) => {
139 storage.bytes[2] = 0;
141 let length = name.len().min(107);
142 storage.bytes[3..3_usize.saturating_add(length)]
143 .copy_from_slice(&name[..length]);
144 #[allow(clippy::cast_possible_truncation)]
146 let addrlen = (2_usize.saturating_add(1).saturating_add(length)) as u32;
147 (storage, addrlen)
148 }
149 UnixSocketAddr::Unnamed => (storage, 2),
150 }
151 }
152 SocketAddr::Ipv4(ipv4) => {
153 storage.bytes[0..2].copy_from_slice(&2u16.to_ne_bytes());
155 let port_be = ipv4.port.to_be();
157 storage.bytes[2..4].copy_from_slice(&port_be.to_ne_bytes());
158 storage.bytes[4..8].copy_from_slice(&ipv4.address);
159 (storage, 16)
161 }
162 SocketAddr::Ipv6(ipv6) => {
163 storage.bytes[0..2].copy_from_slice(&10u16.to_ne_bytes());
165 let port_be = ipv6.port.to_be();
166 storage.bytes[2..4].copy_from_slice(&port_be.to_ne_bytes());
167 storage.bytes[4..8].copy_from_slice(&ipv6.flowinfo.to_ne_bytes());
168 storage.bytes[8..24].copy_from_slice(&ipv6.address);
169 storage.bytes[24..28].copy_from_slice(&ipv6.scope_id.to_ne_bytes());
170 (storage, 28)
171 }
172 }
173}
174
175pub(crate) fn raw_to_socket_addr(buffer: &[u8], length: u32) -> Option<SocketAddr> {
178 if length < 2 {
179 return None;
180 }
181 let len_usize = length as usize;
182 if buffer.len() < len_usize {
183 return None;
184 }
185 let family = u16::from_ne_bytes([buffer[0], buffer[1]]);
186 match family {
187 1 => {
188 if length == 2 {
190 return Some(SocketAddr::Unix(UnixSocketAddr::Unnamed));
191 }
192 if length < 3 {
193 return None;
194 }
195 let path_bytes = buffer.get(2..len_usize)?;
196 if path_bytes.first() == Some(&0) {
197 let name = path_bytes.get(1..).unwrap_or(&[]).to_vec();
199 Some(SocketAddr::Unix(UnixSocketAddr::Abstract(name)))
200 } else {
201 let nul = path_bytes
203 .iter()
204 .position(|&b| b == 0)
205 .unwrap_or(path_bytes.len());
206 let cstr = CString::new(&path_bytes[..nul]).ok()?;
207 Some(SocketAddr::Unix(UnixSocketAddr::Path(cstr)))
208 }
209 }
210 2 => {
211 if length < 16 {
213 return None;
214 }
215 let port = u16::from_be_bytes([buffer[2], buffer[3]]);
216 let address = [buffer[4], buffer[5], buffer[6], buffer[7]];
217 Some(SocketAddr::Ipv4(Ipv4SocketAddr { address, port }))
218 }
219 10 => {
220 if length < 28 {
222 return None;
223 }
224 let port = u16::from_be_bytes([buffer[2], buffer[3]]);
225 let flowinfo = u32::from_ne_bytes([buffer[4], buffer[5], buffer[6], buffer[7]]);
226 let mut address = [0u8; 16];
227 address.copy_from_slice(buffer.get(8..24)?);
228 let scope_id = u32::from_ne_bytes([buffer[24], buffer[25], buffer[26], buffer[27]]);
229 Some(SocketAddr::Ipv6(Ipv6SocketAddr {
230 address,
231 port,
232 flowinfo,
233 scope_id,
234 }))
235 }
236 _ => None,
237 }
238}
239
240#[must_use]
252pub fn socket_addr_from_bytes(bytes: &[u8], length: u32) -> Option<SocketAddr> {
253 raw_to_socket_addr(bytes, length)
254}
255
256#[must_use]
261pub fn socket_addr_to_bytes(address: &SocketAddr, out: &mut [u8]) -> Option<u32> {
262 let (storage, length) = socket_addr_to_raw(address);
263 let length_usize = usize::try_from(length).ok()?;
264 let source = storage.bytes.get(..length_usize)?;
265 let target = out.get_mut(..length_usize)?;
266 target.copy_from_slice(source);
267 Some(length)
268}
269
270pub(crate) fn build_scm_rights_cmsg(fds: &[BorrowedFd<'_>]) -> Vec<u8> {
282 if fds.is_empty() {
283 return Vec::new();
284 }
285 let data_len = fds.len().saturating_mul(4); let cmsg_len = 16_usize.saturating_add(data_len); let total = cmsg_len.saturating_add(7) & !7_usize; let mut buffer = vec![0u8; total];
289 #[allow(clippy::cast_possible_truncation)]
291 buffer[0..8].copy_from_slice(&(cmsg_len as u64).to_ne_bytes());
292 buffer[8..12].copy_from_slice(&1i32.to_ne_bytes());
294 buffer[12..16].copy_from_slice(&1i32.to_ne_bytes());
296 for (i, fd) in fds.iter().enumerate() {
298 let raw = fd.as_raw_fd();
299 let offset = 16_usize.saturating_add(i.saturating_mul(4));
300 buffer[offset..offset.saturating_add(4)].copy_from_slice(&raw.to_ne_bytes());
301 }
302 buffer
303}
304
305pub(crate) fn parse_scm_rights(cmsg_buf: &[u8], cmsg_len: usize) -> Vec<OwnedFd> {
307 let mut fds = Vec::new();
308 let mut offset = 0_usize;
309 while offset.saturating_add(16) <= cmsg_len && offset.saturating_add(16) <= cmsg_buf.len() {
310 let len_bytes: [u8; 8] = match cmsg_buf[offset..offset.saturating_add(8)].try_into() {
311 Ok(b) => b,
312 Err(_) => break,
313 };
314 #[allow(clippy::cast_possible_truncation)]
318 let length = u64::from_ne_bytes(len_bytes) as usize;
319 let level_bytes: [u8; 4] =
320 match cmsg_buf[offset.saturating_add(8)..offset.saturating_add(12)].try_into() {
321 Ok(b) => b,
322 Err(_) => break,
323 };
324 let level = i32::from_ne_bytes(level_bytes);
325 let ty_bytes: [u8; 4] =
326 match cmsg_buf[offset.saturating_add(12)..offset.saturating_add(16)].try_into() {
327 Ok(b) => b,
328 Err(_) => break,
329 };
330 let ty = i32::from_ne_bytes(ty_bytes);
331
332 if level == 1 && ty == 1 && length >= 16 {
334 let mut fd_off = offset.saturating_add(16);
335 let end = offset.saturating_add(length);
336 while fd_off.saturating_add(4) <= end && fd_off.saturating_add(4) <= cmsg_buf.len() {
337 let raw_bytes: [u8; 4] = match cmsg_buf[fd_off..fd_off.saturating_add(4)].try_into()
338 {
339 Ok(b) => b,
340 Err(_) => break,
341 };
342 let raw = i32::from_ne_bytes(raw_bytes);
343 fds.push(unsafe { OwnedFd::from_raw_fd(raw) });
346 fd_off = fd_off.saturating_add(4);
347 }
348 }
349 let aligned = length.saturating_add(7) & !7_usize;
350 if aligned == 0 {
351 break;
352 }
353 offset = offset.saturating_add(aligned);
354 }
355 fds
356}
357
358#[repr(C)]
367struct KernelMsghdr {
368 msg_name: u64, msg_namelen: u32, _pad: u32, msg_iov: u64, msg_iovlen: u64, msg_control: u64, msg_controllen: u64, msg_flags: i32, _pad2: u32,
377}
378
379fn getsockopt_i32(sock: BorrowedFd<'_>, level: i32, optname: i32) -> Result<i32, Errno> {
385 let mut val: i32 = 0;
386 let mut length: u32 = 4;
387 let val_ptr: *mut i32 = &mut val;
388 let len_ptr: *mut u32 = &mut length;
389 let ret = unsafe {
394 raw_syscall_getsockopt(
395 sock.as_raw_fd(),
396 level,
397 optname,
398 val_ptr as u64,
399 len_ptr as u64,
400 )
401 };
402 if ret < 0 {
403 return Err(errno_from_negative_syscall_ret(ret));
404 }
405 Ok(val)
406}
407
408fn setsockopt_i32(sock: BorrowedFd<'_>, level: i32, optname: i32, val: i32) -> Result<(), Errno> {
410 let val_ref: &i32 = &val;
411 let val_ptr: *const i32 = val_ref;
412 let length: u32 = 4;
413 let ret =
418 unsafe { raw_syscall_setsockopt(sock.as_raw_fd(), level, optname, val_ptr as u64, length) };
419 if ret < 0 {
420 return Err(errno_from_negative_syscall_ret(ret));
421 }
422 Ok(())
423}
424
425pub fn set_socket_option_int(
438 sock: BorrowedFd<'_>,
439 level: i32,
440 optname: i32,
441 value: i32,
442) -> Result<(), Errno> {
443 setsockopt_i32(sock, level, optname, value)
444}
445
446pub fn get_socket_option_int(sock: BorrowedFd<'_>, level: i32, optname: i32) -> Result<i32, Errno> {
452 getsockopt_i32(sock, level, optname)
453}
454
455pub fn socket(domain: SocketDomain, ty: SocketType, protocol: i32) -> Result<AirOwnedFd, Errno> {
489 let domain_raw = domain as i32;
490 let ty_raw = (ty as i32) | SOCK_CLOEXEC;
491 let ret = unsafe { raw_syscall_socket(domain_raw, ty_raw, protocol) };
496 if ret < 0 {
497 return Err(errno_from_negative_syscall_ret(ret));
498 }
499 #[allow(clippy::cast_possible_truncation)]
500 let raw_fd = ret as i32;
501 Ok(unsafe { AirOwnedFd::from_raw_fd(raw_fd) })
503}
504
505pub fn bind(sock: BorrowedFd<'_>, address: &SocketAddr) -> Result<(), Errno> {
537 let (raw, addrlen) = socket_addr_to_raw(address);
538 let addr_ptr: *const u8 = raw.bytes.as_ptr();
539 let ret = unsafe { raw_syscall_bind(sock.as_raw_fd(), addr_ptr as u64, addrlen) };
544 if ret < 0 {
545 return Err(errno_from_negative_syscall_ret(ret));
546 }
547 Ok(())
548}
549
550pub fn listen(sock: BorrowedFd<'_>, backlog: u32) -> Result<(), Errno> {
575 #[allow(clippy::cast_possible_truncation)]
577 let backlog_i32 = if backlog > i32::MAX as u32 {
578 i32::MAX
579 } else {
580 backlog as i32
581 };
582 let ret = unsafe { raw_syscall_listen(sock.as_raw_fd(), backlog_i32) };
586 if ret < 0 {
587 return Err(errno_from_negative_syscall_ret(ret));
588 }
589 Ok(())
590}
591
592pub fn connect(sock: BorrowedFd<'_>, address: &SocketAddr) -> Result<(), Errno> {
628 let (raw, addrlen) = socket_addr_to_raw(address);
629 let addr_ptr: *const u8 = raw.bytes.as_ptr();
630 let ret = unsafe { raw_syscall_connect(sock.as_raw_fd(), addr_ptr as u64, addrlen) };
635 if ret < 0 {
636 return Err(errno_from_negative_syscall_ret(ret));
637 }
638 Ok(())
639}
640
641pub fn accept4(listener: BorrowedFd<'_>, flags: AcceptFlags) -> Result<AcceptResult, Errno> {
670 let mut addr_buf = RawSockaddrStorage {
671 bytes: [0u8; MAX_SOCKADDR_LEN],
672 };
673 #[allow(clippy::cast_possible_truncation)]
675 let mut addrlen: u32 = MAX_SOCKADDR_LEN as u32;
676 let addr_ptr: *mut u8 = addr_buf.bytes.as_mut_ptr();
677 let addrlen_ptr: *mut u32 = &mut addrlen;
678 let effective_flags = (flags | AcceptFlags::CLOEXEC).bits();
680 let ret = unsafe {
687 raw_syscall_accept4(
688 listener.as_raw_fd(),
689 addr_ptr as u64,
690 addrlen_ptr as u64,
691 effective_flags,
692 )
693 };
694 if ret < 0 {
695 return Err(errno_from_negative_syscall_ret(ret));
696 }
697 #[allow(clippy::cast_possible_truncation)]
698 let raw_fd = ret as i32;
699 let fd = unsafe { AirOwnedFd::from_raw_fd(raw_fd) };
701 let address = raw_to_socket_addr(&addr_buf.bytes, addrlen);
702 Ok(AcceptResult { fd, address })
703}
704
705pub fn send(sock: BorrowedFd<'_>, buffer: &[u8], flags: MessageFlags) -> Result<usize, Errno> {
735 let buf_ptr: *const u8 = buffer.as_ptr();
736 #[allow(clippy::cast_sign_loss)]
738 let effective_flags = (flags.bits() | MSG_NOSIGNAL) as u64;
739 let ret = unsafe {
744 raw_syscall_sendto(
745 sock.as_raw_fd(),
746 buf_ptr as u64,
747 buffer.len(),
748 effective_flags,
749 0,
750 0,
751 )
752 };
753 if ret < 0 {
754 return Err(errno_from_negative_syscall_ret(ret));
755 }
756 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
757 Ok(ret as usize)
758}
759
760pub fn recv(sock: BorrowedFd<'_>, buffer: &mut [u8], flags: MessageFlags) -> Result<usize, Errno> {
790 let buf_ptr: *mut u8 = buffer.as_mut_ptr();
791 #[allow(clippy::cast_sign_loss)]
792 let flags_u64 = flags.bits() as u64;
793 let ret = unsafe {
799 raw_syscall_recvfrom(
800 sock.as_raw_fd(),
801 buf_ptr as u64,
802 buffer.len(),
803 flags_u64,
804 0,
805 0,
806 )
807 };
808 if ret < 0 {
809 return Err(errno_from_negative_syscall_ret(ret));
810 }
811 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
812 Ok(ret as usize)
813}
814
815pub fn sendmsg(
850 sock: BorrowedFd<'_>,
851 request: &SendMessageRequest<'_>,
852) -> Result<SendMessageResult, Errno> {
853 let (addr_storage, addr_storage_len) = if let Some(address) = request.address {
855 let (s, l) = socket_addr_to_raw(address);
856 (Some(s), l)
857 } else {
858 (None, 0u32)
859 };
860
861 let cmsg_buf = build_scm_rights_cmsg(request.fds);
863
864 let iov_ptr: *const IoSlice<'_> = request.iov.as_ptr();
865
866 let (name_ptr, name_len) = if let Some(ref s) = addr_storage {
867 (s.bytes.as_ptr() as u64, addr_storage_len)
868 } else {
869 (0u64, 0u32)
870 };
871
872 let (ctrl_ptr, ctrl_len) = if cmsg_buf.is_empty() {
873 (0u64, 0u64)
874 } else {
875 (cmsg_buf.as_ptr() as u64, cmsg_buf.len() as u64)
876 };
877
878 let mut msghdr = KernelMsghdr {
879 msg_name: name_ptr,
880 msg_namelen: name_len,
881 _pad: 0,
882 msg_iov: iov_ptr as u64,
883 msg_iovlen: request.iov.len() as u64,
884 msg_control: ctrl_ptr,
885 msg_controllen: ctrl_len,
886 msg_flags: 0,
887 _pad2: 0,
888 };
889
890 #[allow(clippy::cast_sign_loss)]
891 let effective_flags = (request.flags.bits() | MSG_NOSIGNAL) as u64;
892 let hdr_ptr: *mut KernelMsghdr = &mut msghdr;
893
894 let ret = unsafe { raw_syscall_sendmsg(sock.as_raw_fd(), hdr_ptr as u64, effective_flags) };
901 if ret < 0 {
902 return Err(errno_from_negative_syscall_ret(ret));
903 }
904 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
905 Ok(SendMessageResult {
906 bytes_sent: ret as usize,
907 })
908}
909
910pub fn recvmsg(
944 sock: BorrowedFd<'_>,
945 request: &mut ReceiveMessageRequest<'_>,
946) -> Result<ReceiveMessageResult, Errno> {
947 let mut cmsg_buf = [0u8; 1024];
949 let mut addr_buf = RawSockaddrStorage {
950 bytes: [0u8; MAX_SOCKADDR_LEN],
951 };
952 #[allow(clippy::cast_possible_truncation)]
954 let mut addrlen: u32 = MAX_SOCKADDR_LEN as u32;
955
956 let iov_ptr: *mut IoSliceMut<'_> = request.iov.as_mut_ptr();
957 let addr_ptr: *mut u8 = addr_buf.bytes.as_mut_ptr();
958 let addrlen_ptr: *mut u32 = &mut addrlen;
959 let cmsg_ptr: *mut u8 = cmsg_buf.as_mut_ptr();
960
961 let mut msghdr = KernelMsghdr {
962 msg_name: addr_ptr as u64,
963 msg_namelen: addrlen,
964 _pad: 0,
965 msg_iov: iov_ptr as u64,
966 msg_iovlen: request.iov.len() as u64,
967 msg_control: cmsg_ptr as u64,
968 msg_controllen: cmsg_buf.len() as u64,
969 msg_flags: 0,
970 _pad2: 0,
971 };
972
973 #[allow(clippy::cast_sign_loss)]
974 let flags_u64 = request.flags.bits() as u64;
975 let hdr_ptr: *mut KernelMsghdr = &mut msghdr;
976
977 let ret = unsafe { raw_syscall_recvmsg(sock.as_raw_fd(), hdr_ptr as u64, flags_u64) };
986 if ret < 0 {
987 return Err(errno_from_negative_syscall_ret(ret));
988 }
989
990 let returned_addrlen = msghdr.msg_namelen;
992 #[allow(clippy::cast_possible_truncation)]
994 let returned_cmsg_len = msghdr.msg_controllen as usize;
995 let returned_flags_bits = msghdr.msg_flags;
997
998 let _ = addrlen_ptr; let address = raw_to_socket_addr(&addr_buf.bytes, returned_addrlen);
1001 let fds = parse_scm_rights(&cmsg_buf, returned_cmsg_len);
1002
1003 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
1004 let bytes_received = ret as usize;
1005
1006 let flags = MessageFlags::from_bits_truncate(returned_flags_bits);
1007
1008 Ok(ReceiveMessageResult {
1009 bytes_received,
1010 address,
1011 fds,
1012 flags,
1013 })
1014}
1015
1016pub fn shutdown(sock: BorrowedFd<'_>, mode: ShutdownMode) -> Result<(), Errno> {
1043 let how = mode as i32;
1044 let ret = unsafe { raw_syscall_shutdown(sock.as_raw_fd(), how) };
1048 if ret < 0 {
1049 return Err(errno_from_negative_syscall_ret(ret));
1050 }
1051 Ok(())
1052}
1053
1054pub fn getsockname(sock: BorrowedFd<'_>) -> Result<SocketAddr, Errno> {
1076 let mut addr_buf = RawSockaddrStorage {
1077 bytes: [0u8; MAX_SOCKADDR_LEN],
1078 };
1079 #[allow(clippy::cast_possible_truncation)]
1081 let mut addrlen: u32 = MAX_SOCKADDR_LEN as u32;
1082 let addr_ptr: *mut u8 = addr_buf.bytes.as_mut_ptr();
1083 let addrlen_ptr: *mut u32 = &mut addrlen;
1084 let ret =
1090 unsafe { raw_syscall_getsockname(sock.as_raw_fd(), addr_ptr as u64, addrlen_ptr as u64) };
1091 if ret < 0 {
1092 return Err(errno_from_negative_syscall_ret(ret));
1093 }
1094 raw_to_socket_addr(&addr_buf.bytes, addrlen).ok_or_else(|| {
1095 #[allow(clippy::unwrap_used)]
1097 Errno::from_nonzero(NonZeroI32::new(97).unwrap()) })
1099}
1100
1101pub fn getpeername(sock: BorrowedFd<'_>) -> Result<SocketAddr, Errno> {
1119 let mut addr_buf = RawSockaddrStorage {
1120 bytes: [0u8; MAX_SOCKADDR_LEN],
1121 };
1122 #[allow(clippy::cast_possible_truncation)]
1124 let mut addrlen: u32 = MAX_SOCKADDR_LEN as u32;
1125 let addr_ptr: *mut u8 = addr_buf.bytes.as_mut_ptr();
1126 let addrlen_ptr: *mut u32 = &mut addrlen;
1127 let ret =
1132 unsafe { raw_syscall_getpeername(sock.as_raw_fd(), addr_ptr as u64, addrlen_ptr as u64) };
1133 if ret < 0 {
1134 return Err(errno_from_negative_syscall_ret(ret));
1135 }
1136 raw_to_socket_addr(&addr_buf.bytes, addrlen).ok_or_else(|| {
1143 #[allow(clippy::unwrap_used)]
1144 Errno::from_nonzero(NonZeroI32::new(97).unwrap()) })
1146}
1147
1148pub fn socketpair(
1177 domain: SocketDomain,
1178 ty: SocketType,
1179 protocol: i32,
1180) -> Result<(AirOwnedFd, AirOwnedFd), Errno> {
1181 let mut sv = [0i32; 2];
1182 let sv_ptr: *mut i32 = sv.as_mut_ptr();
1183 let domain_raw = domain as i32;
1184 let ty_raw = (ty as i32) | SOCK_CLOEXEC;
1185 let ret = unsafe { raw_syscall_socketpair(domain_raw, ty_raw, protocol, sv_ptr as u64) };
1190 if ret < 0 {
1191 return Err(errno_from_negative_syscall_ret(ret));
1192 }
1193 let fd_a = unsafe { AirOwnedFd::from_raw_fd(sv[0]) };
1195 let fd_b = unsafe { AirOwnedFd::from_raw_fd(sv[1]) };
1196 Ok((fd_a, fd_b))
1197}
1198
1199pub fn get_so_keepalive(sock: BorrowedFd<'_>) -> Result<bool, Errno> {
1205 getsockopt_i32(sock, SOL_SOCKET, SO_KEEPALIVE).map(|v| v != 0)
1206}
1207
1208pub fn set_so_keepalive(sock: BorrowedFd<'_>, enable: bool) -> Result<(), Errno> {
1210 setsockopt_i32(sock, SOL_SOCKET, SO_KEEPALIVE, i32::from(enable))
1211}
1212
1213pub fn get_so_reuseaddr(sock: BorrowedFd<'_>) -> Result<bool, Errno> {
1215 getsockopt_i32(sock, SOL_SOCKET, SO_REUSEADDR).map(|v| v != 0)
1216}
1217
1218pub fn set_so_reuseaddr(sock: BorrowedFd<'_>, enable: bool) -> Result<(), Errno> {
1220 setsockopt_i32(sock, SOL_SOCKET, SO_REUSEADDR, i32::from(enable))
1221}
1222
1223pub fn get_so_reuseport(sock: BorrowedFd<'_>) -> Result<bool, Errno> {
1225 getsockopt_i32(sock, SOL_SOCKET, SO_REUSEPORT).map(|v| v != 0)
1226}
1227
1228pub fn set_so_reuseport(sock: BorrowedFd<'_>, enable: bool) -> Result<(), Errno> {
1230 setsockopt_i32(sock, SOL_SOCKET, SO_REUSEPORT, i32::from(enable))
1231}
1232
1233pub fn get_tcp_nodelay(sock: BorrowedFd<'_>) -> Result<bool, Errno> {
1235 getsockopt_i32(sock, IPPROTO_TCP, TCP_NODELAY).map(|v| v != 0)
1236}
1237
1238pub fn set_tcp_nodelay(sock: BorrowedFd<'_>, enable: bool) -> Result<(), Errno> {
1240 setsockopt_i32(sock, IPPROTO_TCP, TCP_NODELAY, i32::from(enable))
1241}
1242
1243pub fn get_so_rcvbuf(sock: BorrowedFd<'_>) -> Result<u32, Errno> {
1245 getsockopt_i32(sock, SOL_SOCKET, SO_RCVBUF).map(|v| {
1246 #[allow(clippy::cast_sign_loss)]
1248 let u = v as u32;
1249 u
1250 })
1251}
1252
1253pub fn set_so_rcvbuf(sock: BorrowedFd<'_>, size: u32) -> Result<(), Errno> {
1255 #[allow(clippy::cast_possible_truncation)]
1257 let val = if size > i32::MAX as u32 {
1258 i32::MAX
1259 } else {
1260 size as i32
1261 };
1262 setsockopt_i32(sock, SOL_SOCKET, SO_RCVBUF, val)
1263}
1264
1265pub fn get_so_sndbuf(sock: BorrowedFd<'_>) -> Result<u32, Errno> {
1267 getsockopt_i32(sock, SOL_SOCKET, SO_SNDBUF).map(|v| {
1268 #[allow(clippy::cast_sign_loss)]
1269 let u = v as u32;
1270 u
1271 })
1272}
1273
1274pub fn set_so_sndbuf(sock: BorrowedFd<'_>, size: u32) -> Result<(), Errno> {
1276 #[allow(clippy::cast_possible_truncation)]
1277 let val = if size > i32::MAX as u32 {
1278 i32::MAX
1279 } else {
1280 size as i32
1281 };
1282 setsockopt_i32(sock, SOL_SOCKET, SO_SNDBUF, val)
1283}
1284
1285pub fn get_so_error(sock: BorrowedFd<'_>) -> Result<Option<Errno>, Errno> {
1289 let val = getsockopt_i32(sock, SOL_SOCKET, SO_ERROR)?;
1290 if val == 0 {
1291 Ok(None)
1292 } else {
1293 let nz = NonZeroI32::new(val).ok_or_else(|| {
1294 #[allow(clippy::unwrap_used)]
1296 Errno::from_nonzero(NonZeroI32::new(22).unwrap()) })?;
1298 Ok(Some(Errno::from_nonzero(nz)))
1299 }
1300}
1301
1302pub fn get_so_peercred(sock: BorrowedFd<'_>) -> Result<UnixCredentials, Errno> {
1306 let mut cred = [0i32; 3];
1308 let mut length: u32 = 12;
1309 let cred_ptr: *mut i32 = cred.as_mut_ptr();
1310 let len_ptr: *mut u32 = &mut length;
1311 let ret = unsafe {
1316 raw_syscall_getsockopt(
1317 sock.as_raw_fd(),
1318 SOL_SOCKET,
1319 SO_PEERCRED,
1320 cred_ptr as u64,
1321 len_ptr as u64,
1322 )
1323 };
1324 if ret < 0 {
1325 return Err(errno_from_negative_syscall_ret(ret));
1326 }
1327 let pid_raw = cred[0];
1329 #[allow(clippy::cast_sign_loss)]
1330 let uid = cred[1] as u32;
1331 #[allow(clippy::cast_sign_loss)]
1332 let gid = cred[2] as u32;
1333 let nz = NonZeroI32::new(pid_raw).ok_or_else(|| {
1334 #[allow(clippy::unwrap_used)]
1335 Errno::from_nonzero(NonZeroI32::new(22).unwrap()) })?;
1337 Ok(UnixCredentials {
1338 pid: Pid::from_nonzero(nz),
1339 uid,
1340 gid,
1341 })
1342}
1343
1344pub fn get_so_linger(sock: BorrowedFd<'_>) -> Result<LingerOption, Errno> {
1346 let mut linger = [0i32; 2];
1348 let mut length: u32 = 8;
1349 let linger_ptr: *mut i32 = linger.as_mut_ptr();
1350 let len_ptr: *mut u32 = &mut length;
1351 let ret = unsafe {
1356 raw_syscall_getsockopt(
1357 sock.as_raw_fd(),
1358 SOL_SOCKET,
1359 SO_LINGER,
1360 linger_ptr as u64,
1361 len_ptr as u64,
1362 )
1363 };
1364 if ret < 0 {
1365 return Err(errno_from_negative_syscall_ret(ret));
1366 }
1367 if linger[0] == 0 {
1368 Ok(LingerOption::Disabled)
1369 } else {
1370 #[allow(clippy::cast_sign_loss)]
1371 let secs = linger[1] as u64;
1372 Ok(LingerOption::Enabled(core::time::Duration::from_secs(secs)))
1373 }
1374}
1375
1376pub fn set_so_linger(sock: BorrowedFd<'_>, linger: LingerOption) -> Result<(), Errno> {
1378 let (l_onoff, l_linger): (i32, i32) = match linger {
1379 LingerOption::Disabled => (0, 0),
1380 LingerOption::Enabled(d) => {
1381 let secs = d.as_secs();
1383 #[allow(clippy::cast_possible_truncation)]
1384 let secs_i32 = if secs > i32::MAX as u64 {
1385 i32::MAX
1386 } else {
1387 secs as i32
1388 };
1389 (1, secs_i32)
1390 }
1391 };
1392 let buffer = [l_onoff, l_linger];
1393 let buf_ptr: *const i32 = buffer.as_ptr();
1394 let length: u32 = 8;
1395 let ret = unsafe {
1400 raw_syscall_setsockopt(
1401 sock.as_raw_fd(),
1402 SOL_SOCKET,
1403 SO_LINGER,
1404 buf_ptr as u64,
1405 length,
1406 )
1407 };
1408 if ret < 0 {
1409 return Err(errno_from_negative_syscall_ret(ret));
1410 }
1411 Ok(())
1412}
1413
1414pub fn set_so_bindtodevice(sock: BorrowedFd<'_>, ifname: &CStr) -> Result<(), Errno> {
1416 let bytes = ifname.to_bytes_with_nul();
1417 let ptr: *const u8 = bytes.as_ptr();
1418 #[allow(clippy::cast_possible_truncation)]
1419 let length = bytes.len() as u32;
1420 let ret = unsafe {
1425 raw_syscall_setsockopt(
1426 sock.as_raw_fd(),
1427 SOL_SOCKET,
1428 SO_BINDTODEVICE,
1429 ptr as u64,
1430 length,
1431 )
1432 };
1433 if ret < 0 {
1434 return Err(errno_from_negative_syscall_ret(ret));
1435 }
1436 Ok(())
1437}
1438
1439pub fn get_so_bindtodevice(sock: BorrowedFd<'_>) -> Result<CString, Errno> {
1441 let mut buffer = [0u8; 16];
1443 let mut length: u32 = 16;
1444 let buf_ptr: *mut u8 = buffer.as_mut_ptr();
1445 let len_ptr: *mut u32 = &mut length;
1446 let ret = unsafe {
1451 raw_syscall_getsockopt(
1452 sock.as_raw_fd(),
1453 SOL_SOCKET,
1454 SO_BINDTODEVICE,
1455 buf_ptr as u64,
1456 len_ptr as u64,
1457 )
1458 };
1459 if ret < 0 {
1460 return Err(errno_from_negative_syscall_ret(ret));
1461 }
1462 let nul_pos = buffer
1464 .iter()
1465 .position(|&b| b == 0)
1466 .unwrap_or(length as usize);
1467 CString::new(&buffer[..nul_pos]).map_err(|_| {
1473 #[allow(clippy::unwrap_used)]
1474 Errno::from_nonzero(NonZeroI32::new(22).unwrap()) })
1476}
1477
1478pub fn set_tcp_keepidle(sock: BorrowedFd<'_>, seconds: u32) -> Result<(), Errno> {
1480 #[allow(clippy::cast_possible_truncation)]
1481 let val = if seconds > i32::MAX as u32 {
1482 i32::MAX
1483 } else {
1484 seconds as i32
1485 };
1486 setsockopt_i32(sock, IPPROTO_TCP, TCP_KEEPIDLE, val)
1487}
1488
1489pub fn set_tcp_keepintvl(sock: BorrowedFd<'_>, seconds: u32) -> Result<(), Errno> {
1491 #[allow(clippy::cast_possible_truncation)]
1492 let val = if seconds > i32::MAX as u32 {
1493 i32::MAX
1494 } else {
1495 seconds as i32
1496 };
1497 setsockopt_i32(sock, IPPROTO_TCP, TCP_KEEPINTVL, val)
1498}
1499
1500pub fn set_tcp_keepcnt(sock: BorrowedFd<'_>, count: u32) -> Result<(), Errno> {
1502 #[allow(clippy::cast_possible_truncation)]
1503 let val = if count > i32::MAX as u32 {
1504 i32::MAX
1505 } else {
1506 count as i32
1507 };
1508 setsockopt_i32(sock, IPPROTO_TCP, TCP_KEEPCNT, val)
1509}
1510
1511pub fn set_ip_ttl(sock: BorrowedFd<'_>, ttl: u8) -> Result<(), Errno> {
1513 setsockopt_i32(sock, IPPROTO_IP, IP_TTL, i32::from(ttl))
1514}
1515
1516pub fn set_ipv6_v6only(sock: BorrowedFd<'_>, v6only: bool) -> Result<(), Errno> {
1518 setsockopt_i32(sock, IPPROTO_IPV6, IPV6_V6ONLY, i32::from(v6only))
1519}
1520
1521fn decode_timeout(tv: Timeval) -> Option<Timeval> {
1535 if tv.tv_sec == 0 && tv.tv_usec == 0 {
1536 None
1537 } else {
1538 Some(tv)
1539 }
1540}
1541
1542fn set_socket_timeout(
1548 sock: BorrowedFd<'_>,
1549 optname: i32,
1550 timeout: Option<Timeval>,
1551) -> Result<(), Errno> {
1552 let tv = timeout.unwrap_or(Timeval {
1553 tv_sec: 0,
1554 tv_usec: 0,
1555 });
1556 let tv_ptr: *const Timeval = &tv;
1557 let ret = unsafe {
1563 raw_syscall_setsockopt(
1564 sock.as_raw_fd(),
1565 SOL_SOCKET,
1566 optname,
1567 tv_ptr as u64,
1568 TIMEVAL_LEN,
1569 )
1570 };
1571 if ret < 0 {
1572 return Err(errno_from_negative_syscall_ret(ret));
1573 }
1574 Ok(())
1575}
1576
1577fn get_socket_timeout(sock: BorrowedFd<'_>, optname: i32) -> Result<Option<Timeval>, Errno> {
1580 let mut tv = Timeval {
1581 tv_sec: 0,
1582 tv_usec: 0,
1583 };
1584 let mut length: u32 = TIMEVAL_LEN;
1585 let tv_ptr: *mut Timeval = &mut tv;
1586 let len_ptr: *mut u32 = &mut length;
1587 let ret = unsafe {
1593 raw_syscall_getsockopt(
1594 sock.as_raw_fd(),
1595 SOL_SOCKET,
1596 optname,
1597 tv_ptr as u64,
1598 len_ptr as u64,
1599 )
1600 };
1601 if ret < 0 {
1602 return Err(errno_from_negative_syscall_ret(ret));
1603 }
1604 Ok(decode_timeout(tv))
1605}
1606
1607pub fn set_receive_timeout(sock: BorrowedFd<'_>, timeout: Option<Timeval>) -> Result<(), Errno> {
1609 set_socket_timeout(sock, SO_RCVTIMEO, timeout)
1610}
1611
1612pub fn receive_timeout(sock: BorrowedFd<'_>) -> Result<Option<Timeval>, Errno> {
1614 get_socket_timeout(sock, SO_RCVTIMEO)
1615}
1616
1617pub fn set_send_timeout(sock: BorrowedFd<'_>, timeout: Option<Timeval>) -> Result<(), Errno> {
1619 set_socket_timeout(sock, SO_SNDTIMEO, timeout)
1620}
1621
1622pub fn send_timeout(sock: BorrowedFd<'_>) -> Result<Option<Timeval>, Errno> {
1624 get_socket_timeout(sock, SO_SNDTIMEO)
1625}
1626
1627fn set_ip_membership_v4(
1635 sock: BorrowedFd<'_>,
1636 optname: i32,
1637 membership: &IpMembershipV4,
1638) -> Result<(), Errno> {
1639 let ptr: *const IpMembershipV4 = membership;
1640 let ret = unsafe {
1646 raw_syscall_setsockopt(
1647 sock.as_raw_fd(),
1648 IPPROTO_IP,
1649 optname,
1650 ptr as u64,
1651 IP_MREQ_LEN,
1652 )
1653 };
1654 if ret < 0 {
1655 return Err(errno_from_negative_syscall_ret(ret));
1656 }
1657 Ok(())
1658}
1659
1660fn set_ip_membership_v6(
1663 sock: BorrowedFd<'_>,
1664 optname: i32,
1665 membership: &IpMembershipV6,
1666) -> Result<(), Errno> {
1667 let ptr: *const IpMembershipV6 = membership;
1668 let ret = unsafe {
1674 raw_syscall_setsockopt(
1675 sock.as_raw_fd(),
1676 IPPROTO_IPV6,
1677 optname,
1678 ptr as u64,
1679 IPV6_MREQ_LEN,
1680 )
1681 };
1682 if ret < 0 {
1683 return Err(errno_from_negative_syscall_ret(ret));
1684 }
1685 Ok(())
1686}
1687
1688pub fn join_multicast_v4(sock: BorrowedFd<'_>, membership: &IpMembershipV4) -> Result<(), Errno> {
1690 set_ip_membership_v4(sock, IP_ADD_MEMBERSHIP, membership)
1691}
1692
1693pub fn leave_multicast_v4(sock: BorrowedFd<'_>, membership: &IpMembershipV4) -> Result<(), Errno> {
1695 set_ip_membership_v4(sock, IP_DROP_MEMBERSHIP, membership)
1696}
1697
1698pub fn join_multicast_v6(sock: BorrowedFd<'_>, membership: &IpMembershipV6) -> Result<(), Errno> {
1700 set_ip_membership_v6(sock, IPV6_ADD_MEMBERSHIP, membership)
1701}
1702
1703pub fn leave_multicast_v6(sock: BorrowedFd<'_>, membership: &IpMembershipV6) -> Result<(), Errno> {
1705 set_ip_membership_v6(sock, IPV6_DROP_MEMBERSHIP, membership)
1706}
1707
1708#[cfg(target_arch = "x86_64")]
1713#[inline]
1714unsafe fn raw_syscall_socket(domain: i32, ty: i32, protocol: i32) -> i64 {
1715 let ret: i64;
1716 unsafe {
1718 core::arch::asm!(
1719 "syscall",
1720 in("rax") 41_i64,
1721 in("rdi") i64::from(domain),
1722 in("rsi") i64::from(ty),
1723 in("rdx") i64::from(protocol),
1724 lateout("rax") ret,
1725 lateout("rcx") _,
1726 lateout("r11") _,
1727 options(nostack, preserves_flags),
1728 );
1729 }
1730 ret
1731}
1732
1733#[cfg(target_arch = "x86_64")]
1734#[inline]
1735unsafe fn raw_syscall_bind(fd: i32, address: u64, addrlen: u32) -> i64 {
1736 let ret: i64;
1737 unsafe {
1739 core::arch::asm!(
1740 "syscall",
1741 in("rax") 49_i64,
1742 in("rdi") i64::from(fd),
1743 in("rsi") address,
1744 in("rdx") i64::from(addrlen),
1745 lateout("rax") ret,
1746 lateout("rcx") _,
1747 lateout("r11") _,
1748 options(nostack, preserves_flags),
1749 );
1750 }
1751 ret
1752}
1753
1754#[cfg(target_arch = "x86_64")]
1755#[inline]
1756unsafe fn raw_syscall_listen(fd: i32, backlog: i32) -> i64 {
1757 let ret: i64;
1758 unsafe {
1760 core::arch::asm!(
1761 "syscall",
1762 in("rax") 50_i64,
1763 in("rdi") i64::from(fd),
1764 in("rsi") i64::from(backlog),
1765 lateout("rax") ret,
1766 lateout("rcx") _,
1767 lateout("r11") _,
1768 options(nostack, preserves_flags),
1769 );
1770 }
1771 ret
1772}
1773
1774#[cfg(target_arch = "x86_64")]
1775#[inline]
1776unsafe fn raw_syscall_connect(fd: i32, address: u64, addrlen: u32) -> i64 {
1777 let ret: i64;
1778 unsafe {
1780 core::arch::asm!(
1781 "syscall",
1782 in("rax") 42_i64,
1783 in("rdi") i64::from(fd),
1784 in("rsi") address,
1785 in("rdx") i64::from(addrlen),
1786 lateout("rax") ret,
1787 lateout("rcx") _,
1788 lateout("r11") _,
1789 options(nostack, preserves_flags),
1790 );
1791 }
1792 ret
1793}
1794
1795#[cfg(target_arch = "x86_64")]
1796#[inline]
1797unsafe fn raw_syscall_accept4(fd: i32, address: u64, addrlen: u64, flags: i32) -> i64 {
1798 let ret: i64;
1799 unsafe {
1801 core::arch::asm!(
1802 "syscall",
1803 in("rax") 288_i64,
1804 in("rdi") i64::from(fd),
1805 in("rsi") address,
1806 in("rdx") addrlen,
1807 in("r10") i64::from(flags),
1808 lateout("rax") ret,
1809 lateout("rcx") _,
1810 lateout("r11") _,
1811 options(nostack, preserves_flags),
1812 );
1813 }
1814 ret
1815}
1816
1817#[cfg(target_arch = "x86_64")]
1818#[inline]
1819unsafe fn raw_syscall_sendto(
1820 fd: i32,
1821 buffer: u64,
1822 length: usize,
1823 flags: u64,
1824 address: u64,
1825 addrlen: u32,
1826) -> i64 {
1827 let ret: i64;
1828 unsafe {
1830 core::arch::asm!(
1831 "syscall",
1832 in("rax") 44_i64,
1833 in("rdi") i64::from(fd),
1834 in("rsi") buffer,
1835 in("rdx") length,
1836 in("r10") flags,
1837 in("r8") address,
1838 in("r9") i64::from(addrlen),
1839 lateout("rax") ret,
1840 lateout("rcx") _,
1841 lateout("r11") _,
1842 options(nostack, preserves_flags),
1843 );
1844 }
1845 ret
1846}
1847
1848#[cfg(target_arch = "x86_64")]
1849#[inline]
1850unsafe fn raw_syscall_recvfrom(
1851 fd: i32,
1852 buffer: u64,
1853 length: usize,
1854 flags: u64,
1855 address: u64,
1856 addrlen: u64,
1857) -> i64 {
1858 let ret: i64;
1859 unsafe {
1861 core::arch::asm!(
1862 "syscall",
1863 in("rax") 45_i64,
1864 in("rdi") i64::from(fd),
1865 in("rsi") buffer,
1866 in("rdx") length,
1867 in("r10") flags,
1868 in("r8") address,
1869 in("r9") addrlen,
1870 lateout("rax") ret,
1871 lateout("rcx") _,
1872 lateout("r11") _,
1873 options(nostack, preserves_flags),
1874 );
1875 }
1876 ret
1877}
1878
1879#[cfg(target_arch = "x86_64")]
1880#[inline]
1881unsafe fn raw_syscall_sendmsg(fd: i32, msghdr: u64, flags: u64) -> i64 {
1882 let ret: i64;
1883 unsafe {
1885 core::arch::asm!(
1886 "syscall",
1887 in("rax") 46_i64,
1888 in("rdi") i64::from(fd),
1889 in("rsi") msghdr,
1890 in("rdx") flags,
1891 lateout("rax") ret,
1892 lateout("rcx") _,
1893 lateout("r11") _,
1894 options(nostack, preserves_flags),
1895 );
1896 }
1897 ret
1898}
1899
1900#[cfg(target_arch = "x86_64")]
1901#[inline]
1902unsafe fn raw_syscall_recvmsg(fd: i32, msghdr: u64, flags: u64) -> i64 {
1903 let ret: i64;
1904 unsafe {
1906 core::arch::asm!(
1907 "syscall",
1908 in("rax") 47_i64,
1909 in("rdi") i64::from(fd),
1910 in("rsi") msghdr,
1911 in("rdx") flags,
1912 lateout("rax") ret,
1913 lateout("rcx") _,
1914 lateout("r11") _,
1915 options(nostack, preserves_flags),
1916 );
1917 }
1918 ret
1919}
1920
1921#[cfg(target_arch = "x86_64")]
1922#[inline]
1923unsafe fn raw_syscall_shutdown(fd: i32, how: i32) -> i64 {
1924 let ret: i64;
1925 unsafe {
1927 core::arch::asm!(
1928 "syscall",
1929 in("rax") 48_i64,
1930 in("rdi") i64::from(fd),
1931 in("rsi") i64::from(how),
1932 lateout("rax") ret,
1933 lateout("rcx") _,
1934 lateout("r11") _,
1935 options(nostack, preserves_flags),
1936 );
1937 }
1938 ret
1939}
1940
1941#[cfg(target_arch = "x86_64")]
1942#[inline]
1943unsafe fn raw_syscall_getsockname(fd: i32, address: u64, addrlen: u64) -> i64 {
1944 let ret: i64;
1945 unsafe {
1947 core::arch::asm!(
1948 "syscall",
1949 in("rax") 51_i64,
1950 in("rdi") i64::from(fd),
1951 in("rsi") address,
1952 in("rdx") addrlen,
1953 lateout("rax") ret,
1954 lateout("rcx") _,
1955 lateout("r11") _,
1956 options(nostack, preserves_flags),
1957 );
1958 }
1959 ret
1960}
1961
1962#[cfg(target_arch = "x86_64")]
1963#[inline]
1964unsafe fn raw_syscall_getpeername(fd: i32, address: u64, addrlen: u64) -> i64 {
1965 let ret: i64;
1966 unsafe {
1968 core::arch::asm!(
1969 "syscall",
1970 in("rax") 52_i64,
1971 in("rdi") i64::from(fd),
1972 in("rsi") address,
1973 in("rdx") addrlen,
1974 lateout("rax") ret,
1975 lateout("rcx") _,
1976 lateout("r11") _,
1977 options(nostack, preserves_flags),
1978 );
1979 }
1980 ret
1981}
1982
1983#[cfg(target_arch = "x86_64")]
1984#[inline]
1985unsafe fn raw_syscall_socketpair(domain: i32, ty: i32, protocol: i32, sv: u64) -> i64 {
1986 let ret: i64;
1987 unsafe {
1989 core::arch::asm!(
1990 "syscall",
1991 in("rax") 53_i64,
1992 in("rdi") i64::from(domain),
1993 in("rsi") i64::from(ty),
1994 in("rdx") i64::from(protocol),
1995 in("r10") sv,
1996 lateout("rax") ret,
1997 lateout("rcx") _,
1998 lateout("r11") _,
1999 options(nostack, preserves_flags),
2000 );
2001 }
2002 ret
2003}
2004
2005#[cfg(target_arch = "x86_64")]
2006#[inline]
2007unsafe fn raw_syscall_getsockopt(
2008 fd: i32,
2009 level: i32,
2010 optname: i32,
2011 optval: u64,
2012 optlen: u64,
2013) -> i64 {
2014 let ret: i64;
2015 unsafe {
2017 core::arch::asm!(
2018 "syscall",
2019 in("rax") 55_i64,
2020 in("rdi") i64::from(fd),
2021 in("rsi") i64::from(level),
2022 in("rdx") i64::from(optname),
2023 in("r10") optval,
2024 in("r8") optlen,
2025 lateout("rax") ret,
2026 lateout("rcx") _,
2027 lateout("r11") _,
2028 options(nostack, preserves_flags),
2029 );
2030 }
2031 ret
2032}
2033
2034#[cfg(target_arch = "x86_64")]
2035#[inline]
2036unsafe fn raw_syscall_setsockopt(
2037 fd: i32,
2038 level: i32,
2039 optname: i32,
2040 optval: u64,
2041 optlen: u32,
2042) -> i64 {
2043 let ret: i64;
2044 unsafe {
2046 core::arch::asm!(
2047 "syscall",
2048 in("rax") 54_i64,
2049 in("rdi") i64::from(fd),
2050 in("rsi") i64::from(level),
2051 in("rdx") i64::from(optname),
2052 in("r10") optval,
2053 in("r8") i64::from(optlen),
2054 lateout("rax") ret,
2055 lateout("rcx") _,
2056 lateout("r11") _,
2057 options(nostack, preserves_flags),
2058 );
2059 }
2060 ret
2061}
2062
2063#[cfg(target_arch = "aarch64")]
2068#[inline]
2069unsafe fn raw_syscall_socket(domain: i32, ty: i32, protocol: i32) -> i64 {
2070 let ret: i64;
2071 unsafe {
2073 core::arch::asm!(
2074 "svc 0",
2075 in("x8") 198_i64,
2076 inout("x0") i64::from(domain) => ret,
2077 in("x1") i64::from(ty),
2078 in("x2") i64::from(protocol),
2079 options(nostack, preserves_flags),
2080 );
2081 }
2082 ret
2083}
2084
2085#[cfg(target_arch = "aarch64")]
2086#[inline]
2087unsafe fn raw_syscall_bind(fd: i32, address: u64, addrlen: u32) -> i64 {
2088 let ret: i64;
2089 unsafe {
2091 core::arch::asm!(
2092 "svc 0",
2093 in("x8") 200_i64,
2094 inout("x0") i64::from(fd) => ret,
2095 in("x1") address,
2096 in("x2") i64::from(addrlen),
2097 options(nostack, preserves_flags),
2098 );
2099 }
2100 ret
2101}
2102
2103#[cfg(target_arch = "aarch64")]
2104#[inline]
2105unsafe fn raw_syscall_listen(fd: i32, backlog: i32) -> i64 {
2106 let ret: i64;
2107 unsafe {
2109 core::arch::asm!(
2110 "svc 0",
2111 in("x8") 201_i64,
2112 inout("x0") i64::from(fd) => ret,
2113 in("x1") i64::from(backlog),
2114 options(nostack, preserves_flags),
2115 );
2116 }
2117 ret
2118}
2119
2120#[cfg(target_arch = "aarch64")]
2121#[inline]
2122unsafe fn raw_syscall_connect(fd: i32, address: u64, addrlen: u32) -> i64 {
2123 let ret: i64;
2124 unsafe {
2126 core::arch::asm!(
2127 "svc 0",
2128 in("x8") 203_i64,
2129 inout("x0") i64::from(fd) => ret,
2130 in("x1") address,
2131 in("x2") i64::from(addrlen),
2132 options(nostack, preserves_flags),
2133 );
2134 }
2135 ret
2136}
2137
2138#[cfg(target_arch = "aarch64")]
2139#[inline]
2140unsafe fn raw_syscall_accept4(fd: i32, address: u64, addrlen: u64, flags: i32) -> i64 {
2141 let ret: i64;
2142 unsafe {
2144 core::arch::asm!(
2145 "svc 0",
2146 in("x8") 242_i64,
2147 inout("x0") i64::from(fd) => ret,
2148 in("x1") address,
2149 in("x2") addrlen,
2150 in("x3") i64::from(flags),
2151 options(nostack, preserves_flags),
2152 );
2153 }
2154 ret
2155}
2156
2157#[cfg(target_arch = "aarch64")]
2158#[inline]
2159unsafe fn raw_syscall_sendto(
2160 fd: i32,
2161 buffer: u64,
2162 length: usize,
2163 flags: u64,
2164 address: u64,
2165 addrlen: u32,
2166) -> i64 {
2167 let ret: i64;
2168 unsafe {
2170 core::arch::asm!(
2171 "svc 0",
2172 in("x8") 206_i64,
2173 inout("x0") i64::from(fd) => ret,
2174 in("x1") buffer,
2175 in("x2") length,
2176 in("x3") flags,
2177 in("x4") address,
2178 in("x5") i64::from(addrlen),
2179 options(nostack, preserves_flags),
2180 );
2181 }
2182 ret
2183}
2184
2185#[cfg(target_arch = "aarch64")]
2186#[inline]
2187unsafe fn raw_syscall_recvfrom(
2188 fd: i32,
2189 buffer: u64,
2190 length: usize,
2191 flags: u64,
2192 address: u64,
2193 addrlen: u64,
2194) -> i64 {
2195 let ret: i64;
2196 unsafe {
2198 core::arch::asm!(
2199 "svc 0",
2200 in("x8") 207_i64,
2201 inout("x0") i64::from(fd) => ret,
2202 in("x1") buffer,
2203 in("x2") length,
2204 in("x3") flags,
2205 in("x4") address,
2206 in("x5") addrlen,
2207 options(nostack, preserves_flags),
2208 );
2209 }
2210 ret
2211}
2212
2213#[cfg(target_arch = "aarch64")]
2214#[inline]
2215unsafe fn raw_syscall_sendmsg(fd: i32, msghdr: u64, flags: u64) -> i64 {
2216 let ret: i64;
2217 unsafe {
2219 core::arch::asm!(
2220 "svc 0",
2221 in("x8") 211_i64,
2222 inout("x0") i64::from(fd) => ret,
2223 in("x1") msghdr,
2224 in("x2") flags,
2225 options(nostack, preserves_flags),
2226 );
2227 }
2228 ret
2229}
2230
2231#[cfg(target_arch = "aarch64")]
2232#[inline]
2233unsafe fn raw_syscall_recvmsg(fd: i32, msghdr: u64, flags: u64) -> i64 {
2234 let ret: i64;
2235 unsafe {
2237 core::arch::asm!(
2238 "svc 0",
2239 in("x8") 212_i64,
2240 inout("x0") i64::from(fd) => ret,
2241 in("x1") msghdr,
2242 in("x2") flags,
2243 options(nostack, preserves_flags),
2244 );
2245 }
2246 ret
2247}
2248
2249#[cfg(target_arch = "aarch64")]
2250#[inline]
2251unsafe fn raw_syscall_shutdown(fd: i32, how: i32) -> i64 {
2252 let ret: i64;
2253 unsafe {
2255 core::arch::asm!(
2256 "svc 0",
2257 in("x8") 210_i64,
2258 inout("x0") i64::from(fd) => ret,
2259 in("x1") i64::from(how),
2260 options(nostack, preserves_flags),
2261 );
2262 }
2263 ret
2264}
2265
2266#[cfg(target_arch = "aarch64")]
2267#[inline]
2268unsafe fn raw_syscall_getsockname(fd: i32, address: u64, addrlen: u64) -> i64 {
2269 let ret: i64;
2270 unsafe {
2272 core::arch::asm!(
2273 "svc 0",
2274 in("x8") 204_i64,
2275 inout("x0") i64::from(fd) => ret,
2276 in("x1") address,
2277 in("x2") addrlen,
2278 options(nostack, preserves_flags),
2279 );
2280 }
2281 ret
2282}
2283
2284#[cfg(target_arch = "aarch64")]
2285#[inline]
2286unsafe fn raw_syscall_getpeername(fd: i32, address: u64, addrlen: u64) -> i64 {
2287 let ret: i64;
2288 unsafe {
2290 core::arch::asm!(
2291 "svc 0",
2292 in("x8") 205_i64,
2293 inout("x0") i64::from(fd) => ret,
2294 in("x1") address,
2295 in("x2") addrlen,
2296 options(nostack, preserves_flags),
2297 );
2298 }
2299 ret
2300}
2301
2302#[cfg(target_arch = "aarch64")]
2303#[inline]
2304unsafe fn raw_syscall_socketpair(domain: i32, ty: i32, protocol: i32, sv: u64) -> i64 {
2305 let ret: i64;
2306 unsafe {
2308 core::arch::asm!(
2309 "svc 0",
2310 in("x8") 199_i64,
2311 inout("x0") i64::from(domain) => ret,
2312 in("x1") i64::from(ty),
2313 in("x2") i64::from(protocol),
2314 in("x3") sv,
2315 options(nostack, preserves_flags),
2316 );
2317 }
2318 ret
2319}
2320
2321#[cfg(target_arch = "aarch64")]
2322#[inline]
2323unsafe fn raw_syscall_getsockopt(
2324 fd: i32,
2325 level: i32,
2326 optname: i32,
2327 optval: u64,
2328 optlen: u64,
2329) -> i64 {
2330 let ret: i64;
2331 unsafe {
2333 core::arch::asm!(
2334 "svc 0",
2335 in("x8") 209_i64,
2336 inout("x0") i64::from(fd) => ret,
2337 in("x1") i64::from(level),
2338 in("x2") i64::from(optname),
2339 in("x3") optval,
2340 in("x4") optlen,
2341 options(nostack, preserves_flags),
2342 );
2343 }
2344 ret
2345}
2346
2347#[cfg(target_arch = "aarch64")]
2348#[inline]
2349unsafe fn raw_syscall_setsockopt(
2350 fd: i32,
2351 level: i32,
2352 optname: i32,
2353 optval: u64,
2354 optlen: u32,
2355) -> i64 {
2356 let ret: i64;
2357 unsafe {
2359 core::arch::asm!(
2360 "svc 0",
2361 in("x8") 208_i64,
2362 inout("x0") i64::from(fd) => ret,
2363 in("x1") i64::from(level),
2364 in("x2") i64::from(optname),
2365 in("x3") optval,
2366 in("x4") i64::from(optlen),
2367 options(nostack, preserves_flags),
2368 );
2369 }
2370 ret
2371}
2372
2373#[cfg(all(test, target_os = "linux"))]
2378mod tests;