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(feature = "all", any(target_os = "android", target_os = "linux")))]
1816 pub fn tcp_notsent_lowat(&self) -> io::Result<u32> {
1817 unsafe {
1818 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_NOTSENT_LOWAT)
1819 .map(|lowat| lowat as u32)
1820 }
1821 }
1822
1823 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1828 pub fn set_tcp_notsent_lowat(&self, lowat: u32) -> io::Result<()> {
1829 unsafe {
1830 setsockopt(
1831 self.as_raw(),
1832 libc::IPPROTO_TCP,
1833 libc::TCP_NOTSENT_LOWAT,
1834 lowat as c_int,
1835 )
1836 }
1837 }
1838
1839 #[cfg(all(
1843 feature = "all",
1844 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1845 ))]
1846 pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1847 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1849 unsafe { MaybeUninit::uninit().assume_init() };
1850 let mut len = buf.len() as libc::socklen_t;
1851 syscall!(getsockopt(
1852 self.as_raw(),
1853 libc::SOL_SOCKET,
1854 libc::SO_BINDTODEVICE,
1855 buf.as_mut_ptr().cast(),
1856 &mut len,
1857 ))?;
1858 if len == 0 {
1859 Ok(None)
1860 } else {
1861 let buf = &buf[..len as usize - 1];
1862 Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
1864 }
1865 }
1866
1867 #[cfg(all(
1875 feature = "all",
1876 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1877 ))]
1878 pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
1879 let (value, len) = if let Some(interface) = interface {
1880 (interface.as_ptr(), interface.len())
1881 } else {
1882 (ptr::null(), 0)
1883 };
1884 syscall!(setsockopt(
1885 self.as_raw(),
1886 libc::SOL_SOCKET,
1887 libc::SO_BINDTODEVICE,
1888 value.cast(),
1889 len as libc::socklen_t,
1890 ))
1891 .map(|_| ())
1892 }
1893
1894 #[cfg(all(feature = "all", target_os = "freebsd"))]
1898 pub fn set_fib(&self, fib: u32) -> io::Result<()> {
1899 syscall!(setsockopt(
1900 self.as_raw(),
1901 libc::SOL_SOCKET,
1902 libc::SO_SETFIB,
1903 (&fib as *const u32).cast(),
1904 mem::size_of::<u32>() as libc::socklen_t,
1905 ))
1906 .map(|_| ())
1907 }
1908
1909 #[cfg(all(
1920 feature = "all",
1921 any(
1922 target_os = "ios",
1923 target_os = "visionos",
1924 target_os = "macos",
1925 target_os = "tvos",
1926 target_os = "watchos",
1927 target_os = "illumos",
1928 target_os = "solaris",
1929 target_os = "linux",
1930 target_os = "android",
1931 )
1932 ))]
1933 pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
1934 let index = interface.map_or(0, NonZeroU32::get);
1935
1936 #[cfg(any(
1937 target_os = "ios",
1938 target_os = "visionos",
1939 target_os = "macos",
1940 target_os = "tvos",
1941 target_os = "watchos",
1942 target_os = "illumos",
1943 target_os = "solaris",
1944 ))]
1945 unsafe {
1946 setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index)
1947 }
1948
1949 #[cfg(any(target_os = "linux", target_os = "android",))]
1950 unsafe {
1951 setsockopt(
1952 self.as_raw(),
1953 libc::SOL_SOCKET,
1954 libc::SO_BINDTOIFINDEX,
1955 index,
1956 )
1957 }
1958 }
1959
1960 #[cfg(all(
1971 feature = "all",
1972 any(
1973 target_os = "ios",
1974 target_os = "visionos",
1975 target_os = "macos",
1976 target_os = "tvos",
1977 target_os = "watchos",
1978 target_os = "illumos",
1979 target_os = "solaris",
1980 target_os = "linux",
1981 target_os = "android",
1982 )
1983 ))]
1984 pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
1985 let index = interface.map_or(0, NonZeroU32::get);
1986
1987 #[cfg(any(
1988 target_os = "ios",
1989 target_os = "visionos",
1990 target_os = "macos",
1991 target_os = "tvos",
1992 target_os = "watchos",
1993 target_os = "illumos",
1994 target_os = "solaris",
1995 ))]
1996 unsafe {
1997 setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index)
1998 }
1999
2000 #[cfg(any(target_os = "linux", target_os = "android",))]
2001 unsafe {
2002 setsockopt(
2003 self.as_raw(),
2004 libc::SOL_SOCKET,
2005 libc::SO_BINDTOIFINDEX,
2006 index,
2007 )
2008 }
2009 }
2010
2011 #[cfg(all(
2017 feature = "all",
2018 any(
2019 target_os = "ios",
2020 target_os = "visionos",
2021 target_os = "macos",
2022 target_os = "tvos",
2023 target_os = "watchos",
2024 target_os = "illumos",
2025 target_os = "solaris",
2026 target_os = "linux",
2027 target_os = "android",
2028 )
2029 ))]
2030 pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
2031 #[cfg(any(
2032 target_os = "ios",
2033 target_os = "visionos",
2034 target_os = "macos",
2035 target_os = "tvos",
2036 target_os = "watchos",
2037 target_os = "illumos",
2038 target_os = "solaris",
2039 ))]
2040 let index =
2041 unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
2042
2043 #[cfg(any(target_os = "linux", target_os = "android",))]
2044 let index = unsafe {
2045 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2046 };
2047
2048 Ok(NonZeroU32::new(index))
2049 }
2050
2051 #[cfg(all(
2057 feature = "all",
2058 any(
2059 target_os = "ios",
2060 target_os = "visionos",
2061 target_os = "macos",
2062 target_os = "tvos",
2063 target_os = "watchos",
2064 target_os = "illumos",
2065 target_os = "solaris",
2066 target_os = "linux",
2067 target_os = "android",
2068 )
2069 ))]
2070 pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
2071 #[cfg(any(
2072 target_os = "ios",
2073 target_os = "visionos",
2074 target_os = "macos",
2075 target_os = "tvos",
2076 target_os = "watchos",
2077 target_os = "illumos",
2078 target_os = "solaris",
2079 ))]
2080 let index = unsafe {
2081 getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)?
2082 };
2083
2084 #[cfg(any(target_os = "linux", target_os = "android",))]
2085 let index = unsafe {
2086 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2087 };
2088
2089 Ok(NonZeroU32::new(index))
2090 }
2091
2092 #[cfg(all(feature = "all", target_os = "linux"))]
2098 pub fn cpu_affinity(&self) -> io::Result<usize> {
2099 unsafe {
2100 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
2101 .map(|cpu| cpu as usize)
2102 }
2103 }
2104
2105 #[cfg(all(feature = "all", target_os = "linux"))]
2109 pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
2110 unsafe {
2111 setsockopt(
2112 self.as_raw(),
2113 libc::SOL_SOCKET,
2114 libc::SO_INCOMING_CPU,
2115 cpu as c_int,
2116 )
2117 }
2118 }
2119
2120 #[cfg(all(
2126 feature = "all",
2127 not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin"))
2128 ))]
2129 pub fn reuse_port(&self) -> io::Result<bool> {
2130 unsafe {
2131 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
2132 .map(|reuse| reuse != 0)
2133 }
2134 }
2135
2136 #[cfg(all(
2142 feature = "all",
2143 not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin"))
2144 ))]
2145 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
2146 unsafe {
2147 setsockopt(
2148 self.as_raw(),
2149 libc::SOL_SOCKET,
2150 libc::SO_REUSEPORT,
2151 reuse as c_int,
2152 )
2153 }
2154 }
2155
2156 #[cfg(all(feature = "all", target_os = "freebsd"))]
2162 pub fn reuse_port_lb(&self) -> io::Result<bool> {
2163 unsafe {
2164 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT_LB)
2165 .map(|reuse| reuse != 0)
2166 }
2167 }
2168
2169 #[cfg(all(feature = "all", target_os = "freebsd"))]
2174 pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
2175 unsafe {
2176 setsockopt(
2177 self.as_raw(),
2178 libc::SOL_SOCKET,
2179 libc::SO_REUSEPORT_LB,
2180 reuse as c_int,
2181 )
2182 }
2183 }
2184
2185 #[cfg(all(
2191 feature = "all",
2192 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2193 ))]
2194 pub fn freebind_v4(&self) -> io::Result<bool> {
2195 unsafe {
2196 getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
2197 .map(|freebind| freebind != 0)
2198 }
2199 }
2200
2201 #[cfg(all(
2209 feature = "all",
2210 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2211 ))]
2212 pub fn set_freebind_v4(&self, freebind: bool) -> io::Result<()> {
2213 unsafe {
2214 setsockopt(
2215 self.as_raw(),
2216 libc::SOL_IP,
2217 libc::IP_FREEBIND,
2218 freebind as c_int,
2219 )
2220 }
2221 }
2222
2223 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2231 pub fn freebind_v6(&self) -> io::Result<bool> {
2232 unsafe {
2233 getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
2234 .map(|freebind| freebind != 0)
2235 }
2236 }
2237
2238 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2269 pub fn set_freebind_v6(&self, freebind: bool) -> io::Result<()> {
2270 unsafe {
2271 setsockopt(
2272 self.as_raw(),
2273 libc::SOL_IPV6,
2274 libc::IPV6_FREEBIND,
2275 freebind as c_int,
2276 )
2277 }
2278 }
2279
2280 #[doc = man_links!(unix: sendfile(2))]
2290 #[cfg(all(
2300 feature = "all",
2301 any(
2302 target_os = "aix",
2303 target_os = "android",
2304 target_os = "freebsd",
2305 target_os = "ios",
2306 target_os = "visionos",
2307 target_os = "linux",
2308 target_os = "macos",
2309 target_os = "tvos",
2310 target_os = "watchos",
2311 )
2312 ))]
2313 pub fn sendfile<F>(
2314 &self,
2315 file: &F,
2316 offset: usize,
2317 length: Option<NonZeroUsize>,
2318 ) -> io::Result<usize>
2319 where
2320 F: AsRawFd,
2321 {
2322 self._sendfile(file.as_raw_fd(), offset as _, length)
2323 }
2324
2325 #[cfg(all(
2326 feature = "all",
2327 any(
2328 target_os = "ios",
2329 target_os = "visionos",
2330 target_os = "macos",
2331 target_os = "tvos",
2332 target_os = "watchos",
2333 )
2334 ))]
2335 fn _sendfile(
2336 &self,
2337 file: RawFd,
2338 offset: libc::off_t,
2339 length: Option<NonZeroUsize>,
2340 ) -> io::Result<usize> {
2341 let mut length = match length {
2344 Some(n) => n.get() as libc::off_t,
2345 None => 0,
2347 };
2348 syscall!(sendfile(
2349 file,
2350 self.as_raw(),
2351 offset,
2352 &mut length,
2353 ptr::null_mut(),
2354 0,
2355 ))
2356 .map(|_| length as usize)
2357 }
2358
2359 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2360 fn _sendfile(
2361 &self,
2362 file: RawFd,
2363 offset: libc::off_t,
2364 length: Option<NonZeroUsize>,
2365 ) -> io::Result<usize> {
2366 let count = match length {
2367 Some(n) => n.get() as libc::size_t,
2368 None => 0x7ffff000, };
2371 let mut offset = offset;
2372 syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
2373 }
2374
2375 #[cfg(all(feature = "all", target_os = "freebsd"))]
2376 fn _sendfile(
2377 &self,
2378 file: RawFd,
2379 offset: libc::off_t,
2380 length: Option<NonZeroUsize>,
2381 ) -> io::Result<usize> {
2382 let nbytes = match length {
2383 Some(n) => n.get() as libc::size_t,
2384 None => 0,
2386 };
2387 let mut sbytes: libc::off_t = 0;
2388 syscall!(sendfile(
2389 file,
2390 self.as_raw(),
2391 offset,
2392 nbytes,
2393 ptr::null_mut(),
2394 &mut sbytes,
2395 0,
2396 ))
2397 .map(|_| sbytes as usize)
2398 }
2399
2400 #[cfg(all(feature = "all", target_os = "aix"))]
2401 fn _sendfile(
2402 &self,
2403 file: RawFd,
2404 offset: libc::off_t,
2405 length: Option<NonZeroUsize>,
2406 ) -> io::Result<usize> {
2407 let nbytes = match length {
2408 Some(n) => n.get() as i64,
2409 None => -1,
2410 };
2411 let mut params = libc::sf_parms {
2412 header_data: ptr::null_mut(),
2413 header_length: 0,
2414 file_descriptor: file,
2415 file_size: 0,
2416 file_offset: offset as u64,
2417 file_bytes: nbytes,
2418 trailer_data: ptr::null_mut(),
2419 trailer_length: 0,
2420 bytes_sent: 0,
2421 };
2422 syscall!(send_file(
2424 &mut self.as_raw() as *mut _,
2425 &mut params as *mut _,
2426 libc::SF_CLOSE as libc::c_uint,
2427 ))
2428 .map(|_| params.bytes_sent as usize)
2429 }
2430
2431 #[cfg(all(
2442 feature = "all",
2443 any(
2444 target_os = "android",
2445 target_os = "fuchsia",
2446 target_os = "linux",
2447 target_os = "cygwin",
2448 )
2449 ))]
2450 pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
2451 let timeout = timeout.map_or(0, |to| {
2452 min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint
2453 });
2454 unsafe {
2455 setsockopt(
2456 self.as_raw(),
2457 libc::IPPROTO_TCP,
2458 libc::TCP_USER_TIMEOUT,
2459 timeout,
2460 )
2461 }
2462 }
2463
2464 #[cfg(all(
2470 feature = "all",
2471 any(
2472 target_os = "android",
2473 target_os = "fuchsia",
2474 target_os = "linux",
2475 target_os = "cygwin",
2476 )
2477 ))]
2478 pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
2479 unsafe {
2480 getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
2481 .map(|millis| {
2482 if millis == 0 {
2483 None
2484 } else {
2485 Some(Duration::from_millis(millis as u64))
2486 }
2487 })
2488 }
2489 }
2490
2491 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2498 pub fn attach_filter(&self, filters: &[SockFilter]) -> io::Result<()> {
2499 let prog = libc::sock_fprog {
2500 len: filters.len() as u16,
2501 filter: filters.as_ptr() as *mut _,
2503 };
2504
2505 unsafe {
2506 setsockopt(
2507 self.as_raw(),
2508 libc::SOL_SOCKET,
2509 libc::SO_ATTACH_FILTER,
2510 prog,
2511 )
2512 }
2513 }
2514
2515 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2521 pub fn detach_filter(&self) -> io::Result<()> {
2522 unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) }
2523 }
2524
2525 #[cfg(all(feature = "all", target_os = "linux"))]
2532 pub fn cookie(&self) -> io::Result<u64> {
2533 unsafe { getsockopt::<libc::c_ulonglong>(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) }
2534 }
2535
2536 #[cfg(all(
2542 feature = "all",
2543 any(
2544 target_os = "android",
2545 target_os = "dragonfly",
2546 target_os = "freebsd",
2547 target_os = "fuchsia",
2548 target_os = "linux",
2549 target_os = "macos",
2550 target_os = "netbsd",
2551 target_os = "openbsd",
2552 target_os = "cygwin",
2553 )
2554 ))]
2555 pub fn tclass_v6(&self) -> io::Result<u32> {
2556 unsafe {
2557 getsockopt::<c_int>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS)
2558 .map(|tclass| tclass as u32)
2559 }
2560 }
2561
2562 #[cfg(all(
2567 feature = "all",
2568 any(
2569 target_os = "android",
2570 target_os = "dragonfly",
2571 target_os = "freebsd",
2572 target_os = "fuchsia",
2573 target_os = "linux",
2574 target_os = "macos",
2575 target_os = "netbsd",
2576 target_os = "openbsd",
2577 target_os = "cygwin",
2578 )
2579 ))]
2580 pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
2581 unsafe {
2582 setsockopt(
2583 self.as_raw(),
2584 IPPROTO_IPV6,
2585 libc::IPV6_TCLASS,
2586 tclass as c_int,
2587 )
2588 }
2589 }
2590
2591 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2597 pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
2598 let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX];
2599 let mut len = payload.len() as libc::socklen_t;
2600 syscall!(getsockopt(
2601 self.as_raw(),
2602 IPPROTO_TCP,
2603 libc::TCP_CONGESTION,
2604 payload.as_mut_ptr().cast(),
2605 &mut len,
2606 ))
2607 .map(|_| payload[..len as usize].to_vec())
2608 }
2609
2610 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2617 pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
2618 syscall!(setsockopt(
2619 self.as_raw(),
2620 IPPROTO_TCP,
2621 libc::TCP_CONGESTION,
2622 tcp_ca_name.as_ptr() as *const _,
2623 tcp_ca_name.len() as libc::socklen_t,
2624 ))
2625 .map(|_| ())
2626 }
2627
2628 #[cfg(all(feature = "all", target_os = "linux"))]
2639 pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
2640 unsafe {
2641 setsockopt(
2642 self.as_raw(),
2643 libc::SOL_DCCP,
2644 libc::DCCP_SOCKOPT_SERVICE,
2645 code,
2646 )
2647 }
2648 }
2649
2650 #[cfg(all(feature = "all", target_os = "linux"))]
2656 pub fn dccp_service(&self) -> io::Result<u32> {
2657 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) }
2658 }
2659
2660 #[cfg(all(feature = "all", target_os = "linux"))]
2664 pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
2665 unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) }
2666 }
2667
2668 #[cfg(all(feature = "all", target_os = "linux"))]
2674 pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
2675 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) }
2676 }
2677
2678 #[cfg(all(feature = "all", target_os = "linux"))]
2684 pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
2685 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) }
2686 }
2687
2688 #[cfg(all(feature = "all", target_os = "linux"))]
2693 pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> {
2694 unsafe {
2695 setsockopt(
2696 self.as_raw(),
2697 libc::SOL_DCCP,
2698 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2699 hold_timewait as c_int,
2700 )
2701 }
2702 }
2703
2704 #[cfg(all(feature = "all", target_os = "linux"))]
2710 pub fn dccp_server_timewait(&self) -> io::Result<bool> {
2711 unsafe {
2712 getsockopt(
2713 self.as_raw(),
2714 libc::SOL_DCCP,
2715 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2716 )
2717 }
2718 }
2719
2720 #[cfg(all(feature = "all", target_os = "linux"))]
2728 pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
2729 unsafe {
2730 setsockopt(
2731 self.as_raw(),
2732 libc::SOL_DCCP,
2733 libc::DCCP_SOCKOPT_SEND_CSCOV,
2734 level,
2735 )
2736 }
2737 }
2738
2739 #[cfg(all(feature = "all", target_os = "linux"))]
2745 pub fn dccp_send_cscov(&self) -> io::Result<u32> {
2746 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) }
2747 }
2748
2749 #[cfg(all(feature = "all", target_os = "linux"))]
2755 pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
2756 unsafe {
2757 setsockopt(
2758 self.as_raw(),
2759 libc::SOL_DCCP,
2760 libc::DCCP_SOCKOPT_RECV_CSCOV,
2761 level,
2762 )
2763 }
2764 }
2765
2766 #[cfg(all(feature = "all", target_os = "linux"))]
2772 pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
2773 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) }
2774 }
2775
2776 #[cfg(all(feature = "all", target_os = "linux"))]
2781 pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
2782 unsafe {
2783 setsockopt(
2784 self.as_raw(),
2785 libc::SOL_DCCP,
2786 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2787 length,
2788 )
2789 }
2790 }
2791
2792 #[cfg(all(feature = "all", target_os = "linux"))]
2798 pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
2799 unsafe {
2800 getsockopt(
2801 self.as_raw(),
2802 libc::SOL_DCCP,
2803 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2804 )
2805 }
2806 }
2807
2808 #[cfg(all(feature = "all", target_os = "linux"))]
2818 pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEndpoints<N>> {
2819 let mut endpoints = [0; N];
2820 let mut length = endpoints.len() as libc::socklen_t;
2821 syscall!(getsockopt(
2822 self.as_raw(),
2823 libc::SOL_DCCP,
2824 libc::DCCP_SOCKOPT_AVAILABLE_CCIDS,
2825 endpoints.as_mut_ptr().cast(),
2826 &mut length,
2827 ))?;
2828 Ok(CcidEndpoints { endpoints, length })
2829 }
2830
2831 #[cfg(all(feature = "all", target_os = "linux"))]
2836 pub fn dccp_cur_mps(&self) -> io::Result<u32> {
2837 unsafe {
2838 getsockopt(
2839 self.as_raw(),
2840 libc::SOL_DCCP,
2841 libc::DCCP_SOCKOPT_GET_CUR_MPS,
2842 )
2843 }
2844 }
2845
2846 #[cfg(all(feature = "all", target_os = "linux"))]
2850 pub fn busy_poll(&self) -> io::Result<u32> {
2851 unsafe { getsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_BUSY_POLL) }
2852 }
2853
2854 #[cfg(all(feature = "all", target_os = "linux"))]
2858 pub fn set_busy_poll(&self, busy_poll: u32) -> io::Result<()> {
2859 unsafe {
2860 setsockopt(
2861 self.as_raw(),
2862 libc::SOL_SOCKET,
2863 libc::SO_BUSY_POLL,
2864 busy_poll as c_int,
2865 )
2866 }
2867 }
2868}
2869
2870#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2876#[repr(transparent)]
2877pub struct SockFilter {
2878 #[allow(dead_code)]
2881 filter: libc::sock_filter,
2882}
2883
2884#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2885impl SockFilter {
2886 pub const fn new(code: u16, jt: u8, jf: u8, k: u32) -> SockFilter {
2888 SockFilter {
2889 filter: libc::sock_filter { code, jt, jf, k },
2890 }
2891 }
2892}
2893
2894#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2895impl std::fmt::Debug for SockFilter {
2896 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2897 f.debug_struct("SockFilter").finish_non_exhaustive()
2898 }
2899}
2900
2901#[cfg(all(feature = "all", target_os = "linux"))]
2905#[derive(Debug)]
2906pub struct CcidEndpoints<const N: usize> {
2907 endpoints: [u8; N],
2908 length: u32,
2909}
2910
2911#[cfg(all(feature = "all", target_os = "linux"))]
2912impl<const N: usize> std::ops::Deref for CcidEndpoints<N> {
2913 type Target = [u8];
2914
2915 fn deref(&self) -> &[u8] {
2916 &self.endpoints[0..self.length as usize]
2917 }
2918}
2919
2920impl AsFd for crate::Socket {
2921 fn as_fd(&self) -> BorrowedFd<'_> {
2922 unsafe { BorrowedFd::borrow_raw(self.as_raw()) }
2924 }
2925}
2926
2927impl AsRawFd for crate::Socket {
2928 fn as_raw_fd(&self) -> RawFd {
2929 self.as_raw()
2930 }
2931}
2932
2933impl From<crate::Socket> for OwnedFd {
2934 fn from(sock: crate::Socket) -> OwnedFd {
2935 unsafe { OwnedFd::from_raw_fd(sock.into_raw()) }
2937 }
2938}
2939
2940impl IntoRawFd for crate::Socket {
2941 fn into_raw_fd(self) -> c_int {
2942 self.into_raw()
2943 }
2944}
2945
2946impl From<OwnedFd> for crate::Socket {
2947 fn from(fd: OwnedFd) -> crate::Socket {
2948 unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) }
2950 }
2951}
2952
2953impl FromRawFd for crate::Socket {
2954 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
2955 crate::Socket::from_raw(fd)
2956 }
2957}
2958
2959#[cfg(feature = "all")]
2960from!(UnixStream, crate::Socket);
2961#[cfg(feature = "all")]
2962from!(UnixListener, crate::Socket);
2963#[cfg(feature = "all")]
2964from!(UnixDatagram, crate::Socket);
2965#[cfg(feature = "all")]
2966from!(crate::Socket, UnixStream);
2967#[cfg(feature = "all")]
2968from!(crate::Socket, UnixListener);
2969#[cfg(feature = "all")]
2970from!(crate::Socket, UnixDatagram);
2971
2972#[test]
2973fn in_addr_convertion() {
2974 let ip = Ipv4Addr::new(127, 0, 0, 1);
2975 let raw = to_in_addr(&ip);
2976 let a = raw.s_addr;
2978 assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
2979 assert_eq!(from_in_addr(raw), ip);
2980
2981 let ip = Ipv4Addr::new(127, 34, 4, 12);
2982 let raw = to_in_addr(&ip);
2983 let a = raw.s_addr;
2984 assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
2985 assert_eq!(from_in_addr(raw), ip);
2986}
2987
2988#[test]
2989fn in6_addr_convertion() {
2990 let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
2991 let raw = to_in6_addr(&ip);
2992 let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
2993 assert_eq!(raw.s6_addr, want);
2994 assert_eq!(from_in6_addr(raw), ip);
2995}