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]) };
1198 Ok((fd_a, fd_b))
1199}
1200
1201pub fn get_so_keepalive(sock: BorrowedFd<'_>) -> Result<bool, Errno> {
1207 getsockopt_i32(sock, SOL_SOCKET, SO_KEEPALIVE).map(|v| v != 0)
1208}
1209
1210pub fn set_so_keepalive(sock: BorrowedFd<'_>, enable: bool) -> Result<(), Errno> {
1212 setsockopt_i32(sock, SOL_SOCKET, SO_KEEPALIVE, i32::from(enable))
1213}
1214
1215pub fn get_so_reuseaddr(sock: BorrowedFd<'_>) -> Result<bool, Errno> {
1217 getsockopt_i32(sock, SOL_SOCKET, SO_REUSEADDR).map(|v| v != 0)
1218}
1219
1220pub fn set_so_reuseaddr(sock: BorrowedFd<'_>, enable: bool) -> Result<(), Errno> {
1222 setsockopt_i32(sock, SOL_SOCKET, SO_REUSEADDR, i32::from(enable))
1223}
1224
1225pub fn get_so_reuseport(sock: BorrowedFd<'_>) -> Result<bool, Errno> {
1227 getsockopt_i32(sock, SOL_SOCKET, SO_REUSEPORT).map(|v| v != 0)
1228}
1229
1230pub fn set_so_reuseport(sock: BorrowedFd<'_>, enable: bool) -> Result<(), Errno> {
1232 setsockopt_i32(sock, SOL_SOCKET, SO_REUSEPORT, i32::from(enable))
1233}
1234
1235pub fn get_tcp_nodelay(sock: BorrowedFd<'_>) -> Result<bool, Errno> {
1237 getsockopt_i32(sock, IPPROTO_TCP, TCP_NODELAY).map(|v| v != 0)
1238}
1239
1240pub fn set_tcp_nodelay(sock: BorrowedFd<'_>, enable: bool) -> Result<(), Errno> {
1242 setsockopt_i32(sock, IPPROTO_TCP, TCP_NODELAY, i32::from(enable))
1243}
1244
1245pub fn get_so_rcvbuf(sock: BorrowedFd<'_>) -> Result<u32, Errno> {
1247 getsockopt_i32(sock, SOL_SOCKET, SO_RCVBUF).map(|v| {
1248 #[allow(clippy::cast_sign_loss)]
1250 let u = v as u32;
1251 u
1252 })
1253}
1254
1255pub fn set_so_rcvbuf(sock: BorrowedFd<'_>, size: u32) -> Result<(), Errno> {
1257 #[allow(clippy::cast_possible_truncation)]
1259 let val = if size > i32::MAX as u32 {
1260 i32::MAX
1261 } else {
1262 size as i32
1263 };
1264 setsockopt_i32(sock, SOL_SOCKET, SO_RCVBUF, val)
1265}
1266
1267pub fn get_so_sndbuf(sock: BorrowedFd<'_>) -> Result<u32, Errno> {
1269 getsockopt_i32(sock, SOL_SOCKET, SO_SNDBUF).map(|v| {
1270 #[allow(clippy::cast_sign_loss)]
1271 let u = v as u32;
1272 u
1273 })
1274}
1275
1276pub fn set_so_sndbuf(sock: BorrowedFd<'_>, size: u32) -> Result<(), Errno> {
1278 #[allow(clippy::cast_possible_truncation)]
1279 let val = if size > i32::MAX as u32 {
1280 i32::MAX
1281 } else {
1282 size as i32
1283 };
1284 setsockopt_i32(sock, SOL_SOCKET, SO_SNDBUF, val)
1285}
1286
1287pub fn get_so_error(sock: BorrowedFd<'_>) -> Result<Option<Errno>, Errno> {
1291 let val = getsockopt_i32(sock, SOL_SOCKET, SO_ERROR)?;
1292 if val == 0 {
1293 Ok(None)
1294 } else {
1295 let nz = NonZeroI32::new(val).ok_or_else(|| {
1296 #[allow(clippy::unwrap_used)]
1298 Errno::from_nonzero(NonZeroI32::new(22).unwrap()) })?;
1300 Ok(Some(Errno::from_nonzero(nz)))
1301 }
1302}
1303
1304pub fn get_so_peercred(sock: BorrowedFd<'_>) -> Result<UnixCredentials, Errno> {
1308 let mut cred = [0i32; 3];
1310 let mut length: u32 = 12;
1311 let cred_ptr: *mut i32 = cred.as_mut_ptr();
1312 let len_ptr: *mut u32 = &mut length;
1313 let ret = unsafe {
1318 raw_syscall_getsockopt(
1319 sock.as_raw_fd(),
1320 SOL_SOCKET,
1321 SO_PEERCRED,
1322 cred_ptr as u64,
1323 len_ptr as u64,
1324 )
1325 };
1326 if ret < 0 {
1327 return Err(errno_from_negative_syscall_ret(ret));
1328 }
1329 let pid_raw = cred[0];
1331 #[allow(clippy::cast_sign_loss)]
1332 let uid = cred[1] as u32;
1333 #[allow(clippy::cast_sign_loss)]
1334 let gid = cred[2] as u32;
1335 let nz = NonZeroI32::new(pid_raw).ok_or_else(|| {
1336 #[allow(clippy::unwrap_used)]
1337 Errno::from_nonzero(NonZeroI32::new(22).unwrap()) })?;
1339 Ok(UnixCredentials {
1340 pid: Pid::from_nonzero(nz),
1341 uid,
1342 gid,
1343 })
1344}
1345
1346pub fn get_so_linger(sock: BorrowedFd<'_>) -> Result<LingerOption, Errno> {
1348 let mut linger = [0i32; 2];
1350 let mut length: u32 = 8;
1351 let linger_ptr: *mut i32 = linger.as_mut_ptr();
1352 let len_ptr: *mut u32 = &mut length;
1353 let ret = unsafe {
1358 raw_syscall_getsockopt(
1359 sock.as_raw_fd(),
1360 SOL_SOCKET,
1361 SO_LINGER,
1362 linger_ptr as u64,
1363 len_ptr as u64,
1364 )
1365 };
1366 if ret < 0 {
1367 return Err(errno_from_negative_syscall_ret(ret));
1368 }
1369 if linger[0] == 0 {
1370 Ok(LingerOption::Disabled)
1371 } else {
1372 #[allow(clippy::cast_sign_loss)]
1373 let secs = linger[1] as u64;
1374 Ok(LingerOption::Enabled(core::time::Duration::from_secs(secs)))
1375 }
1376}
1377
1378pub fn set_so_linger(sock: BorrowedFd<'_>, linger: LingerOption) -> Result<(), Errno> {
1380 let (l_onoff, l_linger): (i32, i32) = match linger {
1381 LingerOption::Disabled => (0, 0),
1382 LingerOption::Enabled(d) => {
1383 let secs = d.as_secs();
1385 #[allow(clippy::cast_possible_truncation)]
1386 let secs_i32 = if secs > i32::MAX as u64 {
1387 i32::MAX
1388 } else {
1389 secs as i32
1390 };
1391 (1, secs_i32)
1392 }
1393 };
1394 let buffer = [l_onoff, l_linger];
1395 let buf_ptr: *const i32 = buffer.as_ptr();
1396 let length: u32 = 8;
1397 let ret = unsafe {
1402 raw_syscall_setsockopt(
1403 sock.as_raw_fd(),
1404 SOL_SOCKET,
1405 SO_LINGER,
1406 buf_ptr as u64,
1407 length,
1408 )
1409 };
1410 if ret < 0 {
1411 return Err(errno_from_negative_syscall_ret(ret));
1412 }
1413 Ok(())
1414}
1415
1416pub fn set_so_bindtodevice(sock: BorrowedFd<'_>, ifname: &CStr) -> Result<(), Errno> {
1418 let bytes = ifname.to_bytes_with_nul();
1419 let ptr: *const u8 = bytes.as_ptr();
1420 #[allow(clippy::cast_possible_truncation)]
1421 let length = bytes.len() as u32;
1422 let ret = unsafe {
1427 raw_syscall_setsockopt(
1428 sock.as_raw_fd(),
1429 SOL_SOCKET,
1430 SO_BINDTODEVICE,
1431 ptr as u64,
1432 length,
1433 )
1434 };
1435 if ret < 0 {
1436 return Err(errno_from_negative_syscall_ret(ret));
1437 }
1438 Ok(())
1439}
1440
1441pub fn get_so_bindtodevice(sock: BorrowedFd<'_>) -> Result<CString, Errno> {
1443 let mut buffer = [0u8; 16];
1445 let mut length: u32 = 16;
1446 let buf_ptr: *mut u8 = buffer.as_mut_ptr();
1447 let len_ptr: *mut u32 = &mut length;
1448 let ret = unsafe {
1453 raw_syscall_getsockopt(
1454 sock.as_raw_fd(),
1455 SOL_SOCKET,
1456 SO_BINDTODEVICE,
1457 buf_ptr as u64,
1458 len_ptr as u64,
1459 )
1460 };
1461 if ret < 0 {
1462 return Err(errno_from_negative_syscall_ret(ret));
1463 }
1464 let nul_pos = buffer
1466 .iter()
1467 .position(|&b| b == 0)
1468 .unwrap_or(length as usize);
1469 CString::new(&buffer[..nul_pos]).map_err(|_| {
1475 #[allow(clippy::unwrap_used)]
1476 Errno::from_nonzero(NonZeroI32::new(22).unwrap()) })
1478}
1479
1480pub fn set_tcp_keepidle(sock: BorrowedFd<'_>, seconds: u32) -> Result<(), Errno> {
1482 #[allow(clippy::cast_possible_truncation)]
1483 let val = if seconds > i32::MAX as u32 {
1484 i32::MAX
1485 } else {
1486 seconds as i32
1487 };
1488 setsockopt_i32(sock, IPPROTO_TCP, TCP_KEEPIDLE, val)
1489}
1490
1491pub fn set_tcp_keepintvl(sock: BorrowedFd<'_>, seconds: u32) -> Result<(), Errno> {
1493 #[allow(clippy::cast_possible_truncation)]
1494 let val = if seconds > i32::MAX as u32 {
1495 i32::MAX
1496 } else {
1497 seconds as i32
1498 };
1499 setsockopt_i32(sock, IPPROTO_TCP, TCP_KEEPINTVL, val)
1500}
1501
1502pub fn set_tcp_keepcnt(sock: BorrowedFd<'_>, count: u32) -> Result<(), Errno> {
1504 #[allow(clippy::cast_possible_truncation)]
1505 let val = if count > i32::MAX as u32 {
1506 i32::MAX
1507 } else {
1508 count as i32
1509 };
1510 setsockopt_i32(sock, IPPROTO_TCP, TCP_KEEPCNT, val)
1511}
1512
1513pub fn set_ip_ttl(sock: BorrowedFd<'_>, ttl: u8) -> Result<(), Errno> {
1515 setsockopt_i32(sock, IPPROTO_IP, IP_TTL, i32::from(ttl))
1516}
1517
1518pub fn set_ipv6_v6only(sock: BorrowedFd<'_>, v6only: bool) -> Result<(), Errno> {
1520 setsockopt_i32(sock, IPPROTO_IPV6, IPV6_V6ONLY, i32::from(v6only))
1521}
1522
1523fn decode_timeout(tv: Timeval) -> Option<Timeval> {
1537 if tv.tv_sec == 0 && tv.tv_usec == 0 {
1538 None
1539 } else {
1540 Some(tv)
1541 }
1542}
1543
1544fn set_socket_timeout(
1550 sock: BorrowedFd<'_>,
1551 optname: i32,
1552 timeout: Option<Timeval>,
1553) -> Result<(), Errno> {
1554 let tv = timeout.unwrap_or(Timeval {
1555 tv_sec: 0,
1556 tv_usec: 0,
1557 });
1558 let tv_ptr: *const Timeval = &tv;
1559 let ret = unsafe {
1565 raw_syscall_setsockopt(
1566 sock.as_raw_fd(),
1567 SOL_SOCKET,
1568 optname,
1569 tv_ptr as u64,
1570 TIMEVAL_LEN,
1571 )
1572 };
1573 if ret < 0 {
1574 return Err(errno_from_negative_syscall_ret(ret));
1575 }
1576 Ok(())
1577}
1578
1579fn get_socket_timeout(sock: BorrowedFd<'_>, optname: i32) -> Result<Option<Timeval>, Errno> {
1582 let mut tv = Timeval {
1583 tv_sec: 0,
1584 tv_usec: 0,
1585 };
1586 let mut length: u32 = TIMEVAL_LEN;
1587 let tv_ptr: *mut Timeval = &mut tv;
1588 let len_ptr: *mut u32 = &mut length;
1589 let ret = unsafe {
1595 raw_syscall_getsockopt(
1596 sock.as_raw_fd(),
1597 SOL_SOCKET,
1598 optname,
1599 tv_ptr as u64,
1600 len_ptr as u64,
1601 )
1602 };
1603 if ret < 0 {
1604 return Err(errno_from_negative_syscall_ret(ret));
1605 }
1606 Ok(decode_timeout(tv))
1607}
1608
1609pub fn set_receive_timeout(sock: BorrowedFd<'_>, timeout: Option<Timeval>) -> Result<(), Errno> {
1611 set_socket_timeout(sock, SO_RCVTIMEO, timeout)
1612}
1613
1614pub fn receive_timeout(sock: BorrowedFd<'_>) -> Result<Option<Timeval>, Errno> {
1616 get_socket_timeout(sock, SO_RCVTIMEO)
1617}
1618
1619pub fn set_send_timeout(sock: BorrowedFd<'_>, timeout: Option<Timeval>) -> Result<(), Errno> {
1621 set_socket_timeout(sock, SO_SNDTIMEO, timeout)
1622}
1623
1624pub fn send_timeout(sock: BorrowedFd<'_>) -> Result<Option<Timeval>, Errno> {
1626 get_socket_timeout(sock, SO_SNDTIMEO)
1627}
1628
1629fn set_ip_membership_v4(
1637 sock: BorrowedFd<'_>,
1638 optname: i32,
1639 membership: &IpMembershipV4,
1640) -> Result<(), Errno> {
1641 let ptr: *const IpMembershipV4 = membership;
1642 let ret = unsafe {
1648 raw_syscall_setsockopt(
1649 sock.as_raw_fd(),
1650 IPPROTO_IP,
1651 optname,
1652 ptr as u64,
1653 IP_MREQ_LEN,
1654 )
1655 };
1656 if ret < 0 {
1657 return Err(errno_from_negative_syscall_ret(ret));
1658 }
1659 Ok(())
1660}
1661
1662fn set_ip_membership_v6(
1665 sock: BorrowedFd<'_>,
1666 optname: i32,
1667 membership: &IpMembershipV6,
1668) -> Result<(), Errno> {
1669 let ptr: *const IpMembershipV6 = membership;
1670 let ret = unsafe {
1676 raw_syscall_setsockopt(
1677 sock.as_raw_fd(),
1678 IPPROTO_IPV6,
1679 optname,
1680 ptr as u64,
1681 IPV6_MREQ_LEN,
1682 )
1683 };
1684 if ret < 0 {
1685 return Err(errno_from_negative_syscall_ret(ret));
1686 }
1687 Ok(())
1688}
1689
1690pub fn join_multicast_v4(sock: BorrowedFd<'_>, membership: &IpMembershipV4) -> Result<(), Errno> {
1692 set_ip_membership_v4(sock, IP_ADD_MEMBERSHIP, membership)
1693}
1694
1695pub fn leave_multicast_v4(sock: BorrowedFd<'_>, membership: &IpMembershipV4) -> Result<(), Errno> {
1697 set_ip_membership_v4(sock, IP_DROP_MEMBERSHIP, membership)
1698}
1699
1700pub fn join_multicast_v6(sock: BorrowedFd<'_>, membership: &IpMembershipV6) -> Result<(), Errno> {
1702 set_ip_membership_v6(sock, IPV6_ADD_MEMBERSHIP, membership)
1703}
1704
1705pub fn leave_multicast_v6(sock: BorrowedFd<'_>, membership: &IpMembershipV6) -> Result<(), Errno> {
1707 set_ip_membership_v6(sock, IPV6_DROP_MEMBERSHIP, membership)
1708}
1709
1710#[cfg(target_arch = "x86_64")]
1715#[inline]
1716unsafe fn raw_syscall_socket(domain: i32, ty: i32, protocol: i32) -> i64 {
1717 let ret: i64;
1718 unsafe {
1720 core::arch::asm!(
1721 "syscall",
1722 in("rax") 41_i64,
1723 in("rdi") i64::from(domain),
1724 in("rsi") i64::from(ty),
1725 in("rdx") i64::from(protocol),
1726 lateout("rax") ret,
1727 lateout("rcx") _,
1728 lateout("r11") _,
1729 options(nostack, preserves_flags),
1730 );
1731 }
1732 ret
1733}
1734
1735#[cfg(target_arch = "x86_64")]
1736#[inline]
1737unsafe fn raw_syscall_bind(fd: i32, address: u64, addrlen: u32) -> i64 {
1738 let ret: i64;
1739 unsafe {
1741 core::arch::asm!(
1742 "syscall",
1743 in("rax") 49_i64,
1744 in("rdi") i64::from(fd),
1745 in("rsi") address,
1746 in("rdx") i64::from(addrlen),
1747 lateout("rax") ret,
1748 lateout("rcx") _,
1749 lateout("r11") _,
1750 options(nostack, preserves_flags),
1751 );
1752 }
1753 ret
1754}
1755
1756#[cfg(target_arch = "x86_64")]
1757#[inline]
1758unsafe fn raw_syscall_listen(fd: i32, backlog: i32) -> i64 {
1759 let ret: i64;
1760 unsafe {
1762 core::arch::asm!(
1763 "syscall",
1764 in("rax") 50_i64,
1765 in("rdi") i64::from(fd),
1766 in("rsi") i64::from(backlog),
1767 lateout("rax") ret,
1768 lateout("rcx") _,
1769 lateout("r11") _,
1770 options(nostack, preserves_flags),
1771 );
1772 }
1773 ret
1774}
1775
1776#[cfg(target_arch = "x86_64")]
1777#[inline]
1778unsafe fn raw_syscall_connect(fd: i32, address: u64, addrlen: u32) -> i64 {
1779 let ret: i64;
1780 unsafe {
1782 core::arch::asm!(
1783 "syscall",
1784 in("rax") 42_i64,
1785 in("rdi") i64::from(fd),
1786 in("rsi") address,
1787 in("rdx") i64::from(addrlen),
1788 lateout("rax") ret,
1789 lateout("rcx") _,
1790 lateout("r11") _,
1791 options(nostack, preserves_flags),
1792 );
1793 }
1794 ret
1795}
1796
1797#[cfg(target_arch = "x86_64")]
1798#[inline]
1799unsafe fn raw_syscall_accept4(fd: i32, address: u64, addrlen: u64, flags: i32) -> i64 {
1800 let ret: i64;
1801 unsafe {
1803 core::arch::asm!(
1804 "syscall",
1805 in("rax") 288_i64,
1806 in("rdi") i64::from(fd),
1807 in("rsi") address,
1808 in("rdx") addrlen,
1809 in("r10") i64::from(flags),
1810 lateout("rax") ret,
1811 lateout("rcx") _,
1812 lateout("r11") _,
1813 options(nostack, preserves_flags),
1814 );
1815 }
1816 ret
1817}
1818
1819#[cfg(target_arch = "x86_64")]
1820#[inline]
1821unsafe fn raw_syscall_sendto(
1822 fd: i32,
1823 buffer: u64,
1824 length: usize,
1825 flags: u64,
1826 address: u64,
1827 addrlen: u32,
1828) -> i64 {
1829 let ret: i64;
1830 unsafe {
1832 core::arch::asm!(
1833 "syscall",
1834 in("rax") 44_i64,
1835 in("rdi") i64::from(fd),
1836 in("rsi") buffer,
1837 in("rdx") length,
1838 in("r10") flags,
1839 in("r8") address,
1840 in("r9") i64::from(addrlen),
1841 lateout("rax") ret,
1842 lateout("rcx") _,
1843 lateout("r11") _,
1844 options(nostack, preserves_flags),
1845 );
1846 }
1847 ret
1848}
1849
1850#[cfg(target_arch = "x86_64")]
1851#[inline]
1852unsafe fn raw_syscall_recvfrom(
1853 fd: i32,
1854 buffer: u64,
1855 length: usize,
1856 flags: u64,
1857 address: u64,
1858 addrlen: u64,
1859) -> i64 {
1860 let ret: i64;
1861 unsafe {
1863 core::arch::asm!(
1864 "syscall",
1865 in("rax") 45_i64,
1866 in("rdi") i64::from(fd),
1867 in("rsi") buffer,
1868 in("rdx") length,
1869 in("r10") flags,
1870 in("r8") address,
1871 in("r9") addrlen,
1872 lateout("rax") ret,
1873 lateout("rcx") _,
1874 lateout("r11") _,
1875 options(nostack, preserves_flags),
1876 );
1877 }
1878 ret
1879}
1880
1881#[cfg(target_arch = "x86_64")]
1882#[inline]
1883unsafe fn raw_syscall_sendmsg(fd: i32, msghdr: u64, flags: u64) -> i64 {
1884 let ret: i64;
1885 unsafe {
1887 core::arch::asm!(
1888 "syscall",
1889 in("rax") 46_i64,
1890 in("rdi") i64::from(fd),
1891 in("rsi") msghdr,
1892 in("rdx") flags,
1893 lateout("rax") ret,
1894 lateout("rcx") _,
1895 lateout("r11") _,
1896 options(nostack, preserves_flags),
1897 );
1898 }
1899 ret
1900}
1901
1902#[cfg(target_arch = "x86_64")]
1903#[inline]
1904unsafe fn raw_syscall_recvmsg(fd: i32, msghdr: u64, flags: u64) -> i64 {
1905 let ret: i64;
1906 unsafe {
1908 core::arch::asm!(
1909 "syscall",
1910 in("rax") 47_i64,
1911 in("rdi") i64::from(fd),
1912 in("rsi") msghdr,
1913 in("rdx") flags,
1914 lateout("rax") ret,
1915 lateout("rcx") _,
1916 lateout("r11") _,
1917 options(nostack, preserves_flags),
1918 );
1919 }
1920 ret
1921}
1922
1923#[cfg(target_arch = "x86_64")]
1924#[inline]
1925unsafe fn raw_syscall_shutdown(fd: i32, how: i32) -> i64 {
1926 let ret: i64;
1927 unsafe {
1929 core::arch::asm!(
1930 "syscall",
1931 in("rax") 48_i64,
1932 in("rdi") i64::from(fd),
1933 in("rsi") i64::from(how),
1934 lateout("rax") ret,
1935 lateout("rcx") _,
1936 lateout("r11") _,
1937 options(nostack, preserves_flags),
1938 );
1939 }
1940 ret
1941}
1942
1943#[cfg(target_arch = "x86_64")]
1944#[inline]
1945unsafe fn raw_syscall_getsockname(fd: i32, address: u64, addrlen: u64) -> i64 {
1946 let ret: i64;
1947 unsafe {
1949 core::arch::asm!(
1950 "syscall",
1951 in("rax") 51_i64,
1952 in("rdi") i64::from(fd),
1953 in("rsi") address,
1954 in("rdx") addrlen,
1955 lateout("rax") ret,
1956 lateout("rcx") _,
1957 lateout("r11") _,
1958 options(nostack, preserves_flags),
1959 );
1960 }
1961 ret
1962}
1963
1964#[cfg(target_arch = "x86_64")]
1965#[inline]
1966unsafe fn raw_syscall_getpeername(fd: i32, address: u64, addrlen: u64) -> i64 {
1967 let ret: i64;
1968 unsafe {
1970 core::arch::asm!(
1971 "syscall",
1972 in("rax") 52_i64,
1973 in("rdi") i64::from(fd),
1974 in("rsi") address,
1975 in("rdx") addrlen,
1976 lateout("rax") ret,
1977 lateout("rcx") _,
1978 lateout("r11") _,
1979 options(nostack, preserves_flags),
1980 );
1981 }
1982 ret
1983}
1984
1985#[cfg(target_arch = "x86_64")]
1986#[inline]
1987unsafe fn raw_syscall_socketpair(domain: i32, ty: i32, protocol: i32, sv: u64) -> i64 {
1988 let ret: i64;
1989 unsafe {
1991 core::arch::asm!(
1992 "syscall",
1993 in("rax") 53_i64,
1994 in("rdi") i64::from(domain),
1995 in("rsi") i64::from(ty),
1996 in("rdx") i64::from(protocol),
1997 in("r10") sv,
1998 lateout("rax") ret,
1999 lateout("rcx") _,
2000 lateout("r11") _,
2001 options(nostack, preserves_flags),
2002 );
2003 }
2004 ret
2005}
2006
2007#[cfg(target_arch = "x86_64")]
2008#[inline]
2009unsafe fn raw_syscall_getsockopt(
2010 fd: i32,
2011 level: i32,
2012 optname: i32,
2013 optval: u64,
2014 optlen: u64,
2015) -> i64 {
2016 let ret: i64;
2017 unsafe {
2019 core::arch::asm!(
2020 "syscall",
2021 in("rax") 55_i64,
2022 in("rdi") i64::from(fd),
2023 in("rsi") i64::from(level),
2024 in("rdx") i64::from(optname),
2025 in("r10") optval,
2026 in("r8") optlen,
2027 lateout("rax") ret,
2028 lateout("rcx") _,
2029 lateout("r11") _,
2030 options(nostack, preserves_flags),
2031 );
2032 }
2033 ret
2034}
2035
2036#[cfg(target_arch = "x86_64")]
2037#[inline]
2038unsafe fn raw_syscall_setsockopt(
2039 fd: i32,
2040 level: i32,
2041 optname: i32,
2042 optval: u64,
2043 optlen: u32,
2044) -> i64 {
2045 let ret: i64;
2046 unsafe {
2048 core::arch::asm!(
2049 "syscall",
2050 in("rax") 54_i64,
2051 in("rdi") i64::from(fd),
2052 in("rsi") i64::from(level),
2053 in("rdx") i64::from(optname),
2054 in("r10") optval,
2055 in("r8") i64::from(optlen),
2056 lateout("rax") ret,
2057 lateout("rcx") _,
2058 lateout("r11") _,
2059 options(nostack, preserves_flags),
2060 );
2061 }
2062 ret
2063}
2064
2065#[cfg(target_arch = "aarch64")]
2070#[inline]
2071unsafe fn raw_syscall_socket(domain: i32, ty: i32, protocol: i32) -> i64 {
2072 let ret: i64;
2073 unsafe {
2075 core::arch::asm!(
2076 "svc 0",
2077 in("x8") 198_i64,
2078 inout("x0") i64::from(domain) => ret,
2079 in("x1") i64::from(ty),
2080 in("x2") i64::from(protocol),
2081 options(nostack, preserves_flags),
2082 );
2083 }
2084 ret
2085}
2086
2087#[cfg(target_arch = "aarch64")]
2088#[inline]
2089unsafe fn raw_syscall_bind(fd: i32, address: u64, addrlen: u32) -> i64 {
2090 let ret: i64;
2091 unsafe {
2093 core::arch::asm!(
2094 "svc 0",
2095 in("x8") 200_i64,
2096 inout("x0") i64::from(fd) => ret,
2097 in("x1") address,
2098 in("x2") i64::from(addrlen),
2099 options(nostack, preserves_flags),
2100 );
2101 }
2102 ret
2103}
2104
2105#[cfg(target_arch = "aarch64")]
2106#[inline]
2107unsafe fn raw_syscall_listen(fd: i32, backlog: i32) -> i64 {
2108 let ret: i64;
2109 unsafe {
2111 core::arch::asm!(
2112 "svc 0",
2113 in("x8") 201_i64,
2114 inout("x0") i64::from(fd) => ret,
2115 in("x1") i64::from(backlog),
2116 options(nostack, preserves_flags),
2117 );
2118 }
2119 ret
2120}
2121
2122#[cfg(target_arch = "aarch64")]
2123#[inline]
2124unsafe fn raw_syscall_connect(fd: i32, address: u64, addrlen: u32) -> i64 {
2125 let ret: i64;
2126 unsafe {
2128 core::arch::asm!(
2129 "svc 0",
2130 in("x8") 203_i64,
2131 inout("x0") i64::from(fd) => ret,
2132 in("x1") address,
2133 in("x2") i64::from(addrlen),
2134 options(nostack, preserves_flags),
2135 );
2136 }
2137 ret
2138}
2139
2140#[cfg(target_arch = "aarch64")]
2141#[inline]
2142unsafe fn raw_syscall_accept4(fd: i32, address: u64, addrlen: u64, flags: i32) -> i64 {
2143 let ret: i64;
2144 unsafe {
2146 core::arch::asm!(
2147 "svc 0",
2148 in("x8") 242_i64,
2149 inout("x0") i64::from(fd) => ret,
2150 in("x1") address,
2151 in("x2") addrlen,
2152 in("x3") i64::from(flags),
2153 options(nostack, preserves_flags),
2154 );
2155 }
2156 ret
2157}
2158
2159#[cfg(target_arch = "aarch64")]
2160#[inline]
2161unsafe fn raw_syscall_sendto(
2162 fd: i32,
2163 buffer: u64,
2164 length: usize,
2165 flags: u64,
2166 address: u64,
2167 addrlen: u32,
2168) -> i64 {
2169 let ret: i64;
2170 unsafe {
2172 core::arch::asm!(
2173 "svc 0",
2174 in("x8") 206_i64,
2175 inout("x0") i64::from(fd) => ret,
2176 in("x1") buffer,
2177 in("x2") length,
2178 in("x3") flags,
2179 in("x4") address,
2180 in("x5") i64::from(addrlen),
2181 options(nostack, preserves_flags),
2182 );
2183 }
2184 ret
2185}
2186
2187#[cfg(target_arch = "aarch64")]
2188#[inline]
2189unsafe fn raw_syscall_recvfrom(
2190 fd: i32,
2191 buffer: u64,
2192 length: usize,
2193 flags: u64,
2194 address: u64,
2195 addrlen: u64,
2196) -> i64 {
2197 let ret: i64;
2198 unsafe {
2200 core::arch::asm!(
2201 "svc 0",
2202 in("x8") 207_i64,
2203 inout("x0") i64::from(fd) => ret,
2204 in("x1") buffer,
2205 in("x2") length,
2206 in("x3") flags,
2207 in("x4") address,
2208 in("x5") addrlen,
2209 options(nostack, preserves_flags),
2210 );
2211 }
2212 ret
2213}
2214
2215#[cfg(target_arch = "aarch64")]
2216#[inline]
2217unsafe fn raw_syscall_sendmsg(fd: i32, msghdr: u64, flags: u64) -> i64 {
2218 let ret: i64;
2219 unsafe {
2221 core::arch::asm!(
2222 "svc 0",
2223 in("x8") 211_i64,
2224 inout("x0") i64::from(fd) => ret,
2225 in("x1") msghdr,
2226 in("x2") flags,
2227 options(nostack, preserves_flags),
2228 );
2229 }
2230 ret
2231}
2232
2233#[cfg(target_arch = "aarch64")]
2234#[inline]
2235unsafe fn raw_syscall_recvmsg(fd: i32, msghdr: u64, flags: u64) -> i64 {
2236 let ret: i64;
2237 unsafe {
2239 core::arch::asm!(
2240 "svc 0",
2241 in("x8") 212_i64,
2242 inout("x0") i64::from(fd) => ret,
2243 in("x1") msghdr,
2244 in("x2") flags,
2245 options(nostack, preserves_flags),
2246 );
2247 }
2248 ret
2249}
2250
2251#[cfg(target_arch = "aarch64")]
2252#[inline]
2253unsafe fn raw_syscall_shutdown(fd: i32, how: i32) -> i64 {
2254 let ret: i64;
2255 unsafe {
2257 core::arch::asm!(
2258 "svc 0",
2259 in("x8") 210_i64,
2260 inout("x0") i64::from(fd) => ret,
2261 in("x1") i64::from(how),
2262 options(nostack, preserves_flags),
2263 );
2264 }
2265 ret
2266}
2267
2268#[cfg(target_arch = "aarch64")]
2269#[inline]
2270unsafe fn raw_syscall_getsockname(fd: i32, address: u64, addrlen: u64) -> i64 {
2271 let ret: i64;
2272 unsafe {
2274 core::arch::asm!(
2275 "svc 0",
2276 in("x8") 204_i64,
2277 inout("x0") i64::from(fd) => ret,
2278 in("x1") address,
2279 in("x2") addrlen,
2280 options(nostack, preserves_flags),
2281 );
2282 }
2283 ret
2284}
2285
2286#[cfg(target_arch = "aarch64")]
2287#[inline]
2288unsafe fn raw_syscall_getpeername(fd: i32, address: u64, addrlen: u64) -> i64 {
2289 let ret: i64;
2290 unsafe {
2292 core::arch::asm!(
2293 "svc 0",
2294 in("x8") 205_i64,
2295 inout("x0") i64::from(fd) => ret,
2296 in("x1") address,
2297 in("x2") addrlen,
2298 options(nostack, preserves_flags),
2299 );
2300 }
2301 ret
2302}
2303
2304#[cfg(target_arch = "aarch64")]
2305#[inline]
2306unsafe fn raw_syscall_socketpair(domain: i32, ty: i32, protocol: i32, sv: u64) -> i64 {
2307 let ret: i64;
2308 unsafe {
2310 core::arch::asm!(
2311 "svc 0",
2312 in("x8") 199_i64,
2313 inout("x0") i64::from(domain) => ret,
2314 in("x1") i64::from(ty),
2315 in("x2") i64::from(protocol),
2316 in("x3") sv,
2317 options(nostack, preserves_flags),
2318 );
2319 }
2320 ret
2321}
2322
2323#[cfg(target_arch = "aarch64")]
2324#[inline]
2325unsafe fn raw_syscall_getsockopt(
2326 fd: i32,
2327 level: i32,
2328 optname: i32,
2329 optval: u64,
2330 optlen: u64,
2331) -> i64 {
2332 let ret: i64;
2333 unsafe {
2335 core::arch::asm!(
2336 "svc 0",
2337 in("x8") 209_i64,
2338 inout("x0") i64::from(fd) => ret,
2339 in("x1") i64::from(level),
2340 in("x2") i64::from(optname),
2341 in("x3") optval,
2342 in("x4") optlen,
2343 options(nostack, preserves_flags),
2344 );
2345 }
2346 ret
2347}
2348
2349#[cfg(target_arch = "aarch64")]
2350#[inline]
2351unsafe fn raw_syscall_setsockopt(
2352 fd: i32,
2353 level: i32,
2354 optname: i32,
2355 optval: u64,
2356 optlen: u32,
2357) -> i64 {
2358 let ret: i64;
2359 unsafe {
2361 core::arch::asm!(
2362 "svc 0",
2363 in("x8") 208_i64,
2364 inout("x0") i64::from(fd) => ret,
2365 in("x1") i64::from(level),
2366 in("x2") i64::from(optname),
2367 in("x3") optval,
2368 in("x4") i64::from(optlen),
2369 options(nostack, preserves_flags),
2370 );
2371 }
2372 ret
2373}
2374
2375#[cfg(all(test, target_os = "linux"))]
2380mod tests;