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 )
26))]
27use std::num::NonZeroU32;
28#[cfg(all(
29 feature = "all",
30 any(
31 target_os = "aix",
32 target_os = "android",
33 target_os = "freebsd",
34 target_os = "ios",
35 target_os = "visionos",
36 target_os = "linux",
37 target_os = "macos",
38 target_os = "tvos",
39 target_os = "watchos",
40 )
41))]
42use std::num::NonZeroUsize;
43use std::os::unix::ffi::OsStrExt;
44#[cfg(all(
45 feature = "all",
46 any(
47 target_os = "aix",
48 target_os = "android",
49 target_os = "freebsd",
50 target_os = "ios",
51 target_os = "visionos",
52 target_os = "linux",
53 target_os = "macos",
54 target_os = "tvos",
55 target_os = "watchos",
56 )
57))]
58use std::os::unix::io::RawFd;
59use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd};
60#[cfg(feature = "all")]
61use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
62use std::path::Path;
63use std::ptr;
64use std::time::{Duration, Instant};
65use std::{io, slice};
66
67#[cfg(not(any(
68 target_os = "ios",
69 target_os = "visionos",
70 target_os = "macos",
71 target_os = "tvos",
72 target_os = "watchos",
73)))]
74use libc::ssize_t;
75use libc::{in6_addr, in_addr};
76
77use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
78#[cfg(not(target_os = "redox"))]
79use crate::{MsgHdr, MsgHdrMut, RecvFlags};
80
81pub(crate) use libc::c_int;
82
83pub(crate) use libc::{AF_INET, AF_INET6, AF_UNIX};
85#[cfg(all(feature = "all", target_os = "linux"))]
87pub(crate) use libc::SOCK_DCCP;
88#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
89pub(crate) use libc::SOCK_RAW;
90#[cfg(all(feature = "all", not(target_os = "espidf")))]
91pub(crate) use libc::SOCK_SEQPACKET;
92pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM};
93#[cfg(all(feature = "all", target_os = "linux"))]
95pub(crate) use libc::IPPROTO_DCCP;
96#[cfg(target_os = "linux")]
97pub(crate) use libc::IPPROTO_MPTCP;
98#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
99pub(crate) use libc::IPPROTO_SCTP;
100#[cfg(all(
101 feature = "all",
102 any(
103 target_os = "android",
104 target_os = "freebsd",
105 target_os = "fuchsia",
106 target_os = "linux",
107 )
108))]
109pub(crate) use libc::IPPROTO_UDPLITE;
110pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP};
111#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
113pub(crate) use libc::IPPROTO_DIVERT;
114pub(crate) use libc::{
115 sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t,
116};
117#[cfg(not(any(target_os = "redox", target_os = "espidf")))]
119pub(crate) use libc::MSG_TRUNC;
120#[cfg(not(target_os = "redox"))]
121pub(crate) use libc::SO_OOBINLINE;
122#[cfg(not(target_os = "nto"))]
124pub(crate) use libc::ipv6_mreq as Ipv6Mreq;
125#[cfg(not(any(
126 target_os = "dragonfly",
127 target_os = "fuchsia",
128 target_os = "hurd",
129 target_os = "illumos",
130 target_os = "netbsd",
131 target_os = "openbsd",
132 target_os = "redox",
133 target_os = "solaris",
134 target_os = "haiku",
135 target_os = "espidf",
136 target_os = "vita",
137)))]
138pub(crate) use libc::IPV6_RECVTCLASS;
139#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
140pub(crate) use libc::IP_HDRINCL;
141#[cfg(not(any(
142 target_os = "aix",
143 target_os = "dragonfly",
144 target_os = "fuchsia",
145 target_os = "illumos",
146 target_os = "netbsd",
147 target_os = "openbsd",
148 target_os = "redox",
149 target_os = "solaris",
150 target_os = "haiku",
151 target_os = "hurd",
152 target_os = "nto",
153 target_os = "espidf",
154 target_os = "vita",
155)))]
156pub(crate) use libc::IP_RECVTOS;
157#[cfg(not(any(
158 target_os = "fuchsia",
159 target_os = "redox",
160 target_os = "solaris",
161 target_os = "haiku",
162 target_os = "illumos",
163)))]
164pub(crate) use libc::IP_TOS;
165#[cfg(not(any(
166 target_os = "ios",
167 target_os = "visionos",
168 target_os = "macos",
169 target_os = "tvos",
170 target_os = "watchos",
171)))]
172pub(crate) use libc::SO_LINGER;
173#[cfg(any(
174 target_os = "ios",
175 target_os = "visionos",
176 target_os = "macos",
177 target_os = "tvos",
178 target_os = "watchos",
179))]
180pub(crate) use libc::SO_LINGER_SEC as SO_LINGER;
181#[cfg(target_os = "linux")]
182pub(crate) use libc::SO_PASSCRED;
183pub(crate) use libc::{
184 ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF,
185 IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
186 IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET,
187 SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF,
188 SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
189};
190#[cfg(not(any(
191 target_os = "dragonfly",
192 target_os = "haiku",
193 target_os = "hurd",
194 target_os = "netbsd",
195 target_os = "openbsd",
196 target_os = "redox",
197 target_os = "fuchsia",
198 target_os = "nto",
199 target_os = "espidf",
200 target_os = "vita",
201)))]
202pub(crate) use libc::{
203 ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
204};
205#[cfg(not(any(
206 target_os = "dragonfly",
207 target_os = "freebsd",
208 target_os = "haiku",
209 target_os = "illumos",
210 target_os = "ios",
211 target_os = "visionos",
212 target_os = "macos",
213 target_os = "netbsd",
214 target_os = "nto",
215 target_os = "openbsd",
216 target_os = "solaris",
217 target_os = "tvos",
218 target_os = "watchos",
219)))]
220pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
221#[cfg(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 = "openbsd",
231 target_os = "solaris",
232 target_os = "tvos",
233 target_os = "watchos",
234))]
235pub(crate) use libc::{
236 IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP,
237};
238#[cfg(all(
239 feature = "all",
240 any(
241 target_os = "android",
242 target_os = "dragonfly",
243 target_os = "freebsd",
244 target_os = "fuchsia",
245 target_os = "illumos",
246 target_os = "ios",
247 target_os = "visionos",
248 target_os = "linux",
249 target_os = "macos",
250 target_os = "netbsd",
251 target_os = "tvos",
252 target_os = "watchos",
253 )
254))]
255pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
256
257pub(crate) type Bool = c_int;
259
260#[cfg(any(
261 target_os = "ios",
262 target_os = "visionos",
263 target_os = "macos",
264 target_os = "nto",
265 target_os = "tvos",
266 target_os = "watchos",
267))]
268use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
269#[cfg(not(any(
270 target_os = "haiku",
271 target_os = "ios",
272 target_os = "visionos",
273 target_os = "macos",
274 target_os = "nto",
275 target_os = "openbsd",
276 target_os = "tvos",
277 target_os = "watchos",
278 target_os = "vita",
279)))]
280use libc::TCP_KEEPIDLE as KEEPALIVE_TIME;
281
282macro_rules! syscall {
284 ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
285 #[allow(unused_unsafe)]
286 let res = unsafe { libc::$fn($($arg, )*) };
287 if res == -1 {
288 Err(std::io::Error::last_os_error())
289 } else {
290 Ok(res)
291 }
292 }};
293}
294
295#[cfg(not(any(
297 target_os = "ios",
298 target_os = "visionos",
299 target_os = "macos",
300 target_os = "tvos",
301 target_os = "watchos",
302)))]
303const MAX_BUF_LEN: usize = ssize_t::MAX as usize;
304
305#[cfg(any(
314 target_os = "ios",
315 target_os = "visionos",
316 target_os = "macos",
317 target_os = "tvos",
318 target_os = "watchos",
319))]
320const MAX_BUF_LEN: usize = c_int::MAX as usize - 1;
321
322#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
324const TCP_CA_NAME_MAX: usize = 16;
325
326#[cfg(any(
327 all(
328 target_os = "linux",
329 any(
330 target_env = "gnu",
331 all(target_env = "uclibc", target_pointer_width = "64")
332 )
333 ),
334 target_os = "android",
335))]
336type IovLen = usize;
337
338#[cfg(any(
339 all(
340 target_os = "linux",
341 any(
342 target_env = "musl",
343 target_env = "ohos",
344 all(target_env = "uclibc", target_pointer_width = "32")
345 )
346 ),
347 target_os = "aix",
348 target_os = "dragonfly",
349 target_os = "freebsd",
350 target_os = "fuchsia",
351 target_os = "haiku",
352 target_os = "hurd",
353 target_os = "illumos",
354 target_os = "ios",
355 target_os = "visionos",
356 target_os = "macos",
357 target_os = "netbsd",
358 target_os = "nto",
359 target_os = "openbsd",
360 target_os = "solaris",
361 target_os = "tvos",
362 target_os = "watchos",
363 target_os = "espidf",
364 target_os = "vita",
365))]
366type IovLen = c_int;
367
368impl Domain {
370 #[cfg(all(
372 feature = "all",
373 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
374 ))]
375 #[cfg_attr(
376 docsrs,
377 doc(cfg(all(
378 feature = "all",
379 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
380 )))
381 )]
382 pub const PACKET: Domain = Domain(libc::AF_PACKET);
383
384 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
386 #[cfg_attr(
387 docsrs,
388 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
389 )]
390 pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
391}
392
393impl_debug!(
394 Domain,
395 libc::AF_INET,
396 libc::AF_INET6,
397 libc::AF_UNIX,
398 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
399 #[cfg_attr(
400 docsrs,
401 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
402 )]
403 libc::AF_PACKET,
404 #[cfg(any(target_os = "android", target_os = "linux"))]
405 #[cfg_attr(docsrs, doc(cfg(any(target_os = "android", target_os = "linux"))))]
406 libc::AF_VSOCK,
407 libc::AF_UNSPEC, );
409
410impl Type {
412 #[cfg(all(
414 feature = "all",
415 any(
416 target_os = "android",
417 target_os = "dragonfly",
418 target_os = "freebsd",
419 target_os = "fuchsia",
420 target_os = "illumos",
421 target_os = "linux",
422 target_os = "netbsd",
423 target_os = "openbsd"
424 )
425 ))]
426 #[cfg_attr(
427 docsrs,
428 doc(cfg(all(
429 feature = "all",
430 any(
431 target_os = "android",
432 target_os = "dragonfly",
433 target_os = "freebsd",
434 target_os = "fuchsia",
435 target_os = "illumos",
436 target_os = "linux",
437 target_os = "netbsd",
438 target_os = "openbsd"
439 )
440 )))
441 )]
442 pub const fn nonblocking(self) -> Type {
443 Type(self.0 | libc::SOCK_NONBLOCK)
444 }
445
446 #[cfg(all(
448 feature = "all",
449 any(
450 target_os = "android",
451 target_os = "dragonfly",
452 target_os = "freebsd",
453 target_os = "fuchsia",
454 target_os = "hurd",
455 target_os = "illumos",
456 target_os = "linux",
457 target_os = "netbsd",
458 target_os = "openbsd",
459 target_os = "redox",
460 target_os = "solaris",
461 )
462 ))]
463 #[cfg_attr(
464 docsrs,
465 doc(cfg(all(
466 feature = "all",
467 any(
468 target_os = "android",
469 target_os = "dragonfly",
470 target_os = "freebsd",
471 target_os = "fuchsia",
472 target_os = "hurd",
473 target_os = "illumos",
474 target_os = "linux",
475 target_os = "netbsd",
476 target_os = "openbsd",
477 target_os = "redox",
478 target_os = "solaris",
479 )
480 )))
481 )]
482 pub const fn cloexec(self) -> Type {
483 self._cloexec()
484 }
485
486 #[cfg(any(
487 target_os = "android",
488 target_os = "dragonfly",
489 target_os = "freebsd",
490 target_os = "fuchsia",
491 target_os = "hurd",
492 target_os = "illumos",
493 target_os = "linux",
494 target_os = "netbsd",
495 target_os = "openbsd",
496 target_os = "redox",
497 target_os = "solaris",
498 ))]
499 pub(crate) const fn _cloexec(self) -> Type {
500 Type(self.0 | libc::SOCK_CLOEXEC)
501 }
502}
503
504impl_debug!(
505 Type,
506 libc::SOCK_STREAM,
507 libc::SOCK_DGRAM,
508 #[cfg(all(feature = "all", target_os = "linux"))]
509 libc::SOCK_DCCP,
510 #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
511 libc::SOCK_RAW,
512 #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "espidf")))]
513 libc::SOCK_RDM,
514 #[cfg(not(target_os = "espidf"))]
515 libc::SOCK_SEQPACKET,
516 );
539
540impl_debug!(
541 Protocol,
542 libc::IPPROTO_ICMP,
543 libc::IPPROTO_ICMPV6,
544 libc::IPPROTO_TCP,
545 libc::IPPROTO_UDP,
546 #[cfg(target_os = "linux")]
547 libc::IPPROTO_MPTCP,
548 #[cfg(all(feature = "all", target_os = "linux"))]
549 libc::IPPROTO_DCCP,
550 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
551 libc::IPPROTO_SCTP,
552 #[cfg(all(
553 feature = "all",
554 any(
555 target_os = "android",
556 target_os = "freebsd",
557 target_os = "fuchsia",
558 target_os = "linux",
559 )
560 ))]
561 libc::IPPROTO_UDPLITE,
562 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
563 libc::IPPROTO_DIVERT,
564);
565
566#[cfg(not(target_os = "redox"))]
568impl RecvFlags {
569 #[cfg(not(target_os = "espidf"))]
579 pub const fn is_end_of_record(self) -> bool {
580 self.0 & libc::MSG_EOR != 0
581 }
582
583 pub const fn is_out_of_band(self) -> bool {
590 self.0 & libc::MSG_OOB != 0
591 }
592
593 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
601 #[cfg_attr(
602 docsrs,
603 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
604 )]
605 pub const fn is_confirm(self) -> bool {
606 self.0 & libc::MSG_CONFIRM != 0
607 }
608
609 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
616 #[cfg_attr(
617 docsrs,
618 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
619 )]
620 pub const fn is_dontroute(self) -> bool {
621 self.0 & libc::MSG_DONTROUTE != 0
622 }
623}
624
625#[cfg(not(target_os = "redox"))]
626impl std::fmt::Debug for RecvFlags {
627 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
628 let mut s = f.debug_struct("RecvFlags");
629 #[cfg(not(target_os = "espidf"))]
630 s.field("is_end_of_record", &self.is_end_of_record());
631 s.field("is_out_of_band", &self.is_out_of_band());
632 #[cfg(not(target_os = "espidf"))]
633 s.field("is_truncated", &self.is_truncated());
634 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
635 s.field("is_confirm", &self.is_confirm());
636 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
637 s.field("is_dontroute", &self.is_dontroute());
638 s.finish()
639 }
640}
641
642#[repr(transparent)]
643pub struct MaybeUninitSlice<'a> {
644 vec: libc::iovec,
645 _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
646}
647
648unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
649
650unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
651
652impl<'a> MaybeUninitSlice<'a> {
653 pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
654 MaybeUninitSlice {
655 vec: libc::iovec {
656 iov_base: buf.as_mut_ptr().cast(),
657 iov_len: buf.len(),
658 },
659 _lifetime: PhantomData,
660 }
661 }
662
663 pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
664 unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
665 }
666
667 pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
668 unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
669 }
670}
671
672pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize {
674 let base = storage as *const _ as usize;
675 let path = ptr::addr_of!(storage.sun_path) as usize;
676 path - base
677}
678
679#[allow(unsafe_op_in_unsafe_fn)]
680pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
681 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
683 let len = {
684 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<libc::sockaddr_un>() };
685
686 let bytes = path.as_os_str().as_bytes();
687 let too_long = match bytes.first() {
688 None => false,
689 Some(&0) => bytes.len() > storage.sun_path.len(),
691 Some(_) => bytes.len() >= storage.sun_path.len(),
692 };
693 if too_long {
694 return Err(io::Error::new(
695 io::ErrorKind::InvalidInput,
696 "path must be shorter than SUN_LEN",
697 ));
698 }
699
700 storage.sun_family = libc::AF_UNIX as sa_family_t;
701 unsafe {
706 ptr::copy_nonoverlapping(
707 bytes.as_ptr(),
708 storage.sun_path.as_mut_ptr().cast(),
709 bytes.len(),
710 );
711 }
712
713 let sun_path_offset = offset_of_path(storage);
714 sun_path_offset
715 + bytes.len()
716 + match bytes.first() {
717 Some(&0) | None => 0,
718 Some(_) => 1,
719 }
720 };
721 Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
722}
723
724#[cfg(not(target_os = "redox"))]
726pub(crate) use libc::msghdr;
727
728#[cfg(not(target_os = "redox"))]
729pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
730 msg.msg_name = name.as_ptr() as *mut _;
731 msg.msg_namelen = name.len();
732}
733
734#[cfg(not(target_os = "redox"))]
735#[allow(clippy::unnecessary_cast)] pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) {
737 msg.msg_iov = ptr;
738 msg.msg_iovlen = min(len, IovLen::MAX as usize) as IovLen;
739}
740
741#[cfg(not(target_os = "redox"))]
742pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) {
743 msg.msg_control = ptr;
744 msg.msg_controllen = len as _;
745}
746
747#[cfg(not(target_os = "redox"))]
748pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: libc::c_int) {
749 msg.msg_flags = flags;
750}
751
752#[cfg(not(target_os = "redox"))]
753pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
754 RecvFlags(msg.msg_flags)
755}
756
757#[cfg(not(target_os = "redox"))]
758pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
759 msg.msg_controllen as _
760}
761
762impl SockAddr {
764 #[allow(unsafe_op_in_unsafe_fn)]
771 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
772 #[cfg_attr(
773 docsrs,
774 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
775 )]
776 pub fn vsock(cid: u32, port: u32) -> SockAddr {
777 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
779 {
780 let storage: &mut libc::sockaddr_vm =
781 unsafe { &mut *((&mut storage as *mut sockaddr_storage).cast()) };
782 storage.svm_family = libc::AF_VSOCK as sa_family_t;
783 storage.svm_cid = cid;
784 storage.svm_port = port;
785 }
786 unsafe { SockAddr::new(storage, mem::size_of::<libc::sockaddr_vm>() as socklen_t) }
787 }
788
789 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
792 #[cfg_attr(
793 docsrs,
794 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
795 )]
796 pub fn as_vsock_address(&self) -> Option<(u32, u32)> {
797 if self.family() == libc::AF_VSOCK as sa_family_t {
798 let addr = unsafe { &*(self.as_ptr() as *const libc::sockaddr_vm) };
800 Some((addr.svm_cid, addr.svm_port))
801 } else {
802 None
803 }
804 }
805
806 pub fn is_unnamed(&self) -> bool {
809 self.as_sockaddr_un()
810 .map(|storage| {
811 self.len() == offset_of_path(storage) as _
812 || (cfg!(not(any(target_os = "linux", target_os = "android")))
817 && storage.sun_path[0] == 0)
818 })
819 .unwrap_or_default()
820 }
821
822 pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> {
825 self.is_unix().then(|| {
826 unsafe { &*self.as_ptr().cast::<libc::sockaddr_un>() }
829 })
830 }
831
832 fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
837 debug_assert!(!self.is_unnamed());
838 self.len() as usize - offset_of_path(storage) - 1
839 }
840
841 fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] {
845 debug_assert!(!self.is_unnamed());
846 unsafe {
854 slice::from_raw_parts(
855 (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize),
856 self.path_len(storage),
857 )
858 }
859 }
860
861 pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
864 let path = self.as_pathname()?;
865 Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
868 }
869
870 pub fn as_pathname(&self) -> Option<&Path> {
873 self.as_sockaddr_un().and_then(|storage| {
874 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] != 0).then(|| {
875 let path_slice = self.path_bytes(storage, false);
876 Path::new::<OsStr>(OsStrExt::from_bytes(path_slice))
877 })
878 })
879 }
880
881 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
887 #[cfg(any(target_os = "linux", target_os = "android"))]
890 {
891 self.as_sockaddr_un().and_then(|storage| {
892 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] == 0)
893 .then(|| self.path_bytes(storage, true))
894 })
895 }
896 #[cfg(not(any(target_os = "linux", target_os = "android")))]
897 None
898 }
899}
900
901pub(crate) type Socket = c_int;
902
903pub(crate) unsafe fn socket_from_raw(socket: Socket) -> crate::socket::Inner {
904 crate::socket::Inner::from_raw_fd(socket)
905}
906
907pub(crate) fn socket_as_raw(socket: &crate::socket::Inner) -> Socket {
908 socket.as_raw_fd()
909}
910
911pub(crate) fn socket_into_raw(socket: crate::socket::Inner) -> Socket {
912 socket.into_raw_fd()
913}
914
915pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> {
916 syscall!(socket(family, ty, protocol))
917}
918
919#[cfg(all(feature = "all", unix))]
920#[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
921pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[Socket; 2]> {
922 let mut fds = [0, 0];
923 syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds)
924}
925
926pub(crate) fn bind(fd: Socket, addr: &SockAddr) -> io::Result<()> {
927 syscall!(bind(fd, addr.as_ptr(), addr.len() as _)).map(|_| ())
928}
929
930pub(crate) fn connect(fd: Socket, addr: &SockAddr) -> io::Result<()> {
931 syscall!(connect(fd, addr.as_ptr(), addr.len())).map(|_| ())
932}
933
934pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
935 let start = Instant::now();
936
937 let mut pollfd = libc::pollfd {
938 fd: socket.as_raw(),
939 events: libc::POLLIN | libc::POLLOUT,
940 revents: 0,
941 };
942
943 loop {
944 let elapsed = start.elapsed();
945 if elapsed >= timeout {
946 return Err(io::ErrorKind::TimedOut.into());
947 }
948
949 let timeout = (timeout - elapsed).as_millis();
950 let timeout = timeout.clamp(1, c_int::MAX as u128) as c_int;
951
952 match syscall!(poll(&mut pollfd, 1, timeout)) {
953 Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
954 Ok(_) => {
955 if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0 {
957 match socket.take_error() {
958 Ok(Some(err)) | Err(err) => return Err(err),
959 Ok(None) => {
960 return Err(io::Error::new(
961 io::ErrorKind::Other,
962 "no error set after POLLHUP",
963 ))
964 }
965 }
966 }
967 return Ok(());
968 }
969 Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
971 Err(err) => return Err(err),
972 }
973 }
974}
975
976pub(crate) fn listen(fd: Socket, backlog: c_int) -> io::Result<()> {
977 syscall!(listen(fd, backlog)).map(|_| ())
978}
979
980pub(crate) fn accept(fd: Socket) -> io::Result<(Socket, SockAddr)> {
981 unsafe { SockAddr::try_init(|storage, len| syscall!(accept(fd, storage.cast(), len))) }
983}
984
985pub(crate) fn getsockname(fd: Socket) -> io::Result<SockAddr> {
986 unsafe { SockAddr::try_init(|storage, len| syscall!(getsockname(fd, storage.cast(), len))) }
988 .map(|(_, addr)| addr)
989}
990
991pub(crate) fn getpeername(fd: Socket) -> io::Result<SockAddr> {
992 unsafe { SockAddr::try_init(|storage, len| syscall!(getpeername(fd, storage.cast(), len))) }
994 .map(|(_, addr)| addr)
995}
996
997pub(crate) fn try_clone(fd: Socket) -> io::Result<Socket> {
998 syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0))
999}
1000
1001#[cfg(all(feature = "all", unix, not(target_os = "vita")))]
1002pub(crate) fn nonblocking(fd: Socket) -> io::Result<bool> {
1003 let file_status_flags = fcntl_get(fd, libc::F_GETFL)?;
1004 Ok((file_status_flags & libc::O_NONBLOCK) != 0)
1005}
1006
1007#[cfg(all(feature = "all", target_os = "vita"))]
1008pub(crate) fn nonblocking(fd: Socket) -> io::Result<bool> {
1009 unsafe {
1010 getsockopt::<Bool>(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK).map(|non_block| non_block != 0)
1011 }
1012}
1013
1014#[cfg(not(target_os = "vita"))]
1015pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> {
1016 if nonblocking {
1017 fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1018 } else {
1019 fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1020 }
1021}
1022
1023#[cfg(target_os = "vita")]
1024pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> {
1025 unsafe {
1026 setsockopt(
1027 fd,
1028 libc::SOL_SOCKET,
1029 libc::SO_NONBLOCK,
1030 nonblocking as libc::c_int,
1031 )
1032 }
1033}
1034
1035pub(crate) fn shutdown(fd: Socket, how: Shutdown) -> io::Result<()> {
1036 let how = match how {
1037 Shutdown::Write => libc::SHUT_WR,
1038 Shutdown::Read => libc::SHUT_RD,
1039 Shutdown::Both => libc::SHUT_RDWR,
1040 };
1041 syscall!(shutdown(fd, how)).map(|_| ())
1042}
1043
1044pub(crate) fn recv(fd: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
1045 syscall!(recv(
1046 fd,
1047 buf.as_mut_ptr().cast(),
1048 min(buf.len(), MAX_BUF_LEN),
1049 flags,
1050 ))
1051 .map(|n| n as usize)
1052}
1053
1054pub(crate) fn recv_from(
1055 fd: Socket,
1056 buf: &mut [MaybeUninit<u8>],
1057 flags: c_int,
1058) -> io::Result<(usize, SockAddr)> {
1059 unsafe {
1061 SockAddr::try_init(|addr, addrlen| {
1062 syscall!(recvfrom(
1063 fd,
1064 buf.as_mut_ptr().cast(),
1065 min(buf.len(), MAX_BUF_LEN),
1066 flags,
1067 addr.cast(),
1068 addrlen
1069 ))
1070 .map(|n| n as usize)
1071 })
1072 }
1073}
1074
1075pub(crate) fn peek_sender(fd: Socket) -> io::Result<SockAddr> {
1076 let (_, sender) = recv_from(fd, &mut [MaybeUninit::uninit(); 8], MSG_PEEK)?;
1081 Ok(sender)
1082}
1083
1084#[cfg(not(target_os = "redox"))]
1085pub(crate) fn recv_vectored(
1086 fd: Socket,
1087 bufs: &mut [crate::MaybeUninitSlice<'_>],
1088 flags: c_int,
1089) -> io::Result<(usize, RecvFlags)> {
1090 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1091 let n = recvmsg(fd, &mut msg, flags)?;
1092 Ok((n, msg.flags()))
1093}
1094
1095#[cfg(not(target_os = "redox"))]
1096pub(crate) fn recv_from_vectored(
1097 fd: Socket,
1098 bufs: &mut [crate::MaybeUninitSlice<'_>],
1099 flags: c_int,
1100) -> io::Result<(usize, RecvFlags, SockAddr)> {
1101 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1102 let (n, addr) = unsafe {
1105 SockAddr::try_init(|storage, len| {
1106 msg.inner.msg_name = storage.cast();
1107 msg.inner.msg_namelen = *len;
1108 let n = recvmsg(fd, &mut msg, flags)?;
1109 *len = msg.inner.msg_namelen;
1111 Ok(n)
1112 })?
1113 };
1114 Ok((n, msg.flags(), addr))
1115}
1116
1117#[cfg(not(target_os = "redox"))]
1118pub(crate) fn recvmsg(
1119 fd: Socket,
1120 msg: &mut MsgHdrMut<'_, '_, '_>,
1121 flags: c_int,
1122) -> io::Result<usize> {
1123 syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|n| n as usize)
1124}
1125
1126pub(crate) fn send(fd: Socket, buf: &[u8], flags: c_int) -> io::Result<usize> {
1127 syscall!(send(
1128 fd,
1129 buf.as_ptr().cast(),
1130 min(buf.len(), MAX_BUF_LEN),
1131 flags,
1132 ))
1133 .map(|n| n as usize)
1134}
1135
1136#[cfg(not(target_os = "redox"))]
1137pub(crate) fn send_vectored(fd: Socket, bufs: &[IoSlice<'_>], flags: c_int) -> io::Result<usize> {
1138 let msg = MsgHdr::new().with_buffers(bufs);
1139 sendmsg(fd, &msg, flags)
1140}
1141
1142pub(crate) fn send_to(fd: Socket, buf: &[u8], addr: &SockAddr, flags: c_int) -> io::Result<usize> {
1143 syscall!(sendto(
1144 fd,
1145 buf.as_ptr().cast(),
1146 min(buf.len(), MAX_BUF_LEN),
1147 flags,
1148 addr.as_ptr(),
1149 addr.len(),
1150 ))
1151 .map(|n| n as usize)
1152}
1153
1154#[cfg(not(target_os = "redox"))]
1155pub(crate) fn send_to_vectored(
1156 fd: Socket,
1157 bufs: &[IoSlice<'_>],
1158 addr: &SockAddr,
1159 flags: c_int,
1160) -> io::Result<usize> {
1161 let msg = MsgHdr::new().with_addr(addr).with_buffers(bufs);
1162 sendmsg(fd, &msg, flags)
1163}
1164
1165#[cfg(not(target_os = "redox"))]
1166pub(crate) fn sendmsg(fd: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
1167 syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
1168}
1169
1170pub(crate) fn timeout_opt(fd: Socket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
1172 unsafe { getsockopt(fd, opt, val).map(from_timeval) }
1173}
1174
1175const fn from_timeval(duration: libc::timeval) -> Option<Duration> {
1176 if duration.tv_sec == 0 && duration.tv_usec == 0 {
1177 None
1178 } else {
1179 let sec = duration.tv_sec as u64;
1180 let nsec = (duration.tv_usec as u32) * 1000;
1181 Some(Duration::new(sec, nsec))
1182 }
1183}
1184
1185pub(crate) fn set_timeout_opt(
1187 fd: Socket,
1188 opt: c_int,
1189 val: c_int,
1190 duration: Option<Duration>,
1191) -> io::Result<()> {
1192 let duration = into_timeval(duration);
1193 unsafe { setsockopt(fd, opt, val, duration) }
1194}
1195
1196fn into_timeval(duration: Option<Duration>) -> libc::timeval {
1197 match duration {
1198 #[cfg_attr(target_env = "musl", allow(deprecated))]
1200 Some(duration) => libc::timeval {
1201 tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
1202 tv_usec: duration.subsec_micros() as libc::suseconds_t,
1203 },
1204 None => libc::timeval {
1205 tv_sec: 0,
1206 tv_usec: 0,
1207 },
1208 }
1209}
1210
1211#[cfg(all(
1212 feature = "all",
1213 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1214))]
1215#[cfg_attr(
1216 docsrs,
1217 doc(cfg(all(
1218 feature = "all",
1219 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1220 )))
1221)]
1222pub(crate) fn keepalive_time(fd: Socket) -> io::Result<Duration> {
1223 unsafe {
1224 getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
1225 .map(|secs| Duration::from_secs(secs as u64))
1226 }
1227}
1228
1229#[allow(unused_variables)]
1230pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()> {
1231 #[cfg(not(any(
1232 target_os = "haiku",
1233 target_os = "openbsd",
1234 target_os = "nto",
1235 target_os = "vita"
1236 )))]
1237 if let Some(time) = keepalive.time {
1238 let secs = into_secs(time);
1239 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1240 }
1241
1242 #[cfg(any(
1243 target_os = "aix",
1244 target_os = "android",
1245 target_os = "dragonfly",
1246 target_os = "freebsd",
1247 target_os = "fuchsia",
1248 target_os = "hurd",
1249 target_os = "illumos",
1250 target_os = "ios",
1251 target_os = "visionos",
1252 target_os = "linux",
1253 target_os = "macos",
1254 target_os = "netbsd",
1255 target_os = "tvos",
1256 target_os = "watchos",
1257 ))]
1258 {
1259 if let Some(interval) = keepalive.interval {
1260 let secs = into_secs(interval);
1261 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
1262 }
1263
1264 if let Some(retries) = keepalive.retries {
1265 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
1266 }
1267 }
1268
1269 #[cfg(target_os = "nto")]
1270 if let Some(time) = keepalive.time {
1271 let secs = into_timeval(Some(time));
1272 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1273 }
1274
1275 Ok(())
1276}
1277
1278#[cfg(not(any(
1279 target_os = "haiku",
1280 target_os = "openbsd",
1281 target_os = "nto",
1282 target_os = "vita"
1283)))]
1284fn into_secs(duration: Duration) -> c_int {
1285 min(duration.as_secs(), c_int::MAX as u64) as c_int
1286}
1287
1288#[cfg(not(target_os = "vita"))]
1290fn fcntl_get(fd: Socket, cmd: c_int) -> io::Result<c_int> {
1291 syscall!(fcntl(fd, cmd))
1292}
1293
1294#[cfg(not(target_os = "vita"))]
1296fn fcntl_add(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1297 let previous = fcntl_get(fd, get_cmd)?;
1298 let new = previous | flag;
1299 if new != previous {
1300 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1301 } else {
1302 Ok(())
1304 }
1305}
1306
1307#[cfg(not(target_os = "vita"))]
1309fn fcntl_remove(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1310 let previous = fcntl_get(fd, get_cmd)?;
1311 let new = previous & !flag;
1312 if new != previous {
1313 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1314 } else {
1315 Ok(())
1317 }
1318}
1319
1320pub(crate) unsafe fn getsockopt<T>(fd: Socket, opt: c_int, val: c_int) -> io::Result<T> {
1322 let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
1323 let mut len = size_of::<T>() as libc::socklen_t;
1324 syscall!(getsockopt(
1325 fd,
1326 opt,
1327 val,
1328 payload.as_mut_ptr().cast(),
1329 &mut len,
1330 ))
1331 .map(|_| {
1332 debug_assert_eq!(len as usize, size_of::<T>());
1333 payload.assume_init()
1335 })
1336}
1337
1338pub(crate) unsafe fn setsockopt<T>(
1340 fd: Socket,
1341 opt: c_int,
1342 val: c_int,
1343 payload: T,
1344) -> io::Result<()> {
1345 let payload = ptr::addr_of!(payload).cast();
1346 syscall!(setsockopt(
1347 fd,
1348 opt,
1349 val,
1350 payload,
1351 mem::size_of::<T>() as libc::socklen_t,
1352 ))
1353 .map(|_| ())
1354}
1355
1356pub(crate) const fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
1357 in_addr {
1361 s_addr: u32::from_ne_bytes(addr.octets()),
1362 }
1363}
1364
1365pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
1366 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1367}
1368
1369pub(crate) const fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
1370 in6_addr {
1371 s6_addr: addr.octets(),
1372 }
1373}
1374
1375pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
1376 Ipv6Addr::from(addr.s6_addr)
1377}
1378
1379#[cfg(not(any(
1380 target_os = "aix",
1381 target_os = "haiku",
1382 target_os = "illumos",
1383 target_os = "netbsd",
1384 target_os = "openbsd",
1385 target_os = "redox",
1386 target_os = "solaris",
1387 target_os = "nto",
1388 target_os = "espidf",
1389 target_os = "vita",
1390)))]
1391pub(crate) const fn to_mreqn(
1392 multiaddr: &Ipv4Addr,
1393 interface: &crate::socket::InterfaceIndexOrAddress,
1394) -> libc::ip_mreqn {
1395 match interface {
1396 crate::socket::InterfaceIndexOrAddress::Index(interface) => libc::ip_mreqn {
1397 imr_multiaddr: to_in_addr(multiaddr),
1398 imr_address: to_in_addr(&Ipv4Addr::UNSPECIFIED),
1399 imr_ifindex: *interface as _,
1400 },
1401 crate::socket::InterfaceIndexOrAddress::Address(interface) => libc::ip_mreqn {
1402 imr_multiaddr: to_in_addr(multiaddr),
1403 imr_address: to_in_addr(interface),
1404 imr_ifindex: 0,
1405 },
1406 }
1407}
1408
1409#[cfg(all(
1410 feature = "all",
1411 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1412))]
1413pub(crate) fn original_dst(fd: Socket) -> io::Result<SockAddr> {
1414 unsafe {
1416 SockAddr::try_init(|storage, len| {
1417 syscall!(getsockopt(
1418 fd,
1419 libc::SOL_IP,
1420 libc::SO_ORIGINAL_DST,
1421 storage.cast(),
1422 len
1423 ))
1424 })
1425 }
1426 .map(|(_, addr)| addr)
1427}
1428
1429#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1434pub(crate) fn original_dst_ipv6(fd: Socket) -> io::Result<SockAddr> {
1435 unsafe {
1437 SockAddr::try_init(|storage, len| {
1438 syscall!(getsockopt(
1439 fd,
1440 libc::SOL_IPV6,
1441 libc::IP6T_SO_ORIGINAL_DST,
1442 storage.cast(),
1443 len
1444 ))
1445 })
1446 }
1447 .map(|(_, addr)| addr)
1448}
1449
1450impl crate::Socket {
1452 #[doc = man_links!(unix: accept4(2))]
1460 #[cfg(all(
1461 feature = "all",
1462 any(
1463 target_os = "android",
1464 target_os = "dragonfly",
1465 target_os = "freebsd",
1466 target_os = "fuchsia",
1467 target_os = "illumos",
1468 target_os = "linux",
1469 target_os = "netbsd",
1470 target_os = "openbsd",
1471 )
1472 ))]
1473 #[cfg_attr(
1474 docsrs,
1475 doc(cfg(all(
1476 feature = "all",
1477 any(
1478 target_os = "android",
1479 target_os = "dragonfly",
1480 target_os = "freebsd",
1481 target_os = "fuchsia",
1482 target_os = "illumos",
1483 target_os = "linux",
1484 target_os = "netbsd",
1485 target_os = "openbsd",
1486 )
1487 )))
1488 )]
1489 pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1490 self._accept4(flags)
1491 }
1492
1493 #[cfg(any(
1494 target_os = "android",
1495 target_os = "dragonfly",
1496 target_os = "freebsd",
1497 target_os = "fuchsia",
1498 target_os = "illumos",
1499 target_os = "linux",
1500 target_os = "netbsd",
1501 target_os = "openbsd",
1502 ))]
1503 pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1504 unsafe {
1506 SockAddr::try_init(|storage, len| {
1507 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1508 .map(crate::Socket::from_raw)
1509 })
1510 }
1511 }
1512
1513 #[cfg_attr(
1519 any(
1520 target_os = "ios",
1521 target_os = "visionos",
1522 target_os = "macos",
1523 target_os = "tvos",
1524 target_os = "watchos"
1525 ),
1526 allow(rustdoc::broken_intra_doc_links)
1527 )]
1528 #[cfg(all(feature = "all", not(target_os = "vita")))]
1529 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
1530 pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1531 self._set_cloexec(close_on_exec)
1532 }
1533
1534 #[cfg(not(target_os = "vita"))]
1535 pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1536 if close_on_exec {
1537 fcntl_add(
1538 self.as_raw(),
1539 libc::F_GETFD,
1540 libc::F_SETFD,
1541 libc::FD_CLOEXEC,
1542 )
1543 } else {
1544 fcntl_remove(
1545 self.as_raw(),
1546 libc::F_GETFD,
1547 libc::F_SETFD,
1548 libc::FD_CLOEXEC,
1549 )
1550 }
1551 }
1552
1553 #[cfg(all(
1555 feature = "all",
1556 any(
1557 target_os = "ios",
1558 target_os = "visionos",
1559 target_os = "macos",
1560 target_os = "tvos",
1561 target_os = "watchos",
1562 )
1563 ))]
1564 #[cfg_attr(
1565 docsrs,
1566 doc(cfg(all(
1567 feature = "all",
1568 any(
1569 target_os = "ios",
1570 target_os = "visionos",
1571 target_os = "macos",
1572 target_os = "tvos",
1573 target_os = "watchos",
1574 )
1575 )))
1576 )]
1577 pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1578 self._set_nosigpipe(nosigpipe)
1579 }
1580
1581 #[cfg(any(
1582 target_os = "ios",
1583 target_os = "visionos",
1584 target_os = "macos",
1585 target_os = "tvos",
1586 target_os = "watchos",
1587 ))]
1588 pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1589 unsafe {
1590 setsockopt(
1591 self.as_raw(),
1592 libc::SOL_SOCKET,
1593 libc::SO_NOSIGPIPE,
1594 nosigpipe as c_int,
1595 )
1596 }
1597 }
1598
1599 #[cfg(all(feature = "all", not(target_os = "redox")))]
1605 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
1606 pub fn mss(&self) -> io::Result<u32> {
1607 unsafe {
1608 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1609 .map(|mss| mss as u32)
1610 }
1611 }
1612
1613 #[cfg(all(feature = "all", not(target_os = "redox")))]
1618 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
1619 pub fn set_mss(&self, mss: u32) -> io::Result<()> {
1620 unsafe {
1621 setsockopt(
1622 self.as_raw(),
1623 libc::IPPROTO_TCP,
1624 libc::TCP_MAXSEG,
1625 mss as c_int,
1626 )
1627 }
1628 }
1629
1630 #[cfg(all(
1633 feature = "all",
1634 any(
1635 target_os = "aix",
1636 target_os = "android",
1637 target_os = "freebsd",
1638 target_os = "fuchsia",
1639 target_os = "linux",
1640 )
1641 ))]
1642 #[cfg_attr(
1643 docsrs,
1644 doc(cfg(all(
1645 feature = "all",
1646 any(
1647 target_os = "aix",
1648 target_os = "android",
1649 target_os = "freebsd",
1650 target_os = "fuchsia",
1651 target_os = "linux",
1652 )
1653 )))
1654 )]
1655 pub fn is_listener(&self) -> io::Result<bool> {
1656 unsafe {
1657 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1658 .map(|v| v != 0)
1659 }
1660 }
1661
1662 #[cfg(all(
1665 feature = "all",
1666 any(
1667 target_os = "android",
1668 target_os = "fuchsia",
1671 target_os = "linux",
1672 )
1673 ))]
1674 #[cfg_attr(docsrs, doc(cfg(all(
1675 feature = "all",
1676 any(
1677 target_os = "android",
1678 target_os = "fuchsia",
1681 target_os = "linux",
1682 )
1683 ))))]
1684 pub fn domain(&self) -> io::Result<Domain> {
1685 unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1686 }
1687
1688 #[cfg(all(
1691 feature = "all",
1692 any(
1693 target_os = "android",
1694 target_os = "freebsd",
1695 target_os = "fuchsia",
1696 target_os = "linux",
1697 )
1698 ))]
1699 #[cfg_attr(
1700 docsrs,
1701 doc(cfg(all(
1702 feature = "all",
1703 any(
1704 target_os = "android",
1705 target_os = "freebsd",
1706 target_os = "fuchsia",
1707 target_os = "linux",
1708 )
1709 )))
1710 )]
1711 pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1712 unsafe {
1713 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1714 {
1715 0 => None,
1716 p => Some(Protocol(p)),
1717 })
1718 }
1719 }
1720
1721 #[cfg(all(
1728 feature = "all",
1729 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1730 ))]
1731 #[cfg_attr(
1732 docsrs,
1733 doc(cfg(all(
1734 feature = "all",
1735 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1736 )))
1737 )]
1738 pub fn mark(&self) -> io::Result<u32> {
1739 unsafe {
1740 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1741 .map(|mark| mark as u32)
1742 }
1743 }
1744
1745 #[cfg(all(
1753 feature = "all",
1754 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1755 ))]
1756 #[cfg_attr(
1757 docsrs,
1758 doc(cfg(all(
1759 feature = "all",
1760 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1761 )))
1762 )]
1763 pub fn set_mark(&self, mark: u32) -> io::Result<()> {
1764 unsafe {
1765 setsockopt::<c_int>(
1766 self.as_raw(),
1767 libc::SOL_SOCKET,
1768 libc::SO_MARK,
1769 mark as c_int,
1770 )
1771 }
1772 }
1773
1774 #[cfg(all(
1780 feature = "all",
1781 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1782 ))]
1783 #[cfg_attr(
1784 docsrs,
1785 doc(cfg(all(
1786 feature = "all",
1787 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1788 )))
1789 )]
1790 pub fn cork(&self) -> io::Result<bool> {
1791 unsafe {
1792 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK)
1793 .map(|cork| cork != 0)
1794 }
1795 }
1796
1797 #[cfg(all(
1804 feature = "all",
1805 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1806 ))]
1807 #[cfg_attr(
1808 docsrs,
1809 doc(cfg(all(
1810 feature = "all",
1811 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1812 )))
1813 )]
1814 pub fn set_cork(&self, cork: bool) -> io::Result<()> {
1815 unsafe {
1816 setsockopt(
1817 self.as_raw(),
1818 libc::IPPROTO_TCP,
1819 libc::TCP_CORK,
1820 cork as c_int,
1821 )
1822 }
1823 }
1824
1825 #[cfg(all(
1831 feature = "all",
1832 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1833 ))]
1834 #[cfg_attr(
1835 docsrs,
1836 doc(cfg(all(
1837 feature = "all",
1838 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1839 )))
1840 )]
1841 pub fn quickack(&self) -> io::Result<bool> {
1842 unsafe {
1843 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK)
1844 .map(|quickack| quickack != 0)
1845 }
1846 }
1847
1848 #[cfg(all(
1855 feature = "all",
1856 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1857 ))]
1858 #[cfg_attr(
1859 docsrs,
1860 doc(cfg(all(
1861 feature = "all",
1862 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1863 )))
1864 )]
1865 pub fn set_quickack(&self, quickack: bool) -> io::Result<()> {
1866 unsafe {
1867 setsockopt(
1868 self.as_raw(),
1869 libc::IPPROTO_TCP,
1870 libc::TCP_QUICKACK,
1871 quickack as c_int,
1872 )
1873 }
1874 }
1875
1876 #[cfg(all(
1882 feature = "all",
1883 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1884 ))]
1885 #[cfg_attr(
1886 docsrs,
1887 doc(cfg(all(
1888 feature = "all",
1889 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1890 )))
1891 )]
1892 pub fn thin_linear_timeouts(&self) -> io::Result<bool> {
1893 unsafe {
1894 getsockopt::<Bool>(
1895 self.as_raw(),
1896 libc::IPPROTO_TCP,
1897 libc::TCP_THIN_LINEAR_TIMEOUTS,
1898 )
1899 .map(|timeouts| timeouts != 0)
1900 }
1901 }
1902
1903 #[cfg(all(
1909 feature = "all",
1910 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1911 ))]
1912 #[cfg_attr(
1913 docsrs,
1914 doc(cfg(all(
1915 feature = "all",
1916 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1917 )))
1918 )]
1919 pub fn set_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> {
1920 unsafe {
1921 setsockopt(
1922 self.as_raw(),
1923 libc::IPPROTO_TCP,
1924 libc::TCP_THIN_LINEAR_TIMEOUTS,
1925 timeouts as c_int,
1926 )
1927 }
1928 }
1929
1930 #[cfg(all(
1934 feature = "all",
1935 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1936 ))]
1937 #[cfg_attr(
1938 docsrs,
1939 doc(cfg(all(
1940 feature = "all",
1941 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1942 )))
1943 )]
1944 pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1945 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1947 unsafe { MaybeUninit::uninit().assume_init() };
1948 let mut len = buf.len() as libc::socklen_t;
1949 syscall!(getsockopt(
1950 self.as_raw(),
1951 libc::SOL_SOCKET,
1952 libc::SO_BINDTODEVICE,
1953 buf.as_mut_ptr().cast(),
1954 &mut len,
1955 ))?;
1956 if len == 0 {
1957 Ok(None)
1958 } else {
1959 let buf = &buf[..len as usize - 1];
1960 Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
1962 }
1963 }
1964
1965 #[cfg(all(
1973 feature = "all",
1974 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1975 ))]
1976 #[cfg_attr(
1977 docsrs,
1978 doc(cfg(all(
1979 feature = "all",
1980 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1981 )))
1982 )]
1983 pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
1984 let (value, len) = if let Some(interface) = interface {
1985 (interface.as_ptr(), interface.len())
1986 } else {
1987 (ptr::null(), 0)
1988 };
1989 syscall!(setsockopt(
1990 self.as_raw(),
1991 libc::SOL_SOCKET,
1992 libc::SO_BINDTODEVICE,
1993 value.cast(),
1994 len as libc::socklen_t,
1995 ))
1996 .map(|_| ())
1997 }
1998
1999 #[cfg(all(feature = "all", target_os = "freebsd"))]
2003 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "freebsd"))))]
2004 pub fn set_fib(&self, fib: u32) -> io::Result<()> {
2005 syscall!(setsockopt(
2006 self.as_raw(),
2007 libc::SOL_SOCKET,
2008 libc::SO_SETFIB,
2009 (&fib as *const u32).cast(),
2010 mem::size_of::<u32>() as libc::socklen_t,
2011 ))
2012 .map(|_| ())
2013 }
2014
2015 #[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 )
2025 ))]
2026 #[cfg_attr(
2027 docsrs,
2028 doc(cfg(all(
2029 feature = "all",
2030 any(
2031 target_os = "ios",
2032 target_os = "visionos",
2033 target_os = "macos",
2034 target_os = "tvos",
2035 target_os = "watchos",
2036 )
2037 )))
2038 )]
2039 #[deprecated = "Use `Socket::bind_device_by_index_v4` instead"]
2040 pub fn bind_device_by_index(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2041 self.bind_device_by_index_v4(interface)
2042 }
2043
2044 #[cfg(all(
2055 feature = "all",
2056 any(
2057 target_os = "ios",
2058 target_os = "visionos",
2059 target_os = "macos",
2060 target_os = "tvos",
2061 target_os = "watchos",
2062 )
2063 ))]
2064 #[cfg_attr(
2065 docsrs,
2066 doc(cfg(all(
2067 feature = "all",
2068 any(
2069 target_os = "ios",
2070 target_os = "visionos",
2071 target_os = "macos",
2072 target_os = "tvos",
2073 target_os = "watchos",
2074 )
2075 )))
2076 )]
2077 pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2078 let index = interface.map_or(0, NonZeroU32::get);
2079 unsafe { setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index) }
2080 }
2081
2082 #[cfg(all(
2093 feature = "all",
2094 any(
2095 target_os = "ios",
2096 target_os = "visionos",
2097 target_os = "macos",
2098 target_os = "tvos",
2099 target_os = "watchos",
2100 )
2101 ))]
2102 #[cfg_attr(
2103 docsrs,
2104 doc(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 )]
2115 pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2116 let index = interface.map_or(0, NonZeroU32::get);
2117 unsafe { setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index) }
2118 }
2119
2120 #[cfg(all(
2126 feature = "all",
2127 any(
2128 target_os = "ios",
2129 target_os = "visionos",
2130 target_os = "macos",
2131 target_os = "tvos",
2132 target_os = "watchos",
2133 )
2134 ))]
2135 #[cfg_attr(
2136 docsrs,
2137 doc(cfg(all(
2138 feature = "all",
2139 any(
2140 target_os = "ios",
2141 target_os = "visionos",
2142 target_os = "macos",
2143 target_os = "tvos",
2144 target_os = "watchos",
2145 )
2146 )))
2147 )]
2148 pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
2149 let index =
2150 unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
2151 Ok(NonZeroU32::new(index))
2152 }
2153
2154 #[cfg(all(
2156 feature = "all",
2157 any(
2158 target_os = "ios",
2159 target_os = "visionos",
2160 target_os = "macos",
2161 target_os = "tvos",
2162 target_os = "watchos",
2163 )
2164 ))]
2165 #[cfg_attr(
2166 docsrs,
2167 doc(cfg(all(
2168 feature = "all",
2169 any(
2170 target_os = "ios",
2171 target_os = "visionos",
2172 target_os = "macos",
2173 target_os = "tvos",
2174 target_os = "watchos",
2175 )
2176 )))
2177 )]
2178 #[deprecated = "Use `Socket::device_index_v4` instead"]
2179 pub fn device_index(&self) -> io::Result<Option<NonZeroU32>> {
2180 self.device_index_v4()
2181 }
2182
2183 #[cfg(all(
2189 feature = "all",
2190 any(
2191 target_os = "ios",
2192 target_os = "visionos",
2193 target_os = "macos",
2194 target_os = "tvos",
2195 target_os = "watchos",
2196 )
2197 ))]
2198 #[cfg_attr(
2199 docsrs,
2200 doc(cfg(all(
2201 feature = "all",
2202 any(
2203 target_os = "ios",
2204 target_os = "visionos",
2205 target_os = "macos",
2206 target_os = "tvos",
2207 target_os = "watchos",
2208 )
2209 )))
2210 )]
2211 pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
2212 let index = unsafe {
2213 getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)?
2214 };
2215 Ok(NonZeroU32::new(index))
2216 }
2217
2218 #[cfg(all(feature = "all", target_os = "linux"))]
2224 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2225 pub fn cpu_affinity(&self) -> io::Result<usize> {
2226 unsafe {
2227 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
2228 .map(|cpu| cpu as usize)
2229 }
2230 }
2231
2232 #[cfg(all(feature = "all", target_os = "linux"))]
2236 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2237 pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
2238 unsafe {
2239 setsockopt(
2240 self.as_raw(),
2241 libc::SOL_SOCKET,
2242 libc::SO_INCOMING_CPU,
2243 cpu as c_int,
2244 )
2245 }
2246 }
2247
2248 #[cfg(all(
2254 feature = "all",
2255 not(any(target_os = "solaris", target_os = "illumos"))
2256 ))]
2257 #[cfg_attr(
2258 docsrs,
2259 doc(cfg(all(
2260 feature = "all",
2261 unix,
2262 not(any(target_os = "solaris", target_os = "illumos"))
2263 )))
2264 )]
2265 pub fn reuse_port(&self) -> io::Result<bool> {
2266 unsafe {
2267 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
2268 .map(|reuse| reuse != 0)
2269 }
2270 }
2271
2272 #[cfg(all(
2278 feature = "all",
2279 not(any(target_os = "solaris", target_os = "illumos"))
2280 ))]
2281 #[cfg_attr(
2282 docsrs,
2283 doc(cfg(all(
2284 feature = "all",
2285 unix,
2286 not(any(target_os = "solaris", target_os = "illumos"))
2287 )))
2288 )]
2289 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
2290 unsafe {
2291 setsockopt(
2292 self.as_raw(),
2293 libc::SOL_SOCKET,
2294 libc::SO_REUSEPORT,
2295 reuse as c_int,
2296 )
2297 }
2298 }
2299
2300 #[cfg(all(feature = "all", target_os = "freebsd"))]
2306 pub fn reuse_port_lb(&self) -> io::Result<bool> {
2307 unsafe {
2308 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT_LB)
2309 .map(|reuse| reuse != 0)
2310 }
2311 }
2312
2313 #[cfg(all(feature = "all", target_os = "freebsd"))]
2318 pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
2319 unsafe {
2320 setsockopt(
2321 self.as_raw(),
2322 libc::SOL_SOCKET,
2323 libc::SO_REUSEPORT_LB,
2324 reuse as c_int,
2325 )
2326 }
2327 }
2328
2329 #[cfg(all(
2335 feature = "all",
2336 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2337 ))]
2338 #[cfg_attr(
2339 docsrs,
2340 doc(cfg(all(
2341 feature = "all",
2342 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2343 )))
2344 )]
2345 pub fn freebind(&self) -> io::Result<bool> {
2346 unsafe {
2347 getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
2348 .map(|freebind| freebind != 0)
2349 }
2350 }
2351
2352 #[cfg(all(
2360 feature = "all",
2361 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2362 ))]
2363 #[cfg_attr(
2364 docsrs,
2365 doc(cfg(all(
2366 feature = "all",
2367 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2368 )))
2369 )]
2370 pub fn set_freebind(&self, freebind: bool) -> io::Result<()> {
2371 unsafe {
2372 setsockopt(
2373 self.as_raw(),
2374 libc::SOL_IP,
2375 libc::IP_FREEBIND,
2376 freebind as c_int,
2377 )
2378 }
2379 }
2380
2381 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2389 #[cfg_attr(
2390 docsrs,
2391 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2392 )]
2393 pub fn freebind_ipv6(&self) -> io::Result<bool> {
2394 unsafe {
2395 getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
2396 .map(|freebind| freebind != 0)
2397 }
2398 }
2399
2400 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2431 #[cfg_attr(
2432 docsrs,
2433 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2434 )]
2435 pub fn set_freebind_ipv6(&self, freebind: bool) -> io::Result<()> {
2436 unsafe {
2437 setsockopt(
2438 self.as_raw(),
2439 libc::SOL_IPV6,
2440 libc::IPV6_FREEBIND,
2441 freebind as c_int,
2442 )
2443 }
2444 }
2445
2446 #[doc = man_links!(unix: sendfile(2))]
2456 #[cfg(all(
2466 feature = "all",
2467 any(
2468 target_os = "aix",
2469 target_os = "android",
2470 target_os = "freebsd",
2471 target_os = "ios",
2472 target_os = "visionos",
2473 target_os = "linux",
2474 target_os = "macos",
2475 target_os = "tvos",
2476 target_os = "watchos",
2477 )
2478 ))]
2479 #[cfg_attr(
2480 docsrs,
2481 doc(cfg(all(
2482 feature = "all",
2483 any(
2484 target_os = "aix",
2485 target_os = "android",
2486 target_os = "freebsd",
2487 target_os = "ios",
2488 target_os = "visionos",
2489 target_os = "linux",
2490 target_os = "macos",
2491 target_os = "tvos",
2492 target_os = "watchos",
2493 )
2494 )))
2495 )]
2496 pub fn sendfile<F>(
2497 &self,
2498 file: &F,
2499 offset: usize,
2500 length: Option<NonZeroUsize>,
2501 ) -> io::Result<usize>
2502 where
2503 F: AsRawFd,
2504 {
2505 self._sendfile(file.as_raw_fd(), offset as _, length)
2506 }
2507
2508 #[cfg(all(
2509 feature = "all",
2510 any(
2511 target_os = "ios",
2512 target_os = "visionos",
2513 target_os = "macos",
2514 target_os = "tvos",
2515 target_os = "watchos",
2516 )
2517 ))]
2518 fn _sendfile(
2519 &self,
2520 file: RawFd,
2521 offset: libc::off_t,
2522 length: Option<NonZeroUsize>,
2523 ) -> io::Result<usize> {
2524 let mut length = match length {
2527 Some(n) => n.get() as libc::off_t,
2528 None => 0,
2530 };
2531 syscall!(sendfile(
2532 file,
2533 self.as_raw(),
2534 offset,
2535 &mut length,
2536 ptr::null_mut(),
2537 0,
2538 ))
2539 .map(|_| length as usize)
2540 }
2541
2542 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2543 fn _sendfile(
2544 &self,
2545 file: RawFd,
2546 offset: libc::off_t,
2547 length: Option<NonZeroUsize>,
2548 ) -> io::Result<usize> {
2549 let count = match length {
2550 Some(n) => n.get() as libc::size_t,
2551 None => 0x7ffff000, };
2554 let mut offset = offset;
2555 syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
2556 }
2557
2558 #[cfg(all(feature = "all", target_os = "freebsd"))]
2559 fn _sendfile(
2560 &self,
2561 file: RawFd,
2562 offset: libc::off_t,
2563 length: Option<NonZeroUsize>,
2564 ) -> io::Result<usize> {
2565 let nbytes = match length {
2566 Some(n) => n.get() as libc::size_t,
2567 None => 0,
2569 };
2570 let mut sbytes: libc::off_t = 0;
2571 syscall!(sendfile(
2572 file,
2573 self.as_raw(),
2574 offset,
2575 nbytes,
2576 ptr::null_mut(),
2577 &mut sbytes,
2578 0,
2579 ))
2580 .map(|_| sbytes as usize)
2581 }
2582
2583 #[cfg(all(feature = "all", target_os = "aix"))]
2584 fn _sendfile(
2585 &self,
2586 file: RawFd,
2587 offset: libc::off_t,
2588 length: Option<NonZeroUsize>,
2589 ) -> io::Result<usize> {
2590 let nbytes = match length {
2591 Some(n) => n.get() as i64,
2592 None => -1,
2593 };
2594 let mut params = libc::sf_parms {
2595 header_data: ptr::null_mut(),
2596 header_length: 0,
2597 file_descriptor: file,
2598 file_size: 0,
2599 file_offset: offset as u64,
2600 file_bytes: nbytes,
2601 trailer_data: ptr::null_mut(),
2602 trailer_length: 0,
2603 bytes_sent: 0,
2604 };
2605 syscall!(send_file(
2607 &mut self.as_raw() as *mut _,
2608 &mut params as *mut _,
2609 libc::SF_CLOSE as libc::c_uint,
2610 ))
2611 .map(|_| params.bytes_sent as usize)
2612 }
2613
2614 #[cfg(all(
2625 feature = "all",
2626 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2627 ))]
2628 #[cfg_attr(
2629 docsrs,
2630 doc(cfg(all(
2631 feature = "all",
2632 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2633 )))
2634 )]
2635 pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
2636 let timeout = timeout.map_or(0, |to| {
2637 min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint
2638 });
2639 unsafe {
2640 setsockopt(
2641 self.as_raw(),
2642 libc::IPPROTO_TCP,
2643 libc::TCP_USER_TIMEOUT,
2644 timeout,
2645 )
2646 }
2647 }
2648
2649 #[cfg(all(
2655 feature = "all",
2656 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2657 ))]
2658 #[cfg_attr(
2659 docsrs,
2660 doc(cfg(all(
2661 feature = "all",
2662 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2663 )))
2664 )]
2665 pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
2666 unsafe {
2667 getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
2668 .map(|millis| {
2669 if millis == 0 {
2670 None
2671 } else {
2672 Some(Duration::from_millis(millis as u64))
2673 }
2674 })
2675 }
2676 }
2677
2678 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2685 pub fn attach_filter(&self, filters: &[libc::sock_filter]) -> io::Result<()> {
2686 let prog = libc::sock_fprog {
2687 len: filters.len() as u16,
2688 filter: filters.as_ptr() as *mut _,
2689 };
2690
2691 unsafe {
2692 setsockopt(
2693 self.as_raw(),
2694 libc::SOL_SOCKET,
2695 libc::SO_ATTACH_FILTER,
2696 prog,
2697 )
2698 }
2699 }
2700
2701 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2707 pub fn detach_filter(&self) -> io::Result<()> {
2708 unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) }
2709 }
2710
2711 #[cfg(all(feature = "all", target_os = "linux"))]
2718 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2719 pub fn cookie(&self) -> io::Result<u64> {
2720 unsafe { getsockopt::<libc::c_ulonglong>(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) }
2721 }
2722
2723 #[cfg(all(
2729 feature = "all",
2730 any(
2731 target_os = "android",
2732 target_os = "dragonfly",
2733 target_os = "freebsd",
2734 target_os = "fuchsia",
2735 target_os = "linux",
2736 target_os = "macos",
2737 target_os = "netbsd",
2738 target_os = "openbsd"
2739 )
2740 ))]
2741 #[cfg_attr(
2742 docsrs,
2743 doc(cfg(all(
2744 feature = "all",
2745 any(
2746 target_os = "android",
2747 target_os = "dragonfly",
2748 target_os = "freebsd",
2749 target_os = "fuchsia",
2750 target_os = "linux",
2751 target_os = "macos",
2752 target_os = "netbsd",
2753 target_os = "openbsd"
2754 )
2755 )))
2756 )]
2757 pub fn tclass_v6(&self) -> io::Result<u32> {
2758 unsafe {
2759 getsockopt::<c_int>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS)
2760 .map(|tclass| tclass as u32)
2761 }
2762 }
2763
2764 #[cfg(all(
2769 feature = "all",
2770 any(
2771 target_os = "android",
2772 target_os = "dragonfly",
2773 target_os = "freebsd",
2774 target_os = "fuchsia",
2775 target_os = "linux",
2776 target_os = "macos",
2777 target_os = "netbsd",
2778 target_os = "openbsd"
2779 )
2780 ))]
2781 #[cfg_attr(
2782 docsrs,
2783 doc(cfg(all(
2784 feature = "all",
2785 any(
2786 target_os = "android",
2787 target_os = "dragonfly",
2788 target_os = "freebsd",
2789 target_os = "fuchsia",
2790 target_os = "linux",
2791 target_os = "macos",
2792 target_os = "netbsd",
2793 target_os = "openbsd"
2794 )
2795 )))
2796 )]
2797 pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
2798 unsafe {
2799 setsockopt(
2800 self.as_raw(),
2801 IPPROTO_IPV6,
2802 libc::IPV6_TCLASS,
2803 tclass as c_int,
2804 )
2805 }
2806 }
2807
2808 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2814 #[cfg_attr(
2815 docsrs,
2816 doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux"))))
2817 )]
2818 pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
2819 let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX];
2820 let mut len = payload.len() as libc::socklen_t;
2821 syscall!(getsockopt(
2822 self.as_raw(),
2823 IPPROTO_TCP,
2824 libc::TCP_CONGESTION,
2825 payload.as_mut_ptr().cast(),
2826 &mut len,
2827 ))
2828 .map(|_| payload[..len as usize].to_vec())
2829 }
2830
2831 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2838 #[cfg_attr(
2839 docsrs,
2840 doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux"))))
2841 )]
2842 pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
2843 syscall!(setsockopt(
2844 self.as_raw(),
2845 IPPROTO_TCP,
2846 libc::TCP_CONGESTION,
2847 tcp_ca_name.as_ptr() as *const _,
2848 tcp_ca_name.len() as libc::socklen_t,
2849 ))
2850 .map(|_| ())
2851 }
2852
2853 #[cfg(all(feature = "all", target_os = "linux"))]
2864 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2865 pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
2866 unsafe {
2867 setsockopt(
2868 self.as_raw(),
2869 libc::SOL_DCCP,
2870 libc::DCCP_SOCKOPT_SERVICE,
2871 code,
2872 )
2873 }
2874 }
2875
2876 #[cfg(all(feature = "all", target_os = "linux"))]
2882 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2883 pub fn dccp_service(&self) -> io::Result<u32> {
2884 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) }
2885 }
2886
2887 #[cfg(all(feature = "all", target_os = "linux"))]
2891 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2892 pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
2893 unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) }
2894 }
2895
2896 #[cfg(all(feature = "all", target_os = "linux"))]
2902 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2903 pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
2904 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) }
2905 }
2906
2907 #[cfg(all(feature = "all", target_os = "linux"))]
2913 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2914 pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
2915 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) }
2916 }
2917
2918 #[cfg(all(feature = "all", target_os = "linux"))]
2923 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2924 pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> {
2925 unsafe {
2926 setsockopt(
2927 self.as_raw(),
2928 libc::SOL_DCCP,
2929 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2930 hold_timewait as c_int,
2931 )
2932 }
2933 }
2934
2935 #[cfg(all(feature = "all", target_os = "linux"))]
2941 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2942 pub fn dccp_server_timewait(&self) -> io::Result<bool> {
2943 unsafe {
2944 getsockopt(
2945 self.as_raw(),
2946 libc::SOL_DCCP,
2947 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2948 )
2949 }
2950 }
2951
2952 #[cfg(all(feature = "all", target_os = "linux"))]
2960 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2961 pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
2962 unsafe {
2963 setsockopt(
2964 self.as_raw(),
2965 libc::SOL_DCCP,
2966 libc::DCCP_SOCKOPT_SEND_CSCOV,
2967 level,
2968 )
2969 }
2970 }
2971
2972 #[cfg(all(feature = "all", target_os = "linux"))]
2978 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2979 pub fn dccp_send_cscov(&self) -> io::Result<u32> {
2980 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) }
2981 }
2982
2983 #[cfg(all(feature = "all", target_os = "linux"))]
2989 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2990 pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
2991 unsafe {
2992 setsockopt(
2993 self.as_raw(),
2994 libc::SOL_DCCP,
2995 libc::DCCP_SOCKOPT_RECV_CSCOV,
2996 level,
2997 )
2998 }
2999 }
3000
3001 #[cfg(all(feature = "all", target_os = "linux"))]
3007 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3008 pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
3009 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) }
3010 }
3011
3012 #[cfg(all(feature = "all", target_os = "linux"))]
3017 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3018 pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
3019 unsafe {
3020 setsockopt(
3021 self.as_raw(),
3022 libc::SOL_DCCP,
3023 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
3024 length,
3025 )
3026 }
3027 }
3028
3029 #[cfg(all(feature = "all", target_os = "linux"))]
3035 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3036 pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
3037 unsafe {
3038 getsockopt(
3039 self.as_raw(),
3040 libc::SOL_DCCP,
3041 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
3042 )
3043 }
3044 }
3045
3046 #[cfg(all(feature = "all", target_os = "linux"))]
3056 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3057 pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEndpoints<N>> {
3058 let mut endpoints = [0; N];
3059 let mut length = endpoints.len() as libc::socklen_t;
3060 syscall!(getsockopt(
3061 self.as_raw(),
3062 libc::SOL_DCCP,
3063 libc::DCCP_SOCKOPT_AVAILABLE_CCIDS,
3064 endpoints.as_mut_ptr().cast(),
3065 &mut length,
3066 ))?;
3067 Ok(CcidEndpoints { endpoints, length })
3068 }
3069
3070 #[cfg(all(feature = "all", target_os = "linux"))]
3075 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3076 pub fn dccp_cur_mps(&self) -> io::Result<u32> {
3077 unsafe {
3078 getsockopt(
3079 self.as_raw(),
3080 libc::SOL_DCCP,
3081 libc::DCCP_SOCKOPT_GET_CUR_MPS,
3082 )
3083 }
3084 }
3085}
3086
3087#[cfg(all(feature = "all", target_os = "linux"))]
3089#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3090#[derive(Debug)]
3091pub struct CcidEndpoints<const N: usize> {
3092 endpoints: [u8; N],
3093 length: u32,
3094}
3095
3096#[cfg(all(feature = "all", target_os = "linux"))]
3097#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3098impl<const N: usize> std::ops::Deref for CcidEndpoints<N> {
3099 type Target = [u8];
3100
3101 fn deref(&self) -> &[u8] {
3102 &self.endpoints[0..self.length as usize]
3103 }
3104}
3105
3106#[cfg_attr(docsrs, doc(cfg(unix)))]
3107impl AsFd for crate::Socket {
3108 fn as_fd(&self) -> BorrowedFd<'_> {
3109 unsafe { BorrowedFd::borrow_raw(self.as_raw()) }
3111 }
3112}
3113
3114#[cfg_attr(docsrs, doc(cfg(unix)))]
3115impl AsRawFd for crate::Socket {
3116 fn as_raw_fd(&self) -> c_int {
3117 self.as_raw()
3118 }
3119}
3120
3121#[cfg_attr(docsrs, doc(cfg(unix)))]
3122impl From<crate::Socket> for OwnedFd {
3123 fn from(sock: crate::Socket) -> OwnedFd {
3124 unsafe { OwnedFd::from_raw_fd(sock.into_raw()) }
3126 }
3127}
3128
3129#[cfg_attr(docsrs, doc(cfg(unix)))]
3130impl IntoRawFd for crate::Socket {
3131 fn into_raw_fd(self) -> c_int {
3132 self.into_raw()
3133 }
3134}
3135
3136#[cfg_attr(docsrs, doc(cfg(unix)))]
3137impl From<OwnedFd> for crate::Socket {
3138 fn from(fd: OwnedFd) -> crate::Socket {
3139 unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) }
3141 }
3142}
3143
3144#[cfg_attr(docsrs, doc(cfg(unix)))]
3145impl FromRawFd for crate::Socket {
3146 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
3147 crate::Socket::from_raw(fd)
3148 }
3149}
3150
3151#[cfg(feature = "all")]
3152from!(UnixStream, crate::Socket);
3153#[cfg(feature = "all")]
3154from!(UnixListener, crate::Socket);
3155#[cfg(feature = "all")]
3156from!(UnixDatagram, crate::Socket);
3157#[cfg(feature = "all")]
3158from!(crate::Socket, UnixStream);
3159#[cfg(feature = "all")]
3160from!(crate::Socket, UnixListener);
3161#[cfg(feature = "all")]
3162from!(crate::Socket, UnixDatagram);
3163
3164#[test]
3165fn in_addr_convertion() {
3166 let ip = Ipv4Addr::new(127, 0, 0, 1);
3167 let raw = to_in_addr(&ip);
3168 let a = raw.s_addr;
3170 assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
3171 assert_eq!(from_in_addr(raw), ip);
3172
3173 let ip = Ipv4Addr::new(127, 34, 4, 12);
3174 let raw = to_in_addr(&ip);
3175 let a = raw.s_addr;
3176 assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
3177 assert_eq!(from_in_addr(raw), ip);
3178}
3179
3180#[test]
3181fn in6_addr_convertion() {
3182 let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
3183 let raw = to_in6_addr(&ip);
3184 let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
3185 assert_eq!(raw.s6_addr, want);
3186 assert_eq!(from_in6_addr(raw), ip);
3187}