1use std::cmp::min;
10use std::ffi::OsStr;
11#[cfg(not(target_os = "redox"))]
12use std::io::IoSlice;
13use std::marker::PhantomData;
14use std::mem::{self, size_of, MaybeUninit};
15use std::net::Shutdown;
16use std::net::{Ipv4Addr, Ipv6Addr};
17#[cfg(all(
18 feature = "all",
19 any(
20 target_os = "ios",
21 target_os = "visionos",
22 target_os = "macos",
23 target_os = "tvos",
24 target_os = "watchos",
25 target_os = "illumos",
26 target_os = "solaris",
27 target_os = "linux",
28 target_os = "android",
29 )
30))]
31use std::num::NonZeroU32;
32#[cfg(all(
33 feature = "all",
34 any(
35 target_os = "aix",
36 target_os = "android",
37 target_os = "freebsd",
38 target_os = "ios",
39 target_os = "visionos",
40 target_os = "linux",
41 target_os = "macos",
42 target_os = "tvos",
43 target_os = "watchos",
44 )
45))]
46use std::num::NonZeroUsize;
47use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
48use std::os::unix::ffi::OsStrExt;
49#[cfg(feature = "all")]
50use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
51use std::path::Path;
52use std::ptr;
53use std::time::{Duration, Instant};
54use std::{io, slice};
55
56#[cfg(not(any(
57 target_os = "ios",
58 target_os = "visionos",
59 target_os = "macos",
60 target_os = "tvos",
61 target_os = "watchos",
62 target_os = "cygwin",
63)))]
64use libc::ssize_t;
65use libc::{in6_addr, in_addr};
66
67use crate::{Domain, Protocol, SockAddr, SockAddrStorage, TcpKeepalive, Type};
68#[cfg(not(target_os = "redox"))]
69use crate::{MsgHdr, MsgHdrMut, RecvFlags};
70
71pub(crate) use std::ffi::c_int;
72
73pub(crate) use libc::{AF_INET, AF_INET6, AF_UNIX};
75#[cfg(all(feature = "all", target_os = "linux"))]
77pub(crate) use libc::SOCK_DCCP;
78#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
79pub(crate) use libc::SOCK_RAW;
80#[cfg(all(feature = "all", not(target_os = "espidf")))]
81pub(crate) use libc::SOCK_SEQPACKET;
82pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM};
83#[cfg(all(feature = "all", target_os = "linux"))]
85pub(crate) use libc::IPPROTO_DCCP;
86#[cfg(target_os = "linux")]
87pub(crate) use libc::IPPROTO_MPTCP;
88#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
89pub(crate) use libc::IPPROTO_SCTP;
90#[cfg(all(
91 feature = "all",
92 any(
93 target_os = "android",
94 target_os = "freebsd",
95 target_os = "fuchsia",
96 target_os = "linux",
97 )
98))]
99pub(crate) use libc::IPPROTO_UDPLITE;
100pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP};
101#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
103pub(crate) use libc::IPPROTO_DIVERT;
104pub(crate) use libc::{
105 sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t,
106};
107#[cfg(not(any(target_os = "redox", target_os = "espidf")))]
109pub(crate) use libc::MSG_TRUNC;
110#[cfg(not(target_os = "redox"))]
111pub(crate) use libc::SO_OOBINLINE;
112#[cfg(not(target_os = "nto"))]
114pub(crate) use libc::ipv6_mreq as Ipv6Mreq;
115#[cfg(all(feature = "all", target_os = "linux"))]
116pub(crate) use libc::IPV6_HDRINCL;
117#[cfg(all(
118 feature = "all",
119 not(any(
120 target_os = "dragonfly",
121 target_os = "fuchsia",
122 target_os = "hurd",
123 target_os = "illumos",
124 target_os = "netbsd",
125 target_os = "openbsd",
126 target_os = "redox",
127 target_os = "solaris",
128 target_os = "haiku",
129 target_os = "espidf",
130 target_os = "vita",
131 target_os = "cygwin",
132 ))
133))]
134pub(crate) use libc::IPV6_RECVHOPLIMIT;
135#[cfg(not(any(
136 target_os = "dragonfly",
137 target_os = "fuchsia",
138 target_os = "hurd",
139 target_os = "illumos",
140 target_os = "netbsd",
141 target_os = "openbsd",
142 target_os = "redox",
143 target_os = "solaris",
144 target_os = "haiku",
145 target_os = "espidf",
146 target_os = "vita",
147)))]
148pub(crate) use libc::IPV6_RECVTCLASS;
149#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
150pub(crate) use libc::IP_HDRINCL;
151#[cfg(not(any(
152 target_os = "aix",
153 target_os = "dragonfly",
154 target_os = "fuchsia",
155 target_os = "illumos",
156 target_os = "netbsd",
157 target_os = "openbsd",
158 target_os = "redox",
159 target_os = "solaris",
160 target_os = "haiku",
161 target_os = "hurd",
162 target_os = "nto",
163 target_os = "espidf",
164 target_os = "vita",
165 target_os = "cygwin",
166)))]
167pub(crate) use libc::IP_RECVTOS;
168#[cfg(not(any(
169 target_os = "fuchsia",
170 target_os = "redox",
171 target_os = "solaris",
172 target_os = "haiku",
173 target_os = "illumos",
174)))]
175pub(crate) use libc::IP_TOS;
176#[cfg(not(any(
177 target_os = "ios",
178 target_os = "visionos",
179 target_os = "macos",
180 target_os = "tvos",
181 target_os = "watchos",
182)))]
183pub(crate) use libc::SO_LINGER;
184#[cfg(any(
185 target_os = "ios",
186 target_os = "visionos",
187 target_os = "macos",
188 target_os = "tvos",
189 target_os = "watchos",
190))]
191pub(crate) use libc::SO_LINGER_SEC as SO_LINGER;
192#[cfg(any(target_os = "linux", target_os = "cygwin"))]
193pub(crate) use libc::SO_PASSCRED;
194#[cfg(all(
195 feature = "all",
196 any(target_os = "linux", target_os = "android", target_os = "fuchsia")
197))]
198pub(crate) use libc::SO_PRIORITY;
199pub(crate) use libc::{
200 ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF,
201 IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
202 IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET,
203 SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF,
204 SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
205};
206#[cfg(not(any(
207 target_os = "dragonfly",
208 target_os = "haiku",
209 target_os = "hurd",
210 target_os = "netbsd",
211 target_os = "openbsd",
212 target_os = "redox",
213 target_os = "fuchsia",
214 target_os = "nto",
215 target_os = "espidf",
216 target_os = "vita",
217)))]
218pub(crate) use libc::{
219 ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
220};
221#[cfg(not(any(
222 target_os = "dragonfly",
223 target_os = "freebsd",
224 target_os = "haiku",
225 target_os = "illumos",
226 target_os = "ios",
227 target_os = "visionos",
228 target_os = "macos",
229 target_os = "netbsd",
230 target_os = "nto",
231 target_os = "openbsd",
232 target_os = "solaris",
233 target_os = "tvos",
234 target_os = "watchos",
235)))]
236pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
237#[cfg(any(
238 target_os = "dragonfly",
239 target_os = "freebsd",
240 target_os = "haiku",
241 target_os = "illumos",
242 target_os = "ios",
243 target_os = "visionos",
244 target_os = "macos",
245 target_os = "netbsd",
246 target_os = "openbsd",
247 target_os = "solaris",
248 target_os = "tvos",
249 target_os = "watchos",
250))]
251pub(crate) use libc::{
252 IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP,
253};
254#[cfg(all(
255 feature = "all",
256 any(
257 target_os = "android",
258 target_os = "dragonfly",
259 target_os = "freebsd",
260 target_os = "fuchsia",
261 target_os = "illumos",
262 target_os = "ios",
263 target_os = "visionos",
264 target_os = "linux",
265 target_os = "macos",
266 target_os = "netbsd",
267 target_os = "tvos",
268 target_os = "watchos",
269 target_os = "cygwin",
270 )
271))]
272pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
273
274pub(crate) type Bool = c_int;
276
277#[cfg(any(
278 target_os = "ios",
279 target_os = "visionos",
280 target_os = "macos",
281 target_os = "nto",
282 target_os = "tvos",
283 target_os = "watchos",
284))]
285use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
286#[cfg(not(any(
287 target_os = "haiku",
288 target_os = "ios",
289 target_os = "visionos",
290 target_os = "macos",
291 target_os = "nto",
292 target_os = "openbsd",
293 target_os = "tvos",
294 target_os = "watchos",
295 target_os = "vita",
296)))]
297use libc::TCP_KEEPIDLE as KEEPALIVE_TIME;
298
299macro_rules! syscall {
301 ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
302 #[allow(unused_unsafe)]
303 let res = unsafe { libc::$fn($($arg, )*) };
304 if res == -1 {
305 Err(std::io::Error::last_os_error())
306 } else {
307 Ok(res)
308 }
309 }};
310}
311
312#[cfg(not(any(
314 target_os = "ios",
315 target_os = "visionos",
316 target_os = "macos",
317 target_os = "tvos",
318 target_os = "watchos",
319 target_os = "cygwin",
320)))]
321const MAX_BUF_LEN: usize = ssize_t::MAX as usize;
322
323#[cfg(any(
332 target_os = "ios",
333 target_os = "visionos",
334 target_os = "macos",
335 target_os = "tvos",
336 target_os = "watchos",
337 target_os = "cygwin",
338))]
339const MAX_BUF_LEN: usize = c_int::MAX as usize - 1;
340
341#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
343const TCP_CA_NAME_MAX: usize = 16;
344
345#[cfg(any(
346 all(
347 target_os = "linux",
348 any(
349 target_env = "gnu",
350 all(target_env = "uclibc", target_pointer_width = "64")
351 )
352 ),
353 target_os = "android",
354))]
355type IovLen = usize;
356
357#[cfg(any(
358 all(
359 target_os = "linux",
360 any(
361 target_env = "musl",
362 target_env = "ohos",
363 all(target_env = "uclibc", target_pointer_width = "32")
364 )
365 ),
366 target_os = "aix",
367 target_os = "dragonfly",
368 target_os = "freebsd",
369 target_os = "fuchsia",
370 target_os = "haiku",
371 target_os = "hurd",
372 target_os = "illumos",
373 target_os = "ios",
374 target_os = "visionos",
375 target_os = "macos",
376 target_os = "netbsd",
377 target_os = "nto",
378 target_os = "openbsd",
379 target_os = "solaris",
380 target_os = "tvos",
381 target_os = "watchos",
382 target_os = "espidf",
383 target_os = "vita",
384 target_os = "cygwin",
385))]
386type IovLen = c_int;
387
388impl Domain {
390 #[cfg(all(
392 feature = "all",
393 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
394 ))]
395 pub const PACKET: Domain = Domain(libc::AF_PACKET);
396
397 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
399 pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
400}
401
402impl_debug!(
403 Domain,
404 libc::AF_INET,
405 libc::AF_INET6,
406 libc::AF_UNIX,
407 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
408 libc::AF_PACKET,
409 #[cfg(any(target_os = "android", target_os = "linux"))]
410 libc::AF_VSOCK,
411 libc::AF_UNSPEC, );
413
414impl Type {
416 #[cfg(all(
418 feature = "all",
419 any(
420 target_os = "android",
421 target_os = "dragonfly",
422 target_os = "freebsd",
423 target_os = "fuchsia",
424 target_os = "illumos",
425 target_os = "linux",
426 target_os = "netbsd",
427 target_os = "openbsd",
428 target_os = "cygwin",
429 )
430 ))]
431 pub const fn nonblocking(self) -> Type {
432 Type(self.0 | libc::SOCK_NONBLOCK)
433 }
434
435 #[cfg(all(
437 feature = "all",
438 any(
439 target_os = "android",
440 target_os = "dragonfly",
441 target_os = "freebsd",
442 target_os = "fuchsia",
443 target_os = "hurd",
444 target_os = "illumos",
445 target_os = "linux",
446 target_os = "netbsd",
447 target_os = "openbsd",
448 target_os = "redox",
449 target_os = "solaris",
450 target_os = "cygwin",
451 )
452 ))]
453 pub const fn cloexec(self) -> Type {
454 self._cloexec()
455 }
456
457 #[cfg(any(
458 target_os = "android",
459 target_os = "dragonfly",
460 target_os = "freebsd",
461 target_os = "fuchsia",
462 target_os = "hurd",
463 target_os = "illumos",
464 target_os = "linux",
465 target_os = "netbsd",
466 target_os = "openbsd",
467 target_os = "redox",
468 target_os = "solaris",
469 target_os = "cygwin",
470 ))]
471 pub(crate) const fn _cloexec(self) -> Type {
472 Type(self.0 | libc::SOCK_CLOEXEC)
473 }
474}
475
476impl_debug!(
477 Type,
478 libc::SOCK_STREAM,
479 libc::SOCK_DGRAM,
480 #[cfg(all(feature = "all", target_os = "linux"))]
481 libc::SOCK_DCCP,
482 #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
483 libc::SOCK_RAW,
484 #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "espidf")))]
485 libc::SOCK_RDM,
486 #[cfg(not(target_os = "espidf"))]
487 libc::SOCK_SEQPACKET,
488 );
511
512impl_debug!(
513 Protocol,
514 libc::IPPROTO_ICMP,
515 libc::IPPROTO_ICMPV6,
516 libc::IPPROTO_TCP,
517 libc::IPPROTO_UDP,
518 #[cfg(target_os = "linux")]
519 libc::IPPROTO_MPTCP,
520 #[cfg(all(feature = "all", target_os = "linux"))]
521 libc::IPPROTO_DCCP,
522 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
523 libc::IPPROTO_SCTP,
524 #[cfg(all(
525 feature = "all",
526 any(
527 target_os = "android",
528 target_os = "freebsd",
529 target_os = "fuchsia",
530 target_os = "linux",
531 )
532 ))]
533 libc::IPPROTO_UDPLITE,
534 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
535 libc::IPPROTO_DIVERT,
536);
537
538#[cfg(not(target_os = "redox"))]
540impl RecvFlags {
541 #[cfg(not(target_os = "espidf"))]
551 pub const fn is_end_of_record(self) -> bool {
552 self.0 & libc::MSG_EOR != 0
553 }
554
555 pub const fn is_out_of_band(self) -> bool {
562 self.0 & libc::MSG_OOB != 0
563 }
564
565 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
573 pub const fn is_confirm(self) -> bool {
574 self.0 & libc::MSG_CONFIRM != 0
575 }
576
577 #[cfg(all(
584 feature = "all",
585 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
586 ))]
587 pub const fn is_dontroute(self) -> bool {
588 self.0 & libc::MSG_DONTROUTE != 0
589 }
590}
591
592#[cfg(not(target_os = "redox"))]
593impl std::fmt::Debug for RecvFlags {
594 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
595 let mut s = f.debug_struct("RecvFlags");
596 #[cfg(not(target_os = "espidf"))]
597 s.field("is_end_of_record", &self.is_end_of_record());
598 s.field("is_out_of_band", &self.is_out_of_band());
599 #[cfg(not(target_os = "espidf"))]
600 s.field("is_truncated", &self.is_truncated());
601 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
602 s.field("is_confirm", &self.is_confirm());
603 #[cfg(all(
604 feature = "all",
605 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
606 ))]
607 s.field("is_dontroute", &self.is_dontroute());
608 s.finish()
609 }
610}
611
612#[repr(transparent)]
613pub struct MaybeUninitSlice<'a> {
614 vec: libc::iovec,
615 _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
616}
617
618unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
619
620unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
621
622impl<'a> MaybeUninitSlice<'a> {
623 pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
624 MaybeUninitSlice {
625 vec: libc::iovec {
626 iov_base: buf.as_mut_ptr().cast(),
627 iov_len: buf.len(),
628 },
629 _lifetime: PhantomData,
630 }
631 }
632
633 pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
634 unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
635 }
636
637 pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
638 unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
639 }
640}
641
642pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize {
644 let base = storage as *const _ as usize;
645 let path = ptr::addr_of!(storage.sun_path) as usize;
646 path - base
647}
648
649#[allow(unsafe_op_in_unsafe_fn)]
650pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
651 let mut storage = SockAddrStorage::zeroed();
652 let len = {
653 let storage = unsafe { storage.view_as::<libc::sockaddr_un>() };
655
656 let bytes = path.as_os_str().as_bytes();
657 let too_long = match bytes.first() {
658 None => false,
659 Some(&0) => bytes.len() > storage.sun_path.len(),
661 Some(_) => bytes.len() >= storage.sun_path.len(),
662 };
663 if too_long {
664 return Err(io::Error::new(
665 io::ErrorKind::InvalidInput,
666 "path must be shorter than SUN_LEN",
667 ));
668 }
669
670 storage.sun_family = libc::AF_UNIX as sa_family_t;
671 unsafe {
676 ptr::copy_nonoverlapping(
677 bytes.as_ptr(),
678 storage.sun_path.as_mut_ptr().cast(),
679 bytes.len(),
680 );
681 }
682
683 let sun_path_offset = offset_of_path(storage);
684 sun_path_offset
685 + bytes.len()
686 + match bytes.first() {
687 Some(&0) | None => 0,
688 Some(_) => 1,
689 }
690 };
691 Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
692}
693
694#[cfg(not(target_os = "redox"))]
696pub(crate) use libc::msghdr;
697
698#[cfg(not(target_os = "redox"))]
699pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
700 msg.msg_name = name.as_ptr() as *mut _;
701 msg.msg_namelen = name.len();
702}
703
704#[cfg(not(target_os = "redox"))]
705#[allow(clippy::unnecessary_cast)] pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) {
707 msg.msg_iov = ptr;
708 msg.msg_iovlen = min(len, IovLen::MAX as usize) as IovLen;
709}
710
711#[cfg(not(target_os = "redox"))]
712pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) {
713 msg.msg_control = ptr;
714 msg.msg_controllen = len as _;
715}
716
717#[cfg(not(target_os = "redox"))]
718pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: c_int) {
719 msg.msg_flags = flags;
720}
721
722#[cfg(not(target_os = "redox"))]
723pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
724 RecvFlags(msg.msg_flags)
725}
726
727#[cfg(not(target_os = "redox"))]
728pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
729 msg.msg_controllen as _
730}
731
732impl SockAddr {
734 #[allow(unsafe_op_in_unsafe_fn)]
741 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
742 pub fn vsock(cid: u32, port: u32) -> SockAddr {
743 let mut storage = SockAddrStorage::zeroed();
744 {
745 let storage = unsafe { storage.view_as::<libc::sockaddr_vm>() };
747 storage.svm_family = libc::AF_VSOCK as sa_family_t;
748 storage.svm_cid = cid;
749 storage.svm_port = port;
750 }
751 unsafe { SockAddr::new(storage, mem::size_of::<libc::sockaddr_vm>() as socklen_t) }
752 }
753
754 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
757 pub fn as_vsock_address(&self) -> Option<(u32, u32)> {
758 if self.family() == libc::AF_VSOCK as sa_family_t {
759 let addr = unsafe { &*(self.as_ptr() as *const libc::sockaddr_vm) };
761 Some((addr.svm_cid, addr.svm_port))
762 } else {
763 None
764 }
765 }
766
767 pub fn is_unnamed(&self) -> bool {
770 self.as_sockaddr_un()
771 .map(|storage| {
772 self.len() == offset_of_path(storage) as _
773 || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))
778 && storage.sun_path[0] == 0)
779 })
780 .unwrap_or_default()
781 }
782
783 pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> {
786 self.is_unix().then(|| {
787 unsafe { &*self.as_ptr().cast::<libc::sockaddr_un>() }
790 })
791 }
792
793 fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
798 debug_assert!(!self.is_unnamed());
799 self.len() as usize - offset_of_path(storage) - 1
800 }
801
802 fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] {
806 debug_assert!(!self.is_unnamed());
807 unsafe {
815 slice::from_raw_parts(
816 (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize),
817 self.path_len(storage),
818 )
819 }
820 }
821
822 pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
825 let path = self.as_pathname()?;
826 Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
829 }
830
831 pub fn as_pathname(&self) -> Option<&Path> {
834 self.as_sockaddr_un().and_then(|storage| {
835 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] != 0).then(|| {
836 let path_slice = self.path_bytes(storage, false);
837 Path::new::<OsStr>(OsStrExt::from_bytes(path_slice))
838 })
839 })
840 }
841
842 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
848 #[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
851 {
852 self.as_sockaddr_un().and_then(|storage| {
853 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] == 0)
854 .then(|| self.path_bytes(storage, true))
855 })
856 }
857 #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))]
858 None
859 }
860}
861
862pub(crate) type Socket = std::os::fd::OwnedFd;
863pub(crate) type RawSocket = c_int;
864
865pub(crate) unsafe fn socket_from_raw(socket: RawSocket) -> Socket {
866 Socket::from_raw_fd(socket)
867}
868
869pub(crate) fn socket_as_raw(socket: &Socket) -> RawSocket {
870 socket.as_raw_fd()
871}
872
873pub(crate) fn socket_into_raw(socket: Socket) -> RawSocket {
874 socket.into_raw_fd()
875}
876
877pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<RawSocket> {
878 syscall!(socket(family, ty, protocol))
879}
880
881#[cfg(all(feature = "all", unix))]
882pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[RawSocket; 2]> {
883 let mut fds = [0, 0];
884 syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds)
885}
886
887pub(crate) fn bind(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
888 syscall!(bind(fd, addr.as_ptr().cast::<sockaddr>(), addr.len() as _)).map(|_| ())
889}
890
891pub(crate) fn connect(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
892 syscall!(connect(fd, addr.as_ptr().cast::<sockaddr>(), addr.len())).map(|_| ())
893}
894
895pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
896 let start = Instant::now();
897
898 let mut pollfd = libc::pollfd {
899 fd: socket.as_raw(),
900 events: libc::POLLIN | libc::POLLOUT,
901 revents: 0,
902 };
903
904 loop {
905 let elapsed = start.elapsed();
906 if elapsed >= timeout {
907 return Err(io::ErrorKind::TimedOut.into());
908 }
909
910 let timeout = (timeout - elapsed).as_millis();
911 let timeout = timeout.clamp(1, c_int::MAX as u128) as c_int;
912
913 match syscall!(poll(&mut pollfd, 1, timeout)) {
914 Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
915 Ok(_) => {
916 if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0 {
918 match socket.take_error() {
919 Ok(Some(err)) | Err(err) => return Err(err),
920 Ok(None) => {
921 return Err(io::Error::new(
922 io::ErrorKind::Other,
923 "no error set after POLLHUP",
924 ))
925 }
926 }
927 }
928 return Ok(());
929 }
930 Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
932 Err(err) => return Err(err),
933 }
934 }
935}
936
937pub(crate) fn listen(fd: RawSocket, backlog: c_int) -> io::Result<()> {
938 syscall!(listen(fd, backlog)).map(|_| ())
939}
940
941pub(crate) fn accept(fd: RawSocket) -> io::Result<(RawSocket, SockAddr)> {
942 unsafe { SockAddr::try_init(|storage, len| syscall!(accept(fd, storage.cast(), len))) }
944}
945
946pub(crate) fn getsockname(fd: RawSocket) -> io::Result<SockAddr> {
947 unsafe { SockAddr::try_init(|storage, len| syscall!(getsockname(fd, storage.cast(), len))) }
949 .map(|(_, addr)| addr)
950}
951
952pub(crate) fn getpeername(fd: RawSocket) -> io::Result<SockAddr> {
953 unsafe { SockAddr::try_init(|storage, len| syscall!(getpeername(fd, storage.cast(), len))) }
955 .map(|(_, addr)| addr)
956}
957
958pub(crate) fn try_clone(fd: RawSocket) -> io::Result<RawSocket> {
959 syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0))
960}
961
962#[cfg(all(feature = "all", unix, not(target_os = "vita")))]
963pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
964 let file_status_flags = fcntl_get(fd, libc::F_GETFL)?;
965 Ok((file_status_flags & libc::O_NONBLOCK) != 0)
966}
967
968#[cfg(all(feature = "all", target_os = "vita"))]
969pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
970 unsafe {
971 getsockopt::<Bool>(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK).map(|non_block| non_block != 0)
972 }
973}
974
975#[cfg(not(target_os = "vita"))]
976pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::Result<()> {
977 if nonblocking {
978 fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
979 } else {
980 fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
981 }
982}
983
984#[cfg(target_os = "vita")]
985pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::Result<()> {
986 unsafe {
987 setsockopt(
988 fd,
989 libc::SOL_SOCKET,
990 libc::SO_NONBLOCK,
991 nonblocking as c_int,
992 )
993 }
994}
995
996pub(crate) fn shutdown(fd: RawSocket, how: Shutdown) -> io::Result<()> {
997 let how = match how {
998 Shutdown::Write => libc::SHUT_WR,
999 Shutdown::Read => libc::SHUT_RD,
1000 Shutdown::Both => libc::SHUT_RDWR,
1001 };
1002 syscall!(shutdown(fd, how)).map(|_| ())
1003}
1004
1005pub(crate) fn recv(fd: RawSocket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
1006 syscall!(recv(
1007 fd,
1008 buf.as_mut_ptr().cast(),
1009 min(buf.len(), MAX_BUF_LEN),
1010 flags,
1011 ))
1012 .map(|n| n as usize)
1013}
1014
1015pub(crate) fn recv_from(
1016 fd: RawSocket,
1017 buf: &mut [MaybeUninit<u8>],
1018 flags: c_int,
1019) -> io::Result<(usize, SockAddr)> {
1020 unsafe {
1022 SockAddr::try_init(|addr, addrlen| {
1023 syscall!(recvfrom(
1024 fd,
1025 buf.as_mut_ptr().cast(),
1026 min(buf.len(), MAX_BUF_LEN),
1027 flags,
1028 addr.cast(),
1029 addrlen
1030 ))
1031 .map(|n| n as usize)
1032 })
1033 }
1034}
1035
1036pub(crate) fn peek_sender(fd: RawSocket) -> io::Result<SockAddr> {
1037 let (_, sender) = recv_from(fd, &mut [MaybeUninit::uninit(); 8], MSG_PEEK)?;
1042 Ok(sender)
1043}
1044
1045#[cfg(not(target_os = "redox"))]
1046pub(crate) fn recv_vectored(
1047 fd: RawSocket,
1048 bufs: &mut [crate::MaybeUninitSlice<'_>],
1049 flags: c_int,
1050) -> io::Result<(usize, RecvFlags)> {
1051 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1052 let n = recvmsg(fd, &mut msg, flags)?;
1053 Ok((n, msg.flags()))
1054}
1055
1056#[cfg(not(target_os = "redox"))]
1057pub(crate) fn recv_from_vectored(
1058 fd: RawSocket,
1059 bufs: &mut [crate::MaybeUninitSlice<'_>],
1060 flags: c_int,
1061) -> io::Result<(usize, RecvFlags, SockAddr)> {
1062 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1063 let (n, addr) = unsafe {
1066 SockAddr::try_init(|storage, len| {
1067 msg.inner.msg_name = storage.cast();
1068 msg.inner.msg_namelen = *len;
1069 let n = recvmsg(fd, &mut msg, flags)?;
1070 *len = msg.inner.msg_namelen;
1072 Ok(n)
1073 })?
1074 };
1075 Ok((n, msg.flags(), addr))
1076}
1077
1078#[cfg(not(target_os = "redox"))]
1079pub(crate) fn recvmsg(
1080 fd: RawSocket,
1081 msg: &mut MsgHdrMut<'_, '_, '_>,
1082 flags: c_int,
1083) -> io::Result<usize> {
1084 syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|n| n as usize)
1085}
1086
1087pub(crate) fn send(fd: RawSocket, buf: &[u8], flags: c_int) -> io::Result<usize> {
1088 syscall!(send(
1089 fd,
1090 buf.as_ptr().cast(),
1091 min(buf.len(), MAX_BUF_LEN),
1092 flags,
1093 ))
1094 .map(|n| n as usize)
1095}
1096
1097#[cfg(not(target_os = "redox"))]
1098pub(crate) fn send_vectored(
1099 fd: RawSocket,
1100 bufs: &[IoSlice<'_>],
1101 flags: c_int,
1102) -> io::Result<usize> {
1103 let msg = MsgHdr::new().with_buffers(bufs);
1104 sendmsg(fd, &msg, flags)
1105}
1106
1107pub(crate) fn send_to(
1108 fd: RawSocket,
1109 buf: &[u8],
1110 addr: &SockAddr,
1111 flags: c_int,
1112) -> io::Result<usize> {
1113 syscall!(sendto(
1114 fd,
1115 buf.as_ptr().cast(),
1116 min(buf.len(), MAX_BUF_LEN),
1117 flags,
1118 addr.as_ptr().cast::<sockaddr>(),
1119 addr.len(),
1120 ))
1121 .map(|n| n as usize)
1122}
1123
1124#[cfg(not(target_os = "redox"))]
1125pub(crate) fn send_to_vectored(
1126 fd: RawSocket,
1127 bufs: &[IoSlice<'_>],
1128 addr: &SockAddr,
1129 flags: c_int,
1130) -> io::Result<usize> {
1131 let msg = MsgHdr::new().with_addr(addr).with_buffers(bufs);
1132 sendmsg(fd, &msg, flags)
1133}
1134
1135#[cfg(not(target_os = "redox"))]
1136pub(crate) fn sendmsg(fd: RawSocket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
1137 syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
1138}
1139
1140pub(crate) fn timeout_opt(fd: RawSocket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
1142 unsafe { getsockopt(fd, opt, val).map(from_timeval) }
1143}
1144
1145const fn from_timeval(duration: libc::timeval) -> Option<Duration> {
1146 if duration.tv_sec == 0 && duration.tv_usec == 0 {
1147 None
1148 } else {
1149 let sec = duration.tv_sec as u64;
1150 let nsec = (duration.tv_usec as u32) * 1000;
1151 Some(Duration::new(sec, nsec))
1152 }
1153}
1154
1155pub(crate) fn set_timeout_opt(
1157 fd: RawSocket,
1158 opt: c_int,
1159 val: c_int,
1160 duration: Option<Duration>,
1161) -> io::Result<()> {
1162 let duration = into_timeval(duration);
1163 unsafe { setsockopt(fd, opt, val, duration) }
1164}
1165
1166fn into_timeval(duration: Option<Duration>) -> libc::timeval {
1167 match duration {
1168 #[cfg_attr(target_env = "musl", allow(deprecated))]
1170 Some(duration) => libc::timeval {
1171 tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
1172 tv_usec: duration.subsec_micros() as libc::suseconds_t,
1173 },
1174 None => libc::timeval {
1175 tv_sec: 0,
1176 tv_usec: 0,
1177 },
1178 }
1179}
1180
1181#[cfg(all(
1182 feature = "all",
1183 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1184))]
1185pub(crate) fn tcp_keepalive_time(fd: RawSocket) -> io::Result<Duration> {
1186 unsafe {
1187 getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
1188 .map(|secs| Duration::from_secs(secs as u64))
1189 }
1190}
1191
1192#[allow(unused_variables)]
1193pub(crate) fn set_tcp_keepalive(fd: RawSocket, keepalive: &TcpKeepalive) -> io::Result<()> {
1194 #[cfg(not(any(
1195 target_os = "haiku",
1196 target_os = "openbsd",
1197 target_os = "nto",
1198 target_os = "vita"
1199 )))]
1200 if let Some(time) = keepalive.time {
1201 let secs = into_secs(time);
1202 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1203 }
1204
1205 #[cfg(any(
1206 target_os = "aix",
1207 target_os = "android",
1208 target_os = "dragonfly",
1209 target_os = "freebsd",
1210 target_os = "fuchsia",
1211 target_os = "hurd",
1212 target_os = "illumos",
1213 target_os = "ios",
1214 target_os = "visionos",
1215 target_os = "linux",
1216 target_os = "macos",
1217 target_os = "netbsd",
1218 target_os = "tvos",
1219 target_os = "watchos",
1220 target_os = "cygwin",
1221 ))]
1222 {
1223 if let Some(interval) = keepalive.interval {
1224 let secs = into_secs(interval);
1225 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
1226 }
1227
1228 if let Some(retries) = keepalive.retries {
1229 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
1230 }
1231 }
1232
1233 #[cfg(target_os = "nto")]
1234 if let Some(time) = keepalive.time {
1235 let secs = into_timeval(Some(time));
1236 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1237 }
1238
1239 Ok(())
1240}
1241
1242#[cfg(not(any(
1243 target_os = "haiku",
1244 target_os = "openbsd",
1245 target_os = "nto",
1246 target_os = "vita"
1247)))]
1248fn into_secs(duration: Duration) -> c_int {
1249 min(duration.as_secs(), c_int::MAX as u64) as c_int
1250}
1251
1252#[cfg(not(target_os = "vita"))]
1254fn fcntl_get(fd: RawSocket, cmd: c_int) -> io::Result<c_int> {
1255 syscall!(fcntl(fd, cmd))
1256}
1257
1258#[cfg(not(target_os = "vita"))]
1260fn fcntl_add(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1261 let previous = fcntl_get(fd, get_cmd)?;
1262 let new = previous | flag;
1263 if new != previous {
1264 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1265 } else {
1266 Ok(())
1268 }
1269}
1270
1271#[cfg(not(target_os = "vita"))]
1273fn fcntl_remove(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1274 let previous = fcntl_get(fd, get_cmd)?;
1275 let new = previous & !flag;
1276 if new != previous {
1277 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1278 } else {
1279 Ok(())
1281 }
1282}
1283
1284pub(crate) unsafe fn getsockopt<T>(fd: RawSocket, opt: c_int, val: c_int) -> io::Result<T> {
1286 let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
1287 let mut len = size_of::<T>() as libc::socklen_t;
1288 syscall!(getsockopt(
1289 fd,
1290 opt,
1291 val,
1292 payload.as_mut_ptr().cast(),
1293 &mut len,
1294 ))
1295 .map(|_| {
1296 debug_assert_eq!(len as usize, size_of::<T>());
1297 payload.assume_init()
1299 })
1300}
1301
1302pub(crate) unsafe fn setsockopt<T>(
1304 fd: RawSocket,
1305 opt: c_int,
1306 val: c_int,
1307 payload: T,
1308) -> io::Result<()> {
1309 let payload = ptr::addr_of!(payload).cast();
1310 syscall!(setsockopt(
1311 fd,
1312 opt,
1313 val,
1314 payload,
1315 mem::size_of::<T>() as libc::socklen_t,
1316 ))
1317 .map(|_| ())
1318}
1319
1320pub(crate) const fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
1321 in_addr {
1325 s_addr: u32::from_ne_bytes(addr.octets()),
1326 }
1327}
1328
1329pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
1330 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1331}
1332
1333pub(crate) const fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
1334 in6_addr {
1335 s6_addr: addr.octets(),
1336 }
1337}
1338
1339pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
1340 Ipv6Addr::from(addr.s6_addr)
1341}
1342
1343#[cfg(not(any(
1344 target_os = "aix",
1345 target_os = "haiku",
1346 target_os = "illumos",
1347 target_os = "netbsd",
1348 target_os = "openbsd",
1349 target_os = "redox",
1350 target_os = "solaris",
1351 target_os = "nto",
1352 target_os = "espidf",
1353 target_os = "vita",
1354 target_os = "cygwin",
1355)))]
1356pub(crate) const fn to_mreqn(
1357 multiaddr: &Ipv4Addr,
1358 interface: &crate::socket::InterfaceIndexOrAddress,
1359) -> libc::ip_mreqn {
1360 match interface {
1361 crate::socket::InterfaceIndexOrAddress::Index(interface) => libc::ip_mreqn {
1362 imr_multiaddr: to_in_addr(multiaddr),
1363 imr_address: to_in_addr(&Ipv4Addr::UNSPECIFIED),
1364 imr_ifindex: *interface as _,
1365 },
1366 crate::socket::InterfaceIndexOrAddress::Address(interface) => libc::ip_mreqn {
1367 imr_multiaddr: to_in_addr(multiaddr),
1368 imr_address: to_in_addr(interface),
1369 imr_ifindex: 0,
1370 },
1371 }
1372}
1373
1374#[cfg(all(
1375 feature = "all",
1376 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1377))]
1378pub(crate) fn original_dst_v4(fd: RawSocket) -> io::Result<SockAddr> {
1379 unsafe {
1381 SockAddr::try_init(|storage, len| {
1382 syscall!(getsockopt(
1383 fd,
1384 libc::SOL_IP,
1385 libc::SO_ORIGINAL_DST,
1386 storage.cast(),
1387 len
1388 ))
1389 })
1390 }
1391 .map(|(_, addr)| addr)
1392}
1393
1394#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1399pub(crate) fn original_dst_v6(fd: RawSocket) -> io::Result<SockAddr> {
1400 unsafe {
1402 SockAddr::try_init(|storage, len| {
1403 syscall!(getsockopt(
1404 fd,
1405 libc::SOL_IPV6,
1406 libc::IP6T_SO_ORIGINAL_DST,
1407 storage.cast(),
1408 len
1409 ))
1410 })
1411 }
1412 .map(|(_, addr)| addr)
1413}
1414
1415impl crate::Socket {
1417 #[doc = man_links!(unix: accept4(2))]
1425 #[cfg(all(
1426 feature = "all",
1427 any(
1428 target_os = "android",
1429 target_os = "dragonfly",
1430 target_os = "freebsd",
1431 target_os = "fuchsia",
1432 target_os = "illumos",
1433 target_os = "linux",
1434 target_os = "netbsd",
1435 target_os = "openbsd",
1436 target_os = "cygwin",
1437 )
1438 ))]
1439 pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1440 self._accept4(flags)
1441 }
1442
1443 #[cfg(any(
1444 target_os = "android",
1445 target_os = "dragonfly",
1446 target_os = "freebsd",
1447 target_os = "fuchsia",
1448 target_os = "illumos",
1449 target_os = "linux",
1450 target_os = "netbsd",
1451 target_os = "openbsd",
1452 target_os = "cygwin",
1453 ))]
1454 pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1455 unsafe {
1457 SockAddr::try_init(|storage, len| {
1458 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1459 .map(crate::Socket::from_raw)
1460 })
1461 }
1462 }
1463
1464 #[cfg_attr(
1470 any(
1471 target_os = "ios",
1472 target_os = "visionos",
1473 target_os = "macos",
1474 target_os = "tvos",
1475 target_os = "watchos"
1476 ),
1477 allow(rustdoc::broken_intra_doc_links)
1478 )]
1479 #[cfg(all(feature = "all", not(target_os = "vita")))]
1480 pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1481 self._set_cloexec(close_on_exec)
1482 }
1483
1484 #[cfg(not(target_os = "vita"))]
1485 pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1486 if close_on_exec {
1487 fcntl_add(
1488 self.as_raw(),
1489 libc::F_GETFD,
1490 libc::F_SETFD,
1491 libc::FD_CLOEXEC,
1492 )
1493 } else {
1494 fcntl_remove(
1495 self.as_raw(),
1496 libc::F_GETFD,
1497 libc::F_SETFD,
1498 libc::FD_CLOEXEC,
1499 )
1500 }
1501 }
1502
1503 #[cfg(target_os = "cygwin")]
1516 #[cfg(any(doc, target_os = "cygwin"))]
1517 pub fn set_no_peercred(&self) -> io::Result<()> {
1518 syscall!(setsockopt(
1519 self.as_raw(),
1520 libc::SOL_SOCKET,
1521 libc::SO_PEERCRED,
1522 ptr::null_mut(),
1523 0,
1524 ))
1525 .map(|_| ())
1526 }
1527
1528 #[cfg(all(
1530 feature = "all",
1531 any(
1532 target_os = "ios",
1533 target_os = "visionos",
1534 target_os = "macos",
1535 target_os = "tvos",
1536 target_os = "watchos",
1537 )
1538 ))]
1539 pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1540 self._set_nosigpipe(nosigpipe)
1541 }
1542
1543 #[cfg(any(
1544 target_os = "ios",
1545 target_os = "visionos",
1546 target_os = "macos",
1547 target_os = "tvos",
1548 target_os = "watchos",
1549 ))]
1550 pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1551 unsafe {
1552 setsockopt(
1553 self.as_raw(),
1554 libc::SOL_SOCKET,
1555 libc::SO_NOSIGPIPE,
1556 nosigpipe as c_int,
1557 )
1558 }
1559 }
1560
1561 #[cfg(all(feature = "all", not(target_os = "redox")))]
1567 pub fn tcp_mss(&self) -> io::Result<u32> {
1568 unsafe {
1569 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1570 .map(|mss| mss as u32)
1571 }
1572 }
1573
1574 #[cfg(all(feature = "all", not(target_os = "redox")))]
1579 pub fn set_tcp_mss(&self, mss: u32) -> io::Result<()> {
1580 unsafe {
1581 setsockopt(
1582 self.as_raw(),
1583 libc::IPPROTO_TCP,
1584 libc::TCP_MAXSEG,
1585 mss as c_int,
1586 )
1587 }
1588 }
1589
1590 #[cfg(all(
1593 feature = "all",
1594 any(
1595 target_os = "aix",
1596 target_os = "android",
1597 target_os = "freebsd",
1598 target_os = "fuchsia",
1599 target_os = "linux",
1600 target_os = "cygwin",
1601 )
1602 ))]
1603 pub fn is_listener(&self) -> io::Result<bool> {
1604 unsafe {
1605 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1606 .map(|v| v != 0)
1607 }
1608 }
1609
1610 #[cfg(all(
1613 feature = "all",
1614 any(
1615 target_os = "android",
1616 target_os = "fuchsia",
1619 target_os = "linux",
1620 )
1621 ))]
1622 pub fn domain(&self) -> io::Result<Domain> {
1623 unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1624 }
1625
1626 #[cfg(all(
1629 feature = "all",
1630 any(
1631 target_os = "android",
1632 target_os = "freebsd",
1633 target_os = "fuchsia",
1634 target_os = "linux",
1635 )
1636 ))]
1637 pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1638 unsafe {
1639 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1640 {
1641 0 => None,
1642 p => Some(Protocol(p)),
1643 })
1644 }
1645 }
1646
1647 #[cfg(all(
1654 feature = "all",
1655 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1656 ))]
1657 pub fn mark(&self) -> io::Result<u32> {
1658 unsafe {
1659 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1660 .map(|mark| mark as u32)
1661 }
1662 }
1663
1664 #[cfg(all(
1672 feature = "all",
1673 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1674 ))]
1675 pub fn set_mark(&self, mark: u32) -> io::Result<()> {
1676 unsafe {
1677 setsockopt::<c_int>(
1678 self.as_raw(),
1679 libc::SOL_SOCKET,
1680 libc::SO_MARK,
1681 mark as c_int,
1682 )
1683 }
1684 }
1685
1686 #[cfg(all(
1692 feature = "all",
1693 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1694 ))]
1695 pub fn tcp_cork(&self) -> io::Result<bool> {
1696 unsafe {
1697 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK)
1698 .map(|cork| cork != 0)
1699 }
1700 }
1701
1702 #[cfg(all(
1709 feature = "all",
1710 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1711 ))]
1712 pub fn set_tcp_cork(&self, cork: bool) -> io::Result<()> {
1713 unsafe {
1714 setsockopt(
1715 self.as_raw(),
1716 libc::IPPROTO_TCP,
1717 libc::TCP_CORK,
1718 cork as c_int,
1719 )
1720 }
1721 }
1722
1723 #[cfg(all(
1729 feature = "all",
1730 any(
1731 target_os = "android",
1732 target_os = "fuchsia",
1733 target_os = "linux",
1734 target_os = "cygwin",
1735 )
1736 ))]
1737 pub fn tcp_quickack(&self) -> io::Result<bool> {
1738 unsafe {
1739 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK)
1740 .map(|quickack| quickack != 0)
1741 }
1742 }
1743
1744 #[cfg(all(
1751 feature = "all",
1752 any(
1753 target_os = "android",
1754 target_os = "fuchsia",
1755 target_os = "linux",
1756 target_os = "cygwin",
1757 )
1758 ))]
1759 pub fn set_tcp_quickack(&self, quickack: bool) -> io::Result<()> {
1760 unsafe {
1761 setsockopt(
1762 self.as_raw(),
1763 libc::IPPROTO_TCP,
1764 libc::TCP_QUICKACK,
1765 quickack as c_int,
1766 )
1767 }
1768 }
1769
1770 #[cfg(all(
1776 feature = "all",
1777 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1778 ))]
1779 pub fn tcp_thin_linear_timeouts(&self) -> io::Result<bool> {
1780 unsafe {
1781 getsockopt::<Bool>(
1782 self.as_raw(),
1783 libc::IPPROTO_TCP,
1784 libc::TCP_THIN_LINEAR_TIMEOUTS,
1785 )
1786 .map(|timeouts| timeouts != 0)
1787 }
1788 }
1789
1790 #[cfg(all(
1796 feature = "all",
1797 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1798 ))]
1799 pub fn set_tcp_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> {
1800 unsafe {
1801 setsockopt(
1802 self.as_raw(),
1803 libc::IPPROTO_TCP,
1804 libc::TCP_THIN_LINEAR_TIMEOUTS,
1805 timeouts as c_int,
1806 )
1807 }
1808 }
1809
1810 #[cfg(all(
1814 feature = "all",
1815 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1816 ))]
1817 pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1818 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1820 unsafe { MaybeUninit::uninit().assume_init() };
1821 let mut len = buf.len() as libc::socklen_t;
1822 syscall!(getsockopt(
1823 self.as_raw(),
1824 libc::SOL_SOCKET,
1825 libc::SO_BINDTODEVICE,
1826 buf.as_mut_ptr().cast(),
1827 &mut len,
1828 ))?;
1829 if len == 0 {
1830 Ok(None)
1831 } else {
1832 let buf = &buf[..len as usize - 1];
1833 Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
1835 }
1836 }
1837
1838 #[cfg(all(
1846 feature = "all",
1847 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1848 ))]
1849 pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
1850 let (value, len) = if let Some(interface) = interface {
1851 (interface.as_ptr(), interface.len())
1852 } else {
1853 (ptr::null(), 0)
1854 };
1855 syscall!(setsockopt(
1856 self.as_raw(),
1857 libc::SOL_SOCKET,
1858 libc::SO_BINDTODEVICE,
1859 value.cast(),
1860 len as libc::socklen_t,
1861 ))
1862 .map(|_| ())
1863 }
1864
1865 #[cfg(all(feature = "all", target_os = "freebsd"))]
1869 pub fn set_fib(&self, fib: u32) -> io::Result<()> {
1870 syscall!(setsockopt(
1871 self.as_raw(),
1872 libc::SOL_SOCKET,
1873 libc::SO_SETFIB,
1874 (&fib as *const u32).cast(),
1875 mem::size_of::<u32>() as libc::socklen_t,
1876 ))
1877 .map(|_| ())
1878 }
1879
1880 #[cfg(all(
1891 feature = "all",
1892 any(
1893 target_os = "ios",
1894 target_os = "visionos",
1895 target_os = "macos",
1896 target_os = "tvos",
1897 target_os = "watchos",
1898 target_os = "illumos",
1899 target_os = "solaris",
1900 target_os = "linux",
1901 target_os = "android",
1902 )
1903 ))]
1904 pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
1905 let index = interface.map_or(0, NonZeroU32::get);
1906
1907 #[cfg(any(
1908 target_os = "ios",
1909 target_os = "visionos",
1910 target_os = "macos",
1911 target_os = "tvos",
1912 target_os = "watchos",
1913 target_os = "illumos",
1914 target_os = "solaris",
1915 ))]
1916 unsafe {
1917 setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index)
1918 }
1919
1920 #[cfg(any(target_os = "linux", target_os = "android",))]
1921 unsafe {
1922 setsockopt(
1923 self.as_raw(),
1924 libc::SOL_SOCKET,
1925 libc::SO_BINDTOIFINDEX,
1926 index,
1927 )
1928 }
1929 }
1930
1931 #[cfg(all(
1942 feature = "all",
1943 any(
1944 target_os = "ios",
1945 target_os = "visionos",
1946 target_os = "macos",
1947 target_os = "tvos",
1948 target_os = "watchos",
1949 target_os = "illumos",
1950 target_os = "solaris",
1951 target_os = "linux",
1952 target_os = "android",
1953 )
1954 ))]
1955 pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
1956 let index = interface.map_or(0, NonZeroU32::get);
1957
1958 #[cfg(any(
1959 target_os = "ios",
1960 target_os = "visionos",
1961 target_os = "macos",
1962 target_os = "tvos",
1963 target_os = "watchos",
1964 target_os = "illumos",
1965 target_os = "solaris",
1966 ))]
1967 unsafe {
1968 setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index)
1969 }
1970
1971 #[cfg(any(target_os = "linux", target_os = "android",))]
1972 unsafe {
1973 setsockopt(
1974 self.as_raw(),
1975 libc::SOL_SOCKET,
1976 libc::SO_BINDTOIFINDEX,
1977 index,
1978 )
1979 }
1980 }
1981
1982 #[cfg(all(
1988 feature = "all",
1989 any(
1990 target_os = "ios",
1991 target_os = "visionos",
1992 target_os = "macos",
1993 target_os = "tvos",
1994 target_os = "watchos",
1995 target_os = "illumos",
1996 target_os = "solaris",
1997 target_os = "linux",
1998 target_os = "android",
1999 )
2000 ))]
2001 pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
2002 #[cfg(any(
2003 target_os = "ios",
2004 target_os = "visionos",
2005 target_os = "macos",
2006 target_os = "tvos",
2007 target_os = "watchos",
2008 target_os = "illumos",
2009 target_os = "solaris",
2010 ))]
2011 let index =
2012 unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
2013
2014 #[cfg(any(target_os = "linux", target_os = "android",))]
2015 let index = unsafe {
2016 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2017 };
2018
2019 Ok(NonZeroU32::new(index))
2020 }
2021
2022 #[cfg(all(
2028 feature = "all",
2029 any(
2030 target_os = "ios",
2031 target_os = "visionos",
2032 target_os = "macos",
2033 target_os = "tvos",
2034 target_os = "watchos",
2035 target_os = "illumos",
2036 target_os = "solaris",
2037 target_os = "linux",
2038 target_os = "android",
2039 )
2040 ))]
2041 pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
2042 #[cfg(any(
2043 target_os = "ios",
2044 target_os = "visionos",
2045 target_os = "macos",
2046 target_os = "tvos",
2047 target_os = "watchos",
2048 target_os = "illumos",
2049 target_os = "solaris",
2050 ))]
2051 let index = unsafe {
2052 getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)?
2053 };
2054
2055 #[cfg(any(target_os = "linux", target_os = "android",))]
2056 let index = unsafe {
2057 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2058 };
2059
2060 Ok(NonZeroU32::new(index))
2061 }
2062
2063 #[cfg(all(feature = "all", target_os = "linux"))]
2069 pub fn cpu_affinity(&self) -> io::Result<usize> {
2070 unsafe {
2071 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
2072 .map(|cpu| cpu as usize)
2073 }
2074 }
2075
2076 #[cfg(all(feature = "all", target_os = "linux"))]
2080 pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
2081 unsafe {
2082 setsockopt(
2083 self.as_raw(),
2084 libc::SOL_SOCKET,
2085 libc::SO_INCOMING_CPU,
2086 cpu as c_int,
2087 )
2088 }
2089 }
2090
2091 #[cfg(all(
2097 feature = "all",
2098 not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin"))
2099 ))]
2100 pub fn reuse_port(&self) -> io::Result<bool> {
2101 unsafe {
2102 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
2103 .map(|reuse| reuse != 0)
2104 }
2105 }
2106
2107 #[cfg(all(
2113 feature = "all",
2114 not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin"))
2115 ))]
2116 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
2117 unsafe {
2118 setsockopt(
2119 self.as_raw(),
2120 libc::SOL_SOCKET,
2121 libc::SO_REUSEPORT,
2122 reuse as c_int,
2123 )
2124 }
2125 }
2126
2127 #[cfg(all(feature = "all", target_os = "freebsd"))]
2133 pub fn reuse_port_lb(&self) -> io::Result<bool> {
2134 unsafe {
2135 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT_LB)
2136 .map(|reuse| reuse != 0)
2137 }
2138 }
2139
2140 #[cfg(all(feature = "all", target_os = "freebsd"))]
2145 pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
2146 unsafe {
2147 setsockopt(
2148 self.as_raw(),
2149 libc::SOL_SOCKET,
2150 libc::SO_REUSEPORT_LB,
2151 reuse as c_int,
2152 )
2153 }
2154 }
2155
2156 #[cfg(all(
2162 feature = "all",
2163 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2164 ))]
2165 pub fn freebind_v4(&self) -> io::Result<bool> {
2166 unsafe {
2167 getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
2168 .map(|freebind| freebind != 0)
2169 }
2170 }
2171
2172 #[cfg(all(
2180 feature = "all",
2181 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2182 ))]
2183 pub fn set_freebind_v4(&self, freebind: bool) -> io::Result<()> {
2184 unsafe {
2185 setsockopt(
2186 self.as_raw(),
2187 libc::SOL_IP,
2188 libc::IP_FREEBIND,
2189 freebind as c_int,
2190 )
2191 }
2192 }
2193
2194 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2202 pub fn freebind_v6(&self) -> io::Result<bool> {
2203 unsafe {
2204 getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
2205 .map(|freebind| freebind != 0)
2206 }
2207 }
2208
2209 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2240 pub fn set_freebind_v6(&self, freebind: bool) -> io::Result<()> {
2241 unsafe {
2242 setsockopt(
2243 self.as_raw(),
2244 libc::SOL_IPV6,
2245 libc::IPV6_FREEBIND,
2246 freebind as c_int,
2247 )
2248 }
2249 }
2250
2251 #[doc = man_links!(unix: sendfile(2))]
2261 #[cfg(all(
2271 feature = "all",
2272 any(
2273 target_os = "aix",
2274 target_os = "android",
2275 target_os = "freebsd",
2276 target_os = "ios",
2277 target_os = "visionos",
2278 target_os = "linux",
2279 target_os = "macos",
2280 target_os = "tvos",
2281 target_os = "watchos",
2282 )
2283 ))]
2284 pub fn sendfile<F>(
2285 &self,
2286 file: &F,
2287 offset: usize,
2288 length: Option<NonZeroUsize>,
2289 ) -> io::Result<usize>
2290 where
2291 F: AsRawFd,
2292 {
2293 self._sendfile(file.as_raw_fd(), offset as _, length)
2294 }
2295
2296 #[cfg(all(
2297 feature = "all",
2298 any(
2299 target_os = "ios",
2300 target_os = "visionos",
2301 target_os = "macos",
2302 target_os = "tvos",
2303 target_os = "watchos",
2304 )
2305 ))]
2306 fn _sendfile(
2307 &self,
2308 file: RawFd,
2309 offset: libc::off_t,
2310 length: Option<NonZeroUsize>,
2311 ) -> io::Result<usize> {
2312 let mut length = match length {
2315 Some(n) => n.get() as libc::off_t,
2316 None => 0,
2318 };
2319 syscall!(sendfile(
2320 file,
2321 self.as_raw(),
2322 offset,
2323 &mut length,
2324 ptr::null_mut(),
2325 0,
2326 ))
2327 .map(|_| length as usize)
2328 }
2329
2330 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2331 fn _sendfile(
2332 &self,
2333 file: RawFd,
2334 offset: libc::off_t,
2335 length: Option<NonZeroUsize>,
2336 ) -> io::Result<usize> {
2337 let count = match length {
2338 Some(n) => n.get() as libc::size_t,
2339 None => 0x7ffff000, };
2342 let mut offset = offset;
2343 syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
2344 }
2345
2346 #[cfg(all(feature = "all", target_os = "freebsd"))]
2347 fn _sendfile(
2348 &self,
2349 file: RawFd,
2350 offset: libc::off_t,
2351 length: Option<NonZeroUsize>,
2352 ) -> io::Result<usize> {
2353 let nbytes = match length {
2354 Some(n) => n.get() as libc::size_t,
2355 None => 0,
2357 };
2358 let mut sbytes: libc::off_t = 0;
2359 syscall!(sendfile(
2360 file,
2361 self.as_raw(),
2362 offset,
2363 nbytes,
2364 ptr::null_mut(),
2365 &mut sbytes,
2366 0,
2367 ))
2368 .map(|_| sbytes as usize)
2369 }
2370
2371 #[cfg(all(feature = "all", target_os = "aix"))]
2372 fn _sendfile(
2373 &self,
2374 file: RawFd,
2375 offset: libc::off_t,
2376 length: Option<NonZeroUsize>,
2377 ) -> io::Result<usize> {
2378 let nbytes = match length {
2379 Some(n) => n.get() as i64,
2380 None => -1,
2381 };
2382 let mut params = libc::sf_parms {
2383 header_data: ptr::null_mut(),
2384 header_length: 0,
2385 file_descriptor: file,
2386 file_size: 0,
2387 file_offset: offset as u64,
2388 file_bytes: nbytes,
2389 trailer_data: ptr::null_mut(),
2390 trailer_length: 0,
2391 bytes_sent: 0,
2392 };
2393 syscall!(send_file(
2395 &mut self.as_raw() as *mut _,
2396 &mut params as *mut _,
2397 libc::SF_CLOSE as libc::c_uint,
2398 ))
2399 .map(|_| params.bytes_sent as usize)
2400 }
2401
2402 #[cfg(all(
2413 feature = "all",
2414 any(
2415 target_os = "android",
2416 target_os = "fuchsia",
2417 target_os = "linux",
2418 target_os = "cygwin",
2419 )
2420 ))]
2421 pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
2422 let timeout = timeout.map_or(0, |to| {
2423 min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint
2424 });
2425 unsafe {
2426 setsockopt(
2427 self.as_raw(),
2428 libc::IPPROTO_TCP,
2429 libc::TCP_USER_TIMEOUT,
2430 timeout,
2431 )
2432 }
2433 }
2434
2435 #[cfg(all(
2441 feature = "all",
2442 any(
2443 target_os = "android",
2444 target_os = "fuchsia",
2445 target_os = "linux",
2446 target_os = "cygwin",
2447 )
2448 ))]
2449 pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
2450 unsafe {
2451 getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
2452 .map(|millis| {
2453 if millis == 0 {
2454 None
2455 } else {
2456 Some(Duration::from_millis(millis as u64))
2457 }
2458 })
2459 }
2460 }
2461
2462 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2469 pub fn attach_filter(&self, filters: &[SockFilter]) -> io::Result<()> {
2470 let prog = libc::sock_fprog {
2471 len: filters.len() as u16,
2472 filter: filters.as_ptr() as *mut _,
2474 };
2475
2476 unsafe {
2477 setsockopt(
2478 self.as_raw(),
2479 libc::SOL_SOCKET,
2480 libc::SO_ATTACH_FILTER,
2481 prog,
2482 )
2483 }
2484 }
2485
2486 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2492 pub fn detach_filter(&self) -> io::Result<()> {
2493 unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) }
2494 }
2495
2496 #[cfg(all(feature = "all", target_os = "linux"))]
2503 pub fn cookie(&self) -> io::Result<u64> {
2504 unsafe { getsockopt::<libc::c_ulonglong>(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) }
2505 }
2506
2507 #[cfg(all(
2513 feature = "all",
2514 any(
2515 target_os = "android",
2516 target_os = "dragonfly",
2517 target_os = "freebsd",
2518 target_os = "fuchsia",
2519 target_os = "linux",
2520 target_os = "macos",
2521 target_os = "netbsd",
2522 target_os = "openbsd",
2523 target_os = "cygwin",
2524 )
2525 ))]
2526 pub fn tclass_v6(&self) -> io::Result<u32> {
2527 unsafe {
2528 getsockopt::<c_int>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS)
2529 .map(|tclass| tclass as u32)
2530 }
2531 }
2532
2533 #[cfg(all(
2538 feature = "all",
2539 any(
2540 target_os = "android",
2541 target_os = "dragonfly",
2542 target_os = "freebsd",
2543 target_os = "fuchsia",
2544 target_os = "linux",
2545 target_os = "macos",
2546 target_os = "netbsd",
2547 target_os = "openbsd",
2548 target_os = "cygwin",
2549 )
2550 ))]
2551 pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
2552 unsafe {
2553 setsockopt(
2554 self.as_raw(),
2555 IPPROTO_IPV6,
2556 libc::IPV6_TCLASS,
2557 tclass as c_int,
2558 )
2559 }
2560 }
2561
2562 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2568 pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
2569 let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX];
2570 let mut len = payload.len() as libc::socklen_t;
2571 syscall!(getsockopt(
2572 self.as_raw(),
2573 IPPROTO_TCP,
2574 libc::TCP_CONGESTION,
2575 payload.as_mut_ptr().cast(),
2576 &mut len,
2577 ))
2578 .map(|_| payload[..len as usize].to_vec())
2579 }
2580
2581 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2588 pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
2589 syscall!(setsockopt(
2590 self.as_raw(),
2591 IPPROTO_TCP,
2592 libc::TCP_CONGESTION,
2593 tcp_ca_name.as_ptr() as *const _,
2594 tcp_ca_name.len() as libc::socklen_t,
2595 ))
2596 .map(|_| ())
2597 }
2598
2599 #[cfg(all(feature = "all", target_os = "linux"))]
2610 pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
2611 unsafe {
2612 setsockopt(
2613 self.as_raw(),
2614 libc::SOL_DCCP,
2615 libc::DCCP_SOCKOPT_SERVICE,
2616 code,
2617 )
2618 }
2619 }
2620
2621 #[cfg(all(feature = "all", target_os = "linux"))]
2627 pub fn dccp_service(&self) -> io::Result<u32> {
2628 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) }
2629 }
2630
2631 #[cfg(all(feature = "all", target_os = "linux"))]
2635 pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
2636 unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) }
2637 }
2638
2639 #[cfg(all(feature = "all", target_os = "linux"))]
2645 pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
2646 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) }
2647 }
2648
2649 #[cfg(all(feature = "all", target_os = "linux"))]
2655 pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
2656 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) }
2657 }
2658
2659 #[cfg(all(feature = "all", target_os = "linux"))]
2664 pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> {
2665 unsafe {
2666 setsockopt(
2667 self.as_raw(),
2668 libc::SOL_DCCP,
2669 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2670 hold_timewait as c_int,
2671 )
2672 }
2673 }
2674
2675 #[cfg(all(feature = "all", target_os = "linux"))]
2681 pub fn dccp_server_timewait(&self) -> io::Result<bool> {
2682 unsafe {
2683 getsockopt(
2684 self.as_raw(),
2685 libc::SOL_DCCP,
2686 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2687 )
2688 }
2689 }
2690
2691 #[cfg(all(feature = "all", target_os = "linux"))]
2699 pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
2700 unsafe {
2701 setsockopt(
2702 self.as_raw(),
2703 libc::SOL_DCCP,
2704 libc::DCCP_SOCKOPT_SEND_CSCOV,
2705 level,
2706 )
2707 }
2708 }
2709
2710 #[cfg(all(feature = "all", target_os = "linux"))]
2716 pub fn dccp_send_cscov(&self) -> io::Result<u32> {
2717 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) }
2718 }
2719
2720 #[cfg(all(feature = "all", target_os = "linux"))]
2726 pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
2727 unsafe {
2728 setsockopt(
2729 self.as_raw(),
2730 libc::SOL_DCCP,
2731 libc::DCCP_SOCKOPT_RECV_CSCOV,
2732 level,
2733 )
2734 }
2735 }
2736
2737 #[cfg(all(feature = "all", target_os = "linux"))]
2743 pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
2744 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) }
2745 }
2746
2747 #[cfg(all(feature = "all", target_os = "linux"))]
2752 pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
2753 unsafe {
2754 setsockopt(
2755 self.as_raw(),
2756 libc::SOL_DCCP,
2757 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2758 length,
2759 )
2760 }
2761 }
2762
2763 #[cfg(all(feature = "all", target_os = "linux"))]
2769 pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
2770 unsafe {
2771 getsockopt(
2772 self.as_raw(),
2773 libc::SOL_DCCP,
2774 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2775 )
2776 }
2777 }
2778
2779 #[cfg(all(feature = "all", target_os = "linux"))]
2789 pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEndpoints<N>> {
2790 let mut endpoints = [0; N];
2791 let mut length = endpoints.len() as libc::socklen_t;
2792 syscall!(getsockopt(
2793 self.as_raw(),
2794 libc::SOL_DCCP,
2795 libc::DCCP_SOCKOPT_AVAILABLE_CCIDS,
2796 endpoints.as_mut_ptr().cast(),
2797 &mut length,
2798 ))?;
2799 Ok(CcidEndpoints { endpoints, length })
2800 }
2801
2802 #[cfg(all(feature = "all", target_os = "linux"))]
2807 pub fn dccp_cur_mps(&self) -> io::Result<u32> {
2808 unsafe {
2809 getsockopt(
2810 self.as_raw(),
2811 libc::SOL_DCCP,
2812 libc::DCCP_SOCKOPT_GET_CUR_MPS,
2813 )
2814 }
2815 }
2816}
2817
2818#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2824#[repr(transparent)]
2825pub struct SockFilter {
2826 #[allow(dead_code)]
2831 filter: libc::sock_filter,
2832}
2833
2834#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2835impl SockFilter {
2836 pub fn new(code: u16, jt: u8, jf: u8, k: u32) -> SockFilter {
2838 SockFilter {
2839 filter: libc::sock_filter { code, jt, jf, k },
2840 }
2841 }
2842}
2843
2844#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2845impl std::fmt::Debug for SockFilter {
2846 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2847 f.debug_struct("SockFilter").finish_non_exhaustive()
2848 }
2849}
2850
2851#[cfg(all(feature = "all", target_os = "linux"))]
2855#[derive(Debug)]
2856pub struct CcidEndpoints<const N: usize> {
2857 endpoints: [u8; N],
2858 length: u32,
2859}
2860
2861#[cfg(all(feature = "all", target_os = "linux"))]
2862impl<const N: usize> std::ops::Deref for CcidEndpoints<N> {
2863 type Target = [u8];
2864
2865 fn deref(&self) -> &[u8] {
2866 &self.endpoints[0..self.length as usize]
2867 }
2868}
2869
2870impl AsFd for crate::Socket {
2871 fn as_fd(&self) -> BorrowedFd<'_> {
2872 unsafe { BorrowedFd::borrow_raw(self.as_raw()) }
2874 }
2875}
2876
2877impl AsRawFd for crate::Socket {
2878 fn as_raw_fd(&self) -> RawFd {
2879 self.as_raw()
2880 }
2881}
2882
2883impl From<crate::Socket> for OwnedFd {
2884 fn from(sock: crate::Socket) -> OwnedFd {
2885 unsafe { OwnedFd::from_raw_fd(sock.into_raw()) }
2887 }
2888}
2889
2890impl IntoRawFd for crate::Socket {
2891 fn into_raw_fd(self) -> c_int {
2892 self.into_raw()
2893 }
2894}
2895
2896impl From<OwnedFd> for crate::Socket {
2897 fn from(fd: OwnedFd) -> crate::Socket {
2898 unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) }
2900 }
2901}
2902
2903impl FromRawFd for crate::Socket {
2904 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
2905 crate::Socket::from_raw(fd)
2906 }
2907}
2908
2909#[cfg(feature = "all")]
2910from!(UnixStream, crate::Socket);
2911#[cfg(feature = "all")]
2912from!(UnixListener, crate::Socket);
2913#[cfg(feature = "all")]
2914from!(UnixDatagram, crate::Socket);
2915#[cfg(feature = "all")]
2916from!(crate::Socket, UnixStream);
2917#[cfg(feature = "all")]
2918from!(crate::Socket, UnixListener);
2919#[cfg(feature = "all")]
2920from!(crate::Socket, UnixDatagram);
2921
2922#[test]
2923fn in_addr_convertion() {
2924 let ip = Ipv4Addr::new(127, 0, 0, 1);
2925 let raw = to_in_addr(&ip);
2926 let a = raw.s_addr;
2928 assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
2929 assert_eq!(from_in_addr(raw), ip);
2930
2931 let ip = Ipv4Addr::new(127, 34, 4, 12);
2932 let raw = to_in_addr(&ip);
2933 let a = raw.s_addr;
2934 assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
2935 assert_eq!(from_in_addr(raw), ip);
2936}
2937
2938#[test]
2939fn in6_addr_convertion() {
2940 let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
2941 let raw = to_in6_addr(&ip);
2942 let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
2943 assert_eq!(raw.s6_addr, want);
2944 assert_eq!(from_in6_addr(raw), ip);
2945}