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 )
28))]
29use std::num::NonZeroU32;
30#[cfg(all(
31 feature = "all",
32 any(
33 target_os = "aix",
34 target_os = "android",
35 target_os = "freebsd",
36 target_os = "ios",
37 target_os = "visionos",
38 target_os = "linux",
39 target_os = "macos",
40 target_os = "tvos",
41 target_os = "watchos",
42 )
43))]
44use std::num::NonZeroUsize;
45use std::os::unix::ffi::OsStrExt;
46#[cfg(all(
47 feature = "all",
48 any(
49 target_os = "aix",
50 target_os = "android",
51 target_os = "freebsd",
52 target_os = "ios",
53 target_os = "visionos",
54 target_os = "linux",
55 target_os = "macos",
56 target_os = "tvos",
57 target_os = "watchos",
58 )
59))]
60use std::os::unix::io::RawFd;
61use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd};
62#[cfg(feature = "all")]
63use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
64use std::path::Path;
65use std::ptr;
66use std::time::{Duration, Instant};
67use std::{io, slice};
68
69#[cfg(not(any(
70 target_os = "ios",
71 target_os = "visionos",
72 target_os = "macos",
73 target_os = "tvos",
74 target_os = "watchos",
75 target_os = "cygwin",
76)))]
77use libc::ssize_t;
78use libc::{in6_addr, in_addr};
79
80use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
81#[cfg(not(target_os = "redox"))]
82use crate::{MsgHdr, MsgHdrMut, RecvFlags};
83
84pub(crate) use libc::c_int;
85
86pub(crate) use libc::{AF_INET, AF_INET6, AF_UNIX};
88#[cfg(all(feature = "all", target_os = "linux"))]
90pub(crate) use libc::SOCK_DCCP;
91#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
92pub(crate) use libc::SOCK_RAW;
93#[cfg(all(feature = "all", not(target_os = "espidf")))]
94pub(crate) use libc::SOCK_SEQPACKET;
95pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM};
96#[cfg(all(feature = "all", target_os = "linux"))]
98pub(crate) use libc::IPPROTO_DCCP;
99#[cfg(target_os = "linux")]
100pub(crate) use libc::IPPROTO_MPTCP;
101#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
102pub(crate) use libc::IPPROTO_SCTP;
103#[cfg(all(
104 feature = "all",
105 any(
106 target_os = "android",
107 target_os = "freebsd",
108 target_os = "fuchsia",
109 target_os = "linux",
110 )
111))]
112pub(crate) use libc::IPPROTO_UDPLITE;
113pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP};
114#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
116pub(crate) use libc::IPPROTO_DIVERT;
117pub(crate) use libc::{
118 sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t,
119};
120#[cfg(not(any(target_os = "redox", target_os = "espidf")))]
122pub(crate) use libc::MSG_TRUNC;
123#[cfg(not(target_os = "redox"))]
124pub(crate) use libc::SO_OOBINLINE;
125#[cfg(not(target_os = "nto"))]
127pub(crate) use libc::ipv6_mreq as Ipv6Mreq;
128#[cfg(all(
129 feature = "all",
130 not(any(
131 target_os = "dragonfly",
132 target_os = "fuchsia",
133 target_os = "hurd",
134 target_os = "illumos",
135 target_os = "netbsd",
136 target_os = "openbsd",
137 target_os = "redox",
138 target_os = "solaris",
139 target_os = "haiku",
140 target_os = "espidf",
141 target_os = "vita",
142 target_os = "cygwin",
143 ))
144))]
145pub(crate) use libc::IPV6_RECVHOPLIMIT;
146#[cfg(not(any(
147 target_os = "dragonfly",
148 target_os = "fuchsia",
149 target_os = "hurd",
150 target_os = "illumos",
151 target_os = "netbsd",
152 target_os = "openbsd",
153 target_os = "redox",
154 target_os = "solaris",
155 target_os = "haiku",
156 target_os = "espidf",
157 target_os = "vita",
158)))]
159pub(crate) use libc::IPV6_RECVTCLASS;
160#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
161pub(crate) use libc::IP_HDRINCL;
162#[cfg(not(any(
163 target_os = "aix",
164 target_os = "dragonfly",
165 target_os = "fuchsia",
166 target_os = "illumos",
167 target_os = "netbsd",
168 target_os = "openbsd",
169 target_os = "redox",
170 target_os = "solaris",
171 target_os = "haiku",
172 target_os = "hurd",
173 target_os = "nto",
174 target_os = "espidf",
175 target_os = "vita",
176 target_os = "cygwin",
177)))]
178pub(crate) use libc::IP_RECVTOS;
179#[cfg(not(any(
180 target_os = "fuchsia",
181 target_os = "redox",
182 target_os = "solaris",
183 target_os = "haiku",
184 target_os = "illumos",
185)))]
186pub(crate) use libc::IP_TOS;
187#[cfg(not(any(
188 target_os = "ios",
189 target_os = "visionos",
190 target_os = "macos",
191 target_os = "tvos",
192 target_os = "watchos",
193)))]
194pub(crate) use libc::SO_LINGER;
195#[cfg(any(
196 target_os = "ios",
197 target_os = "visionos",
198 target_os = "macos",
199 target_os = "tvos",
200 target_os = "watchos",
201))]
202pub(crate) use libc::SO_LINGER_SEC as SO_LINGER;
203#[cfg(any(target_os = "linux", target_os = "cygwin"))]
204pub(crate) use libc::SO_PASSCRED;
205pub(crate) use libc::{
206 ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF,
207 IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
208 IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET,
209 SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF,
210 SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
211};
212#[cfg(not(any(
213 target_os = "dragonfly",
214 target_os = "haiku",
215 target_os = "hurd",
216 target_os = "netbsd",
217 target_os = "openbsd",
218 target_os = "redox",
219 target_os = "fuchsia",
220 target_os = "nto",
221 target_os = "espidf",
222 target_os = "vita",
223)))]
224pub(crate) use libc::{
225 ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
226};
227#[cfg(not(any(
228 target_os = "dragonfly",
229 target_os = "freebsd",
230 target_os = "haiku",
231 target_os = "illumos",
232 target_os = "ios",
233 target_os = "visionos",
234 target_os = "macos",
235 target_os = "netbsd",
236 target_os = "nto",
237 target_os = "openbsd",
238 target_os = "solaris",
239 target_os = "tvos",
240 target_os = "watchos",
241)))]
242pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
243#[cfg(any(
244 target_os = "dragonfly",
245 target_os = "freebsd",
246 target_os = "haiku",
247 target_os = "illumos",
248 target_os = "ios",
249 target_os = "visionos",
250 target_os = "macos",
251 target_os = "netbsd",
252 target_os = "openbsd",
253 target_os = "solaris",
254 target_os = "tvos",
255 target_os = "watchos",
256))]
257pub(crate) use libc::{
258 IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP,
259};
260#[cfg(all(
261 feature = "all",
262 any(
263 target_os = "android",
264 target_os = "dragonfly",
265 target_os = "freebsd",
266 target_os = "fuchsia",
267 target_os = "illumos",
268 target_os = "ios",
269 target_os = "visionos",
270 target_os = "linux",
271 target_os = "macos",
272 target_os = "netbsd",
273 target_os = "tvos",
274 target_os = "watchos",
275 target_os = "cygwin",
276 )
277))]
278pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
279
280pub(crate) type Bool = c_int;
282
283#[cfg(any(
284 target_os = "ios",
285 target_os = "visionos",
286 target_os = "macos",
287 target_os = "nto",
288 target_os = "tvos",
289 target_os = "watchos",
290))]
291use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
292#[cfg(not(any(
293 target_os = "haiku",
294 target_os = "ios",
295 target_os = "visionos",
296 target_os = "macos",
297 target_os = "nto",
298 target_os = "openbsd",
299 target_os = "tvos",
300 target_os = "watchos",
301 target_os = "vita",
302)))]
303use libc::TCP_KEEPIDLE as KEEPALIVE_TIME;
304
305macro_rules! syscall {
307 ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
308 #[allow(unused_unsafe)]
309 let res = unsafe { libc::$fn($($arg, )*) };
310 if res == -1 {
311 Err(std::io::Error::last_os_error())
312 } else {
313 Ok(res)
314 }
315 }};
316}
317
318#[cfg(not(any(
320 target_os = "ios",
321 target_os = "visionos",
322 target_os = "macos",
323 target_os = "tvos",
324 target_os = "watchos",
325 target_os = "cygwin",
326)))]
327const MAX_BUF_LEN: usize = ssize_t::MAX as usize;
328
329#[cfg(any(
338 target_os = "ios",
339 target_os = "visionos",
340 target_os = "macos",
341 target_os = "tvos",
342 target_os = "watchos",
343 target_os = "cygwin",
344))]
345const MAX_BUF_LEN: usize = c_int::MAX as usize - 1;
346
347#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
349const TCP_CA_NAME_MAX: usize = 16;
350
351#[cfg(any(
352 all(
353 target_os = "linux",
354 any(
355 target_env = "gnu",
356 all(target_env = "uclibc", target_pointer_width = "64")
357 )
358 ),
359 target_os = "android",
360))]
361type IovLen = usize;
362
363#[cfg(any(
364 all(
365 target_os = "linux",
366 any(
367 target_env = "musl",
368 target_env = "ohos",
369 all(target_env = "uclibc", target_pointer_width = "32")
370 )
371 ),
372 target_os = "aix",
373 target_os = "dragonfly",
374 target_os = "freebsd",
375 target_os = "fuchsia",
376 target_os = "haiku",
377 target_os = "hurd",
378 target_os = "illumos",
379 target_os = "ios",
380 target_os = "visionos",
381 target_os = "macos",
382 target_os = "netbsd",
383 target_os = "nto",
384 target_os = "openbsd",
385 target_os = "solaris",
386 target_os = "tvos",
387 target_os = "watchos",
388 target_os = "espidf",
389 target_os = "vita",
390 target_os = "cygwin",
391))]
392type IovLen = c_int;
393
394impl Domain {
396 #[cfg(all(
398 feature = "all",
399 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
400 ))]
401 #[cfg_attr(
402 docsrs,
403 doc(cfg(all(
404 feature = "all",
405 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
406 )))
407 )]
408 pub const PACKET: Domain = Domain(libc::AF_PACKET);
409
410 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
412 #[cfg_attr(
413 docsrs,
414 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
415 )]
416 pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
417}
418
419impl_debug!(
420 Domain,
421 libc::AF_INET,
422 libc::AF_INET6,
423 libc::AF_UNIX,
424 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
425 #[cfg_attr(
426 docsrs,
427 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
428 )]
429 libc::AF_PACKET,
430 #[cfg(any(target_os = "android", target_os = "linux"))]
431 #[cfg_attr(docsrs, doc(cfg(any(target_os = "android", target_os = "linux"))))]
432 libc::AF_VSOCK,
433 libc::AF_UNSPEC, );
435
436impl Type {
438 #[cfg(all(
440 feature = "all",
441 any(
442 target_os = "android",
443 target_os = "dragonfly",
444 target_os = "freebsd",
445 target_os = "fuchsia",
446 target_os = "illumos",
447 target_os = "linux",
448 target_os = "netbsd",
449 target_os = "openbsd",
450 target_os = "cygwin",
451 )
452 ))]
453 #[cfg_attr(
454 docsrs,
455 doc(cfg(all(
456 feature = "all",
457 any(
458 target_os = "android",
459 target_os = "dragonfly",
460 target_os = "freebsd",
461 target_os = "fuchsia",
462 target_os = "illumos",
463 target_os = "linux",
464 target_os = "netbsd",
465 target_os = "openbsd"
466 )
467 )))
468 )]
469 pub const fn nonblocking(self) -> Type {
470 Type(self.0 | libc::SOCK_NONBLOCK)
471 }
472
473 #[cfg(all(
475 feature = "all",
476 any(
477 target_os = "android",
478 target_os = "dragonfly",
479 target_os = "freebsd",
480 target_os = "fuchsia",
481 target_os = "hurd",
482 target_os = "illumos",
483 target_os = "linux",
484 target_os = "netbsd",
485 target_os = "openbsd",
486 target_os = "redox",
487 target_os = "solaris",
488 target_os = "cygwin",
489 )
490 ))]
491 #[cfg_attr(
492 docsrs,
493 doc(cfg(all(
494 feature = "all",
495 any(
496 target_os = "android",
497 target_os = "dragonfly",
498 target_os = "freebsd",
499 target_os = "fuchsia",
500 target_os = "hurd",
501 target_os = "illumos",
502 target_os = "linux",
503 target_os = "netbsd",
504 target_os = "openbsd",
505 target_os = "redox",
506 target_os = "solaris",
507 )
508 )))
509 )]
510 pub const fn cloexec(self) -> Type {
511 self._cloexec()
512 }
513
514 #[cfg(any(
515 target_os = "android",
516 target_os = "dragonfly",
517 target_os = "freebsd",
518 target_os = "fuchsia",
519 target_os = "hurd",
520 target_os = "illumos",
521 target_os = "linux",
522 target_os = "netbsd",
523 target_os = "openbsd",
524 target_os = "redox",
525 target_os = "solaris",
526 target_os = "cygwin",
527 ))]
528 pub(crate) const fn _cloexec(self) -> Type {
529 Type(self.0 | libc::SOCK_CLOEXEC)
530 }
531}
532
533impl_debug!(
534 Type,
535 libc::SOCK_STREAM,
536 libc::SOCK_DGRAM,
537 #[cfg(all(feature = "all", target_os = "linux"))]
538 libc::SOCK_DCCP,
539 #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
540 libc::SOCK_RAW,
541 #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "espidf")))]
542 libc::SOCK_RDM,
543 #[cfg(not(target_os = "espidf"))]
544 libc::SOCK_SEQPACKET,
545 );
568
569impl_debug!(
570 Protocol,
571 libc::IPPROTO_ICMP,
572 libc::IPPROTO_ICMPV6,
573 libc::IPPROTO_TCP,
574 libc::IPPROTO_UDP,
575 #[cfg(target_os = "linux")]
576 libc::IPPROTO_MPTCP,
577 #[cfg(all(feature = "all", target_os = "linux"))]
578 libc::IPPROTO_DCCP,
579 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
580 libc::IPPROTO_SCTP,
581 #[cfg(all(
582 feature = "all",
583 any(
584 target_os = "android",
585 target_os = "freebsd",
586 target_os = "fuchsia",
587 target_os = "linux",
588 )
589 ))]
590 libc::IPPROTO_UDPLITE,
591 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
592 libc::IPPROTO_DIVERT,
593);
594
595#[cfg(not(target_os = "redox"))]
597impl RecvFlags {
598 #[cfg(not(target_os = "espidf"))]
608 pub const fn is_end_of_record(self) -> bool {
609 self.0 & libc::MSG_EOR != 0
610 }
611
612 pub const fn is_out_of_band(self) -> bool {
619 self.0 & libc::MSG_OOB != 0
620 }
621
622 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
630 #[cfg_attr(
631 docsrs,
632 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
633 )]
634 pub const fn is_confirm(self) -> bool {
635 self.0 & libc::MSG_CONFIRM != 0
636 }
637
638 #[cfg(all(
645 feature = "all",
646 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
647 ))]
648 #[cfg_attr(
649 docsrs,
650 doc(cfg(all(
651 feature = "all",
652 any(target_os = "android", target_os = "linux", target_os = "cygwin")
653 )))
654 )]
655 pub const fn is_dontroute(self) -> bool {
656 self.0 & libc::MSG_DONTROUTE != 0
657 }
658}
659
660#[cfg(not(target_os = "redox"))]
661impl std::fmt::Debug for RecvFlags {
662 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
663 let mut s = f.debug_struct("RecvFlags");
664 #[cfg(not(target_os = "espidf"))]
665 s.field("is_end_of_record", &self.is_end_of_record());
666 s.field("is_out_of_band", &self.is_out_of_band());
667 #[cfg(not(target_os = "espidf"))]
668 s.field("is_truncated", &self.is_truncated());
669 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
670 s.field("is_confirm", &self.is_confirm());
671 #[cfg(all(
672 feature = "all",
673 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
674 ))]
675 s.field("is_dontroute", &self.is_dontroute());
676 s.finish()
677 }
678}
679
680#[repr(transparent)]
681pub struct MaybeUninitSlice<'a> {
682 vec: libc::iovec,
683 _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
684}
685
686unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
687
688unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
689
690impl<'a> MaybeUninitSlice<'a> {
691 pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
692 MaybeUninitSlice {
693 vec: libc::iovec {
694 iov_base: buf.as_mut_ptr().cast(),
695 iov_len: buf.len(),
696 },
697 _lifetime: PhantomData,
698 }
699 }
700
701 pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
702 unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
703 }
704
705 pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
706 unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
707 }
708}
709
710pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize {
712 let base = storage as *const _ as usize;
713 let path = ptr::addr_of!(storage.sun_path) as usize;
714 path - base
715}
716
717#[allow(unsafe_op_in_unsafe_fn)]
718pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
719 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
721 let len = {
722 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<libc::sockaddr_un>() };
723
724 let bytes = path.as_os_str().as_bytes();
725 let too_long = match bytes.first() {
726 None => false,
727 Some(&0) => bytes.len() > storage.sun_path.len(),
729 Some(_) => bytes.len() >= storage.sun_path.len(),
730 };
731 if too_long {
732 return Err(io::Error::new(
733 io::ErrorKind::InvalidInput,
734 "path must be shorter than SUN_LEN",
735 ));
736 }
737
738 storage.sun_family = libc::AF_UNIX as sa_family_t;
739 unsafe {
744 ptr::copy_nonoverlapping(
745 bytes.as_ptr(),
746 storage.sun_path.as_mut_ptr().cast(),
747 bytes.len(),
748 );
749 }
750
751 let sun_path_offset = offset_of_path(storage);
752 sun_path_offset
753 + bytes.len()
754 + match bytes.first() {
755 Some(&0) | None => 0,
756 Some(_) => 1,
757 }
758 };
759 Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
760}
761
762#[cfg(not(target_os = "redox"))]
764pub(crate) use libc::msghdr;
765
766#[cfg(not(target_os = "redox"))]
767pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
768 msg.msg_name = name.as_ptr() as *mut _;
769 msg.msg_namelen = name.len();
770}
771
772#[cfg(not(target_os = "redox"))]
773#[allow(clippy::unnecessary_cast)] pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) {
775 msg.msg_iov = ptr;
776 msg.msg_iovlen = min(len, IovLen::MAX as usize) as IovLen;
777}
778
779#[cfg(not(target_os = "redox"))]
780pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) {
781 msg.msg_control = ptr;
782 msg.msg_controllen = len as _;
783}
784
785#[cfg(not(target_os = "redox"))]
786pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: libc::c_int) {
787 msg.msg_flags = flags;
788}
789
790#[cfg(not(target_os = "redox"))]
791pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
792 RecvFlags(msg.msg_flags)
793}
794
795#[cfg(not(target_os = "redox"))]
796pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
797 msg.msg_controllen as _
798}
799
800impl SockAddr {
802 #[allow(unsafe_op_in_unsafe_fn)]
809 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
810 #[cfg_attr(
811 docsrs,
812 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
813 )]
814 pub fn vsock(cid: u32, port: u32) -> SockAddr {
815 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
817 {
818 let storage: &mut libc::sockaddr_vm =
819 unsafe { &mut *((&mut storage as *mut sockaddr_storage).cast()) };
820 storage.svm_family = libc::AF_VSOCK as sa_family_t;
821 storage.svm_cid = cid;
822 storage.svm_port = port;
823 }
824 unsafe { SockAddr::new(storage, mem::size_of::<libc::sockaddr_vm>() as socklen_t) }
825 }
826
827 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
830 #[cfg_attr(
831 docsrs,
832 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
833 )]
834 pub fn as_vsock_address(&self) -> Option<(u32, u32)> {
835 if self.family() == libc::AF_VSOCK as sa_family_t {
836 let addr = unsafe { &*(self.as_ptr() as *const libc::sockaddr_vm) };
838 Some((addr.svm_cid, addr.svm_port))
839 } else {
840 None
841 }
842 }
843
844 pub fn is_unnamed(&self) -> bool {
847 self.as_sockaddr_un()
848 .map(|storage| {
849 self.len() == offset_of_path(storage) as _
850 || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))
855 && storage.sun_path[0] == 0)
856 })
857 .unwrap_or_default()
858 }
859
860 pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> {
863 self.is_unix().then(|| {
864 unsafe { &*self.as_ptr().cast::<libc::sockaddr_un>() }
867 })
868 }
869
870 fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
875 debug_assert!(!self.is_unnamed());
876 self.len() as usize - offset_of_path(storage) - 1
877 }
878
879 fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] {
883 debug_assert!(!self.is_unnamed());
884 unsafe {
892 slice::from_raw_parts(
893 (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize),
894 self.path_len(storage),
895 )
896 }
897 }
898
899 pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
902 let path = self.as_pathname()?;
903 Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
906 }
907
908 pub fn as_pathname(&self) -> Option<&Path> {
911 self.as_sockaddr_un().and_then(|storage| {
912 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] != 0).then(|| {
913 let path_slice = self.path_bytes(storage, false);
914 Path::new::<OsStr>(OsStrExt::from_bytes(path_slice))
915 })
916 })
917 }
918
919 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
925 #[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
928 {
929 self.as_sockaddr_un().and_then(|storage| {
930 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] == 0)
931 .then(|| self.path_bytes(storage, true))
932 })
933 }
934 #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))]
935 None
936 }
937}
938
939pub(crate) type Socket = c_int;
940
941pub(crate) unsafe fn socket_from_raw(socket: Socket) -> crate::socket::Inner {
942 crate::socket::Inner::from_raw_fd(socket)
943}
944
945pub(crate) fn socket_as_raw(socket: &crate::socket::Inner) -> Socket {
946 socket.as_raw_fd()
947}
948
949pub(crate) fn socket_into_raw(socket: crate::socket::Inner) -> Socket {
950 socket.into_raw_fd()
951}
952
953pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> {
954 syscall!(socket(family, ty, protocol))
955}
956
957#[cfg(all(feature = "all", unix))]
958#[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
959pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[Socket; 2]> {
960 let mut fds = [0, 0];
961 syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds)
962}
963
964pub(crate) fn bind(fd: Socket, addr: &SockAddr) -> io::Result<()> {
965 syscall!(bind(fd, addr.as_ptr(), addr.len() as _)).map(|_| ())
966}
967
968pub(crate) fn connect(fd: Socket, addr: &SockAddr) -> io::Result<()> {
969 syscall!(connect(fd, addr.as_ptr(), addr.len())).map(|_| ())
970}
971
972pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
973 let start = Instant::now();
974
975 let mut pollfd = libc::pollfd {
976 fd: socket.as_raw(),
977 events: libc::POLLIN | libc::POLLOUT,
978 revents: 0,
979 };
980
981 loop {
982 let elapsed = start.elapsed();
983 if elapsed >= timeout {
984 return Err(io::ErrorKind::TimedOut.into());
985 }
986
987 let timeout = (timeout - elapsed).as_millis();
988 let timeout = timeout.clamp(1, c_int::MAX as u128) as c_int;
989
990 match syscall!(poll(&mut pollfd, 1, timeout)) {
991 Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
992 Ok(_) => {
993 if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0 {
995 match socket.take_error() {
996 Ok(Some(err)) | Err(err) => return Err(err),
997 Ok(None) => {
998 return Err(io::Error::new(
999 io::ErrorKind::Other,
1000 "no error set after POLLHUP",
1001 ))
1002 }
1003 }
1004 }
1005 return Ok(());
1006 }
1007 Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
1009 Err(err) => return Err(err),
1010 }
1011 }
1012}
1013
1014pub(crate) fn listen(fd: Socket, backlog: c_int) -> io::Result<()> {
1015 syscall!(listen(fd, backlog)).map(|_| ())
1016}
1017
1018pub(crate) fn accept(fd: Socket) -> io::Result<(Socket, SockAddr)> {
1019 unsafe { SockAddr::try_init(|storage, len| syscall!(accept(fd, storage.cast(), len))) }
1021}
1022
1023pub(crate) fn getsockname(fd: Socket) -> io::Result<SockAddr> {
1024 unsafe { SockAddr::try_init(|storage, len| syscall!(getsockname(fd, storage.cast(), len))) }
1026 .map(|(_, addr)| addr)
1027}
1028
1029pub(crate) fn getpeername(fd: Socket) -> io::Result<SockAddr> {
1030 unsafe { SockAddr::try_init(|storage, len| syscall!(getpeername(fd, storage.cast(), len))) }
1032 .map(|(_, addr)| addr)
1033}
1034
1035pub(crate) fn try_clone(fd: Socket) -> io::Result<Socket> {
1036 syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0))
1037}
1038
1039#[cfg(all(feature = "all", unix, not(target_os = "vita")))]
1040pub(crate) fn nonblocking(fd: Socket) -> io::Result<bool> {
1041 let file_status_flags = fcntl_get(fd, libc::F_GETFL)?;
1042 Ok((file_status_flags & libc::O_NONBLOCK) != 0)
1043}
1044
1045#[cfg(all(feature = "all", target_os = "vita"))]
1046pub(crate) fn nonblocking(fd: Socket) -> io::Result<bool> {
1047 unsafe {
1048 getsockopt::<Bool>(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK).map(|non_block| non_block != 0)
1049 }
1050}
1051
1052#[cfg(not(target_os = "vita"))]
1053pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> {
1054 if nonblocking {
1055 fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1056 } else {
1057 fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1058 }
1059}
1060
1061#[cfg(target_os = "vita")]
1062pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> {
1063 unsafe {
1064 setsockopt(
1065 fd,
1066 libc::SOL_SOCKET,
1067 libc::SO_NONBLOCK,
1068 nonblocking as libc::c_int,
1069 )
1070 }
1071}
1072
1073pub(crate) fn shutdown(fd: Socket, how: Shutdown) -> io::Result<()> {
1074 let how = match how {
1075 Shutdown::Write => libc::SHUT_WR,
1076 Shutdown::Read => libc::SHUT_RD,
1077 Shutdown::Both => libc::SHUT_RDWR,
1078 };
1079 syscall!(shutdown(fd, how)).map(|_| ())
1080}
1081
1082pub(crate) fn recv(fd: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
1083 syscall!(recv(
1084 fd,
1085 buf.as_mut_ptr().cast(),
1086 min(buf.len(), MAX_BUF_LEN),
1087 flags,
1088 ))
1089 .map(|n| n as usize)
1090}
1091
1092pub(crate) fn recv_from(
1093 fd: Socket,
1094 buf: &mut [MaybeUninit<u8>],
1095 flags: c_int,
1096) -> io::Result<(usize, SockAddr)> {
1097 unsafe {
1099 SockAddr::try_init(|addr, addrlen| {
1100 syscall!(recvfrom(
1101 fd,
1102 buf.as_mut_ptr().cast(),
1103 min(buf.len(), MAX_BUF_LEN),
1104 flags,
1105 addr.cast(),
1106 addrlen
1107 ))
1108 .map(|n| n as usize)
1109 })
1110 }
1111}
1112
1113pub(crate) fn peek_sender(fd: Socket) -> io::Result<SockAddr> {
1114 let (_, sender) = recv_from(fd, &mut [MaybeUninit::uninit(); 8], MSG_PEEK)?;
1119 Ok(sender)
1120}
1121
1122#[cfg(not(target_os = "redox"))]
1123pub(crate) fn recv_vectored(
1124 fd: Socket,
1125 bufs: &mut [crate::MaybeUninitSlice<'_>],
1126 flags: c_int,
1127) -> io::Result<(usize, RecvFlags)> {
1128 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1129 let n = recvmsg(fd, &mut msg, flags)?;
1130 Ok((n, msg.flags()))
1131}
1132
1133#[cfg(not(target_os = "redox"))]
1134pub(crate) fn recv_from_vectored(
1135 fd: Socket,
1136 bufs: &mut [crate::MaybeUninitSlice<'_>],
1137 flags: c_int,
1138) -> io::Result<(usize, RecvFlags, SockAddr)> {
1139 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1140 let (n, addr) = unsafe {
1143 SockAddr::try_init(|storage, len| {
1144 msg.inner.msg_name = storage.cast();
1145 msg.inner.msg_namelen = *len;
1146 let n = recvmsg(fd, &mut msg, flags)?;
1147 *len = msg.inner.msg_namelen;
1149 Ok(n)
1150 })?
1151 };
1152 Ok((n, msg.flags(), addr))
1153}
1154
1155#[cfg(not(target_os = "redox"))]
1156pub(crate) fn recvmsg(
1157 fd: Socket,
1158 msg: &mut MsgHdrMut<'_, '_, '_>,
1159 flags: c_int,
1160) -> io::Result<usize> {
1161 syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|n| n as usize)
1162}
1163
1164pub(crate) fn send(fd: Socket, buf: &[u8], flags: c_int) -> io::Result<usize> {
1165 syscall!(send(
1166 fd,
1167 buf.as_ptr().cast(),
1168 min(buf.len(), MAX_BUF_LEN),
1169 flags,
1170 ))
1171 .map(|n| n as usize)
1172}
1173
1174#[cfg(not(target_os = "redox"))]
1175pub(crate) fn send_vectored(fd: Socket, bufs: &[IoSlice<'_>], flags: c_int) -> io::Result<usize> {
1176 let msg = MsgHdr::new().with_buffers(bufs);
1177 sendmsg(fd, &msg, flags)
1178}
1179
1180pub(crate) fn send_to(fd: Socket, buf: &[u8], addr: &SockAddr, flags: c_int) -> io::Result<usize> {
1181 syscall!(sendto(
1182 fd,
1183 buf.as_ptr().cast(),
1184 min(buf.len(), MAX_BUF_LEN),
1185 flags,
1186 addr.as_ptr(),
1187 addr.len(),
1188 ))
1189 .map(|n| n as usize)
1190}
1191
1192#[cfg(not(target_os = "redox"))]
1193pub(crate) fn send_to_vectored(
1194 fd: Socket,
1195 bufs: &[IoSlice<'_>],
1196 addr: &SockAddr,
1197 flags: c_int,
1198) -> io::Result<usize> {
1199 let msg = MsgHdr::new().with_addr(addr).with_buffers(bufs);
1200 sendmsg(fd, &msg, flags)
1201}
1202
1203#[cfg(not(target_os = "redox"))]
1204pub(crate) fn sendmsg(fd: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
1205 syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
1206}
1207
1208pub(crate) fn timeout_opt(fd: Socket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
1210 unsafe { getsockopt(fd, opt, val).map(from_timeval) }
1211}
1212
1213const fn from_timeval(duration: libc::timeval) -> Option<Duration> {
1214 if duration.tv_sec == 0 && duration.tv_usec == 0 {
1215 None
1216 } else {
1217 let sec = duration.tv_sec as u64;
1218 let nsec = (duration.tv_usec as u32) * 1000;
1219 Some(Duration::new(sec, nsec))
1220 }
1221}
1222
1223pub(crate) fn set_timeout_opt(
1225 fd: Socket,
1226 opt: c_int,
1227 val: c_int,
1228 duration: Option<Duration>,
1229) -> io::Result<()> {
1230 let duration = into_timeval(duration);
1231 unsafe { setsockopt(fd, opt, val, duration) }
1232}
1233
1234fn into_timeval(duration: Option<Duration>) -> libc::timeval {
1235 match duration {
1236 #[cfg_attr(target_env = "musl", allow(deprecated))]
1238 Some(duration) => libc::timeval {
1239 tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
1240 tv_usec: duration.subsec_micros() as libc::suseconds_t,
1241 },
1242 None => libc::timeval {
1243 tv_sec: 0,
1244 tv_usec: 0,
1245 },
1246 }
1247}
1248
1249#[cfg(all(
1250 feature = "all",
1251 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1252))]
1253#[cfg_attr(
1254 docsrs,
1255 doc(cfg(all(
1256 feature = "all",
1257 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1258 )))
1259)]
1260pub(crate) fn keepalive_time(fd: Socket) -> io::Result<Duration> {
1261 unsafe {
1262 getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
1263 .map(|secs| Duration::from_secs(secs as u64))
1264 }
1265}
1266
1267#[allow(unused_variables)]
1268pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()> {
1269 #[cfg(not(any(
1270 target_os = "haiku",
1271 target_os = "openbsd",
1272 target_os = "nto",
1273 target_os = "vita"
1274 )))]
1275 if let Some(time) = keepalive.time {
1276 let secs = into_secs(time);
1277 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1278 }
1279
1280 #[cfg(any(
1281 target_os = "aix",
1282 target_os = "android",
1283 target_os = "dragonfly",
1284 target_os = "freebsd",
1285 target_os = "fuchsia",
1286 target_os = "hurd",
1287 target_os = "illumos",
1288 target_os = "ios",
1289 target_os = "visionos",
1290 target_os = "linux",
1291 target_os = "macos",
1292 target_os = "netbsd",
1293 target_os = "tvos",
1294 target_os = "watchos",
1295 target_os = "cygwin",
1296 ))]
1297 {
1298 if let Some(interval) = keepalive.interval {
1299 let secs = into_secs(interval);
1300 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
1301 }
1302
1303 if let Some(retries) = keepalive.retries {
1304 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
1305 }
1306 }
1307
1308 #[cfg(target_os = "nto")]
1309 if let Some(time) = keepalive.time {
1310 let secs = into_timeval(Some(time));
1311 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1312 }
1313
1314 Ok(())
1315}
1316
1317#[cfg(not(any(
1318 target_os = "haiku",
1319 target_os = "openbsd",
1320 target_os = "nto",
1321 target_os = "vita"
1322)))]
1323fn into_secs(duration: Duration) -> c_int {
1324 min(duration.as_secs(), c_int::MAX as u64) as c_int
1325}
1326
1327#[cfg(not(target_os = "vita"))]
1329fn fcntl_get(fd: Socket, cmd: c_int) -> io::Result<c_int> {
1330 syscall!(fcntl(fd, cmd))
1331}
1332
1333#[cfg(not(target_os = "vita"))]
1335fn fcntl_add(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1336 let previous = fcntl_get(fd, get_cmd)?;
1337 let new = previous | flag;
1338 if new != previous {
1339 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1340 } else {
1341 Ok(())
1343 }
1344}
1345
1346#[cfg(not(target_os = "vita"))]
1348fn fcntl_remove(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1349 let previous = fcntl_get(fd, get_cmd)?;
1350 let new = previous & !flag;
1351 if new != previous {
1352 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1353 } else {
1354 Ok(())
1356 }
1357}
1358
1359pub(crate) unsafe fn getsockopt<T>(fd: Socket, opt: c_int, val: c_int) -> io::Result<T> {
1361 let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
1362 let mut len = size_of::<T>() as libc::socklen_t;
1363 syscall!(getsockopt(
1364 fd,
1365 opt,
1366 val,
1367 payload.as_mut_ptr().cast(),
1368 &mut len,
1369 ))
1370 .map(|_| {
1371 debug_assert_eq!(len as usize, size_of::<T>());
1372 payload.assume_init()
1374 })
1375}
1376
1377pub(crate) unsafe fn setsockopt<T>(
1379 fd: Socket,
1380 opt: c_int,
1381 val: c_int,
1382 payload: T,
1383) -> io::Result<()> {
1384 let payload = ptr::addr_of!(payload).cast();
1385 syscall!(setsockopt(
1386 fd,
1387 opt,
1388 val,
1389 payload,
1390 mem::size_of::<T>() as libc::socklen_t,
1391 ))
1392 .map(|_| ())
1393}
1394
1395pub(crate) const fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
1396 in_addr {
1400 s_addr: u32::from_ne_bytes(addr.octets()),
1401 }
1402}
1403
1404pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
1405 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1406}
1407
1408pub(crate) const fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
1409 in6_addr {
1410 s6_addr: addr.octets(),
1411 }
1412}
1413
1414pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
1415 Ipv6Addr::from(addr.s6_addr)
1416}
1417
1418#[cfg(not(any(
1419 target_os = "aix",
1420 target_os = "haiku",
1421 target_os = "illumos",
1422 target_os = "netbsd",
1423 target_os = "openbsd",
1424 target_os = "redox",
1425 target_os = "solaris",
1426 target_os = "nto",
1427 target_os = "espidf",
1428 target_os = "vita",
1429 target_os = "cygwin",
1430)))]
1431pub(crate) const fn to_mreqn(
1432 multiaddr: &Ipv4Addr,
1433 interface: &crate::socket::InterfaceIndexOrAddress,
1434) -> libc::ip_mreqn {
1435 match interface {
1436 crate::socket::InterfaceIndexOrAddress::Index(interface) => libc::ip_mreqn {
1437 imr_multiaddr: to_in_addr(multiaddr),
1438 imr_address: to_in_addr(&Ipv4Addr::UNSPECIFIED),
1439 imr_ifindex: *interface as _,
1440 },
1441 crate::socket::InterfaceIndexOrAddress::Address(interface) => libc::ip_mreqn {
1442 imr_multiaddr: to_in_addr(multiaddr),
1443 imr_address: to_in_addr(interface),
1444 imr_ifindex: 0,
1445 },
1446 }
1447}
1448
1449#[cfg(all(
1450 feature = "all",
1451 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1452))]
1453pub(crate) fn original_dst(fd: Socket) -> io::Result<SockAddr> {
1454 unsafe {
1456 SockAddr::try_init(|storage, len| {
1457 syscall!(getsockopt(
1458 fd,
1459 libc::SOL_IP,
1460 libc::SO_ORIGINAL_DST,
1461 storage.cast(),
1462 len
1463 ))
1464 })
1465 }
1466 .map(|(_, addr)| addr)
1467}
1468
1469#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1474pub(crate) fn original_dst_ipv6(fd: Socket) -> io::Result<SockAddr> {
1475 unsafe {
1477 SockAddr::try_init(|storage, len| {
1478 syscall!(getsockopt(
1479 fd,
1480 libc::SOL_IPV6,
1481 libc::IP6T_SO_ORIGINAL_DST,
1482 storage.cast(),
1483 len
1484 ))
1485 })
1486 }
1487 .map(|(_, addr)| addr)
1488}
1489
1490impl crate::Socket {
1492 #[doc = man_links!(unix: accept4(2))]
1500 #[cfg(all(
1501 feature = "all",
1502 any(
1503 target_os = "android",
1504 target_os = "dragonfly",
1505 target_os = "freebsd",
1506 target_os = "fuchsia",
1507 target_os = "illumos",
1508 target_os = "linux",
1509 target_os = "netbsd",
1510 target_os = "openbsd",
1511 target_os = "cygwin",
1512 )
1513 ))]
1514 #[cfg_attr(
1515 docsrs,
1516 doc(cfg(all(
1517 feature = "all",
1518 any(
1519 target_os = "android",
1520 target_os = "dragonfly",
1521 target_os = "freebsd",
1522 target_os = "fuchsia",
1523 target_os = "illumos",
1524 target_os = "linux",
1525 target_os = "netbsd",
1526 target_os = "openbsd",
1527 )
1528 )))
1529 )]
1530 pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1531 self._accept4(flags)
1532 }
1533
1534 #[cfg(any(
1535 target_os = "android",
1536 target_os = "dragonfly",
1537 target_os = "freebsd",
1538 target_os = "fuchsia",
1539 target_os = "illumos",
1540 target_os = "linux",
1541 target_os = "netbsd",
1542 target_os = "openbsd",
1543 target_os = "cygwin",
1544 ))]
1545 pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1546 unsafe {
1548 SockAddr::try_init(|storage, len| {
1549 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1550 .map(crate::Socket::from_raw)
1551 })
1552 }
1553 }
1554
1555 #[cfg_attr(
1561 any(
1562 target_os = "ios",
1563 target_os = "visionos",
1564 target_os = "macos",
1565 target_os = "tvos",
1566 target_os = "watchos"
1567 ),
1568 allow(rustdoc::broken_intra_doc_links)
1569 )]
1570 #[cfg(all(feature = "all", not(target_os = "vita")))]
1571 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
1572 pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1573 self._set_cloexec(close_on_exec)
1574 }
1575
1576 #[cfg(not(target_os = "vita"))]
1577 pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1578 if close_on_exec {
1579 fcntl_add(
1580 self.as_raw(),
1581 libc::F_GETFD,
1582 libc::F_SETFD,
1583 libc::FD_CLOEXEC,
1584 )
1585 } else {
1586 fcntl_remove(
1587 self.as_raw(),
1588 libc::F_GETFD,
1589 libc::F_SETFD,
1590 libc::FD_CLOEXEC,
1591 )
1592 }
1593 }
1594
1595 #[cfg(target_os = "cygwin")]
1608 #[cfg(any(doc, target_os = "cygwin"))]
1609 pub fn set_no_peercred(&self) -> io::Result<()> {
1610 syscall!(setsockopt(
1611 self.as_raw(),
1612 libc::SOL_SOCKET,
1613 libc::SO_PEERCRED,
1614 ptr::null_mut(),
1615 0,
1616 ))
1617 .map(|_| ())
1618 }
1619
1620 #[cfg(all(
1622 feature = "all",
1623 any(
1624 target_os = "ios",
1625 target_os = "visionos",
1626 target_os = "macos",
1627 target_os = "tvos",
1628 target_os = "watchos",
1629 )
1630 ))]
1631 #[cfg_attr(
1632 docsrs,
1633 doc(cfg(all(
1634 feature = "all",
1635 any(
1636 target_os = "ios",
1637 target_os = "visionos",
1638 target_os = "macos",
1639 target_os = "tvos",
1640 target_os = "watchos",
1641 )
1642 )))
1643 )]
1644 pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1645 self._set_nosigpipe(nosigpipe)
1646 }
1647
1648 #[cfg(any(
1649 target_os = "ios",
1650 target_os = "visionos",
1651 target_os = "macos",
1652 target_os = "tvos",
1653 target_os = "watchos",
1654 ))]
1655 pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1656 unsafe {
1657 setsockopt(
1658 self.as_raw(),
1659 libc::SOL_SOCKET,
1660 libc::SO_NOSIGPIPE,
1661 nosigpipe as c_int,
1662 )
1663 }
1664 }
1665
1666 #[cfg(all(feature = "all", not(target_os = "redox")))]
1672 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
1673 pub fn mss(&self) -> io::Result<u32> {
1674 unsafe {
1675 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1676 .map(|mss| mss as u32)
1677 }
1678 }
1679
1680 #[cfg(all(feature = "all", not(target_os = "redox")))]
1685 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
1686 pub fn set_mss(&self, mss: u32) -> io::Result<()> {
1687 unsafe {
1688 setsockopt(
1689 self.as_raw(),
1690 libc::IPPROTO_TCP,
1691 libc::TCP_MAXSEG,
1692 mss as c_int,
1693 )
1694 }
1695 }
1696
1697 #[cfg(all(
1700 feature = "all",
1701 any(
1702 target_os = "aix",
1703 target_os = "android",
1704 target_os = "freebsd",
1705 target_os = "fuchsia",
1706 target_os = "linux",
1707 target_os = "cygwin",
1708 )
1709 ))]
1710 #[cfg_attr(
1711 docsrs,
1712 doc(cfg(all(
1713 feature = "all",
1714 any(
1715 target_os = "aix",
1716 target_os = "android",
1717 target_os = "freebsd",
1718 target_os = "fuchsia",
1719 target_os = "linux",
1720 )
1721 )))
1722 )]
1723 pub fn is_listener(&self) -> io::Result<bool> {
1724 unsafe {
1725 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1726 .map(|v| v != 0)
1727 }
1728 }
1729
1730 #[cfg(all(
1733 feature = "all",
1734 any(
1735 target_os = "android",
1736 target_os = "fuchsia",
1739 target_os = "linux",
1740 )
1741 ))]
1742 #[cfg_attr(docsrs, doc(cfg(all(
1743 feature = "all",
1744 any(
1745 target_os = "android",
1746 target_os = "fuchsia",
1749 target_os = "linux",
1750 )
1751 ))))]
1752 pub fn domain(&self) -> io::Result<Domain> {
1753 unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1754 }
1755
1756 #[cfg(all(
1759 feature = "all",
1760 any(
1761 target_os = "android",
1762 target_os = "freebsd",
1763 target_os = "fuchsia",
1764 target_os = "linux",
1765 )
1766 ))]
1767 #[cfg_attr(
1768 docsrs,
1769 doc(cfg(all(
1770 feature = "all",
1771 any(
1772 target_os = "android",
1773 target_os = "freebsd",
1774 target_os = "fuchsia",
1775 target_os = "linux",
1776 )
1777 )))
1778 )]
1779 pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1780 unsafe {
1781 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1782 {
1783 0 => None,
1784 p => Some(Protocol(p)),
1785 })
1786 }
1787 }
1788
1789 #[cfg(all(
1796 feature = "all",
1797 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1798 ))]
1799 #[cfg_attr(
1800 docsrs,
1801 doc(cfg(all(
1802 feature = "all",
1803 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1804 )))
1805 )]
1806 pub fn mark(&self) -> io::Result<u32> {
1807 unsafe {
1808 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1809 .map(|mark| mark as u32)
1810 }
1811 }
1812
1813 #[cfg(all(
1821 feature = "all",
1822 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1823 ))]
1824 #[cfg_attr(
1825 docsrs,
1826 doc(cfg(all(
1827 feature = "all",
1828 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1829 )))
1830 )]
1831 pub fn set_mark(&self, mark: u32) -> io::Result<()> {
1832 unsafe {
1833 setsockopt::<c_int>(
1834 self.as_raw(),
1835 libc::SOL_SOCKET,
1836 libc::SO_MARK,
1837 mark as c_int,
1838 )
1839 }
1840 }
1841
1842 #[cfg(all(
1848 feature = "all",
1849 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1850 ))]
1851 #[cfg_attr(
1852 docsrs,
1853 doc(cfg(all(
1854 feature = "all",
1855 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1856 )))
1857 )]
1858 pub fn cork(&self) -> io::Result<bool> {
1859 unsafe {
1860 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK)
1861 .map(|cork| cork != 0)
1862 }
1863 }
1864
1865 #[cfg(all(
1872 feature = "all",
1873 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1874 ))]
1875 #[cfg_attr(
1876 docsrs,
1877 doc(cfg(all(
1878 feature = "all",
1879 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1880 )))
1881 )]
1882 pub fn set_cork(&self, cork: bool) -> io::Result<()> {
1883 unsafe {
1884 setsockopt(
1885 self.as_raw(),
1886 libc::IPPROTO_TCP,
1887 libc::TCP_CORK,
1888 cork as c_int,
1889 )
1890 }
1891 }
1892
1893 #[cfg(all(
1899 feature = "all",
1900 any(
1901 target_os = "android",
1902 target_os = "fuchsia",
1903 target_os = "linux",
1904 target_os = "cygwin",
1905 )
1906 ))]
1907 #[cfg_attr(
1908 docsrs,
1909 doc(cfg(all(
1910 feature = "all",
1911 any(
1912 target_os = "android",
1913 target_os = "fuchsia",
1914 target_os = "linux",
1915 target_os = "cygwin"
1916 )
1917 )))
1918 )]
1919 pub fn quickack(&self) -> io::Result<bool> {
1920 unsafe {
1921 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK)
1922 .map(|quickack| quickack != 0)
1923 }
1924 }
1925
1926 #[cfg(all(
1933 feature = "all",
1934 any(
1935 target_os = "android",
1936 target_os = "fuchsia",
1937 target_os = "linux",
1938 target_os = "cygwin",
1939 )
1940 ))]
1941 #[cfg_attr(
1942 docsrs,
1943 doc(cfg(all(
1944 feature = "all",
1945 any(
1946 target_os = "android",
1947 target_os = "fuchsia",
1948 target_os = "linux",
1949 target_os = "cygwin"
1950 )
1951 )))
1952 )]
1953 pub fn set_quickack(&self, quickack: bool) -> io::Result<()> {
1954 unsafe {
1955 setsockopt(
1956 self.as_raw(),
1957 libc::IPPROTO_TCP,
1958 libc::TCP_QUICKACK,
1959 quickack as c_int,
1960 )
1961 }
1962 }
1963
1964 #[cfg(all(
1970 feature = "all",
1971 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1972 ))]
1973 #[cfg_attr(
1974 docsrs,
1975 doc(cfg(all(
1976 feature = "all",
1977 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1978 )))
1979 )]
1980 pub fn thin_linear_timeouts(&self) -> io::Result<bool> {
1981 unsafe {
1982 getsockopt::<Bool>(
1983 self.as_raw(),
1984 libc::IPPROTO_TCP,
1985 libc::TCP_THIN_LINEAR_TIMEOUTS,
1986 )
1987 .map(|timeouts| timeouts != 0)
1988 }
1989 }
1990
1991 #[cfg(all(
1997 feature = "all",
1998 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1999 ))]
2000 #[cfg_attr(
2001 docsrs,
2002 doc(cfg(all(
2003 feature = "all",
2004 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2005 )))
2006 )]
2007 pub fn set_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> {
2008 unsafe {
2009 setsockopt(
2010 self.as_raw(),
2011 libc::IPPROTO_TCP,
2012 libc::TCP_THIN_LINEAR_TIMEOUTS,
2013 timeouts as c_int,
2014 )
2015 }
2016 }
2017
2018 #[cfg(all(
2022 feature = "all",
2023 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2024 ))]
2025 #[cfg_attr(
2026 docsrs,
2027 doc(cfg(all(
2028 feature = "all",
2029 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2030 )))
2031 )]
2032 pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
2033 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
2035 unsafe { MaybeUninit::uninit().assume_init() };
2036 let mut len = buf.len() as libc::socklen_t;
2037 syscall!(getsockopt(
2038 self.as_raw(),
2039 libc::SOL_SOCKET,
2040 libc::SO_BINDTODEVICE,
2041 buf.as_mut_ptr().cast(),
2042 &mut len,
2043 ))?;
2044 if len == 0 {
2045 Ok(None)
2046 } else {
2047 let buf = &buf[..len as usize - 1];
2048 Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
2050 }
2051 }
2052
2053 #[cfg(all(
2061 feature = "all",
2062 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2063 ))]
2064 #[cfg_attr(
2065 docsrs,
2066 doc(cfg(all(
2067 feature = "all",
2068 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2069 )))
2070 )]
2071 pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
2072 let (value, len) = if let Some(interface) = interface {
2073 (interface.as_ptr(), interface.len())
2074 } else {
2075 (ptr::null(), 0)
2076 };
2077 syscall!(setsockopt(
2078 self.as_raw(),
2079 libc::SOL_SOCKET,
2080 libc::SO_BINDTODEVICE,
2081 value.cast(),
2082 len as libc::socklen_t,
2083 ))
2084 .map(|_| ())
2085 }
2086
2087 #[cfg(all(feature = "all", target_os = "freebsd"))]
2091 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "freebsd"))))]
2092 pub fn set_fib(&self, fib: u32) -> io::Result<()> {
2093 syscall!(setsockopt(
2094 self.as_raw(),
2095 libc::SOL_SOCKET,
2096 libc::SO_SETFIB,
2097 (&fib as *const u32).cast(),
2098 mem::size_of::<u32>() as libc::socklen_t,
2099 ))
2100 .map(|_| ())
2101 }
2102
2103 #[cfg(all(
2105 feature = "all",
2106 any(
2107 target_os = "ios",
2108 target_os = "visionos",
2109 target_os = "macos",
2110 target_os = "tvos",
2111 target_os = "watchos",
2112 )
2113 ))]
2114 #[cfg_attr(
2115 docsrs,
2116 doc(cfg(all(
2117 feature = "all",
2118 any(
2119 target_os = "ios",
2120 target_os = "visionos",
2121 target_os = "macos",
2122 target_os = "tvos",
2123 target_os = "watchos",
2124 )
2125 )))
2126 )]
2127 #[deprecated = "Use `Socket::bind_device_by_index_v4` instead"]
2128 pub fn bind_device_by_index(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2129 self.bind_device_by_index_v4(interface)
2130 }
2131
2132 #[cfg(all(
2143 feature = "all",
2144 any(
2145 target_os = "ios",
2146 target_os = "visionos",
2147 target_os = "macos",
2148 target_os = "tvos",
2149 target_os = "watchos",
2150 target_os = "illumos",
2151 target_os = "solaris",
2152 )
2153 ))]
2154 #[cfg_attr(
2155 docsrs,
2156 doc(cfg(all(
2157 feature = "all",
2158 any(
2159 target_os = "ios",
2160 target_os = "visionos",
2161 target_os = "macos",
2162 target_os = "tvos",
2163 target_os = "watchos",
2164 )
2165 )))
2166 )]
2167 pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2168 let index = interface.map_or(0, NonZeroU32::get);
2169 unsafe { setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index) }
2170 }
2171
2172 #[cfg(all(
2183 feature = "all",
2184 any(
2185 target_os = "ios",
2186 target_os = "visionos",
2187 target_os = "macos",
2188 target_os = "tvos",
2189 target_os = "watchos",
2190 target_os = "illumos",
2191 target_os = "solaris",
2192 )
2193 ))]
2194 #[cfg_attr(
2195 docsrs,
2196 doc(cfg(all(
2197 feature = "all",
2198 any(
2199 target_os = "ios",
2200 target_os = "visionos",
2201 target_os = "macos",
2202 target_os = "tvos",
2203 target_os = "watchos",
2204 )
2205 )))
2206 )]
2207 pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2208 let index = interface.map_or(0, NonZeroU32::get);
2209 unsafe { setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index) }
2210 }
2211
2212 #[cfg(all(
2218 feature = "all",
2219 any(
2220 target_os = "ios",
2221 target_os = "visionos",
2222 target_os = "macos",
2223 target_os = "tvos",
2224 target_os = "watchos",
2225 target_os = "illumos",
2226 target_os = "solaris",
2227 )
2228 ))]
2229 #[cfg_attr(
2230 docsrs,
2231 doc(cfg(all(
2232 feature = "all",
2233 any(
2234 target_os = "ios",
2235 target_os = "visionos",
2236 target_os = "macos",
2237 target_os = "tvos",
2238 target_os = "watchos",
2239 )
2240 )))
2241 )]
2242 pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
2243 let index =
2244 unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
2245 Ok(NonZeroU32::new(index))
2246 }
2247
2248 #[cfg(all(
2250 feature = "all",
2251 any(
2252 target_os = "ios",
2253 target_os = "visionos",
2254 target_os = "macos",
2255 target_os = "tvos",
2256 target_os = "watchos",
2257 )
2258 ))]
2259 #[cfg_attr(
2260 docsrs,
2261 doc(cfg(all(
2262 feature = "all",
2263 any(
2264 target_os = "ios",
2265 target_os = "visionos",
2266 target_os = "macos",
2267 target_os = "tvos",
2268 target_os = "watchos",
2269 )
2270 )))
2271 )]
2272 #[deprecated = "Use `Socket::device_index_v4` instead"]
2273 pub fn device_index(&self) -> io::Result<Option<NonZeroU32>> {
2274 self.device_index_v4()
2275 }
2276
2277 #[cfg(all(
2283 feature = "all",
2284 any(
2285 target_os = "ios",
2286 target_os = "visionos",
2287 target_os = "macos",
2288 target_os = "tvos",
2289 target_os = "watchos",
2290 target_os = "illumos",
2291 target_os = "solaris",
2292 )
2293 ))]
2294 #[cfg_attr(
2295 docsrs,
2296 doc(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 )]
2307 pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
2308 let index = unsafe {
2309 getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)?
2310 };
2311 Ok(NonZeroU32::new(index))
2312 }
2313
2314 #[cfg(all(feature = "all", target_os = "linux"))]
2320 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2321 pub fn cpu_affinity(&self) -> io::Result<usize> {
2322 unsafe {
2323 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
2324 .map(|cpu| cpu as usize)
2325 }
2326 }
2327
2328 #[cfg(all(feature = "all", target_os = "linux"))]
2332 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2333 pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
2334 unsafe {
2335 setsockopt(
2336 self.as_raw(),
2337 libc::SOL_SOCKET,
2338 libc::SO_INCOMING_CPU,
2339 cpu as c_int,
2340 )
2341 }
2342 }
2343
2344 #[cfg(all(
2350 feature = "all",
2351 not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin"))
2352 ))]
2353 #[cfg_attr(
2354 docsrs,
2355 doc(cfg(all(
2356 feature = "all",
2357 unix,
2358 not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin"))
2359 )))
2360 )]
2361 pub fn reuse_port(&self) -> io::Result<bool> {
2362 unsafe {
2363 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
2364 .map(|reuse| reuse != 0)
2365 }
2366 }
2367
2368 #[cfg(all(
2374 feature = "all",
2375 not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin"))
2376 ))]
2377 #[cfg_attr(
2378 docsrs,
2379 doc(cfg(all(
2380 feature = "all",
2381 unix,
2382 not(any(target_os = "solaris", target_os = "illumos", target_os = "cygwin"))
2383 )))
2384 )]
2385 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
2386 unsafe {
2387 setsockopt(
2388 self.as_raw(),
2389 libc::SOL_SOCKET,
2390 libc::SO_REUSEPORT,
2391 reuse as c_int,
2392 )
2393 }
2394 }
2395
2396 #[cfg(all(feature = "all", target_os = "freebsd"))]
2402 pub fn reuse_port_lb(&self) -> io::Result<bool> {
2403 unsafe {
2404 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT_LB)
2405 .map(|reuse| reuse != 0)
2406 }
2407 }
2408
2409 #[cfg(all(feature = "all", target_os = "freebsd"))]
2414 pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
2415 unsafe {
2416 setsockopt(
2417 self.as_raw(),
2418 libc::SOL_SOCKET,
2419 libc::SO_REUSEPORT_LB,
2420 reuse as c_int,
2421 )
2422 }
2423 }
2424
2425 #[cfg(all(
2431 feature = "all",
2432 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2433 ))]
2434 #[cfg_attr(
2435 docsrs,
2436 doc(cfg(all(
2437 feature = "all",
2438 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2439 )))
2440 )]
2441 pub fn freebind(&self) -> io::Result<bool> {
2442 unsafe {
2443 getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
2444 .map(|freebind| freebind != 0)
2445 }
2446 }
2447
2448 #[cfg(all(
2456 feature = "all",
2457 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2458 ))]
2459 #[cfg_attr(
2460 docsrs,
2461 doc(cfg(all(
2462 feature = "all",
2463 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2464 )))
2465 )]
2466 pub fn set_freebind(&self, freebind: bool) -> io::Result<()> {
2467 unsafe {
2468 setsockopt(
2469 self.as_raw(),
2470 libc::SOL_IP,
2471 libc::IP_FREEBIND,
2472 freebind as c_int,
2473 )
2474 }
2475 }
2476
2477 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2485 #[cfg_attr(
2486 docsrs,
2487 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2488 )]
2489 pub fn freebind_ipv6(&self) -> io::Result<bool> {
2490 unsafe {
2491 getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
2492 .map(|freebind| freebind != 0)
2493 }
2494 }
2495
2496 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2527 #[cfg_attr(
2528 docsrs,
2529 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2530 )]
2531 pub fn set_freebind_ipv6(&self, freebind: bool) -> io::Result<()> {
2532 unsafe {
2533 setsockopt(
2534 self.as_raw(),
2535 libc::SOL_IPV6,
2536 libc::IPV6_FREEBIND,
2537 freebind as c_int,
2538 )
2539 }
2540 }
2541
2542 #[doc = man_links!(unix: sendfile(2))]
2552 #[cfg(all(
2562 feature = "all",
2563 any(
2564 target_os = "aix",
2565 target_os = "android",
2566 target_os = "freebsd",
2567 target_os = "ios",
2568 target_os = "visionos",
2569 target_os = "linux",
2570 target_os = "macos",
2571 target_os = "tvos",
2572 target_os = "watchos",
2573 )
2574 ))]
2575 #[cfg_attr(
2576 docsrs,
2577 doc(cfg(all(
2578 feature = "all",
2579 any(
2580 target_os = "aix",
2581 target_os = "android",
2582 target_os = "freebsd",
2583 target_os = "ios",
2584 target_os = "visionos",
2585 target_os = "linux",
2586 target_os = "macos",
2587 target_os = "tvos",
2588 target_os = "watchos",
2589 )
2590 )))
2591 )]
2592 pub fn sendfile<F>(
2593 &self,
2594 file: &F,
2595 offset: usize,
2596 length: Option<NonZeroUsize>,
2597 ) -> io::Result<usize>
2598 where
2599 F: AsRawFd,
2600 {
2601 self._sendfile(file.as_raw_fd(), offset as _, length)
2602 }
2603
2604 #[cfg(all(
2605 feature = "all",
2606 any(
2607 target_os = "ios",
2608 target_os = "visionos",
2609 target_os = "macos",
2610 target_os = "tvos",
2611 target_os = "watchos",
2612 )
2613 ))]
2614 fn _sendfile(
2615 &self,
2616 file: RawFd,
2617 offset: libc::off_t,
2618 length: Option<NonZeroUsize>,
2619 ) -> io::Result<usize> {
2620 let mut length = match length {
2623 Some(n) => n.get() as libc::off_t,
2624 None => 0,
2626 };
2627 syscall!(sendfile(
2628 file,
2629 self.as_raw(),
2630 offset,
2631 &mut length,
2632 ptr::null_mut(),
2633 0,
2634 ))
2635 .map(|_| length as usize)
2636 }
2637
2638 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2639 fn _sendfile(
2640 &self,
2641 file: RawFd,
2642 offset: libc::off_t,
2643 length: Option<NonZeroUsize>,
2644 ) -> io::Result<usize> {
2645 let count = match length {
2646 Some(n) => n.get() as libc::size_t,
2647 None => 0x7ffff000, };
2650 let mut offset = offset;
2651 syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
2652 }
2653
2654 #[cfg(all(feature = "all", target_os = "freebsd"))]
2655 fn _sendfile(
2656 &self,
2657 file: RawFd,
2658 offset: libc::off_t,
2659 length: Option<NonZeroUsize>,
2660 ) -> io::Result<usize> {
2661 let nbytes = match length {
2662 Some(n) => n.get() as libc::size_t,
2663 None => 0,
2665 };
2666 let mut sbytes: libc::off_t = 0;
2667 syscall!(sendfile(
2668 file,
2669 self.as_raw(),
2670 offset,
2671 nbytes,
2672 ptr::null_mut(),
2673 &mut sbytes,
2674 0,
2675 ))
2676 .map(|_| sbytes as usize)
2677 }
2678
2679 #[cfg(all(feature = "all", target_os = "aix"))]
2680 fn _sendfile(
2681 &self,
2682 file: RawFd,
2683 offset: libc::off_t,
2684 length: Option<NonZeroUsize>,
2685 ) -> io::Result<usize> {
2686 let nbytes = match length {
2687 Some(n) => n.get() as i64,
2688 None => -1,
2689 };
2690 let mut params = libc::sf_parms {
2691 header_data: ptr::null_mut(),
2692 header_length: 0,
2693 file_descriptor: file,
2694 file_size: 0,
2695 file_offset: offset as u64,
2696 file_bytes: nbytes,
2697 trailer_data: ptr::null_mut(),
2698 trailer_length: 0,
2699 bytes_sent: 0,
2700 };
2701 syscall!(send_file(
2703 &mut self.as_raw() as *mut _,
2704 &mut params as *mut _,
2705 libc::SF_CLOSE as libc::c_uint,
2706 ))
2707 .map(|_| params.bytes_sent as usize)
2708 }
2709
2710 #[cfg(all(
2721 feature = "all",
2722 any(
2723 target_os = "android",
2724 target_os = "fuchsia",
2725 target_os = "linux",
2726 target_os = "cygwin",
2727 )
2728 ))]
2729 #[cfg_attr(
2730 docsrs,
2731 doc(cfg(all(
2732 feature = "all",
2733 any(
2734 target_os = "android",
2735 target_os = "fuchsia",
2736 target_os = "linux",
2737 target_os = "cygwin"
2738 )
2739 )))
2740 )]
2741 pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
2742 let timeout = timeout.map_or(0, |to| {
2743 min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint
2744 });
2745 unsafe {
2746 setsockopt(
2747 self.as_raw(),
2748 libc::IPPROTO_TCP,
2749 libc::TCP_USER_TIMEOUT,
2750 timeout,
2751 )
2752 }
2753 }
2754
2755 #[cfg(all(
2761 feature = "all",
2762 any(
2763 target_os = "android",
2764 target_os = "fuchsia",
2765 target_os = "linux",
2766 target_os = "cygwin",
2767 )
2768 ))]
2769 #[cfg_attr(
2770 docsrs,
2771 doc(cfg(all(
2772 feature = "all",
2773 any(
2774 target_os = "android",
2775 target_os = "fuchsia",
2776 target_os = "linux",
2777 target_os = "cygwin"
2778 )
2779 )))
2780 )]
2781 pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
2782 unsafe {
2783 getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
2784 .map(|millis| {
2785 if millis == 0 {
2786 None
2787 } else {
2788 Some(Duration::from_millis(millis as u64))
2789 }
2790 })
2791 }
2792 }
2793
2794 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2801 pub fn attach_filter(&self, filters: &[libc::sock_filter]) -> io::Result<()> {
2802 let prog = libc::sock_fprog {
2803 len: filters.len() as u16,
2804 filter: filters.as_ptr() as *mut _,
2805 };
2806
2807 unsafe {
2808 setsockopt(
2809 self.as_raw(),
2810 libc::SOL_SOCKET,
2811 libc::SO_ATTACH_FILTER,
2812 prog,
2813 )
2814 }
2815 }
2816
2817 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2823 pub fn detach_filter(&self) -> io::Result<()> {
2824 unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) }
2825 }
2826
2827 #[cfg(all(feature = "all", target_os = "linux"))]
2834 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2835 pub fn cookie(&self) -> io::Result<u64> {
2836 unsafe { getsockopt::<libc::c_ulonglong>(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) }
2837 }
2838
2839 #[cfg(all(
2845 feature = "all",
2846 any(
2847 target_os = "android",
2848 target_os = "dragonfly",
2849 target_os = "freebsd",
2850 target_os = "fuchsia",
2851 target_os = "linux",
2852 target_os = "macos",
2853 target_os = "netbsd",
2854 target_os = "openbsd",
2855 target_os = "cygwin",
2856 )
2857 ))]
2858 #[cfg_attr(
2859 docsrs,
2860 doc(cfg(all(
2861 feature = "all",
2862 any(
2863 target_os = "android",
2864 target_os = "dragonfly",
2865 target_os = "freebsd",
2866 target_os = "fuchsia",
2867 target_os = "linux",
2868 target_os = "macos",
2869 target_os = "netbsd",
2870 target_os = "openbsd"
2871 )
2872 )))
2873 )]
2874 pub fn tclass_v6(&self) -> io::Result<u32> {
2875 unsafe {
2876 getsockopt::<c_int>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS)
2877 .map(|tclass| tclass as u32)
2878 }
2879 }
2880
2881 #[cfg(all(
2886 feature = "all",
2887 any(
2888 target_os = "android",
2889 target_os = "dragonfly",
2890 target_os = "freebsd",
2891 target_os = "fuchsia",
2892 target_os = "linux",
2893 target_os = "macos",
2894 target_os = "netbsd",
2895 target_os = "openbsd",
2896 target_os = "cygwin",
2897 )
2898 ))]
2899 #[cfg_attr(
2900 docsrs,
2901 doc(cfg(all(
2902 feature = "all",
2903 any(
2904 target_os = "android",
2905 target_os = "dragonfly",
2906 target_os = "freebsd",
2907 target_os = "fuchsia",
2908 target_os = "linux",
2909 target_os = "macos",
2910 target_os = "netbsd",
2911 target_os = "openbsd"
2912 )
2913 )))
2914 )]
2915 pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
2916 unsafe {
2917 setsockopt(
2918 self.as_raw(),
2919 IPPROTO_IPV6,
2920 libc::IPV6_TCLASS,
2921 tclass as c_int,
2922 )
2923 }
2924 }
2925
2926 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2932 #[cfg_attr(
2933 docsrs,
2934 doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux"))))
2935 )]
2936 pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
2937 let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX];
2938 let mut len = payload.len() as libc::socklen_t;
2939 syscall!(getsockopt(
2940 self.as_raw(),
2941 IPPROTO_TCP,
2942 libc::TCP_CONGESTION,
2943 payload.as_mut_ptr().cast(),
2944 &mut len,
2945 ))
2946 .map(|_| payload[..len as usize].to_vec())
2947 }
2948
2949 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2956 #[cfg_attr(
2957 docsrs,
2958 doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux"))))
2959 )]
2960 pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
2961 syscall!(setsockopt(
2962 self.as_raw(),
2963 IPPROTO_TCP,
2964 libc::TCP_CONGESTION,
2965 tcp_ca_name.as_ptr() as *const _,
2966 tcp_ca_name.len() as libc::socklen_t,
2967 ))
2968 .map(|_| ())
2969 }
2970
2971 #[cfg(all(feature = "all", target_os = "linux"))]
2982 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2983 pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
2984 unsafe {
2985 setsockopt(
2986 self.as_raw(),
2987 libc::SOL_DCCP,
2988 libc::DCCP_SOCKOPT_SERVICE,
2989 code,
2990 )
2991 }
2992 }
2993
2994 #[cfg(all(feature = "all", target_os = "linux"))]
3000 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3001 pub fn dccp_service(&self) -> io::Result<u32> {
3002 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) }
3003 }
3004
3005 #[cfg(all(feature = "all", target_os = "linux"))]
3009 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3010 pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
3011 unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) }
3012 }
3013
3014 #[cfg(all(feature = "all", target_os = "linux"))]
3020 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3021 pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
3022 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) }
3023 }
3024
3025 #[cfg(all(feature = "all", target_os = "linux"))]
3031 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3032 pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
3033 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) }
3034 }
3035
3036 #[cfg(all(feature = "all", target_os = "linux"))]
3041 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3042 pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> {
3043 unsafe {
3044 setsockopt(
3045 self.as_raw(),
3046 libc::SOL_DCCP,
3047 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
3048 hold_timewait as c_int,
3049 )
3050 }
3051 }
3052
3053 #[cfg(all(feature = "all", target_os = "linux"))]
3059 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3060 pub fn dccp_server_timewait(&self) -> io::Result<bool> {
3061 unsafe {
3062 getsockopt(
3063 self.as_raw(),
3064 libc::SOL_DCCP,
3065 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
3066 )
3067 }
3068 }
3069
3070 #[cfg(all(feature = "all", target_os = "linux"))]
3078 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3079 pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
3080 unsafe {
3081 setsockopt(
3082 self.as_raw(),
3083 libc::SOL_DCCP,
3084 libc::DCCP_SOCKOPT_SEND_CSCOV,
3085 level,
3086 )
3087 }
3088 }
3089
3090 #[cfg(all(feature = "all", target_os = "linux"))]
3096 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3097 pub fn dccp_send_cscov(&self) -> io::Result<u32> {
3098 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) }
3099 }
3100
3101 #[cfg(all(feature = "all", target_os = "linux"))]
3107 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3108 pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
3109 unsafe {
3110 setsockopt(
3111 self.as_raw(),
3112 libc::SOL_DCCP,
3113 libc::DCCP_SOCKOPT_RECV_CSCOV,
3114 level,
3115 )
3116 }
3117 }
3118
3119 #[cfg(all(feature = "all", target_os = "linux"))]
3125 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3126 pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
3127 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) }
3128 }
3129
3130 #[cfg(all(feature = "all", target_os = "linux"))]
3135 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3136 pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
3137 unsafe {
3138 setsockopt(
3139 self.as_raw(),
3140 libc::SOL_DCCP,
3141 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
3142 length,
3143 )
3144 }
3145 }
3146
3147 #[cfg(all(feature = "all", target_os = "linux"))]
3153 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3154 pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
3155 unsafe {
3156 getsockopt(
3157 self.as_raw(),
3158 libc::SOL_DCCP,
3159 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
3160 )
3161 }
3162 }
3163
3164 #[cfg(all(feature = "all", target_os = "linux"))]
3174 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3175 pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEndpoints<N>> {
3176 let mut endpoints = [0; N];
3177 let mut length = endpoints.len() as libc::socklen_t;
3178 syscall!(getsockopt(
3179 self.as_raw(),
3180 libc::SOL_DCCP,
3181 libc::DCCP_SOCKOPT_AVAILABLE_CCIDS,
3182 endpoints.as_mut_ptr().cast(),
3183 &mut length,
3184 ))?;
3185 Ok(CcidEndpoints { endpoints, length })
3186 }
3187
3188 #[cfg(all(feature = "all", target_os = "linux"))]
3193 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3194 pub fn dccp_cur_mps(&self) -> io::Result<u32> {
3195 unsafe {
3196 getsockopt(
3197 self.as_raw(),
3198 libc::SOL_DCCP,
3199 libc::DCCP_SOCKOPT_GET_CUR_MPS,
3200 )
3201 }
3202 }
3203}
3204
3205#[cfg(all(feature = "all", target_os = "linux"))]
3207#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3208#[derive(Debug)]
3209pub struct CcidEndpoints<const N: usize> {
3210 endpoints: [u8; N],
3211 length: u32,
3212}
3213
3214#[cfg(all(feature = "all", target_os = "linux"))]
3215#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3216impl<const N: usize> std::ops::Deref for CcidEndpoints<N> {
3217 type Target = [u8];
3218
3219 fn deref(&self) -> &[u8] {
3220 &self.endpoints[0..self.length as usize]
3221 }
3222}
3223
3224#[cfg_attr(docsrs, doc(cfg(unix)))]
3225impl AsFd for crate::Socket {
3226 fn as_fd(&self) -> BorrowedFd<'_> {
3227 unsafe { BorrowedFd::borrow_raw(self.as_raw()) }
3229 }
3230}
3231
3232#[cfg_attr(docsrs, doc(cfg(unix)))]
3233impl AsRawFd for crate::Socket {
3234 fn as_raw_fd(&self) -> c_int {
3235 self.as_raw()
3236 }
3237}
3238
3239#[cfg_attr(docsrs, doc(cfg(unix)))]
3240impl From<crate::Socket> for OwnedFd {
3241 fn from(sock: crate::Socket) -> OwnedFd {
3242 unsafe { OwnedFd::from_raw_fd(sock.into_raw()) }
3244 }
3245}
3246
3247#[cfg_attr(docsrs, doc(cfg(unix)))]
3248impl IntoRawFd for crate::Socket {
3249 fn into_raw_fd(self) -> c_int {
3250 self.into_raw()
3251 }
3252}
3253
3254#[cfg_attr(docsrs, doc(cfg(unix)))]
3255impl From<OwnedFd> for crate::Socket {
3256 fn from(fd: OwnedFd) -> crate::Socket {
3257 unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) }
3259 }
3260}
3261
3262#[cfg_attr(docsrs, doc(cfg(unix)))]
3263impl FromRawFd for crate::Socket {
3264 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
3265 crate::Socket::from_raw(fd)
3266 }
3267}
3268
3269#[cfg(feature = "all")]
3270from!(UnixStream, crate::Socket);
3271#[cfg(feature = "all")]
3272from!(UnixListener, crate::Socket);
3273#[cfg(feature = "all")]
3274from!(UnixDatagram, crate::Socket);
3275#[cfg(feature = "all")]
3276from!(crate::Socket, UnixStream);
3277#[cfg(feature = "all")]
3278from!(crate::Socket, UnixListener);
3279#[cfg(feature = "all")]
3280from!(crate::Socket, UnixDatagram);
3281
3282#[test]
3283fn in_addr_convertion() {
3284 let ip = Ipv4Addr::new(127, 0, 0, 1);
3285 let raw = to_in_addr(&ip);
3286 let a = raw.s_addr;
3288 assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
3289 assert_eq!(from_in_addr(raw), ip);
3290
3291 let ip = Ipv4Addr::new(127, 34, 4, 12);
3292 let raw = to_in_addr(&ip);
3293 let a = raw.s_addr;
3294 assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
3295 assert_eq!(from_in_addr(raw), ip);
3296}
3297
3298#[test]
3299fn in6_addr_convertion() {
3300 let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
3301 let raw = to_in6_addr(&ip);
3302 let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
3303 assert_eq!(raw.s6_addr, want);
3304 assert_eq!(from_in6_addr(raw), ip);
3305}