1use std::cmp::min;
10#[cfg(not(target_os = "wasi"))]
11use std::ffi::OsStr;
12#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
13use std::io::IoSlice;
14use std::marker::PhantomData;
15use std::mem::{self, size_of, MaybeUninit};
16use std::net::Shutdown;
17use std::net::{Ipv4Addr, Ipv6Addr};
18#[cfg(all(
19 feature = "all",
20 any(
21 target_os = "ios",
22 target_os = "visionos",
23 target_os = "macos",
24 target_os = "tvos",
25 target_os = "watchos",
26 target_os = "illumos",
27 target_os = "solaris",
28 target_os = "linux",
29 target_os = "android",
30 )
31))]
32use std::num::NonZeroU32;
33#[cfg(all(
34 feature = "all",
35 any(
36 target_os = "aix",
37 target_os = "android",
38 target_os = "freebsd",
39 target_os = "ios",
40 target_os = "visionos",
41 target_os = "linux",
42 target_os = "macos",
43 target_os = "tvos",
44 target_os = "watchos",
45 )
46))]
47use std::num::NonZeroUsize;
48use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
49#[cfg(not(target_os = "wasi"))]
50use std::os::unix::ffi::OsStrExt;
51#[cfg(all(feature = "all", unix))]
52use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
53#[cfg(not(target_os = "wasi"))]
54use std::path::Path;
55use std::ptr;
56use std::time::{Duration, Instant};
57use std::{io, slice};
58
59#[cfg(not(any(
60 target_os = "ios",
61 target_os = "visionos",
62 target_os = "macos",
63 target_os = "tvos",
64 target_os = "watchos",
65 target_os = "cygwin",
66)))]
67use libc::ssize_t;
68use libc::{in6_addr, in_addr};
69
70#[cfg(not(target_os = "wasi"))]
71use crate::SockAddrStorage;
72use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
73#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
74use crate::{MsgHdr, MsgHdrMut, RecvFlags};
75
76pub(crate) use std::ffi::c_int;
77
78#[cfg(not(target_os = "wasi"))]
80pub(crate) use libc::AF_UNIX;
81pub(crate) use libc::{AF_INET, AF_INET6};
82#[cfg(all(feature = "all", target_os = "linux"))]
84pub(crate) use libc::SOCK_DCCP;
85#[cfg(all(
86 feature = "all",
87 not(any(
88 target_os = "redox",
89 target_os = "espidf",
90 target_os = "wasi",
91 target_os = "horizon"
92 ))
93))]
94pub(crate) use libc::SOCK_RAW;
95#[cfg(all(
96 feature = "all",
97 not(any(target_os = "espidf", target_os = "wasi", target_os = "horizon"))
98))]
99pub(crate) use libc::SOCK_SEQPACKET;
100pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM};
101#[cfg(all(feature = "all", target_os = "linux"))]
103pub(crate) use libc::IPPROTO_DCCP;
104#[cfg(target_os = "linux")]
105pub(crate) use libc::IPPROTO_MPTCP;
106#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
107pub(crate) use libc::IPPROTO_SCTP;
108#[cfg(all(
109 feature = "all",
110 any(
111 target_os = "android",
112 target_os = "freebsd",
113 target_os = "fuchsia",
114 target_os = "linux",
115 )
116))]
117pub(crate) use libc::IPPROTO_UDPLITE;
118#[cfg(not(target_os = "wasi"))]
119pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6};
120pub(crate) use libc::{IPPROTO_TCP, IPPROTO_UDP};
121#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
123pub(crate) use libc::IPPROTO_DIVERT;
124pub(crate) use libc::{
125 sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t,
126};
127#[cfg(not(any(
129 target_os = "redox",
130 target_os = "espidf",
131 target_os = "wasi",
132 target_os = "horizon"
133)))]
134pub(crate) use libc::MSG_TRUNC;
135#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
136pub(crate) use libc::SO_OOBINLINE;
137#[cfg(not(target_os = "nto"))]
139pub(crate) use libc::ipv6_mreq as Ipv6Mreq;
140#[cfg(all(feature = "all", target_os = "linux"))]
141pub(crate) use libc::IPV6_HDRINCL;
142#[cfg(all(
143 feature = "all",
144 not(any(
145 target_os = "dragonfly",
146 target_os = "fuchsia",
147 target_os = "hurd",
148 target_os = "illumos",
149 target_os = "netbsd",
150 target_os = "openbsd",
151 target_os = "redox",
152 target_os = "solaris",
153 target_os = "haiku",
154 target_os = "espidf",
155 target_os = "vita",
156 target_os = "wasi",
157 target_os = "cygwin",
158 target_os = "horizon"
159 ))
160))]
161pub(crate) use libc::IPV6_RECVHOPLIMIT;
162#[cfg(not(any(
163 target_os = "dragonfly",
164 target_os = "fuchsia",
165 target_os = "hurd",
166 target_os = "illumos",
167 target_os = "netbsd",
168 target_os = "openbsd",
169 target_os = "redox",
170 target_os = "solaris",
171 target_os = "haiku",
172 target_os = "espidf",
173 target_os = "vita",
174 target_os = "wasi",
175 target_os = "horizon"
176)))]
177pub(crate) use libc::IPV6_RECVTCLASS;
178#[cfg(all(
179 feature = "all",
180 not(any(
181 target_os = "redox",
182 target_os = "espidf",
183 target_os = "wasi",
184 target_os = "horizon"
185 ))
186))]
187pub(crate) use libc::IP_HDRINCL;
188#[cfg(not(any(
189 target_os = "aix",
190 target_os = "dragonfly",
191 target_os = "fuchsia",
192 target_os = "illumos",
193 target_os = "netbsd",
194 target_os = "openbsd",
195 target_os = "redox",
196 target_os = "solaris",
197 target_os = "haiku",
198 target_os = "hurd",
199 target_os = "nto",
200 target_os = "espidf",
201 target_os = "vita",
202 target_os = "wasi",
203 target_os = "cygwin",
204 target_os = "horizon"
205)))]
206pub(crate) use libc::IP_RECVTOS;
207#[cfg(not(any(
208 target_os = "fuchsia",
209 target_os = "redox",
210 target_os = "solaris",
211 target_os = "haiku",
212 target_os = "illumos",
213 target_os = "wasi",
214)))]
215pub(crate) use libc::IP_TOS;
216#[cfg(not(any(
217 target_os = "ios",
218 target_os = "visionos",
219 target_os = "macos",
220 target_os = "tvos",
221 target_os = "watchos",
222)))]
223pub(crate) use libc::SO_LINGER;
224#[cfg(any(
225 target_os = "ios",
226 target_os = "visionos",
227 target_os = "macos",
228 target_os = "tvos",
229 target_os = "watchos",
230))]
231pub(crate) use libc::SO_LINGER_SEC as SO_LINGER;
232#[cfg(any(target_os = "linux", target_os = "cygwin"))]
233pub(crate) use libc::SO_PASSCRED;
234#[cfg(all(
235 feature = "all",
236 any(target_os = "linux", target_os = "android", target_os = "fuchsia")
237))]
238pub(crate) use libc::SO_PRIORITY;
239pub(crate) use libc::{
240 ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS,
241 IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
242 IP_TTL, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO,
243 SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
244};
245#[cfg(not(any(
246 target_os = "dragonfly",
247 target_os = "haiku",
248 target_os = "hurd",
249 target_os = "netbsd",
250 target_os = "openbsd",
251 target_os = "redox",
252 target_os = "fuchsia",
253 target_os = "nto",
254 target_os = "espidf",
255 target_os = "vita",
256 target_os = "wasi",
257 target_os = "horizon"
258)))]
259pub(crate) use libc::{
260 ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
261};
262#[cfg(not(any(
263 target_os = "dragonfly",
264 target_os = "freebsd",
265 target_os = "haiku",
266 target_os = "illumos",
267 target_os = "ios",
268 target_os = "visionos",
269 target_os = "macos",
270 target_os = "netbsd",
271 target_os = "nto",
272 target_os = "openbsd",
273 target_os = "solaris",
274 target_os = "tvos",
275 target_os = "watchos",
276 target_os = "wasi",
277)))]
278pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
279#[cfg(any(
280 target_os = "dragonfly",
281 target_os = "freebsd",
282 target_os = "haiku",
283 target_os = "illumos",
284 target_os = "ios",
285 target_os = "visionos",
286 target_os = "macos",
287 target_os = "netbsd",
288 target_os = "openbsd",
289 target_os = "solaris",
290 target_os = "tvos",
291 target_os = "watchos",
292 all(target_os = "wasi", not(target_env = "p1")),
293))]
294pub(crate) use libc::{
295 IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP,
296};
297#[cfg(not(target_os = "wasi"))]
298pub(crate) use libc::{IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IP_MULTICAST_IF, MSG_OOB};
299#[cfg(all(
300 feature = "all",
301 any(
302 target_os = "android",
303 target_os = "dragonfly",
304 target_os = "freebsd",
305 target_os = "fuchsia",
306 target_os = "illumos",
307 target_os = "ios",
308 target_os = "visionos",
309 target_os = "linux",
310 target_os = "macos",
311 target_os = "netbsd",
312 target_os = "tvos",
313 target_os = "watchos",
314 target_os = "cygwin",
315 all(target_os = "wasi", not(target_env = "p1")),
316 )
317))]
318pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
319
320pub(crate) type Bool = c_int;
322
323#[cfg(any(
324 target_os = "ios",
325 target_os = "visionos",
326 target_os = "macos",
327 all(target_os = "nto", any(target_env = "nto70", target_env = "nto71"),),
328 target_os = "tvos",
329 target_os = "watchos",
330))]
331use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
332#[cfg(not(any(
333 target_os = "haiku",
334 target_os = "ios",
335 target_os = "visionos",
336 target_os = "macos",
337 all(target_os = "nto", any(target_env = "nto70", target_env = "nto71"),),
338 target_os = "openbsd",
339 target_os = "tvos",
340 target_os = "watchos",
341 target_os = "vita",
342)))]
343use libc::TCP_KEEPIDLE as KEEPALIVE_TIME;
344
345macro_rules! syscall {
347 ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
348 #[allow(unused_unsafe)]
349 let res = unsafe { libc::$fn($($arg, )*) };
350 if res == -1 {
351 Err(std::io::Error::last_os_error())
352 } else {
353 Ok(res)
354 }
355 }};
356}
357
358#[cfg(not(any(
360 target_os = "ios",
361 target_os = "visionos",
362 target_os = "macos",
363 target_os = "tvos",
364 target_os = "watchos",
365 target_os = "cygwin",
366)))]
367const MAX_BUF_LEN: usize = ssize_t::MAX as usize;
368
369#[cfg(any(
378 target_os = "ios",
379 target_os = "visionos",
380 target_os = "macos",
381 target_os = "tvos",
382 target_os = "watchos",
383 target_os = "cygwin",
384))]
385const MAX_BUF_LEN: usize = c_int::MAX as usize - 1;
386
387#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
389const TCP_CA_NAME_MAX: usize = 16;
390
391#[cfg(any(
392 all(
393 target_os = "linux",
394 any(
395 target_env = "gnu",
396 all(target_env = "uclibc", target_pointer_width = "64")
397 )
398 ),
399 target_os = "android",
400))]
401type IovLen = usize;
402
403#[cfg(any(
404 all(
405 target_os = "linux",
406 any(
407 target_env = "musl",
408 target_env = "ohos",
409 all(target_env = "uclibc", target_pointer_width = "32")
410 )
411 ),
412 target_os = "aix",
413 target_os = "dragonfly",
414 target_os = "freebsd",
415 target_os = "fuchsia",
416 target_os = "haiku",
417 target_os = "hurd",
418 target_os = "illumos",
419 target_os = "ios",
420 target_os = "visionos",
421 target_os = "macos",
422 target_os = "netbsd",
423 target_os = "nto",
424 target_os = "openbsd",
425 target_os = "solaris",
426 target_os = "tvos",
427 target_os = "watchos",
428 target_os = "espidf",
429 target_os = "vita",
430 target_os = "cygwin",
431))]
432type IovLen = c_int;
433
434impl Domain {
436 #[cfg(all(
438 feature = "all",
439 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
440 ))]
441 pub const PACKET: Domain = Domain(libc::AF_PACKET);
442
443 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
445 pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
446}
447
448impl_debug!(
449 Domain,
450 libc::AF_INET,
451 libc::AF_INET6,
452 #[cfg(not(target_os = "wasi"))]
453 libc::AF_UNIX,
454 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
455 libc::AF_PACKET,
456 #[cfg(any(target_os = "android", target_os = "linux"))]
457 libc::AF_VSOCK,
458 libc::AF_UNSPEC, );
460
461impl Type {
463 #[cfg(all(
465 feature = "all",
466 any(
467 target_os = "android",
468 target_os = "dragonfly",
469 target_os = "freebsd",
470 target_os = "fuchsia",
471 target_os = "illumos",
472 target_os = "linux",
473 target_os = "netbsd",
474 target_os = "openbsd",
475 target_os = "cygwin",
476 all(target_os = "wasi", not(target_env = "p1")),
477 )
478 ))]
479 pub const fn nonblocking(self) -> Type {
480 Type(self.0 | libc::SOCK_NONBLOCK)
481 }
482
483 #[cfg(all(
485 feature = "all",
486 any(
487 target_os = "android",
488 target_os = "dragonfly",
489 target_os = "freebsd",
490 target_os = "fuchsia",
491 target_os = "hurd",
492 target_os = "illumos",
493 target_os = "linux",
494 target_os = "netbsd",
495 target_os = "openbsd",
496 target_os = "redox",
497 target_os = "solaris",
498 target_os = "cygwin",
499 )
500 ))]
501 pub const fn cloexec(self) -> Type {
502 self._cloexec()
503 }
504
505 #[cfg(any(
506 target_os = "android",
507 target_os = "dragonfly",
508 target_os = "freebsd",
509 target_os = "fuchsia",
510 target_os = "hurd",
511 target_os = "illumos",
512 target_os = "linux",
513 target_os = "netbsd",
514 target_os = "openbsd",
515 target_os = "redox",
516 target_os = "solaris",
517 target_os = "cygwin",
518 ))]
519 pub(crate) const fn _cloexec(self) -> Type {
520 Type(self.0 | libc::SOCK_CLOEXEC)
521 }
522}
523
524impl_debug!(
525 Type,
526 libc::SOCK_STREAM,
527 libc::SOCK_DGRAM,
528 #[cfg(all(feature = "all", target_os = "linux"))]
529 libc::SOCK_DCCP,
530 #[cfg(not(any(
531 target_os = "redox",
532 target_os = "espidf",
533 target_os = "wasi",
534 target_os = "horizon"
535 )))]
536 libc::SOCK_RAW,
537 #[cfg(not(any(
538 target_os = "redox",
539 target_os = "haiku",
540 target_os = "espidf",
541 target_os = "wasi",
542 target_os = "horizon"
543 )))]
544 libc::SOCK_RDM,
545 #[cfg(not(any(target_os = "espidf", target_os = "wasi", target_os = "horizon")))]
546 libc::SOCK_SEQPACKET,
547 );
570
571impl_debug!(
572 Protocol,
573 #[cfg(not(target_os = "wasi"))]
574 libc::IPPROTO_ICMP,
575 #[cfg(not(target_os = "wasi"))]
576 libc::IPPROTO_ICMPV6,
577 libc::IPPROTO_TCP,
578 libc::IPPROTO_UDP,
579 #[cfg(target_os = "linux")]
580 libc::IPPROTO_MPTCP,
581 #[cfg(all(feature = "all", target_os = "linux"))]
582 libc::IPPROTO_DCCP,
583 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
584 libc::IPPROTO_SCTP,
585 #[cfg(all(
586 feature = "all",
587 any(
588 target_os = "android",
589 target_os = "freebsd",
590 target_os = "fuchsia",
591 target_os = "linux",
592 )
593 ))]
594 libc::IPPROTO_UDPLITE,
595 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
596 libc::IPPROTO_DIVERT,
597);
598
599#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
601impl RecvFlags {
602 #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
612 pub const fn is_end_of_record(self) -> bool {
613 self.0 & libc::MSG_EOR != 0
614 }
615
616 pub const fn is_out_of_band(self) -> bool {
623 self.0 & libc::MSG_OOB != 0
624 }
625
626 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
634 pub const fn is_confirm(self) -> bool {
635 self.0 & libc::MSG_CONFIRM != 0
636 }
637
638 #[cfg(all(
645 feature = "all",
646 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
647 ))]
648 pub const fn is_dontroute(self) -> bool {
649 self.0 & libc::MSG_DONTROUTE != 0
650 }
651}
652
653#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
654impl std::fmt::Debug for RecvFlags {
655 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
656 let mut s = f.debug_struct("RecvFlags");
657 #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
658 s.field("is_end_of_record", &self.is_end_of_record());
659 s.field("is_out_of_band", &self.is_out_of_band());
660 #[cfg(not(target_os = "espidf"))]
661 s.field("is_truncated", &self.is_truncated());
662 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
663 s.field("is_confirm", &self.is_confirm());
664 #[cfg(all(
665 feature = "all",
666 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
667 ))]
668 s.field("is_dontroute", &self.is_dontroute());
669 s.finish()
670 }
671}
672
673#[repr(transparent)]
674pub struct MaybeUninitSlice<'a> {
675 vec: libc::iovec,
676 _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
677}
678
679unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
680
681unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
682
683impl<'a> MaybeUninitSlice<'a> {
684 pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
685 MaybeUninitSlice {
686 vec: libc::iovec {
687 iov_base: buf.as_mut_ptr().cast(),
688 iov_len: buf.len(),
689 },
690 _lifetime: PhantomData,
691 }
692 }
693
694 pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
695 unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
696 }
697
698 pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
699 unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
700 }
701}
702
703#[cfg(not(target_os = "wasi"))]
705pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize {
706 let base = storage as *const _ as usize;
707 let path = ptr::addr_of!(storage.sun_path) as usize;
708 path - base
709}
710
711#[cfg(not(target_os = "wasi"))]
712#[allow(unsafe_op_in_unsafe_fn)]
713pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
714 let mut storage = SockAddrStorage::zeroed();
715 let len = {
716 let storage = unsafe { storage.view_as::<libc::sockaddr_un>() };
718
719 let bytes = path.as_os_str().as_bytes();
720 let too_long = match bytes.first() {
721 None => false,
722 Some(&0) => bytes.len() > storage.sun_path.len(),
724 Some(_) => bytes.len() >= storage.sun_path.len(),
725 };
726 if too_long {
727 return Err(io::Error::new(
728 io::ErrorKind::InvalidInput,
729 "path must be shorter than SUN_LEN",
730 ));
731 }
732
733 storage.sun_family = libc::AF_UNIX as sa_family_t;
734 unsafe {
739 ptr::copy_nonoverlapping(
740 bytes.as_ptr(),
741 storage.sun_path.as_mut_ptr().cast(),
742 bytes.len(),
743 );
744 }
745
746 let sun_path_offset = offset_of_path(storage);
747 sun_path_offset
748 + bytes.len()
749 + match bytes.first() {
750 Some(&0) | None => 0,
751 Some(_) => 1,
752 }
753 };
754 Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
755}
756
757#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
759pub(crate) use libc::msghdr;
760
761#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
762pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
763 msg.msg_name = name.as_ptr() as *mut _;
764 msg.msg_namelen = name.len();
765}
766
767#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
768#[allow(clippy::unnecessary_cast)] pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) {
770 msg.msg_iov = ptr;
771 msg.msg_iovlen = min(len, IovLen::MAX as usize) as IovLen;
772}
773
774#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
775pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) {
776 msg.msg_control = ptr;
777 msg.msg_controllen = len as _;
778}
779
780#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
781pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: c_int) {
782 msg.msg_flags = flags;
783}
784
785#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
786pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
787 RecvFlags(msg.msg_flags)
788}
789
790#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
791pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
792 msg.msg_controllen as _
793}
794
795impl SockAddr {
797 #[allow(unsafe_op_in_unsafe_fn)]
804 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
805 pub fn vsock(cid: u32, port: u32) -> SockAddr {
806 let mut storage = SockAddrStorage::zeroed();
807 {
808 let storage = unsafe { storage.view_as::<libc::sockaddr_vm>() };
810 storage.svm_family = libc::AF_VSOCK as sa_family_t;
811 storage.svm_cid = cid;
812 storage.svm_port = port;
813 }
814 unsafe { SockAddr::new(storage, mem::size_of::<libc::sockaddr_vm>() as socklen_t) }
815 }
816
817 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
820 pub fn as_vsock_address(&self) -> Option<(u32, u32)> {
821 if self.family() == libc::AF_VSOCK as sa_family_t {
822 let addr = unsafe { &*(self.as_ptr() as *const libc::sockaddr_vm) };
824 Some((addr.svm_cid, addr.svm_port))
825 } else {
826 None
827 }
828 }
829}
830
831#[cfg(not(target_os = "wasi"))]
833impl SockAddr {
834 pub fn is_unnamed(&self) -> bool {
837 self.as_sockaddr_un()
838 .map(|storage| {
839 self.len() == offset_of_path(storage) as _
840 || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))
845 && storage.sun_path[0] == 0)
846 })
847 .unwrap_or_default()
848 }
849
850 pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> {
853 self.is_unix().then(|| {
854 unsafe { &*self.as_ptr().cast::<libc::sockaddr_un>() }
857 })
858 }
859
860 fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
865 debug_assert!(!self.is_unnamed());
866 self.len() as usize - offset_of_path(storage) - 1
867 }
868
869 fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] {
873 debug_assert!(!self.is_unnamed());
874 unsafe {
882 slice::from_raw_parts(
883 (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize),
884 self.path_len(storage),
885 )
886 }
887 }
888
889 pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
892 let path = self.as_pathname()?;
893 Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
896 }
897
898 pub fn as_pathname(&self) -> Option<&Path> {
901 self.as_sockaddr_un().and_then(|storage| {
902 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] != 0).then(|| {
903 let path_slice = self.path_bytes(storage, false);
904 Path::new::<OsStr>(OsStrExt::from_bytes(path_slice))
905 })
906 })
907 }
908
909 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
915 #[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
918 {
919 self.as_sockaddr_un().and_then(|storage| {
920 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] == 0)
921 .then(|| self.path_bytes(storage, true))
922 })
923 }
924 #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))]
925 None
926 }
927}
928
929pub(crate) type Socket = std::os::fd::OwnedFd;
930pub(crate) type RawSocket = c_int;
931
932pub(crate) unsafe fn socket_from_raw(socket: RawSocket) -> Socket {
933 Socket::from_raw_fd(socket)
934}
935
936pub(crate) fn socket_as_raw(socket: &Socket) -> RawSocket {
937 socket.as_raw_fd()
938}
939
940pub(crate) fn socket_into_raw(socket: Socket) -> RawSocket {
941 socket.into_raw_fd()
942}
943
944pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<RawSocket> {
945 syscall!(socket(family, ty, protocol))
946}
947
948#[cfg(all(feature = "all", unix))]
949pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[RawSocket; 2]> {
950 let mut fds = [0, 0];
951 syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds)
952}
953
954pub(crate) fn bind(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
955 syscall!(bind(fd, addr.as_ptr().cast::<sockaddr>(), addr.len() as _)).map(|_| ())
956}
957
958pub(crate) fn connect(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
959 syscall!(connect(fd, addr.as_ptr().cast::<sockaddr>(), addr.len())).map(|_| ())
960}
961
962pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
963 let start = Instant::now();
964
965 let mut pollfd = libc::pollfd {
966 fd: socket.as_raw(),
967 events: libc::POLLIN | libc::POLLOUT,
968 revents: 0,
969 };
970
971 loop {
972 let elapsed = start.elapsed();
973 if elapsed >= timeout {
974 return Err(io::ErrorKind::TimedOut.into());
975 }
976
977 let timeout = (timeout - elapsed).as_millis();
978 let timeout = timeout.clamp(1, c_int::MAX as u128) as c_int;
979
980 match syscall!(poll(&mut pollfd, 1, timeout)) {
981 Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
982 Ok(_) => {
983 if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0 {
985 match socket.take_error() {
986 Ok(Some(err)) | Err(err) => return Err(err),
987 Ok(None) => {
988 return Err(io::Error::new(
989 io::ErrorKind::Other,
990 "no error set after POLLHUP",
991 ))
992 }
993 }
994 }
995 return Ok(());
996 }
997 Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
999 Err(err) => return Err(err),
1000 }
1001 }
1002}
1003
1004pub(crate) fn listen(fd: RawSocket, backlog: c_int) -> io::Result<()> {
1005 syscall!(listen(fd, backlog)).map(|_| ())
1006}
1007
1008pub(crate) fn accept(fd: RawSocket) -> io::Result<(RawSocket, SockAddr)> {
1009 unsafe { SockAddr::try_init(|storage, len| syscall!(accept(fd, storage.cast(), len))) }
1011}
1012
1013pub(crate) fn getsockname(fd: RawSocket) -> io::Result<SockAddr> {
1014 unsafe { SockAddr::try_init(|storage, len| syscall!(getsockname(fd, storage.cast(), len))) }
1016 .map(|(_, addr)| addr)
1017}
1018
1019pub(crate) fn getpeername(fd: RawSocket) -> io::Result<SockAddr> {
1020 unsafe { SockAddr::try_init(|storage, len| syscall!(getpeername(fd, storage.cast(), len))) }
1022 .map(|(_, addr)| addr)
1023}
1024
1025#[cfg(not(target_os = "wasi"))]
1026pub(crate) fn try_clone(fd: RawSocket) -> io::Result<RawSocket> {
1027 syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0))
1028}
1029
1030#[cfg(all(
1031 feature = "all",
1032 any(unix, all(target_os = "wasi", not(target_env = "p1"))),
1033 not(target_os = "vita")
1034))]
1035pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
1036 let file_status_flags = fcntl_get(fd, libc::F_GETFL)?;
1037 Ok((file_status_flags & libc::O_NONBLOCK) != 0)
1038}
1039
1040#[cfg(all(feature = "all", target_os = "vita"))]
1041pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
1042 unsafe {
1043 getsockopt::<Bool>(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK).map(|non_block| non_block != 0)
1044 }
1045}
1046
1047#[cfg(not(target_os = "vita"))]
1048pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::Result<()> {
1049 if nonblocking {
1050 fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1051 } else {
1052 fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1053 }
1054}
1055
1056#[cfg(target_os = "vita")]
1057pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::Result<()> {
1058 unsafe {
1059 setsockopt(
1060 fd,
1061 libc::SOL_SOCKET,
1062 libc::SO_NONBLOCK,
1063 nonblocking as c_int,
1064 )
1065 }
1066}
1067
1068pub(crate) fn shutdown(fd: RawSocket, how: Shutdown) -> io::Result<()> {
1069 let how = match how {
1070 Shutdown::Write => libc::SHUT_WR,
1071 Shutdown::Read => libc::SHUT_RD,
1072 Shutdown::Both => libc::SHUT_RDWR,
1073 };
1074 syscall!(shutdown(fd, how)).map(|_| ())
1075}
1076
1077pub(crate) fn recv(fd: RawSocket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
1078 syscall!(recv(
1079 fd,
1080 buf.as_mut_ptr().cast(),
1081 min(buf.len(), MAX_BUF_LEN),
1082 flags,
1083 ))
1084 .map(|n| n as usize)
1085}
1086
1087pub(crate) fn recv_from(
1088 fd: RawSocket,
1089 buf: &mut [MaybeUninit<u8>],
1090 flags: c_int,
1091) -> io::Result<(usize, SockAddr)> {
1092 unsafe {
1094 SockAddr::try_init(|addr, addrlen| {
1095 syscall!(recvfrom(
1096 fd,
1097 buf.as_mut_ptr().cast(),
1098 min(buf.len(), MAX_BUF_LEN),
1099 flags,
1100 addr.cast(),
1101 addrlen
1102 ))
1103 .map(|n| n as usize)
1104 })
1105 }
1106}
1107
1108pub(crate) fn peek_sender(fd: RawSocket) -> io::Result<SockAddr> {
1109 let (_, sender) = recv_from(fd, &mut [MaybeUninit::uninit(); 8], MSG_PEEK)?;
1114 Ok(sender)
1115}
1116
1117#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1118pub(crate) fn recv_vectored(
1119 fd: RawSocket,
1120 bufs: &mut [crate::MaybeUninitSlice<'_>],
1121 flags: c_int,
1122) -> io::Result<(usize, RecvFlags)> {
1123 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1124 let n = recvmsg(fd, &mut msg, flags)?;
1125 Ok((n, msg.flags()))
1126}
1127
1128#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1129pub(crate) fn recv_from_vectored(
1130 fd: RawSocket,
1131 bufs: &mut [crate::MaybeUninitSlice<'_>],
1132 flags: c_int,
1133) -> io::Result<(usize, RecvFlags, SockAddr)> {
1134 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1135 let (n, addr) = unsafe {
1138 SockAddr::try_init(|storage, len| {
1139 msg.inner.msg_name = storage.cast();
1140 msg.inner.msg_namelen = *len;
1141 let n = recvmsg(fd, &mut msg, flags)?;
1142 *len = msg.inner.msg_namelen;
1144 Ok(n)
1145 })?
1146 };
1147 Ok((n, msg.flags(), addr))
1148}
1149
1150#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1151pub(crate) fn recvmsg(
1152 fd: RawSocket,
1153 msg: &mut MsgHdrMut<'_, '_, '_>,
1154 flags: c_int,
1155) -> io::Result<usize> {
1156 syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|n| n as usize)
1157}
1158
1159pub(crate) fn send(fd: RawSocket, buf: &[u8], flags: c_int) -> io::Result<usize> {
1160 syscall!(send(
1161 fd,
1162 buf.as_ptr().cast(),
1163 min(buf.len(), MAX_BUF_LEN),
1164 flags,
1165 ))
1166 .map(|n| n as usize)
1167}
1168
1169#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1170pub(crate) fn send_vectored(
1171 fd: RawSocket,
1172 bufs: &[IoSlice<'_>],
1173 flags: c_int,
1174) -> io::Result<usize> {
1175 let msg = MsgHdr::new().with_buffers(bufs);
1176 sendmsg(fd, &msg, flags)
1177}
1178
1179pub(crate) fn send_to(
1180 fd: RawSocket,
1181 buf: &[u8],
1182 addr: &SockAddr,
1183 flags: c_int,
1184) -> io::Result<usize> {
1185 syscall!(sendto(
1186 fd,
1187 buf.as_ptr().cast(),
1188 min(buf.len(), MAX_BUF_LEN),
1189 flags,
1190 addr.as_ptr().cast::<sockaddr>(),
1191 addr.len(),
1192 ))
1193 .map(|n| n as usize)
1194}
1195
1196#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1197pub(crate) fn send_to_vectored(
1198 fd: RawSocket,
1199 bufs: &[IoSlice<'_>],
1200 addr: &SockAddr,
1201 flags: c_int,
1202) -> io::Result<usize> {
1203 let msg = MsgHdr::new().with_addr(addr).with_buffers(bufs);
1204 sendmsg(fd, &msg, flags)
1205}
1206
1207#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1208pub(crate) fn sendmsg(fd: RawSocket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
1209 syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
1210}
1211
1212pub(crate) fn timeout_opt(fd: RawSocket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
1214 unsafe { getsockopt(fd, opt, val).map(from_timeval) }
1215}
1216
1217const fn from_timeval(duration: libc::timeval) -> Option<Duration> {
1218 if duration.tv_sec == 0 && duration.tv_usec == 0 {
1219 None
1220 } else {
1221 let sec = duration.tv_sec as u64;
1222 let nsec = (duration.tv_usec as u32) * 1000;
1223 Some(Duration::new(sec, nsec))
1224 }
1225}
1226
1227pub(crate) fn set_timeout_opt(
1229 fd: RawSocket,
1230 opt: c_int,
1231 val: c_int,
1232 duration: Option<Duration>,
1233) -> io::Result<()> {
1234 let duration = into_timeval(duration);
1235 unsafe { setsockopt(fd, opt, val, duration) }
1236}
1237
1238fn into_timeval(duration: Option<Duration>) -> libc::timeval {
1239 match duration {
1240 #[cfg_attr(target_env = "musl", allow(deprecated))]
1242 Some(duration) => libc::timeval {
1243 tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
1244 tv_usec: duration.subsec_micros() as libc::suseconds_t,
1245 },
1246 None => libc::timeval {
1247 tv_sec: 0,
1248 tv_usec: 0,
1249 },
1250 }
1251}
1252
1253#[cfg(all(
1254 feature = "all",
1255 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1256))]
1257pub(crate) fn tcp_keepalive_time(fd: RawSocket) -> io::Result<Duration> {
1258 unsafe {
1259 getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
1260 .map(|secs| Duration::from_secs(secs as u64))
1261 }
1262}
1263
1264#[allow(unused_variables)]
1265pub(crate) fn set_tcp_keepalive(fd: RawSocket, keepalive: &TcpKeepalive) -> io::Result<()> {
1266 #[cfg(not(any(
1267 target_os = "haiku",
1268 target_os = "openbsd",
1269 target_os = "nto",
1270 target_os = "vita"
1271 )))]
1272 if let Some(time) = keepalive.time {
1273 let secs = into_secs(time);
1274 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1275 }
1276
1277 #[cfg(any(
1278 target_os = "aix",
1279 target_os = "android",
1280 target_os = "dragonfly",
1281 target_os = "freebsd",
1282 target_os = "fuchsia",
1283 target_os = "hurd",
1284 target_os = "illumos",
1285 target_os = "ios",
1286 target_os = "visionos",
1287 target_os = "linux",
1288 target_os = "macos",
1289 target_os = "netbsd",
1290 target_os = "tvos",
1291 target_os = "watchos",
1292 target_os = "cygwin",
1293 all(target_os = "wasi", not(target_env = "p1")),
1294 ))]
1295 {
1296 if let Some(interval) = keepalive.interval {
1297 let secs = into_secs(interval);
1298 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
1299 }
1300
1301 if let Some(retries) = keepalive.retries {
1302 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
1303 }
1304 }
1305
1306 #[cfg(target_os = "nto")]
1307 if let Some(time) = keepalive.time {
1308 let secs = into_timeval(Some(time));
1309 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1310 }
1311
1312 Ok(())
1313}
1314
1315#[cfg(not(any(
1316 target_os = "haiku",
1317 target_os = "openbsd",
1318 target_os = "nto",
1319 target_os = "vita"
1320)))]
1321fn into_secs(duration: Duration) -> c_int {
1322 min(duration.as_secs(), c_int::MAX as u64) as c_int
1323}
1324
1325#[cfg(not(target_os = "vita"))]
1327fn fcntl_get(fd: RawSocket, cmd: c_int) -> io::Result<c_int> {
1328 syscall!(fcntl(fd, cmd))
1329}
1330
1331#[cfg(not(target_os = "vita"))]
1333fn fcntl_add(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1334 let previous = fcntl_get(fd, get_cmd)?;
1335 let new = previous | flag;
1336 if new != previous {
1337 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1338 } else {
1339 Ok(())
1341 }
1342}
1343
1344#[cfg(not(target_os = "vita"))]
1346fn fcntl_remove(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1347 let previous = fcntl_get(fd, get_cmd)?;
1348 let new = previous & !flag;
1349 if new != previous {
1350 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1351 } else {
1352 Ok(())
1354 }
1355}
1356
1357pub(crate) unsafe fn getsockopt<T>(fd: RawSocket, opt: c_int, val: c_int) -> io::Result<T> {
1359 let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
1360 let mut len = size_of::<T>() as libc::socklen_t;
1361 syscall!(getsockopt(
1362 fd,
1363 opt,
1364 val,
1365 payload.as_mut_ptr().cast(),
1366 &mut len,
1367 ))
1368 .map(|_| {
1369 debug_assert_eq!(len as usize, size_of::<T>());
1370 payload.assume_init()
1372 })
1373}
1374
1375pub(crate) unsafe fn setsockopt<T>(
1377 fd: RawSocket,
1378 opt: c_int,
1379 val: c_int,
1380 payload: T,
1381) -> io::Result<()> {
1382 let payload = ptr::addr_of!(payload).cast();
1383 syscall!(setsockopt(
1384 fd,
1385 opt,
1386 val,
1387 payload,
1388 mem::size_of::<T>() as libc::socklen_t,
1389 ))
1390 .map(|_| ())
1391}
1392
1393pub(crate) const fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
1394 in_addr {
1398 s_addr: u32::from_ne_bytes(addr.octets()),
1399 }
1400}
1401
1402pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
1403 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1404}
1405
1406pub(crate) const fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
1407 in6_addr {
1408 s6_addr: addr.octets(),
1409 }
1410}
1411
1412pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
1413 Ipv6Addr::from(addr.s6_addr)
1414}
1415
1416#[cfg(not(any(
1417 target_os = "aix",
1418 target_os = "haiku",
1419 target_os = "illumos",
1420 target_os = "netbsd",
1421 target_os = "openbsd",
1422 target_os = "redox",
1423 target_os = "solaris",
1424 target_os = "nto",
1425 target_os = "espidf",
1426 target_os = "vita",
1427 target_os = "cygwin",
1428 target_os = "wasi",
1429 target_os = "horizon"
1430)))]
1431pub(crate) const fn to_mreqn(
1432 multiaddr: &Ipv4Addr,
1433 interface: &crate::socket::InterfaceIndexOrAddress,
1434) -> libc::ip_mreqn {
1435 match interface {
1436 crate::socket::InterfaceIndexOrAddress::Index(interface) => libc::ip_mreqn {
1437 imr_multiaddr: to_in_addr(multiaddr),
1438 imr_address: to_in_addr(&Ipv4Addr::UNSPECIFIED),
1439 imr_ifindex: *interface as _,
1440 },
1441 crate::socket::InterfaceIndexOrAddress::Address(interface) => libc::ip_mreqn {
1442 imr_multiaddr: to_in_addr(multiaddr),
1443 imr_address: to_in_addr(interface),
1444 imr_ifindex: 0,
1445 },
1446 }
1447}
1448
1449#[cfg(all(
1450 feature = "all",
1451 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1452))]
1453pub(crate) fn original_dst_v4(fd: RawSocket) -> io::Result<SockAddr> {
1454 unsafe {
1456 SockAddr::try_init(|storage, len| {
1457 syscall!(getsockopt(
1458 fd,
1459 libc::SOL_IP,
1460 libc::SO_ORIGINAL_DST,
1461 storage.cast(),
1462 len
1463 ))
1464 })
1465 }
1466 .map(|(_, addr)| addr)
1467}
1468
1469#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1474pub(crate) fn original_dst_v6(fd: RawSocket) -> io::Result<SockAddr> {
1475 unsafe {
1477 SockAddr::try_init(|storage, len| {
1478 syscall!(getsockopt(
1479 fd,
1480 libc::SOL_IPV6,
1481 libc::IP6T_SO_ORIGINAL_DST,
1482 storage.cast(),
1483 len
1484 ))
1485 })
1486 }
1487 .map(|(_, addr)| addr)
1488}
1489
1490impl crate::Socket {
1492 #[doc = man_links!(unix: accept4(2))]
1500 #[cfg(all(
1501 feature = "all",
1502 any(
1503 target_os = "android",
1504 target_os = "dragonfly",
1505 target_os = "freebsd",
1506 target_os = "fuchsia",
1507 target_os = "illumos",
1508 target_os = "linux",
1509 target_os = "netbsd",
1510 target_os = "openbsd",
1511 target_os = "cygwin",
1512 )
1513 ))]
1514 pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1515 self._accept4(flags)
1516 }
1517
1518 #[cfg(any(
1519 target_os = "android",
1520 target_os = "dragonfly",
1521 target_os = "freebsd",
1522 target_os = "fuchsia",
1523 target_os = "illumos",
1524 target_os = "linux",
1525 target_os = "netbsd",
1526 target_os = "openbsd",
1527 target_os = "cygwin",
1528 ))]
1529 pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1530 unsafe {
1532 SockAddr::try_init(|storage, len| {
1533 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1534 .map(crate::Socket::from_raw)
1535 })
1536 }
1537 }
1538
1539 #[cfg_attr(
1545 any(
1546 target_os = "ios",
1547 target_os = "visionos",
1548 target_os = "macos",
1549 target_os = "tvos",
1550 target_os = "watchos",
1551 target_os = "wasi",
1552 target_os = "horizon"
1553 ),
1554 allow(rustdoc::broken_intra_doc_links)
1555 )]
1556 #[cfg(all(feature = "all", not(target_os = "vita")))]
1557 pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1558 self._set_cloexec(close_on_exec)
1559 }
1560
1561 #[cfg(not(target_os = "vita"))]
1562 pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1563 if close_on_exec {
1564 fcntl_add(
1565 self.as_raw(),
1566 libc::F_GETFD,
1567 libc::F_SETFD,
1568 libc::FD_CLOEXEC,
1569 )
1570 } else {
1571 fcntl_remove(
1572 self.as_raw(),
1573 libc::F_GETFD,
1574 libc::F_SETFD,
1575 libc::FD_CLOEXEC,
1576 )
1577 }
1578 }
1579
1580 #[cfg(target_os = "cygwin")]
1593 #[cfg(any(doc, target_os = "cygwin"))]
1594 pub fn set_no_peercred(&self) -> io::Result<()> {
1595 syscall!(setsockopt(
1596 self.as_raw(),
1597 libc::SOL_SOCKET,
1598 libc::SO_PEERCRED,
1599 ptr::null_mut(),
1600 0,
1601 ))
1602 .map(|_| ())
1603 }
1604
1605 #[cfg(all(
1607 feature = "all",
1608 any(
1609 target_os = "ios",
1610 target_os = "visionos",
1611 target_os = "macos",
1612 target_os = "tvos",
1613 target_os = "watchos",
1614 )
1615 ))]
1616 pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1617 self._set_nosigpipe(nosigpipe)
1618 }
1619
1620 #[cfg(any(
1621 target_os = "ios",
1622 target_os = "visionos",
1623 target_os = "macos",
1624 target_os = "tvos",
1625 target_os = "watchos",
1626 ))]
1627 pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1628 unsafe {
1629 setsockopt(
1630 self.as_raw(),
1631 libc::SOL_SOCKET,
1632 libc::SO_NOSIGPIPE,
1633 nosigpipe as c_int,
1634 )
1635 }
1636 }
1637
1638 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))]
1644 pub fn tcp_mss(&self) -> io::Result<u32> {
1645 unsafe {
1646 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1647 .map(|mss| mss as u32)
1648 }
1649 }
1650
1651 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))]
1656 pub fn set_tcp_mss(&self, mss: u32) -> io::Result<()> {
1657 unsafe {
1658 setsockopt(
1659 self.as_raw(),
1660 libc::IPPROTO_TCP,
1661 libc::TCP_MAXSEG,
1662 mss as c_int,
1663 )
1664 }
1665 }
1666
1667 #[cfg(all(
1670 feature = "all",
1671 any(
1672 target_os = "aix",
1673 target_os = "android",
1674 target_os = "freebsd",
1675 target_os = "fuchsia",
1676 target_os = "linux",
1677 target_os = "cygwin",
1678 )
1679 ))]
1680 pub fn is_listener(&self) -> io::Result<bool> {
1681 unsafe {
1682 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1683 .map(|v| v != 0)
1684 }
1685 }
1686
1687 #[cfg(all(
1690 feature = "all",
1691 any(
1692 target_os = "android",
1693 target_os = "fuchsia",
1696 target_os = "linux",
1697 )
1698 ))]
1699 pub fn domain(&self) -> io::Result<Domain> {
1700 unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1701 }
1702
1703 #[cfg(all(
1706 feature = "all",
1707 any(
1708 target_os = "android",
1709 target_os = "freebsd",
1710 target_os = "fuchsia",
1711 target_os = "linux",
1712 )
1713 ))]
1714 pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1715 unsafe {
1716 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1717 {
1718 0 => None,
1719 p => Some(Protocol(p)),
1720 })
1721 }
1722 }
1723
1724 #[cfg(all(
1731 feature = "all",
1732 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1733 ))]
1734 pub fn mark(&self) -> io::Result<u32> {
1735 unsafe {
1736 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1737 .map(|mark| mark as u32)
1738 }
1739 }
1740
1741 #[cfg(all(
1749 feature = "all",
1750 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1751 ))]
1752 pub fn set_mark(&self, mark: u32) -> io::Result<()> {
1753 unsafe {
1754 setsockopt::<c_int>(
1755 self.as_raw(),
1756 libc::SOL_SOCKET,
1757 libc::SO_MARK,
1758 mark as c_int,
1759 )
1760 }
1761 }
1762
1763 #[cfg(all(
1769 feature = "all",
1770 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1771 ))]
1772 pub fn tcp_cork(&self) -> io::Result<bool> {
1773 unsafe {
1774 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK)
1775 .map(|cork| cork != 0)
1776 }
1777 }
1778
1779 #[cfg(all(
1786 feature = "all",
1787 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1788 ))]
1789 pub fn set_tcp_cork(&self, cork: bool) -> io::Result<()> {
1790 unsafe {
1791 setsockopt(
1792 self.as_raw(),
1793 libc::IPPROTO_TCP,
1794 libc::TCP_CORK,
1795 cork as c_int,
1796 )
1797 }
1798 }
1799
1800 #[cfg(all(
1806 feature = "all",
1807 any(
1808 target_os = "android",
1809 target_os = "fuchsia",
1810 target_os = "linux",
1811 target_os = "cygwin",
1812 )
1813 ))]
1814 pub fn tcp_quickack(&self) -> io::Result<bool> {
1815 unsafe {
1816 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK)
1817 .map(|quickack| quickack != 0)
1818 }
1819 }
1820
1821 #[cfg(all(
1828 feature = "all",
1829 any(
1830 target_os = "android",
1831 target_os = "fuchsia",
1832 target_os = "linux",
1833 target_os = "cygwin",
1834 )
1835 ))]
1836 pub fn set_tcp_quickack(&self, quickack: bool) -> io::Result<()> {
1837 unsafe {
1838 setsockopt(
1839 self.as_raw(),
1840 libc::IPPROTO_TCP,
1841 libc::TCP_QUICKACK,
1842 quickack as c_int,
1843 )
1844 }
1845 }
1846
1847 #[cfg(all(
1853 feature = "all",
1854 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1855 ))]
1856 pub fn tcp_thin_linear_timeouts(&self) -> io::Result<bool> {
1857 unsafe {
1858 getsockopt::<Bool>(
1859 self.as_raw(),
1860 libc::IPPROTO_TCP,
1861 libc::TCP_THIN_LINEAR_TIMEOUTS,
1862 )
1863 .map(|timeouts| timeouts != 0)
1864 }
1865 }
1866
1867 #[cfg(all(
1873 feature = "all",
1874 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1875 ))]
1876 pub fn set_tcp_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> {
1877 unsafe {
1878 setsockopt(
1879 self.as_raw(),
1880 libc::IPPROTO_TCP,
1881 libc::TCP_THIN_LINEAR_TIMEOUTS,
1882 timeouts as c_int,
1883 )
1884 }
1885 }
1886
1887 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1893 pub fn tcp_notsent_lowat(&self) -> io::Result<u32> {
1894 unsafe {
1895 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_NOTSENT_LOWAT)
1896 .map(|lowat| lowat as u32)
1897 }
1898 }
1899
1900 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1905 pub fn set_tcp_notsent_lowat(&self, lowat: u32) -> io::Result<()> {
1906 unsafe {
1907 setsockopt(
1908 self.as_raw(),
1909 libc::IPPROTO_TCP,
1910 libc::TCP_NOTSENT_LOWAT,
1911 lowat as c_int,
1912 )
1913 }
1914 }
1915
1916 #[cfg(all(
1920 feature = "all",
1921 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1922 ))]
1923 pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1924 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1926 unsafe { MaybeUninit::uninit().assume_init() };
1927 let mut len = buf.len() as libc::socklen_t;
1928 syscall!(getsockopt(
1929 self.as_raw(),
1930 libc::SOL_SOCKET,
1931 libc::SO_BINDTODEVICE,
1932 buf.as_mut_ptr().cast(),
1933 &mut len,
1934 ))?;
1935 if len == 0 {
1936 Ok(None)
1937 } else {
1938 let buf = &buf[..len as usize - 1];
1939 Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
1941 }
1942 }
1943
1944 #[cfg(all(
1952 feature = "all",
1953 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1954 ))]
1955 pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
1956 let (value, len) = if let Some(interface) = interface {
1957 (interface.as_ptr(), interface.len())
1958 } else {
1959 (ptr::null(), 0)
1960 };
1961 syscall!(setsockopt(
1962 self.as_raw(),
1963 libc::SOL_SOCKET,
1964 libc::SO_BINDTODEVICE,
1965 value.cast(),
1966 len as libc::socklen_t,
1967 ))
1968 .map(|_| ())
1969 }
1970
1971 #[cfg(all(feature = "all", target_os = "freebsd"))]
1975 pub fn set_fib(&self, fib: u32) -> io::Result<()> {
1976 syscall!(setsockopt(
1977 self.as_raw(),
1978 libc::SOL_SOCKET,
1979 libc::SO_SETFIB,
1980 (&fib as *const u32).cast(),
1981 mem::size_of::<u32>() as libc::socklen_t,
1982 ))
1983 .map(|_| ())
1984 }
1985
1986 #[cfg(all(
1997 feature = "all",
1998 any(
1999 target_os = "ios",
2000 target_os = "visionos",
2001 target_os = "macos",
2002 target_os = "tvos",
2003 target_os = "watchos",
2004 target_os = "illumos",
2005 target_os = "solaris",
2006 target_os = "linux",
2007 target_os = "android",
2008 )
2009 ))]
2010 pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2011 let index = interface.map_or(0, NonZeroU32::get);
2012
2013 #[cfg(any(
2014 target_os = "ios",
2015 target_os = "visionos",
2016 target_os = "macos",
2017 target_os = "tvos",
2018 target_os = "watchos",
2019 target_os = "illumos",
2020 target_os = "solaris",
2021 ))]
2022 unsafe {
2023 setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index)
2024 }
2025
2026 #[cfg(any(target_os = "linux", target_os = "android",))]
2027 unsafe {
2028 setsockopt(
2029 self.as_raw(),
2030 libc::SOL_SOCKET,
2031 libc::SO_BINDTOIFINDEX,
2032 index,
2033 )
2034 }
2035 }
2036
2037 #[cfg(all(
2048 feature = "all",
2049 any(
2050 target_os = "ios",
2051 target_os = "visionos",
2052 target_os = "macos",
2053 target_os = "tvos",
2054 target_os = "watchos",
2055 target_os = "illumos",
2056 target_os = "solaris",
2057 target_os = "linux",
2058 target_os = "android",
2059 )
2060 ))]
2061 pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2062 let index = interface.map_or(0, NonZeroU32::get);
2063
2064 #[cfg(any(
2065 target_os = "ios",
2066 target_os = "visionos",
2067 target_os = "macos",
2068 target_os = "tvos",
2069 target_os = "watchos",
2070 target_os = "illumos",
2071 target_os = "solaris",
2072 ))]
2073 unsafe {
2074 setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index)
2075 }
2076
2077 #[cfg(any(target_os = "linux", target_os = "android",))]
2078 unsafe {
2079 setsockopt(
2080 self.as_raw(),
2081 libc::SOL_SOCKET,
2082 libc::SO_BINDTOIFINDEX,
2083 index,
2084 )
2085 }
2086 }
2087
2088 #[cfg(all(
2094 feature = "all",
2095 any(
2096 target_os = "ios",
2097 target_os = "visionos",
2098 target_os = "macos",
2099 target_os = "tvos",
2100 target_os = "watchos",
2101 target_os = "illumos",
2102 target_os = "solaris",
2103 target_os = "linux",
2104 target_os = "android",
2105 )
2106 ))]
2107 pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
2108 #[cfg(any(
2109 target_os = "ios",
2110 target_os = "visionos",
2111 target_os = "macos",
2112 target_os = "tvos",
2113 target_os = "watchos",
2114 target_os = "illumos",
2115 target_os = "solaris",
2116 ))]
2117 let index =
2118 unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
2119
2120 #[cfg(any(target_os = "linux", target_os = "android",))]
2121 let index = unsafe {
2122 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2123 };
2124
2125 Ok(NonZeroU32::new(index))
2126 }
2127
2128 #[cfg(all(
2134 feature = "all",
2135 any(
2136 target_os = "ios",
2137 target_os = "visionos",
2138 target_os = "macos",
2139 target_os = "tvos",
2140 target_os = "watchos",
2141 target_os = "illumos",
2142 target_os = "solaris",
2143 target_os = "linux",
2144 target_os = "android",
2145 )
2146 ))]
2147 pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
2148 #[cfg(any(
2149 target_os = "ios",
2150 target_os = "visionos",
2151 target_os = "macos",
2152 target_os = "tvos",
2153 target_os = "watchos",
2154 target_os = "illumos",
2155 target_os = "solaris",
2156 ))]
2157 let index = unsafe {
2158 getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)?
2159 };
2160
2161 #[cfg(any(target_os = "linux", target_os = "android",))]
2162 let index = unsafe {
2163 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2164 };
2165
2166 Ok(NonZeroU32::new(index))
2167 }
2168
2169 #[cfg(all(feature = "all", target_os = "linux"))]
2175 pub fn cpu_affinity(&self) -> io::Result<usize> {
2176 unsafe {
2177 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
2178 .map(|cpu| cpu as usize)
2179 }
2180 }
2181
2182 #[cfg(all(feature = "all", target_os = "linux"))]
2186 pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
2187 unsafe {
2188 setsockopt(
2189 self.as_raw(),
2190 libc::SOL_SOCKET,
2191 libc::SO_INCOMING_CPU,
2192 cpu as c_int,
2193 )
2194 }
2195 }
2196
2197 #[cfg(all(
2203 feature = "all",
2204 not(any(
2205 target_os = "solaris",
2206 target_os = "illumos",
2207 target_os = "cygwin",
2208 target_os = "wasi"
2209 ))
2210 ))]
2211 pub fn reuse_port(&self) -> io::Result<bool> {
2212 unsafe {
2213 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
2214 .map(|reuse| reuse != 0)
2215 }
2216 }
2217
2218 #[cfg(all(
2224 feature = "all",
2225 not(any(
2226 target_os = "solaris",
2227 target_os = "illumos",
2228 target_os = "cygwin",
2229 target_os = "wasi"
2230 ))
2231 ))]
2232 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
2233 unsafe {
2234 setsockopt(
2235 self.as_raw(),
2236 libc::SOL_SOCKET,
2237 libc::SO_REUSEPORT,
2238 reuse as c_int,
2239 )
2240 }
2241 }
2242
2243 #[cfg(all(feature = "all", target_os = "freebsd"))]
2249 pub fn reuse_port_lb(&self) -> io::Result<bool> {
2250 unsafe {
2251 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT_LB)
2252 .map(|reuse| reuse != 0)
2253 }
2254 }
2255
2256 #[cfg(all(feature = "all", target_os = "freebsd"))]
2261 pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
2262 unsafe {
2263 setsockopt(
2264 self.as_raw(),
2265 libc::SOL_SOCKET,
2266 libc::SO_REUSEPORT_LB,
2267 reuse as c_int,
2268 )
2269 }
2270 }
2271
2272 #[cfg(all(
2278 feature = "all",
2279 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2280 ))]
2281 pub fn freebind_v4(&self) -> io::Result<bool> {
2282 unsafe {
2283 getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
2284 .map(|freebind| freebind != 0)
2285 }
2286 }
2287
2288 #[cfg(all(
2296 feature = "all",
2297 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2298 ))]
2299 pub fn set_freebind_v4(&self, freebind: bool) -> io::Result<()> {
2300 unsafe {
2301 setsockopt(
2302 self.as_raw(),
2303 libc::SOL_IP,
2304 libc::IP_FREEBIND,
2305 freebind as c_int,
2306 )
2307 }
2308 }
2309
2310 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2318 pub fn freebind_v6(&self) -> io::Result<bool> {
2319 unsafe {
2320 getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
2321 .map(|freebind| freebind != 0)
2322 }
2323 }
2324
2325 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2356 pub fn set_freebind_v6(&self, freebind: bool) -> io::Result<()> {
2357 unsafe {
2358 setsockopt(
2359 self.as_raw(),
2360 libc::SOL_IPV6,
2361 libc::IPV6_FREEBIND,
2362 freebind as c_int,
2363 )
2364 }
2365 }
2366
2367 #[doc = man_links!(unix: sendfile(2))]
2377 #[cfg(all(
2387 feature = "all",
2388 any(
2389 target_os = "aix",
2390 target_os = "android",
2391 target_os = "freebsd",
2392 target_os = "ios",
2393 target_os = "visionos",
2394 target_os = "linux",
2395 target_os = "macos",
2396 target_os = "tvos",
2397 target_os = "watchos",
2398 )
2399 ))]
2400 pub fn sendfile<F>(
2401 &self,
2402 file: &F,
2403 offset: usize,
2404 length: Option<NonZeroUsize>,
2405 ) -> io::Result<usize>
2406 where
2407 F: AsRawFd,
2408 {
2409 self._sendfile(file.as_raw_fd(), offset as _, length)
2410 }
2411
2412 #[cfg(all(
2413 feature = "all",
2414 any(
2415 target_os = "ios",
2416 target_os = "visionos",
2417 target_os = "macos",
2418 target_os = "tvos",
2419 target_os = "watchos",
2420 )
2421 ))]
2422 fn _sendfile(
2423 &self,
2424 file: RawFd,
2425 offset: libc::off_t,
2426 length: Option<NonZeroUsize>,
2427 ) -> io::Result<usize> {
2428 let mut length = match length {
2431 Some(n) => n.get() as libc::off_t,
2432 None => 0,
2434 };
2435 syscall!(sendfile(
2436 file,
2437 self.as_raw(),
2438 offset,
2439 &mut length,
2440 ptr::null_mut(),
2441 0,
2442 ))
2443 .map(|_| length as usize)
2444 }
2445
2446 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2447 fn _sendfile(
2448 &self,
2449 file: RawFd,
2450 offset: libc::off_t,
2451 length: Option<NonZeroUsize>,
2452 ) -> io::Result<usize> {
2453 let count = match length {
2454 Some(n) => n.get() as libc::size_t,
2455 None => 0x7ffff000, };
2458 let mut offset = offset;
2459 syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
2460 }
2461
2462 #[cfg(all(feature = "all", target_os = "freebsd"))]
2463 fn _sendfile(
2464 &self,
2465 file: RawFd,
2466 offset: libc::off_t,
2467 length: Option<NonZeroUsize>,
2468 ) -> io::Result<usize> {
2469 let nbytes = match length {
2470 Some(n) => n.get() as libc::size_t,
2471 None => 0,
2473 };
2474 let mut sbytes: libc::off_t = 0;
2475 syscall!(sendfile(
2476 file,
2477 self.as_raw(),
2478 offset,
2479 nbytes,
2480 ptr::null_mut(),
2481 &mut sbytes,
2482 0,
2483 ))
2484 .map(|_| sbytes as usize)
2485 }
2486
2487 #[cfg(all(feature = "all", target_os = "aix"))]
2488 fn _sendfile(
2489 &self,
2490 file: RawFd,
2491 offset: libc::off_t,
2492 length: Option<NonZeroUsize>,
2493 ) -> io::Result<usize> {
2494 let nbytes = match length {
2495 Some(n) => n.get() as i64,
2496 None => -1,
2497 };
2498 let mut params = libc::sf_parms {
2499 header_data: ptr::null_mut(),
2500 header_length: 0,
2501 file_descriptor: file,
2502 file_size: 0,
2503 file_offset: offset as u64,
2504 file_bytes: nbytes,
2505 trailer_data: ptr::null_mut(),
2506 trailer_length: 0,
2507 bytes_sent: 0,
2508 };
2509 syscall!(send_file(
2511 &mut self.as_raw() as *mut _,
2512 &mut params as *mut _,
2513 libc::SF_CLOSE as libc::c_uint,
2514 ))
2515 .map(|_| params.bytes_sent as usize)
2516 }
2517
2518 #[cfg(all(
2529 feature = "all",
2530 any(
2531 target_os = "android",
2532 target_os = "fuchsia",
2533 target_os = "linux",
2534 target_os = "cygwin",
2535 )
2536 ))]
2537 pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
2538 let timeout = timeout.map_or(0, |to| {
2539 min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint
2540 });
2541 unsafe {
2542 setsockopt(
2543 self.as_raw(),
2544 libc::IPPROTO_TCP,
2545 libc::TCP_USER_TIMEOUT,
2546 timeout,
2547 )
2548 }
2549 }
2550
2551 #[cfg(all(
2557 feature = "all",
2558 any(
2559 target_os = "android",
2560 target_os = "fuchsia",
2561 target_os = "linux",
2562 target_os = "cygwin",
2563 )
2564 ))]
2565 pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
2566 unsafe {
2567 getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
2568 .map(|millis| {
2569 if millis == 0 {
2570 None
2571 } else {
2572 Some(Duration::from_millis(millis as u64))
2573 }
2574 })
2575 }
2576 }
2577
2578 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2585 pub fn attach_filter(&self, filters: &[SockFilter]) -> io::Result<()> {
2586 let prog = libc::sock_fprog {
2587 len: filters.len() as u16,
2588 filter: filters.as_ptr() as *mut _,
2590 };
2591
2592 unsafe {
2593 setsockopt(
2594 self.as_raw(),
2595 libc::SOL_SOCKET,
2596 libc::SO_ATTACH_FILTER,
2597 prog,
2598 )
2599 }
2600 }
2601
2602 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2608 pub fn detach_filter(&self) -> io::Result<()> {
2609 unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) }
2610 }
2611
2612 #[cfg(all(feature = "all", target_os = "linux"))]
2619 pub fn cookie(&self) -> io::Result<u64> {
2620 unsafe { getsockopt::<libc::c_ulonglong>(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) }
2621 }
2622
2623 #[cfg(all(
2629 feature = "all",
2630 any(
2631 target_os = "android",
2632 target_os = "dragonfly",
2633 target_os = "freebsd",
2634 target_os = "fuchsia",
2635 target_os = "linux",
2636 target_os = "macos",
2637 target_os = "netbsd",
2638 target_os = "openbsd",
2639 target_os = "cygwin",
2640 )
2641 ))]
2642 pub fn tclass_v6(&self) -> io::Result<u32> {
2643 unsafe {
2644 getsockopt::<c_int>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS)
2645 .map(|tclass| tclass as u32)
2646 }
2647 }
2648
2649 #[cfg(all(
2654 feature = "all",
2655 any(
2656 target_os = "android",
2657 target_os = "dragonfly",
2658 target_os = "freebsd",
2659 target_os = "fuchsia",
2660 target_os = "linux",
2661 target_os = "macos",
2662 target_os = "netbsd",
2663 target_os = "openbsd",
2664 target_os = "cygwin",
2665 )
2666 ))]
2667 pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
2668 unsafe {
2669 setsockopt(
2670 self.as_raw(),
2671 IPPROTO_IPV6,
2672 libc::IPV6_TCLASS,
2673 tclass as c_int,
2674 )
2675 }
2676 }
2677
2678 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2684 pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
2685 let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX];
2686 let mut len = payload.len() as libc::socklen_t;
2687 syscall!(getsockopt(
2688 self.as_raw(),
2689 IPPROTO_TCP,
2690 libc::TCP_CONGESTION,
2691 payload.as_mut_ptr().cast(),
2692 &mut len,
2693 ))
2694 .map(|_| payload[..len as usize].to_vec())
2695 }
2696
2697 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2704 pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
2705 syscall!(setsockopt(
2706 self.as_raw(),
2707 IPPROTO_TCP,
2708 libc::TCP_CONGESTION,
2709 tcp_ca_name.as_ptr() as *const _,
2710 tcp_ca_name.len() as libc::socklen_t,
2711 ))
2712 .map(|_| ())
2713 }
2714
2715 #[cfg(all(feature = "all", target_os = "linux"))]
2726 pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
2727 unsafe {
2728 setsockopt(
2729 self.as_raw(),
2730 libc::SOL_DCCP,
2731 libc::DCCP_SOCKOPT_SERVICE,
2732 code,
2733 )
2734 }
2735 }
2736
2737 #[cfg(all(feature = "all", target_os = "linux"))]
2743 pub fn dccp_service(&self) -> io::Result<u32> {
2744 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) }
2745 }
2746
2747 #[cfg(all(feature = "all", target_os = "linux"))]
2751 pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
2752 unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) }
2753 }
2754
2755 #[cfg(all(feature = "all", target_os = "linux"))]
2761 pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
2762 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) }
2763 }
2764
2765 #[cfg(all(feature = "all", target_os = "linux"))]
2771 pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
2772 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) }
2773 }
2774
2775 #[cfg(all(feature = "all", target_os = "linux"))]
2780 pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> {
2781 unsafe {
2782 setsockopt(
2783 self.as_raw(),
2784 libc::SOL_DCCP,
2785 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2786 hold_timewait as c_int,
2787 )
2788 }
2789 }
2790
2791 #[cfg(all(feature = "all", target_os = "linux"))]
2797 pub fn dccp_server_timewait(&self) -> io::Result<bool> {
2798 unsafe {
2799 getsockopt(
2800 self.as_raw(),
2801 libc::SOL_DCCP,
2802 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2803 )
2804 }
2805 }
2806
2807 #[cfg(all(feature = "all", target_os = "linux"))]
2815 pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
2816 unsafe {
2817 setsockopt(
2818 self.as_raw(),
2819 libc::SOL_DCCP,
2820 libc::DCCP_SOCKOPT_SEND_CSCOV,
2821 level,
2822 )
2823 }
2824 }
2825
2826 #[cfg(all(feature = "all", target_os = "linux"))]
2832 pub fn dccp_send_cscov(&self) -> io::Result<u32> {
2833 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) }
2834 }
2835
2836 #[cfg(all(feature = "all", target_os = "linux"))]
2842 pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
2843 unsafe {
2844 setsockopt(
2845 self.as_raw(),
2846 libc::SOL_DCCP,
2847 libc::DCCP_SOCKOPT_RECV_CSCOV,
2848 level,
2849 )
2850 }
2851 }
2852
2853 #[cfg(all(feature = "all", target_os = "linux"))]
2859 pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
2860 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) }
2861 }
2862
2863 #[cfg(all(feature = "all", target_os = "linux"))]
2868 pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
2869 unsafe {
2870 setsockopt(
2871 self.as_raw(),
2872 libc::SOL_DCCP,
2873 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2874 length,
2875 )
2876 }
2877 }
2878
2879 #[cfg(all(feature = "all", target_os = "linux"))]
2885 pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
2886 unsafe {
2887 getsockopt(
2888 self.as_raw(),
2889 libc::SOL_DCCP,
2890 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2891 )
2892 }
2893 }
2894
2895 #[cfg(all(feature = "all", target_os = "linux"))]
2905 pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEndpoints<N>> {
2906 let mut endpoints = [0; N];
2907 let mut length = endpoints.len() as libc::socklen_t;
2908 syscall!(getsockopt(
2909 self.as_raw(),
2910 libc::SOL_DCCP,
2911 libc::DCCP_SOCKOPT_AVAILABLE_CCIDS,
2912 endpoints.as_mut_ptr().cast(),
2913 &mut length,
2914 ))?;
2915 Ok(CcidEndpoints { endpoints, length })
2916 }
2917
2918 #[cfg(all(feature = "all", target_os = "linux"))]
2923 pub fn dccp_cur_mps(&self) -> io::Result<u32> {
2924 unsafe {
2925 getsockopt(
2926 self.as_raw(),
2927 libc::SOL_DCCP,
2928 libc::DCCP_SOCKOPT_GET_CUR_MPS,
2929 )
2930 }
2931 }
2932
2933 #[cfg(all(feature = "all", target_os = "linux"))]
2937 pub fn busy_poll(&self) -> io::Result<u32> {
2938 unsafe { getsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_BUSY_POLL) }
2939 }
2940
2941 #[cfg(all(feature = "all", target_os = "linux"))]
2945 pub fn set_busy_poll(&self, busy_poll: u32) -> io::Result<()> {
2946 unsafe {
2947 setsockopt(
2948 self.as_raw(),
2949 libc::SOL_SOCKET,
2950 libc::SO_BUSY_POLL,
2951 busy_poll as c_int,
2952 )
2953 }
2954 }
2955}
2956
2957#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2963#[repr(transparent)]
2964pub struct SockFilter {
2965 #[allow(dead_code)]
2968 filter: libc::sock_filter,
2969}
2970
2971#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2972impl SockFilter {
2973 pub const fn new(code: u16, jt: u8, jf: u8, k: u32) -> SockFilter {
2975 SockFilter {
2976 filter: libc::sock_filter { code, jt, jf, k },
2977 }
2978 }
2979}
2980
2981#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2982impl std::fmt::Debug for SockFilter {
2983 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2984 f.debug_struct("SockFilter").finish_non_exhaustive()
2985 }
2986}
2987
2988#[cfg(all(feature = "all", target_os = "linux"))]
2992#[derive(Debug)]
2993pub struct CcidEndpoints<const N: usize> {
2994 endpoints: [u8; N],
2995 length: u32,
2996}
2997
2998#[cfg(all(feature = "all", target_os = "linux"))]
2999impl<const N: usize> std::ops::Deref for CcidEndpoints<N> {
3000 type Target = [u8];
3001
3002 fn deref(&self) -> &[u8] {
3003 &self.endpoints[0..self.length as usize]
3004 }
3005}
3006
3007impl AsFd for crate::Socket {
3008 fn as_fd(&self) -> BorrowedFd<'_> {
3009 unsafe { BorrowedFd::borrow_raw(self.as_raw()) }
3011 }
3012}
3013
3014impl AsRawFd for crate::Socket {
3015 fn as_raw_fd(&self) -> RawFd {
3016 self.as_raw()
3017 }
3018}
3019
3020impl From<crate::Socket> for OwnedFd {
3021 fn from(sock: crate::Socket) -> OwnedFd {
3022 unsafe { OwnedFd::from_raw_fd(sock.into_raw()) }
3024 }
3025}
3026
3027impl IntoRawFd for crate::Socket {
3028 fn into_raw_fd(self) -> c_int {
3029 self.into_raw()
3030 }
3031}
3032
3033impl From<OwnedFd> for crate::Socket {
3034 fn from(fd: OwnedFd) -> crate::Socket {
3035 unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) }
3037 }
3038}
3039
3040impl FromRawFd for crate::Socket {
3041 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
3042 crate::Socket::from_raw(fd)
3043 }
3044}
3045
3046#[cfg(all(feature = "all", unix))]
3047from!(UnixStream, crate::Socket);
3048#[cfg(all(feature = "all", unix))]
3049from!(UnixListener, crate::Socket);
3050#[cfg(all(feature = "all", unix))]
3051from!(UnixDatagram, crate::Socket);
3052#[cfg(all(feature = "all", unix))]
3053from!(crate::Socket, UnixStream);
3054#[cfg(all(feature = "all", unix))]
3055from!(crate::Socket, UnixListener);
3056#[cfg(all(feature = "all", unix))]
3057from!(crate::Socket, UnixDatagram);
3058
3059#[test]
3060fn in_addr_convertion() {
3061 let ip = Ipv4Addr::new(127, 0, 0, 1);
3062 let raw = to_in_addr(&ip);
3063 let a = raw.s_addr;
3065 assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
3066 assert_eq!(from_in_addr(raw), ip);
3067
3068 let ip = Ipv4Addr::new(127, 34, 4, 12);
3069 let raw = to_in_addr(&ip);
3070 let a = raw.s_addr;
3071 assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
3072 assert_eq!(from_in_addr(raw), ip);
3073}
3074
3075#[test]
3076fn in6_addr_convertion() {
3077 let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
3078 let raw = to_in6_addr(&ip);
3079 let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
3080 assert_eq!(raw.s6_addr, want);
3081 assert_eq!(from_in6_addr(raw), ip);
3082}