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 = "macos",
22 target_os = "tvos",
23 target_os = "watchos",
24 )
25))]
26use std::num::NonZeroU32;
27#[cfg(all(
28 feature = "all",
29 any(
30 target_os = "aix",
31 target_os = "android",
32 target_os = "freebsd",
33 target_os = "ios",
34 target_os = "linux",
35 target_os = "macos",
36 target_os = "tvos",
37 target_os = "watchos",
38 )
39))]
40use std::num::NonZeroUsize;
41use std::os::unix::ffi::OsStrExt;
42#[cfg(all(
43 feature = "all",
44 any(
45 target_os = "aix",
46 target_os = "android",
47 target_os = "freebsd",
48 target_os = "ios",
49 target_os = "linux",
50 target_os = "macos",
51 target_os = "tvos",
52 target_os = "watchos",
53 )
54))]
55use std::os::unix::io::RawFd;
56use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd};
57#[cfg(feature = "all")]
58use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
59use std::path::Path;
60use std::ptr;
61use std::time::{Duration, Instant};
62use std::{io, slice};
63
64#[cfg(not(any(
65 target_os = "ios",
66 target_os = "macos",
67 target_os = "tvos",
68 target_os = "watchos",
69)))]
70use libc::ssize_t;
71use libc::{in6_addr, in_addr};
72
73use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
74#[cfg(not(target_os = "redox"))]
75use crate::{MsgHdr, MsgHdrMut, RecvFlags};
76
77pub(crate) use libc::c_int;
78
79pub(crate) use libc::{AF_INET, AF_INET6, AF_UNIX};
81#[cfg(all(feature = "all", target_os = "linux"))]
83pub(crate) use libc::SOCK_DCCP;
84#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
85pub(crate) use libc::SOCK_RAW;
86#[cfg(all(feature = "all", not(target_os = "espidf")))]
87pub(crate) use libc::SOCK_SEQPACKET;
88pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM};
89#[cfg(all(feature = "all", target_os = "linux"))]
91pub(crate) use libc::IPPROTO_DCCP;
92#[cfg(target_os = "linux")]
93pub(crate) use libc::IPPROTO_MPTCP;
94#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
95pub(crate) use libc::IPPROTO_SCTP;
96#[cfg(all(
97 feature = "all",
98 any(
99 target_os = "android",
100 target_os = "freebsd",
101 target_os = "fuchsia",
102 target_os = "linux",
103 )
104))]
105pub(crate) use libc::IPPROTO_UDPLITE;
106pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP};
107#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
109pub(crate) use libc::IPPROTO_DIVERT;
110pub(crate) use libc::{
111 sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t,
112};
113#[cfg(not(any(target_os = "redox", target_os = "espidf")))]
115pub(crate) use libc::MSG_TRUNC;
116#[cfg(not(target_os = "redox"))]
117pub(crate) use libc::SO_OOBINLINE;
118#[cfg(not(target_os = "nto"))]
120pub(crate) use libc::ipv6_mreq as Ipv6Mreq;
121#[cfg(not(any(
122 target_os = "dragonfly",
123 target_os = "fuchsia",
124 target_os = "hurd",
125 target_os = "illumos",
126 target_os = "netbsd",
127 target_os = "openbsd",
128 target_os = "redox",
129 target_os = "solaris",
130 target_os = "haiku",
131 target_os = "espidf",
132 target_os = "vita",
133)))]
134pub(crate) use libc::IPV6_RECVTCLASS;
135#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
136pub(crate) use libc::IP_HDRINCL;
137#[cfg(not(any(
138 target_os = "aix",
139 target_os = "dragonfly",
140 target_os = "fuchsia",
141 target_os = "illumos",
142 target_os = "netbsd",
143 target_os = "openbsd",
144 target_os = "redox",
145 target_os = "solaris",
146 target_os = "haiku",
147 target_os = "hurd",
148 target_os = "nto",
149 target_os = "espidf",
150 target_os = "vita",
151)))]
152pub(crate) use libc::IP_RECVTOS;
153#[cfg(not(any(
154 target_os = "fuchsia",
155 target_os = "redox",
156 target_os = "solaris",
157 target_os = "haiku",
158 target_os = "illumos",
159)))]
160pub(crate) use libc::IP_TOS;
161#[cfg(not(any(
162 target_os = "ios",
163 target_os = "macos",
164 target_os = "tvos",
165 target_os = "watchos",
166)))]
167pub(crate) use libc::SO_LINGER;
168#[cfg(any(
169 target_os = "ios",
170 target_os = "macos",
171 target_os = "tvos",
172 target_os = "watchos",
173))]
174pub(crate) use libc::SO_LINGER_SEC as SO_LINGER;
175#[cfg(target_os = "linux")]
176pub(crate) use libc::SO_PASSCRED;
177pub(crate) use libc::{
178 ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF,
179 IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
180 IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET,
181 SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF,
182 SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
183};
184#[cfg(not(any(
185 target_os = "dragonfly",
186 target_os = "haiku",
187 target_os = "hurd",
188 target_os = "netbsd",
189 target_os = "openbsd",
190 target_os = "redox",
191 target_os = "fuchsia",
192 target_os = "nto",
193 target_os = "espidf",
194 target_os = "vita",
195)))]
196pub(crate) use libc::{
197 ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
198};
199#[cfg(not(any(
200 target_os = "dragonfly",
201 target_os = "freebsd",
202 target_os = "haiku",
203 target_os = "illumos",
204 target_os = "ios",
205 target_os = "macos",
206 target_os = "netbsd",
207 target_os = "nto",
208 target_os = "openbsd",
209 target_os = "solaris",
210 target_os = "tvos",
211 target_os = "watchos",
212)))]
213pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
214#[cfg(any(
215 target_os = "dragonfly",
216 target_os = "freebsd",
217 target_os = "haiku",
218 target_os = "illumos",
219 target_os = "ios",
220 target_os = "macos",
221 target_os = "netbsd",
222 target_os = "openbsd",
223 target_os = "solaris",
224 target_os = "tvos",
225 target_os = "watchos",
226))]
227pub(crate) use libc::{
228 IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP,
229};
230#[cfg(all(
231 feature = "all",
232 any(
233 target_os = "android",
234 target_os = "dragonfly",
235 target_os = "freebsd",
236 target_os = "fuchsia",
237 target_os = "illumos",
238 target_os = "ios",
239 target_os = "linux",
240 target_os = "macos",
241 target_os = "netbsd",
242 target_os = "tvos",
243 target_os = "watchos",
244 )
245))]
246pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
247
248pub(crate) type Bool = c_int;
250
251#[cfg(any(
252 target_os = "ios",
253 target_os = "macos",
254 target_os = "nto",
255 target_os = "tvos",
256 target_os = "watchos",
257))]
258use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
259#[cfg(not(any(
260 target_os = "haiku",
261 target_os = "ios",
262 target_os = "macos",
263 target_os = "nto",
264 target_os = "openbsd",
265 target_os = "tvos",
266 target_os = "watchos",
267 target_os = "vita",
268)))]
269use libc::TCP_KEEPIDLE as KEEPALIVE_TIME;
270
271macro_rules! syscall {
273 ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
274 #[allow(unused_unsafe)]
275 let res = unsafe { libc::$fn($($arg, )*) };
276 if res == -1 {
277 Err(std::io::Error::last_os_error())
278 } else {
279 Ok(res)
280 }
281 }};
282}
283
284#[cfg(not(any(
286 target_os = "ios",
287 target_os = "macos",
288 target_os = "tvos",
289 target_os = "watchos",
290)))]
291const MAX_BUF_LEN: usize = ssize_t::MAX as usize;
292
293#[cfg(any(
302 target_os = "ios",
303 target_os = "macos",
304 target_os = "tvos",
305 target_os = "watchos",
306))]
307const MAX_BUF_LEN: usize = c_int::MAX as usize - 1;
308
309#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
311const TCP_CA_NAME_MAX: usize = 16;
312
313#[cfg(any(
314 all(
315 target_os = "linux",
316 any(
317 target_env = "gnu",
318 all(target_env = "uclibc", target_pointer_width = "64")
319 )
320 ),
321 target_os = "android",
322))]
323type IovLen = usize;
324
325#[cfg(any(
326 all(
327 target_os = "linux",
328 any(
329 target_env = "musl",
330 target_env = "ohos",
331 all(target_env = "uclibc", target_pointer_width = "32")
332 )
333 ),
334 target_os = "aix",
335 target_os = "dragonfly",
336 target_os = "freebsd",
337 target_os = "fuchsia",
338 target_os = "haiku",
339 target_os = "hurd",
340 target_os = "illumos",
341 target_os = "ios",
342 target_os = "macos",
343 target_os = "netbsd",
344 target_os = "nto",
345 target_os = "openbsd",
346 target_os = "solaris",
347 target_os = "tvos",
348 target_os = "watchos",
349 target_os = "espidf",
350 target_os = "vita",
351))]
352type IovLen = c_int;
353
354impl Domain {
356 #[cfg(all(
358 feature = "all",
359 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
360 ))]
361 #[cfg_attr(
362 docsrs,
363 doc(cfg(all(
364 feature = "all",
365 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
366 )))
367 )]
368 pub const PACKET: Domain = Domain(libc::AF_PACKET);
369
370 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
372 #[cfg_attr(
373 docsrs,
374 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
375 )]
376 pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
377}
378
379impl_debug!(
380 Domain,
381 libc::AF_INET,
382 libc::AF_INET6,
383 libc::AF_UNIX,
384 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
385 #[cfg_attr(
386 docsrs,
387 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
388 )]
389 libc::AF_PACKET,
390 #[cfg(any(target_os = "android", target_os = "linux"))]
391 #[cfg_attr(docsrs, doc(cfg(any(target_os = "android", target_os = "linux"))))]
392 libc::AF_VSOCK,
393 libc::AF_UNSPEC, );
395
396impl Type {
398 #[cfg(all(
400 feature = "all",
401 any(
402 target_os = "android",
403 target_os = "dragonfly",
404 target_os = "freebsd",
405 target_os = "fuchsia",
406 target_os = "illumos",
407 target_os = "linux",
408 target_os = "netbsd",
409 target_os = "openbsd"
410 )
411 ))]
412 #[cfg_attr(
413 docsrs,
414 doc(cfg(all(
415 feature = "all",
416 any(
417 target_os = "android",
418 target_os = "dragonfly",
419 target_os = "freebsd",
420 target_os = "fuchsia",
421 target_os = "illumos",
422 target_os = "linux",
423 target_os = "netbsd",
424 target_os = "openbsd"
425 )
426 )))
427 )]
428 pub const fn nonblocking(self) -> Type {
429 Type(self.0 | libc::SOCK_NONBLOCK)
430 }
431
432 #[cfg(all(
434 feature = "all",
435 any(
436 target_os = "android",
437 target_os = "dragonfly",
438 target_os = "freebsd",
439 target_os = "fuchsia",
440 target_os = "hurd",
441 target_os = "illumos",
442 target_os = "linux",
443 target_os = "netbsd",
444 target_os = "openbsd",
445 target_os = "redox",
446 target_os = "solaris",
447 )
448 ))]
449 #[cfg_attr(
450 docsrs,
451 doc(cfg(all(
452 feature = "all",
453 any(
454 target_os = "android",
455 target_os = "dragonfly",
456 target_os = "freebsd",
457 target_os = "fuchsia",
458 target_os = "hurd",
459 target_os = "illumos",
460 target_os = "linux",
461 target_os = "netbsd",
462 target_os = "openbsd",
463 target_os = "redox",
464 target_os = "solaris",
465 )
466 )))
467 )]
468 pub const fn cloexec(self) -> Type {
469 self._cloexec()
470 }
471
472 #[cfg(any(
473 target_os = "android",
474 target_os = "dragonfly",
475 target_os = "freebsd",
476 target_os = "fuchsia",
477 target_os = "hurd",
478 target_os = "illumos",
479 target_os = "linux",
480 target_os = "netbsd",
481 target_os = "openbsd",
482 target_os = "redox",
483 target_os = "solaris",
484 ))]
485 pub(crate) const fn _cloexec(self) -> Type {
486 Type(self.0 | libc::SOCK_CLOEXEC)
487 }
488}
489
490impl_debug!(
491 Type,
492 libc::SOCK_STREAM,
493 libc::SOCK_DGRAM,
494 #[cfg(all(feature = "all", target_os = "linux"))]
495 libc::SOCK_DCCP,
496 #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
497 libc::SOCK_RAW,
498 #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "espidf")))]
499 libc::SOCK_RDM,
500 #[cfg(not(target_os = "espidf"))]
501 libc::SOCK_SEQPACKET,
502 );
525
526impl_debug!(
527 Protocol,
528 libc::IPPROTO_ICMP,
529 libc::IPPROTO_ICMPV6,
530 libc::IPPROTO_TCP,
531 libc::IPPROTO_UDP,
532 #[cfg(target_os = "linux")]
533 libc::IPPROTO_MPTCP,
534 #[cfg(all(feature = "all", target_os = "linux"))]
535 libc::IPPROTO_DCCP,
536 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
537 libc::IPPROTO_SCTP,
538 #[cfg(all(
539 feature = "all",
540 any(
541 target_os = "android",
542 target_os = "freebsd",
543 target_os = "fuchsia",
544 target_os = "linux",
545 )
546 ))]
547 libc::IPPROTO_UDPLITE,
548 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
549 libc::IPPROTO_DIVERT,
550);
551
552#[cfg(not(target_os = "redox"))]
554impl RecvFlags {
555 #[cfg(not(target_os = "espidf"))]
565 pub const fn is_end_of_record(self) -> bool {
566 self.0 & libc::MSG_EOR != 0
567 }
568
569 pub const fn is_out_of_band(self) -> bool {
576 self.0 & libc::MSG_OOB != 0
577 }
578
579 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
587 #[cfg_attr(
588 docsrs,
589 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
590 )]
591 pub const fn is_confirm(self) -> bool {
592 self.0 & libc::MSG_CONFIRM != 0
593 }
594
595 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
602 #[cfg_attr(
603 docsrs,
604 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
605 )]
606 pub const fn is_dontroute(self) -> bool {
607 self.0 & libc::MSG_DONTROUTE != 0
608 }
609}
610
611#[cfg(not(target_os = "redox"))]
612impl std::fmt::Debug for RecvFlags {
613 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
614 let mut s = f.debug_struct("RecvFlags");
615 #[cfg(not(target_os = "espidf"))]
616 s.field("is_end_of_record", &self.is_end_of_record());
617 s.field("is_out_of_band", &self.is_out_of_band());
618 #[cfg(not(target_os = "espidf"))]
619 s.field("is_truncated", &self.is_truncated());
620 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
621 s.field("is_confirm", &self.is_confirm());
622 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
623 s.field("is_dontroute", &self.is_dontroute());
624 s.finish()
625 }
626}
627
628#[repr(transparent)]
629pub struct MaybeUninitSlice<'a> {
630 vec: libc::iovec,
631 _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
632}
633
634unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
635
636unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
637
638impl<'a> MaybeUninitSlice<'a> {
639 pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
640 MaybeUninitSlice {
641 vec: libc::iovec {
642 iov_base: buf.as_mut_ptr().cast(),
643 iov_len: buf.len(),
644 },
645 _lifetime: PhantomData,
646 }
647 }
648
649 pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
650 unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
651 }
652
653 pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
654 unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
655 }
656}
657
658pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize {
660 let base = storage as *const _ as usize;
661 let path = ptr::addr_of!(storage.sun_path) as usize;
662 path - base
663}
664
665#[allow(unsafe_op_in_unsafe_fn)]
666pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
667 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
669 let len = {
670 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<libc::sockaddr_un>() };
671
672 let bytes = path.as_os_str().as_bytes();
673 let too_long = match bytes.first() {
674 None => false,
675 Some(&0) => bytes.len() > storage.sun_path.len(),
677 Some(_) => bytes.len() >= storage.sun_path.len(),
678 };
679 if too_long {
680 return Err(io::Error::new(
681 io::ErrorKind::InvalidInput,
682 "path must be shorter than SUN_LEN",
683 ));
684 }
685
686 storage.sun_family = libc::AF_UNIX as sa_family_t;
687 unsafe {
692 ptr::copy_nonoverlapping(
693 bytes.as_ptr(),
694 storage.sun_path.as_mut_ptr().cast(),
695 bytes.len(),
696 );
697 }
698
699 let sun_path_offset = offset_of_path(storage);
700 sun_path_offset
701 + bytes.len()
702 + match bytes.first() {
703 Some(&0) | None => 0,
704 Some(_) => 1,
705 }
706 };
707 Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
708}
709
710#[cfg(not(target_os = "redox"))]
712pub(crate) use libc::msghdr;
713
714#[cfg(not(target_os = "redox"))]
715pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
716 msg.msg_name = name.as_ptr() as *mut _;
717 msg.msg_namelen = name.len();
718}
719
720#[cfg(not(target_os = "redox"))]
721#[allow(clippy::unnecessary_cast)] pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) {
723 msg.msg_iov = ptr;
724 msg.msg_iovlen = min(len, IovLen::MAX as usize) as IovLen;
725}
726
727#[cfg(not(target_os = "redox"))]
728pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) {
729 msg.msg_control = ptr;
730 msg.msg_controllen = len as _;
731}
732
733#[cfg(not(target_os = "redox"))]
734pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: libc::c_int) {
735 msg.msg_flags = flags;
736}
737
738#[cfg(not(target_os = "redox"))]
739pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
740 RecvFlags(msg.msg_flags)
741}
742
743#[cfg(not(target_os = "redox"))]
744pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
745 msg.msg_controllen as _
746}
747
748impl SockAddr {
750 #[allow(unsafe_op_in_unsafe_fn)]
757 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
758 #[cfg_attr(
759 docsrs,
760 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
761 )]
762 pub fn vsock(cid: u32, port: u32) -> SockAddr {
763 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
765 {
766 let storage: &mut libc::sockaddr_vm =
767 unsafe { &mut *((&mut storage as *mut sockaddr_storage).cast()) };
768 storage.svm_family = libc::AF_VSOCK as sa_family_t;
769 storage.svm_cid = cid;
770 storage.svm_port = port;
771 }
772 unsafe { SockAddr::new(storage, mem::size_of::<libc::sockaddr_vm>() as socklen_t) }
773 }
774
775 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
778 #[cfg_attr(
779 docsrs,
780 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
781 )]
782 pub fn as_vsock_address(&self) -> Option<(u32, u32)> {
783 if self.family() == libc::AF_VSOCK as sa_family_t {
784 let addr = unsafe { &*(self.as_ptr() as *const libc::sockaddr_vm) };
786 Some((addr.svm_cid, addr.svm_port))
787 } else {
788 None
789 }
790 }
791
792 pub fn is_unnamed(&self) -> bool {
795 self.as_sockaddr_un()
796 .map(|storage| {
797 self.len() == offset_of_path(storage) as _
798 || (cfg!(not(any(target_os = "linux", target_os = "android")))
803 && storage.sun_path[0] == 0)
804 })
805 .unwrap_or_default()
806 }
807
808 pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> {
811 self.is_unix().then(|| {
812 unsafe { &*self.as_ptr().cast::<libc::sockaddr_un>() }
815 })
816 }
817
818 fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
823 debug_assert!(!self.is_unnamed());
824 self.len() as usize - offset_of_path(storage) - 1
825 }
826
827 fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] {
831 debug_assert!(!self.is_unnamed());
832 unsafe {
840 slice::from_raw_parts(
841 (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize),
842 self.path_len(storage),
843 )
844 }
845 }
846
847 pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
850 let path = self.as_pathname()?;
851 Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
854 }
855
856 pub fn as_pathname(&self) -> Option<&Path> {
859 self.as_sockaddr_un().and_then(|storage| {
860 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] != 0).then(|| {
861 let path_slice = self.path_bytes(storage, false);
862 Path::new::<OsStr>(OsStrExt::from_bytes(path_slice))
863 })
864 })
865 }
866
867 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
873 #[cfg(any(target_os = "linux", target_os = "android"))]
876 {
877 self.as_sockaddr_un().and_then(|storage| {
878 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] == 0)
879 .then(|| self.path_bytes(storage, true))
880 })
881 }
882 #[cfg(not(any(target_os = "linux", target_os = "android")))]
883 None
884 }
885}
886
887pub(crate) type Socket = c_int;
888
889pub(crate) unsafe fn socket_from_raw(socket: Socket) -> crate::socket::Inner {
890 crate::socket::Inner::from_raw_fd(socket)
891}
892
893pub(crate) fn socket_as_raw(socket: &crate::socket::Inner) -> Socket {
894 socket.as_raw_fd()
895}
896
897pub(crate) fn socket_into_raw(socket: crate::socket::Inner) -> Socket {
898 socket.into_raw_fd()
899}
900
901pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> {
902 syscall!(socket(family, ty, protocol))
903}
904
905#[cfg(all(feature = "all", unix))]
906#[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
907pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[Socket; 2]> {
908 let mut fds = [0, 0];
909 syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds)
910}
911
912pub(crate) fn bind(fd: Socket, addr: &SockAddr) -> io::Result<()> {
913 syscall!(bind(fd, addr.as_ptr(), addr.len() as _)).map(|_| ())
914}
915
916pub(crate) fn connect(fd: Socket, addr: &SockAddr) -> io::Result<()> {
917 syscall!(connect(fd, addr.as_ptr(), addr.len())).map(|_| ())
918}
919
920pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
921 let start = Instant::now();
922
923 let mut pollfd = libc::pollfd {
924 fd: socket.as_raw(),
925 events: libc::POLLIN | libc::POLLOUT,
926 revents: 0,
927 };
928
929 loop {
930 let elapsed = start.elapsed();
931 if elapsed >= timeout {
932 return Err(io::ErrorKind::TimedOut.into());
933 }
934
935 let timeout = (timeout - elapsed).as_millis();
936 let timeout = timeout.clamp(1, c_int::MAX as u128) as c_int;
937
938 match syscall!(poll(&mut pollfd, 1, timeout)) {
939 Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
940 Ok(_) => {
941 if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0 {
943 match socket.take_error() {
944 Ok(Some(err)) | Err(err) => return Err(err),
945 Ok(None) => {
946 return Err(io::Error::new(
947 io::ErrorKind::Other,
948 "no error set after POLLHUP",
949 ))
950 }
951 }
952 }
953 return Ok(());
954 }
955 Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
957 Err(err) => return Err(err),
958 }
959 }
960}
961
962pub(crate) fn listen(fd: Socket, backlog: c_int) -> io::Result<()> {
963 syscall!(listen(fd, backlog)).map(|_| ())
964}
965
966pub(crate) fn accept(fd: Socket) -> io::Result<(Socket, SockAddr)> {
967 unsafe { SockAddr::try_init(|storage, len| syscall!(accept(fd, storage.cast(), len))) }
969}
970
971pub(crate) fn getsockname(fd: Socket) -> io::Result<SockAddr> {
972 unsafe { SockAddr::try_init(|storage, len| syscall!(getsockname(fd, storage.cast(), len))) }
974 .map(|(_, addr)| addr)
975}
976
977pub(crate) fn getpeername(fd: Socket) -> io::Result<SockAddr> {
978 unsafe { SockAddr::try_init(|storage, len| syscall!(getpeername(fd, storage.cast(), len))) }
980 .map(|(_, addr)| addr)
981}
982
983pub(crate) fn try_clone(fd: Socket) -> io::Result<Socket> {
984 syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0))
985}
986
987#[cfg(all(feature = "all", unix, not(target_os = "vita")))]
988pub(crate) fn nonblocking(fd: Socket) -> io::Result<bool> {
989 let file_status_flags = fcntl_get(fd, libc::F_GETFL)?;
990 Ok((file_status_flags & libc::O_NONBLOCK) != 0)
991}
992
993#[cfg(all(feature = "all", target_os = "vita"))]
994pub(crate) fn nonblocking(fd: Socket) -> io::Result<bool> {
995 unsafe {
996 getsockopt::<Bool>(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK).map(|non_block| non_block != 0)
997 }
998}
999
1000#[cfg(not(target_os = "vita"))]
1001pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> {
1002 if nonblocking {
1003 fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1004 } else {
1005 fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1006 }
1007}
1008
1009#[cfg(target_os = "vita")]
1010pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> {
1011 unsafe {
1012 setsockopt(
1013 fd,
1014 libc::SOL_SOCKET,
1015 libc::SO_NONBLOCK,
1016 nonblocking as libc::c_int,
1017 )
1018 }
1019}
1020
1021pub(crate) fn shutdown(fd: Socket, how: Shutdown) -> io::Result<()> {
1022 let how = match how {
1023 Shutdown::Write => libc::SHUT_WR,
1024 Shutdown::Read => libc::SHUT_RD,
1025 Shutdown::Both => libc::SHUT_RDWR,
1026 };
1027 syscall!(shutdown(fd, how)).map(|_| ())
1028}
1029
1030pub(crate) fn recv(fd: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
1031 syscall!(recv(
1032 fd,
1033 buf.as_mut_ptr().cast(),
1034 min(buf.len(), MAX_BUF_LEN),
1035 flags,
1036 ))
1037 .map(|n| n as usize)
1038}
1039
1040pub(crate) fn recv_from(
1041 fd: Socket,
1042 buf: &mut [MaybeUninit<u8>],
1043 flags: c_int,
1044) -> io::Result<(usize, SockAddr)> {
1045 unsafe {
1047 SockAddr::try_init(|addr, addrlen| {
1048 syscall!(recvfrom(
1049 fd,
1050 buf.as_mut_ptr().cast(),
1051 min(buf.len(), MAX_BUF_LEN),
1052 flags,
1053 addr.cast(),
1054 addrlen
1055 ))
1056 .map(|n| n as usize)
1057 })
1058 }
1059}
1060
1061pub(crate) fn peek_sender(fd: Socket) -> io::Result<SockAddr> {
1062 let (_, sender) = recv_from(fd, &mut [MaybeUninit::uninit(); 8], MSG_PEEK)?;
1067 Ok(sender)
1068}
1069
1070#[cfg(not(target_os = "redox"))]
1071pub(crate) fn recv_vectored(
1072 fd: Socket,
1073 bufs: &mut [crate::MaybeUninitSlice<'_>],
1074 flags: c_int,
1075) -> io::Result<(usize, RecvFlags)> {
1076 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1077 let n = recvmsg(fd, &mut msg, flags)?;
1078 Ok((n, msg.flags()))
1079}
1080
1081#[cfg(not(target_os = "redox"))]
1082pub(crate) fn recv_from_vectored(
1083 fd: Socket,
1084 bufs: &mut [crate::MaybeUninitSlice<'_>],
1085 flags: c_int,
1086) -> io::Result<(usize, RecvFlags, SockAddr)> {
1087 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1088 let (n, addr) = unsafe {
1091 SockAddr::try_init(|storage, len| {
1092 msg.inner.msg_name = storage.cast();
1093 msg.inner.msg_namelen = *len;
1094 let n = recvmsg(fd, &mut msg, flags)?;
1095 *len = msg.inner.msg_namelen;
1097 Ok(n)
1098 })?
1099 };
1100 Ok((n, msg.flags(), addr))
1101}
1102
1103#[cfg(not(target_os = "redox"))]
1104pub(crate) fn recvmsg(
1105 fd: Socket,
1106 msg: &mut MsgHdrMut<'_, '_, '_>,
1107 flags: c_int,
1108) -> io::Result<usize> {
1109 syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|n| n as usize)
1110}
1111
1112pub(crate) fn send(fd: Socket, buf: &[u8], flags: c_int) -> io::Result<usize> {
1113 syscall!(send(
1114 fd,
1115 buf.as_ptr().cast(),
1116 min(buf.len(), MAX_BUF_LEN),
1117 flags,
1118 ))
1119 .map(|n| n as usize)
1120}
1121
1122#[cfg(not(target_os = "redox"))]
1123pub(crate) fn send_vectored(fd: Socket, bufs: &[IoSlice<'_>], flags: c_int) -> io::Result<usize> {
1124 let msg = MsgHdr::new().with_buffers(bufs);
1125 sendmsg(fd, &msg, flags)
1126}
1127
1128pub(crate) fn send_to(fd: Socket, buf: &[u8], addr: &SockAddr, flags: c_int) -> io::Result<usize> {
1129 syscall!(sendto(
1130 fd,
1131 buf.as_ptr().cast(),
1132 min(buf.len(), MAX_BUF_LEN),
1133 flags,
1134 addr.as_ptr(),
1135 addr.len(),
1136 ))
1137 .map(|n| n as usize)
1138}
1139
1140#[cfg(not(target_os = "redox"))]
1141pub(crate) fn send_to_vectored(
1142 fd: Socket,
1143 bufs: &[IoSlice<'_>],
1144 addr: &SockAddr,
1145 flags: c_int,
1146) -> io::Result<usize> {
1147 let msg = MsgHdr::new().with_addr(addr).with_buffers(bufs);
1148 sendmsg(fd, &msg, flags)
1149}
1150
1151#[cfg(not(target_os = "redox"))]
1152pub(crate) fn sendmsg(fd: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
1153 syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
1154}
1155
1156pub(crate) fn timeout_opt(fd: Socket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
1158 unsafe { getsockopt(fd, opt, val).map(from_timeval) }
1159}
1160
1161const fn from_timeval(duration: libc::timeval) -> Option<Duration> {
1162 if duration.tv_sec == 0 && duration.tv_usec == 0 {
1163 None
1164 } else {
1165 let sec = duration.tv_sec as u64;
1166 let nsec = (duration.tv_usec as u32) * 1000;
1167 Some(Duration::new(sec, nsec))
1168 }
1169}
1170
1171pub(crate) fn set_timeout_opt(
1173 fd: Socket,
1174 opt: c_int,
1175 val: c_int,
1176 duration: Option<Duration>,
1177) -> io::Result<()> {
1178 let duration = into_timeval(duration);
1179 unsafe { setsockopt(fd, opt, val, duration) }
1180}
1181
1182fn into_timeval(duration: Option<Duration>) -> libc::timeval {
1183 match duration {
1184 #[cfg_attr(target_env = "musl", allow(deprecated))]
1186 Some(duration) => libc::timeval {
1187 tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
1188 tv_usec: duration.subsec_micros() as libc::suseconds_t,
1189 },
1190 None => libc::timeval {
1191 tv_sec: 0,
1192 tv_usec: 0,
1193 },
1194 }
1195}
1196
1197#[cfg(all(
1198 feature = "all",
1199 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1200))]
1201#[cfg_attr(
1202 docsrs,
1203 doc(cfg(all(
1204 feature = "all",
1205 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1206 )))
1207)]
1208pub(crate) fn keepalive_time(fd: Socket) -> io::Result<Duration> {
1209 unsafe {
1210 getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
1211 .map(|secs| Duration::from_secs(secs as u64))
1212 }
1213}
1214
1215#[allow(unused_variables)]
1216pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()> {
1217 #[cfg(not(any(
1218 target_os = "haiku",
1219 target_os = "openbsd",
1220 target_os = "nto",
1221 target_os = "vita"
1222 )))]
1223 if let Some(time) = keepalive.time {
1224 let secs = into_secs(time);
1225 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1226 }
1227
1228 #[cfg(any(
1229 target_os = "aix",
1230 target_os = "android",
1231 target_os = "dragonfly",
1232 target_os = "freebsd",
1233 target_os = "fuchsia",
1234 target_os = "hurd",
1235 target_os = "illumos",
1236 target_os = "ios",
1237 target_os = "linux",
1238 target_os = "macos",
1239 target_os = "netbsd",
1240 target_os = "tvos",
1241 target_os = "watchos",
1242 ))]
1243 {
1244 if let Some(interval) = keepalive.interval {
1245 let secs = into_secs(interval);
1246 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
1247 }
1248
1249 if let Some(retries) = keepalive.retries {
1250 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
1251 }
1252 }
1253
1254 #[cfg(target_os = "nto")]
1255 if let Some(time) = keepalive.time {
1256 let secs = into_timeval(Some(time));
1257 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1258 }
1259
1260 Ok(())
1261}
1262
1263#[cfg(not(any(
1264 target_os = "haiku",
1265 target_os = "openbsd",
1266 target_os = "nto",
1267 target_os = "vita"
1268)))]
1269fn into_secs(duration: Duration) -> c_int {
1270 min(duration.as_secs(), c_int::MAX as u64) as c_int
1271}
1272
1273#[cfg(not(target_os = "vita"))]
1275fn fcntl_get(fd: Socket, cmd: c_int) -> io::Result<c_int> {
1276 syscall!(fcntl(fd, cmd))
1277}
1278
1279#[cfg(not(target_os = "vita"))]
1281fn fcntl_add(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1282 let previous = fcntl_get(fd, get_cmd)?;
1283 let new = previous | flag;
1284 if new != previous {
1285 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1286 } else {
1287 Ok(())
1289 }
1290}
1291
1292#[cfg(not(target_os = "vita"))]
1294fn fcntl_remove(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1295 let previous = fcntl_get(fd, get_cmd)?;
1296 let new = previous & !flag;
1297 if new != previous {
1298 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1299 } else {
1300 Ok(())
1302 }
1303}
1304
1305pub(crate) unsafe fn getsockopt<T>(fd: Socket, opt: c_int, val: c_int) -> io::Result<T> {
1307 let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
1308 let mut len = size_of::<T>() as libc::socklen_t;
1309 syscall!(getsockopt(
1310 fd,
1311 opt,
1312 val,
1313 payload.as_mut_ptr().cast(),
1314 &mut len,
1315 ))
1316 .map(|_| {
1317 debug_assert_eq!(len as usize, size_of::<T>());
1318 payload.assume_init()
1320 })
1321}
1322
1323pub(crate) unsafe fn setsockopt<T>(
1325 fd: Socket,
1326 opt: c_int,
1327 val: c_int,
1328 payload: T,
1329) -> io::Result<()> {
1330 let payload = ptr::addr_of!(payload).cast();
1331 syscall!(setsockopt(
1332 fd,
1333 opt,
1334 val,
1335 payload,
1336 mem::size_of::<T>() as libc::socklen_t,
1337 ))
1338 .map(|_| ())
1339}
1340
1341pub(crate) const fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
1342 in_addr {
1346 s_addr: u32::from_ne_bytes(addr.octets()),
1347 }
1348}
1349
1350pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
1351 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1352}
1353
1354pub(crate) const fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
1355 in6_addr {
1356 s6_addr: addr.octets(),
1357 }
1358}
1359
1360pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
1361 Ipv6Addr::from(addr.s6_addr)
1362}
1363
1364#[cfg(not(any(
1365 target_os = "aix",
1366 target_os = "haiku",
1367 target_os = "illumos",
1368 target_os = "netbsd",
1369 target_os = "openbsd",
1370 target_os = "redox",
1371 target_os = "solaris",
1372 target_os = "nto",
1373 target_os = "espidf",
1374 target_os = "vita",
1375)))]
1376pub(crate) const fn to_mreqn(
1377 multiaddr: &Ipv4Addr,
1378 interface: &crate::socket::InterfaceIndexOrAddress,
1379) -> libc::ip_mreqn {
1380 match interface {
1381 crate::socket::InterfaceIndexOrAddress::Index(interface) => libc::ip_mreqn {
1382 imr_multiaddr: to_in_addr(multiaddr),
1383 imr_address: to_in_addr(&Ipv4Addr::UNSPECIFIED),
1384 imr_ifindex: *interface as _,
1385 },
1386 crate::socket::InterfaceIndexOrAddress::Address(interface) => libc::ip_mreqn {
1387 imr_multiaddr: to_in_addr(multiaddr),
1388 imr_address: to_in_addr(interface),
1389 imr_ifindex: 0,
1390 },
1391 }
1392}
1393
1394impl crate::Socket {
1396 #[doc = man_links!(unix: accept4(2))]
1404 #[cfg(all(
1405 feature = "all",
1406 any(
1407 target_os = "android",
1408 target_os = "dragonfly",
1409 target_os = "freebsd",
1410 target_os = "fuchsia",
1411 target_os = "illumos",
1412 target_os = "linux",
1413 target_os = "netbsd",
1414 target_os = "openbsd",
1415 )
1416 ))]
1417 #[cfg_attr(
1418 docsrs,
1419 doc(cfg(all(
1420 feature = "all",
1421 any(
1422 target_os = "android",
1423 target_os = "dragonfly",
1424 target_os = "freebsd",
1425 target_os = "fuchsia",
1426 target_os = "illumos",
1427 target_os = "linux",
1428 target_os = "netbsd",
1429 target_os = "openbsd",
1430 )
1431 )))
1432 )]
1433 pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1434 self._accept4(flags)
1435 }
1436
1437 #[cfg(any(
1438 target_os = "android",
1439 target_os = "dragonfly",
1440 target_os = "freebsd",
1441 target_os = "fuchsia",
1442 target_os = "illumos",
1443 target_os = "linux",
1444 target_os = "netbsd",
1445 target_os = "openbsd",
1446 ))]
1447 pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1448 unsafe {
1450 SockAddr::try_init(|storage, len| {
1451 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1452 .map(crate::Socket::from_raw)
1453 })
1454 }
1455 }
1456
1457 #[cfg_attr(
1463 any(
1464 target_os = "ios",
1465 target_os = "macos",
1466 target_os = "tvos",
1467 target_os = "watchos"
1468 ),
1469 allow(rustdoc::broken_intra_doc_links)
1470 )]
1471 #[cfg(all(feature = "all", not(target_os = "vita")))]
1472 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
1473 pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1474 self._set_cloexec(close_on_exec)
1475 }
1476
1477 #[cfg(not(target_os = "vita"))]
1478 pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1479 if close_on_exec {
1480 fcntl_add(
1481 self.as_raw(),
1482 libc::F_GETFD,
1483 libc::F_SETFD,
1484 libc::FD_CLOEXEC,
1485 )
1486 } else {
1487 fcntl_remove(
1488 self.as_raw(),
1489 libc::F_GETFD,
1490 libc::F_SETFD,
1491 libc::FD_CLOEXEC,
1492 )
1493 }
1494 }
1495
1496 #[cfg(all(
1498 feature = "all",
1499 any(
1500 target_os = "ios",
1501 target_os = "macos",
1502 target_os = "tvos",
1503 target_os = "watchos",
1504 )
1505 ))]
1506 #[cfg_attr(
1507 docsrs,
1508 doc(cfg(all(
1509 feature = "all",
1510 any(
1511 target_os = "ios",
1512 target_os = "macos",
1513 target_os = "tvos",
1514 target_os = "watchos",
1515 )
1516 )))
1517 )]
1518 pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1519 self._set_nosigpipe(nosigpipe)
1520 }
1521
1522 #[cfg(any(
1523 target_os = "ios",
1524 target_os = "macos",
1525 target_os = "tvos",
1526 target_os = "watchos",
1527 ))]
1528 pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1529 unsafe {
1530 setsockopt(
1531 self.as_raw(),
1532 libc::SOL_SOCKET,
1533 libc::SO_NOSIGPIPE,
1534 nosigpipe as c_int,
1535 )
1536 }
1537 }
1538
1539 #[cfg(all(feature = "all", not(target_os = "redox")))]
1545 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
1546 pub fn mss(&self) -> io::Result<u32> {
1547 unsafe {
1548 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1549 .map(|mss| mss as u32)
1550 }
1551 }
1552
1553 #[cfg(all(feature = "all", not(target_os = "redox")))]
1558 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
1559 pub fn set_mss(&self, mss: u32) -> io::Result<()> {
1560 unsafe {
1561 setsockopt(
1562 self.as_raw(),
1563 libc::IPPROTO_TCP,
1564 libc::TCP_MAXSEG,
1565 mss as c_int,
1566 )
1567 }
1568 }
1569
1570 #[cfg(all(
1573 feature = "all",
1574 any(
1575 target_os = "aix",
1576 target_os = "android",
1577 target_os = "freebsd",
1578 target_os = "fuchsia",
1579 target_os = "linux",
1580 )
1581 ))]
1582 #[cfg_attr(
1583 docsrs,
1584 doc(cfg(all(
1585 feature = "all",
1586 any(
1587 target_os = "aix",
1588 target_os = "android",
1589 target_os = "freebsd",
1590 target_os = "fuchsia",
1591 target_os = "linux",
1592 )
1593 )))
1594 )]
1595 pub fn is_listener(&self) -> io::Result<bool> {
1596 unsafe {
1597 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1598 .map(|v| v != 0)
1599 }
1600 }
1601
1602 #[cfg(all(
1605 feature = "all",
1606 any(
1607 target_os = "android",
1608 target_os = "fuchsia",
1611 target_os = "linux",
1612 )
1613 ))]
1614 #[cfg_attr(docsrs, doc(cfg(all(
1615 feature = "all",
1616 any(
1617 target_os = "android",
1618 target_os = "fuchsia",
1621 target_os = "linux",
1622 )
1623 ))))]
1624 pub fn domain(&self) -> io::Result<Domain> {
1625 unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1626 }
1627
1628 #[cfg(all(
1631 feature = "all",
1632 any(
1633 target_os = "android",
1634 target_os = "freebsd",
1635 target_os = "fuchsia",
1636 target_os = "linux",
1637 )
1638 ))]
1639 #[cfg_attr(
1640 docsrs,
1641 doc(cfg(all(
1642 feature = "all",
1643 any(
1644 target_os = "android",
1645 target_os = "freebsd",
1646 target_os = "fuchsia",
1647 target_os = "linux",
1648 )
1649 )))
1650 )]
1651 pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1652 unsafe {
1653 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1654 {
1655 0 => None,
1656 p => Some(Protocol(p)),
1657 })
1658 }
1659 }
1660
1661 #[cfg(all(
1668 feature = "all",
1669 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1670 ))]
1671 #[cfg_attr(
1672 docsrs,
1673 doc(cfg(all(
1674 feature = "all",
1675 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1676 )))
1677 )]
1678 pub fn mark(&self) -> io::Result<u32> {
1679 unsafe {
1680 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1681 .map(|mark| mark as u32)
1682 }
1683 }
1684
1685 #[cfg(all(
1693 feature = "all",
1694 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1695 ))]
1696 #[cfg_attr(
1697 docsrs,
1698 doc(cfg(all(
1699 feature = "all",
1700 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1701 )))
1702 )]
1703 pub fn set_mark(&self, mark: u32) -> io::Result<()> {
1704 unsafe {
1705 setsockopt::<c_int>(
1706 self.as_raw(),
1707 libc::SOL_SOCKET,
1708 libc::SO_MARK,
1709 mark as c_int,
1710 )
1711 }
1712 }
1713
1714 #[cfg(all(
1720 feature = "all",
1721 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1722 ))]
1723 #[cfg_attr(
1724 docsrs,
1725 doc(cfg(all(
1726 feature = "all",
1727 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1728 )))
1729 )]
1730 pub fn cork(&self) -> io::Result<bool> {
1731 unsafe {
1732 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK)
1733 .map(|cork| cork != 0)
1734 }
1735 }
1736
1737 #[cfg(all(
1744 feature = "all",
1745 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1746 ))]
1747 #[cfg_attr(
1748 docsrs,
1749 doc(cfg(all(
1750 feature = "all",
1751 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1752 )))
1753 )]
1754 pub fn set_cork(&self, cork: bool) -> io::Result<()> {
1755 unsafe {
1756 setsockopt(
1757 self.as_raw(),
1758 libc::IPPROTO_TCP,
1759 libc::TCP_CORK,
1760 cork as c_int,
1761 )
1762 }
1763 }
1764
1765 #[cfg(all(
1771 feature = "all",
1772 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1773 ))]
1774 #[cfg_attr(
1775 docsrs,
1776 doc(cfg(all(
1777 feature = "all",
1778 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1779 )))
1780 )]
1781 pub fn quickack(&self) -> io::Result<bool> {
1782 unsafe {
1783 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK)
1784 .map(|quickack| quickack != 0)
1785 }
1786 }
1787
1788 #[cfg(all(
1795 feature = "all",
1796 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1797 ))]
1798 #[cfg_attr(
1799 docsrs,
1800 doc(cfg(all(
1801 feature = "all",
1802 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1803 )))
1804 )]
1805 pub fn set_quickack(&self, quickack: bool) -> io::Result<()> {
1806 unsafe {
1807 setsockopt(
1808 self.as_raw(),
1809 libc::IPPROTO_TCP,
1810 libc::TCP_QUICKACK,
1811 quickack as c_int,
1812 )
1813 }
1814 }
1815
1816 #[cfg(all(
1822 feature = "all",
1823 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1824 ))]
1825 #[cfg_attr(
1826 docsrs,
1827 doc(cfg(all(
1828 feature = "all",
1829 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1830 )))
1831 )]
1832 pub fn thin_linear_timeouts(&self) -> io::Result<bool> {
1833 unsafe {
1834 getsockopt::<Bool>(
1835 self.as_raw(),
1836 libc::IPPROTO_TCP,
1837 libc::TCP_THIN_LINEAR_TIMEOUTS,
1838 )
1839 .map(|timeouts| timeouts != 0)
1840 }
1841 }
1842
1843 #[cfg(all(
1849 feature = "all",
1850 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1851 ))]
1852 #[cfg_attr(
1853 docsrs,
1854 doc(cfg(all(
1855 feature = "all",
1856 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1857 )))
1858 )]
1859 pub fn set_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> {
1860 unsafe {
1861 setsockopt(
1862 self.as_raw(),
1863 libc::IPPROTO_TCP,
1864 libc::TCP_THIN_LINEAR_TIMEOUTS,
1865 timeouts as c_int,
1866 )
1867 }
1868 }
1869
1870 #[cfg(all(
1874 feature = "all",
1875 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1876 ))]
1877 #[cfg_attr(
1878 docsrs,
1879 doc(cfg(all(
1880 feature = "all",
1881 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1882 )))
1883 )]
1884 pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1885 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1887 unsafe { MaybeUninit::uninit().assume_init() };
1888 let mut len = buf.len() as libc::socklen_t;
1889 syscall!(getsockopt(
1890 self.as_raw(),
1891 libc::SOL_SOCKET,
1892 libc::SO_BINDTODEVICE,
1893 buf.as_mut_ptr().cast(),
1894 &mut len,
1895 ))?;
1896 if len == 0 {
1897 Ok(None)
1898 } else {
1899 let buf = &buf[..len as usize - 1];
1900 Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
1902 }
1903 }
1904
1905 #[cfg(all(
1913 feature = "all",
1914 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1915 ))]
1916 #[cfg_attr(
1917 docsrs,
1918 doc(cfg(all(
1919 feature = "all",
1920 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1921 )))
1922 )]
1923 pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
1924 let (value, len) = if let Some(interface) = interface {
1925 (interface.as_ptr(), interface.len())
1926 } else {
1927 (ptr::null(), 0)
1928 };
1929 syscall!(setsockopt(
1930 self.as_raw(),
1931 libc::SOL_SOCKET,
1932 libc::SO_BINDTODEVICE,
1933 value.cast(),
1934 len as libc::socklen_t,
1935 ))
1936 .map(|_| ())
1937 }
1938
1939 #[cfg(all(feature = "all", target_os = "freebsd"))]
1943 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "freebsd"))))]
1944 pub fn set_fib(&self, fib: u32) -> io::Result<()> {
1945 syscall!(setsockopt(
1946 self.as_raw(),
1947 libc::SOL_SOCKET,
1948 libc::SO_SETFIB,
1949 (&fib as *const u32).cast(),
1950 mem::size_of::<u32>() as libc::socklen_t,
1951 ))
1952 .map(|_| ())
1953 }
1954
1955 #[cfg(all(
1957 feature = "all",
1958 any(
1959 target_os = "ios",
1960 target_os = "macos",
1961 target_os = "tvos",
1962 target_os = "watchos",
1963 )
1964 ))]
1965 #[cfg_attr(
1966 docsrs,
1967 doc(cfg(all(
1968 feature = "all",
1969 any(
1970 target_os = "ios",
1971 target_os = "macos",
1972 target_os = "tvos",
1973 target_os = "watchos",
1974 )
1975 )))
1976 )]
1977 #[deprecated = "Use `Socket::bind_device_by_index_v4` instead"]
1978 pub fn bind_device_by_index(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
1979 self.bind_device_by_index_v4(interface)
1980 }
1981
1982 #[cfg(all(
1993 feature = "all",
1994 any(
1995 target_os = "ios",
1996 target_os = "macos",
1997 target_os = "tvos",
1998 target_os = "watchos",
1999 )
2000 ))]
2001 #[cfg_attr(
2002 docsrs,
2003 doc(cfg(all(
2004 feature = "all",
2005 any(
2006 target_os = "ios",
2007 target_os = "macos",
2008 target_os = "tvos",
2009 target_os = "watchos",
2010 )
2011 )))
2012 )]
2013 pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2014 let index = interface.map_or(0, NonZeroU32::get);
2015 unsafe { setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index) }
2016 }
2017
2018 #[cfg(all(
2029 feature = "all",
2030 any(
2031 target_os = "ios",
2032 target_os = "macos",
2033 target_os = "tvos",
2034 target_os = "watchos",
2035 )
2036 ))]
2037 #[cfg_attr(
2038 docsrs,
2039 doc(cfg(all(
2040 feature = "all",
2041 any(
2042 target_os = "ios",
2043 target_os = "macos",
2044 target_os = "tvos",
2045 target_os = "watchos",
2046 )
2047 )))
2048 )]
2049 pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2050 let index = interface.map_or(0, NonZeroU32::get);
2051 unsafe { setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index) }
2052 }
2053
2054 #[cfg(all(
2060 feature = "all",
2061 any(
2062 target_os = "ios",
2063 target_os = "macos",
2064 target_os = "tvos",
2065 target_os = "watchos",
2066 )
2067 ))]
2068 #[cfg_attr(
2069 docsrs,
2070 doc(cfg(all(
2071 feature = "all",
2072 any(
2073 target_os = "ios",
2074 target_os = "macos",
2075 target_os = "tvos",
2076 target_os = "watchos",
2077 )
2078 )))
2079 )]
2080 pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
2081 let index =
2082 unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
2083 Ok(NonZeroU32::new(index))
2084 }
2085
2086 #[cfg(all(
2088 feature = "all",
2089 any(
2090 target_os = "ios",
2091 target_os = "macos",
2092 target_os = "tvos",
2093 target_os = "watchos",
2094 )
2095 ))]
2096 #[cfg_attr(
2097 docsrs,
2098 doc(cfg(all(
2099 feature = "all",
2100 any(
2101 target_os = "ios",
2102 target_os = "macos",
2103 target_os = "tvos",
2104 target_os = "watchos",
2105 )
2106 )))
2107 )]
2108 #[deprecated = "Use `Socket::device_index_v4` instead"]
2109 pub fn device_index(&self) -> io::Result<Option<NonZeroU32>> {
2110 self.device_index_v4()
2111 }
2112
2113 #[cfg(all(
2119 feature = "all",
2120 any(
2121 target_os = "ios",
2122 target_os = "macos",
2123 target_os = "tvos",
2124 target_os = "watchos",
2125 )
2126 ))]
2127 #[cfg_attr(
2128 docsrs,
2129 doc(cfg(all(
2130 feature = "all",
2131 any(
2132 target_os = "ios",
2133 target_os = "macos",
2134 target_os = "tvos",
2135 target_os = "watchos",
2136 )
2137 )))
2138 )]
2139 pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
2140 let index = unsafe {
2141 getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)?
2142 };
2143 Ok(NonZeroU32::new(index))
2144 }
2145
2146 #[cfg(all(feature = "all", target_os = "linux"))]
2152 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2153 pub fn cpu_affinity(&self) -> io::Result<usize> {
2154 unsafe {
2155 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
2156 .map(|cpu| cpu as usize)
2157 }
2158 }
2159
2160 #[cfg(all(feature = "all", target_os = "linux"))]
2164 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2165 pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
2166 unsafe {
2167 setsockopt(
2168 self.as_raw(),
2169 libc::SOL_SOCKET,
2170 libc::SO_INCOMING_CPU,
2171 cpu as c_int,
2172 )
2173 }
2174 }
2175
2176 #[cfg(all(
2182 feature = "all",
2183 not(any(target_os = "solaris", target_os = "illumos"))
2184 ))]
2185 #[cfg_attr(
2186 docsrs,
2187 doc(cfg(all(
2188 feature = "all",
2189 unix,
2190 not(any(target_os = "solaris", target_os = "illumos"))
2191 )))
2192 )]
2193 pub fn reuse_port(&self) -> io::Result<bool> {
2194 unsafe {
2195 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
2196 .map(|reuse| reuse != 0)
2197 }
2198 }
2199
2200 #[cfg(all(
2206 feature = "all",
2207 not(any(target_os = "solaris", target_os = "illumos"))
2208 ))]
2209 #[cfg_attr(
2210 docsrs,
2211 doc(cfg(all(
2212 feature = "all",
2213 unix,
2214 not(any(target_os = "solaris", target_os = "illumos"))
2215 )))
2216 )]
2217 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
2218 unsafe {
2219 setsockopt(
2220 self.as_raw(),
2221 libc::SOL_SOCKET,
2222 libc::SO_REUSEPORT,
2223 reuse as c_int,
2224 )
2225 }
2226 }
2227
2228 #[cfg(all(feature = "all", target_os = "freebsd"))]
2234 pub fn reuse_port_lb(&self) -> io::Result<bool> {
2235 unsafe {
2236 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT_LB)
2237 .map(|reuse| reuse != 0)
2238 }
2239 }
2240
2241 #[cfg(all(feature = "all", target_os = "freebsd"))]
2246 pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
2247 unsafe {
2248 setsockopt(
2249 self.as_raw(),
2250 libc::SOL_SOCKET,
2251 libc::SO_REUSEPORT_LB,
2252 reuse as c_int,
2253 )
2254 }
2255 }
2256
2257 #[cfg(all(
2263 feature = "all",
2264 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2265 ))]
2266 #[cfg_attr(
2267 docsrs,
2268 doc(cfg(all(
2269 feature = "all",
2270 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2271 )))
2272 )]
2273 pub fn freebind(&self) -> io::Result<bool> {
2274 unsafe {
2275 getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
2276 .map(|freebind| freebind != 0)
2277 }
2278 }
2279
2280 #[cfg(all(
2288 feature = "all",
2289 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2290 ))]
2291 #[cfg_attr(
2292 docsrs,
2293 doc(cfg(all(
2294 feature = "all",
2295 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2296 )))
2297 )]
2298 pub fn set_freebind(&self, freebind: bool) -> io::Result<()> {
2299 unsafe {
2300 setsockopt(
2301 self.as_raw(),
2302 libc::SOL_IP,
2303 libc::IP_FREEBIND,
2304 freebind as c_int,
2305 )
2306 }
2307 }
2308
2309 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2317 #[cfg_attr(
2318 docsrs,
2319 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2320 )]
2321 pub fn freebind_ipv6(&self) -> io::Result<bool> {
2322 unsafe {
2323 getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
2324 .map(|freebind| freebind != 0)
2325 }
2326 }
2327
2328 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2359 #[cfg_attr(
2360 docsrs,
2361 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2362 )]
2363 pub fn set_freebind_ipv6(&self, freebind: bool) -> io::Result<()> {
2364 unsafe {
2365 setsockopt(
2366 self.as_raw(),
2367 libc::SOL_IPV6,
2368 libc::IPV6_FREEBIND,
2369 freebind as c_int,
2370 )
2371 }
2372 }
2373
2374 #[cfg(all(
2379 feature = "all",
2380 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2381 ))]
2382 #[cfg_attr(
2383 docsrs,
2384 doc(cfg(all(
2385 feature = "all",
2386 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2387 )))
2388 )]
2389 pub fn original_dst(&self) -> io::Result<SockAddr> {
2390 unsafe {
2392 SockAddr::try_init(|storage, len| {
2393 syscall!(getsockopt(
2394 self.as_raw(),
2395 libc::SOL_IP,
2396 libc::SO_ORIGINAL_DST,
2397 storage.cast(),
2398 len
2399 ))
2400 })
2401 }
2402 .map(|(_, addr)| addr)
2403 }
2404
2405 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2410 #[cfg_attr(
2411 docsrs,
2412 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2413 )]
2414 pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
2415 unsafe {
2417 SockAddr::try_init(|storage, len| {
2418 syscall!(getsockopt(
2419 self.as_raw(),
2420 libc::SOL_IPV6,
2421 libc::IP6T_SO_ORIGINAL_DST,
2422 storage.cast(),
2423 len
2424 ))
2425 })
2426 }
2427 .map(|(_, addr)| addr)
2428 }
2429
2430 #[doc = man_links!(unix: sendfile(2))]
2440 #[cfg(all(
2450 feature = "all",
2451 any(
2452 target_os = "aix",
2453 target_os = "android",
2454 target_os = "freebsd",
2455 target_os = "ios",
2456 target_os = "linux",
2457 target_os = "macos",
2458 target_os = "tvos",
2459 target_os = "watchos",
2460 )
2461 ))]
2462 #[cfg_attr(
2463 docsrs,
2464 doc(cfg(all(
2465 feature = "all",
2466 any(
2467 target_os = "aix",
2468 target_os = "android",
2469 target_os = "freebsd",
2470 target_os = "ios",
2471 target_os = "linux",
2472 target_os = "macos",
2473 target_os = "tvos",
2474 target_os = "watchos",
2475 )
2476 )))
2477 )]
2478 pub fn sendfile<F>(
2479 &self,
2480 file: &F,
2481 offset: usize,
2482 length: Option<NonZeroUsize>,
2483 ) -> io::Result<usize>
2484 where
2485 F: AsRawFd,
2486 {
2487 self._sendfile(file.as_raw_fd(), offset as _, length)
2488 }
2489
2490 #[cfg(all(
2491 feature = "all",
2492 any(
2493 target_os = "ios",
2494 target_os = "macos",
2495 target_os = "tvos",
2496 target_os = "watchos",
2497 )
2498 ))]
2499 fn _sendfile(
2500 &self,
2501 file: RawFd,
2502 offset: libc::off_t,
2503 length: Option<NonZeroUsize>,
2504 ) -> io::Result<usize> {
2505 let mut length = match length {
2508 Some(n) => n.get() as libc::off_t,
2509 None => 0,
2511 };
2512 syscall!(sendfile(
2513 file,
2514 self.as_raw(),
2515 offset,
2516 &mut length,
2517 ptr::null_mut(),
2518 0,
2519 ))
2520 .map(|_| length as usize)
2521 }
2522
2523 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2524 fn _sendfile(
2525 &self,
2526 file: RawFd,
2527 offset: libc::off_t,
2528 length: Option<NonZeroUsize>,
2529 ) -> io::Result<usize> {
2530 let count = match length {
2531 Some(n) => n.get() as libc::size_t,
2532 None => 0x7ffff000, };
2535 let mut offset = offset;
2536 syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
2537 }
2538
2539 #[cfg(all(feature = "all", target_os = "freebsd"))]
2540 fn _sendfile(
2541 &self,
2542 file: RawFd,
2543 offset: libc::off_t,
2544 length: Option<NonZeroUsize>,
2545 ) -> io::Result<usize> {
2546 let nbytes = match length {
2547 Some(n) => n.get() as libc::size_t,
2548 None => 0,
2550 };
2551 let mut sbytes: libc::off_t = 0;
2552 syscall!(sendfile(
2553 file,
2554 self.as_raw(),
2555 offset,
2556 nbytes,
2557 ptr::null_mut(),
2558 &mut sbytes,
2559 0,
2560 ))
2561 .map(|_| sbytes as usize)
2562 }
2563
2564 #[cfg(all(feature = "all", target_os = "aix"))]
2565 fn _sendfile(
2566 &self,
2567 file: RawFd,
2568 offset: libc::off_t,
2569 length: Option<NonZeroUsize>,
2570 ) -> io::Result<usize> {
2571 let nbytes = match length {
2572 Some(n) => n.get() as i64,
2573 None => -1,
2574 };
2575 let mut params = libc::sf_parms {
2576 header_data: ptr::null_mut(),
2577 header_length: 0,
2578 file_descriptor: file,
2579 file_size: 0,
2580 file_offset: offset as u64,
2581 file_bytes: nbytes,
2582 trailer_data: ptr::null_mut(),
2583 trailer_length: 0,
2584 bytes_sent: 0,
2585 };
2586 syscall!(send_file(
2588 &mut self.as_raw() as *mut _,
2589 &mut params as *mut _,
2590 libc::SF_CLOSE as libc::c_uint,
2591 ))
2592 .map(|_| params.bytes_sent as usize)
2593 }
2594
2595 #[cfg(all(
2606 feature = "all",
2607 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2608 ))]
2609 #[cfg_attr(
2610 docsrs,
2611 doc(cfg(all(
2612 feature = "all",
2613 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2614 )))
2615 )]
2616 pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
2617 let timeout = timeout.map_or(0, |to| {
2618 min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint
2619 });
2620 unsafe {
2621 setsockopt(
2622 self.as_raw(),
2623 libc::IPPROTO_TCP,
2624 libc::TCP_USER_TIMEOUT,
2625 timeout,
2626 )
2627 }
2628 }
2629
2630 #[cfg(all(
2636 feature = "all",
2637 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2638 ))]
2639 #[cfg_attr(
2640 docsrs,
2641 doc(cfg(all(
2642 feature = "all",
2643 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2644 )))
2645 )]
2646 pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
2647 unsafe {
2648 getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
2649 .map(|millis| {
2650 if millis == 0 {
2651 None
2652 } else {
2653 Some(Duration::from_millis(millis as u64))
2654 }
2655 })
2656 }
2657 }
2658
2659 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2666 pub fn attach_filter(&self, filters: &[libc::sock_filter]) -> io::Result<()> {
2667 let prog = libc::sock_fprog {
2668 len: filters.len() as u16,
2669 filter: filters.as_ptr() as *mut _,
2670 };
2671
2672 unsafe {
2673 setsockopt(
2674 self.as_raw(),
2675 libc::SOL_SOCKET,
2676 libc::SO_ATTACH_FILTER,
2677 prog,
2678 )
2679 }
2680 }
2681
2682 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2688 pub fn detach_filter(&self) -> io::Result<()> {
2689 unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) }
2690 }
2691
2692 #[cfg(all(feature = "all", target_os = "linux"))]
2699 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2700 pub fn cookie(&self) -> io::Result<u64> {
2701 unsafe { getsockopt::<libc::c_ulonglong>(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) }
2702 }
2703
2704 #[cfg(all(
2710 feature = "all",
2711 any(
2712 target_os = "android",
2713 target_os = "dragonfly",
2714 target_os = "freebsd",
2715 target_os = "fuchsia",
2716 target_os = "linux",
2717 target_os = "macos",
2718 target_os = "netbsd",
2719 target_os = "openbsd"
2720 )
2721 ))]
2722 #[cfg_attr(
2723 docsrs,
2724 doc(cfg(all(
2725 feature = "all",
2726 any(
2727 target_os = "android",
2728 target_os = "dragonfly",
2729 target_os = "freebsd",
2730 target_os = "fuchsia",
2731 target_os = "linux",
2732 target_os = "macos",
2733 target_os = "netbsd",
2734 target_os = "openbsd"
2735 )
2736 )))
2737 )]
2738 pub fn tclass_v6(&self) -> io::Result<u32> {
2739 unsafe {
2740 getsockopt::<c_int>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS)
2741 .map(|tclass| tclass as u32)
2742 }
2743 }
2744
2745 #[cfg(all(
2750 feature = "all",
2751 any(
2752 target_os = "android",
2753 target_os = "dragonfly",
2754 target_os = "freebsd",
2755 target_os = "fuchsia",
2756 target_os = "linux",
2757 target_os = "macos",
2758 target_os = "netbsd",
2759 target_os = "openbsd"
2760 )
2761 ))]
2762 #[cfg_attr(
2763 docsrs,
2764 doc(cfg(all(
2765 feature = "all",
2766 any(
2767 target_os = "android",
2768 target_os = "dragonfly",
2769 target_os = "freebsd",
2770 target_os = "fuchsia",
2771 target_os = "linux",
2772 target_os = "macos",
2773 target_os = "netbsd",
2774 target_os = "openbsd"
2775 )
2776 )))
2777 )]
2778 pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
2779 unsafe {
2780 setsockopt(
2781 self.as_raw(),
2782 IPPROTO_IPV6,
2783 libc::IPV6_TCLASS,
2784 tclass as c_int,
2785 )
2786 }
2787 }
2788
2789 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2795 #[cfg_attr(
2796 docsrs,
2797 doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux"))))
2798 )]
2799 pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
2800 let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX];
2801 let mut len = payload.len() as libc::socklen_t;
2802 syscall!(getsockopt(
2803 self.as_raw(),
2804 IPPROTO_TCP,
2805 libc::TCP_CONGESTION,
2806 payload.as_mut_ptr().cast(),
2807 &mut len,
2808 ))
2809 .map(|_| payload[..len as usize].to_vec())
2810 }
2811
2812 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2819 #[cfg_attr(
2820 docsrs,
2821 doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux"))))
2822 )]
2823 pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
2824 syscall!(setsockopt(
2825 self.as_raw(),
2826 IPPROTO_TCP,
2827 libc::TCP_CONGESTION,
2828 tcp_ca_name.as_ptr() as *const _,
2829 tcp_ca_name.len() as libc::socklen_t,
2830 ))
2831 .map(|_| ())
2832 }
2833
2834 #[cfg(all(feature = "all", target_os = "linux"))]
2845 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2846 pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
2847 unsafe {
2848 setsockopt(
2849 self.as_raw(),
2850 libc::SOL_DCCP,
2851 libc::DCCP_SOCKOPT_SERVICE,
2852 code,
2853 )
2854 }
2855 }
2856
2857 #[cfg(all(feature = "all", target_os = "linux"))]
2863 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2864 pub fn dccp_service(&self) -> io::Result<u32> {
2865 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) }
2866 }
2867
2868 #[cfg(all(feature = "all", target_os = "linux"))]
2872 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2873 pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
2874 unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) }
2875 }
2876
2877 #[cfg(all(feature = "all", target_os = "linux"))]
2883 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2884 pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
2885 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) }
2886 }
2887
2888 #[cfg(all(feature = "all", target_os = "linux"))]
2894 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2895 pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
2896 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) }
2897 }
2898
2899 #[cfg(all(feature = "all", target_os = "linux"))]
2904 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2905 pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> {
2906 unsafe {
2907 setsockopt(
2908 self.as_raw(),
2909 libc::SOL_DCCP,
2910 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2911 hold_timewait as c_int,
2912 )
2913 }
2914 }
2915
2916 #[cfg(all(feature = "all", target_os = "linux"))]
2922 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2923 pub fn dccp_server_timewait(&self) -> io::Result<bool> {
2924 unsafe {
2925 getsockopt(
2926 self.as_raw(),
2927 libc::SOL_DCCP,
2928 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2929 )
2930 }
2931 }
2932
2933 #[cfg(all(feature = "all", target_os = "linux"))]
2941 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2942 pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
2943 unsafe {
2944 setsockopt(
2945 self.as_raw(),
2946 libc::SOL_DCCP,
2947 libc::DCCP_SOCKOPT_SEND_CSCOV,
2948 level,
2949 )
2950 }
2951 }
2952
2953 #[cfg(all(feature = "all", target_os = "linux"))]
2959 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2960 pub fn dccp_send_cscov(&self) -> io::Result<u32> {
2961 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) }
2962 }
2963
2964 #[cfg(all(feature = "all", target_os = "linux"))]
2970 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2971 pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
2972 unsafe {
2973 setsockopt(
2974 self.as_raw(),
2975 libc::SOL_DCCP,
2976 libc::DCCP_SOCKOPT_RECV_CSCOV,
2977 level,
2978 )
2979 }
2980 }
2981
2982 #[cfg(all(feature = "all", target_os = "linux"))]
2988 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2989 pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
2990 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) }
2991 }
2992
2993 #[cfg(all(feature = "all", target_os = "linux"))]
2998 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2999 pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
3000 unsafe {
3001 setsockopt(
3002 self.as_raw(),
3003 libc::SOL_DCCP,
3004 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
3005 length,
3006 )
3007 }
3008 }
3009
3010 #[cfg(all(feature = "all", target_os = "linux"))]
3016 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3017 pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
3018 unsafe {
3019 getsockopt(
3020 self.as_raw(),
3021 libc::SOL_DCCP,
3022 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
3023 )
3024 }
3025 }
3026
3027 #[cfg(all(feature = "all", target_os = "linux"))]
3037 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3038 pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEndpoints<N>> {
3039 let mut endpoints = [0; N];
3040 let mut length = endpoints.len() as libc::socklen_t;
3041 syscall!(getsockopt(
3042 self.as_raw(),
3043 libc::SOL_DCCP,
3044 libc::DCCP_SOCKOPT_AVAILABLE_CCIDS,
3045 endpoints.as_mut_ptr().cast(),
3046 &mut length,
3047 ))?;
3048 Ok(CcidEndpoints { endpoints, length })
3049 }
3050
3051 #[cfg(all(feature = "all", target_os = "linux"))]
3056 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3057 pub fn dccp_cur_mps(&self) -> io::Result<u32> {
3058 unsafe {
3059 getsockopt(
3060 self.as_raw(),
3061 libc::SOL_DCCP,
3062 libc::DCCP_SOCKOPT_GET_CUR_MPS,
3063 )
3064 }
3065 }
3066}
3067
3068#[cfg(all(feature = "all", target_os = "linux"))]
3070#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3071#[derive(Debug)]
3072pub struct CcidEndpoints<const N: usize> {
3073 endpoints: [u8; N],
3074 length: u32,
3075}
3076
3077#[cfg(all(feature = "all", target_os = "linux"))]
3078#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3079impl<const N: usize> std::ops::Deref for CcidEndpoints<N> {
3080 type Target = [u8];
3081
3082 fn deref(&self) -> &[u8] {
3083 &self.endpoints[0..self.length as usize]
3084 }
3085}
3086
3087#[cfg_attr(docsrs, doc(cfg(unix)))]
3088impl AsFd for crate::Socket {
3089 fn as_fd(&self) -> BorrowedFd<'_> {
3090 unsafe { BorrowedFd::borrow_raw(self.as_raw()) }
3092 }
3093}
3094
3095#[cfg_attr(docsrs, doc(cfg(unix)))]
3096impl AsRawFd for crate::Socket {
3097 fn as_raw_fd(&self) -> c_int {
3098 self.as_raw()
3099 }
3100}
3101
3102#[cfg_attr(docsrs, doc(cfg(unix)))]
3103impl From<crate::Socket> for OwnedFd {
3104 fn from(sock: crate::Socket) -> OwnedFd {
3105 unsafe { OwnedFd::from_raw_fd(sock.into_raw()) }
3107 }
3108}
3109
3110#[cfg_attr(docsrs, doc(cfg(unix)))]
3111impl IntoRawFd for crate::Socket {
3112 fn into_raw_fd(self) -> c_int {
3113 self.into_raw()
3114 }
3115}
3116
3117#[cfg_attr(docsrs, doc(cfg(unix)))]
3118impl From<OwnedFd> for crate::Socket {
3119 fn from(fd: OwnedFd) -> crate::Socket {
3120 unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) }
3122 }
3123}
3124
3125#[cfg_attr(docsrs, doc(cfg(unix)))]
3126impl FromRawFd for crate::Socket {
3127 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
3128 crate::Socket::from_raw(fd)
3129 }
3130}
3131
3132#[cfg(feature = "all")]
3133from!(UnixStream, crate::Socket);
3134#[cfg(feature = "all")]
3135from!(UnixListener, crate::Socket);
3136#[cfg(feature = "all")]
3137from!(UnixDatagram, crate::Socket);
3138#[cfg(feature = "all")]
3139from!(crate::Socket, UnixStream);
3140#[cfg(feature = "all")]
3141from!(crate::Socket, UnixListener);
3142#[cfg(feature = "all")]
3143from!(crate::Socket, UnixDatagram);
3144
3145#[test]
3146fn in_addr_convertion() {
3147 let ip = Ipv4Addr::new(127, 0, 0, 1);
3148 let raw = to_in_addr(&ip);
3149 let a = raw.s_addr;
3151 assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
3152 assert_eq!(from_in_addr(raw), ip);
3153
3154 let ip = Ipv4Addr::new(127, 34, 4, 12);
3155 let raw = to_in_addr(&ip);
3156 let a = raw.s_addr;
3157 assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
3158 assert_eq!(from_in_addr(raw), ip);
3159}
3160
3161#[test]
3162fn in6_addr_convertion() {
3163 let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
3164 let raw = to_in6_addr(&ip);
3165 let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
3166 assert_eq!(raw.s6_addr, want);
3167 assert_eq!(from_in6_addr(raw), ip);
3168}