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
248#[cfg(not(any(
249 target_os = "freebsd",
250 target_os = "fuchsia",
251 target_os = "hurd",
252 target_os = "redox",
253 target_os = "vita",
254)))]
255pub(crate) use libc::{
256 in6_pktinfo as In6PktInfo, in_pktinfo as InPktInfo, IPV6_PKTINFO, IPV6_RECVPKTINFO, IP_PKTINFO,
257};
258
259pub(crate) type Bool = c_int;
261
262#[cfg(any(
263 target_os = "ios",
264 target_os = "macos",
265 target_os = "nto",
266 target_os = "tvos",
267 target_os = "watchos",
268))]
269use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
270#[cfg(not(any(
271 target_os = "haiku",
272 target_os = "ios",
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 = "macos",
299 target_os = "tvos",
300 target_os = "watchos",
301)))]
302const MAX_BUF_LEN: usize = ssize_t::MAX as usize;
303
304#[cfg(any(
313 target_os = "ios",
314 target_os = "macos",
315 target_os = "tvos",
316 target_os = "watchos",
317))]
318const MAX_BUF_LEN: usize = c_int::MAX as usize - 1;
319
320#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
322const TCP_CA_NAME_MAX: usize = 16;
323
324#[cfg(any(
325 all(
326 target_os = "linux",
327 any(
328 target_env = "gnu",
329 all(target_env = "uclibc", target_pointer_width = "64")
330 )
331 ),
332 target_os = "android",
333))]
334type IovLen = usize;
335
336#[cfg(any(
337 all(
338 target_os = "linux",
339 any(
340 target_env = "musl",
341 target_env = "ohos",
342 all(target_env = "uclibc", target_pointer_width = "32")
343 )
344 ),
345 target_os = "aix",
346 target_os = "dragonfly",
347 target_os = "freebsd",
348 target_os = "fuchsia",
349 target_os = "haiku",
350 target_os = "hurd",
351 target_os = "illumos",
352 target_os = "ios",
353 target_os = "macos",
354 target_os = "netbsd",
355 target_os = "nto",
356 target_os = "openbsd",
357 target_os = "solaris",
358 target_os = "tvos",
359 target_os = "watchos",
360 target_os = "espidf",
361 target_os = "vita",
362))]
363type IovLen = c_int;
364
365impl Domain {
367 #[cfg(all(
369 feature = "all",
370 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
371 ))]
372 #[cfg_attr(
373 docsrs,
374 doc(cfg(all(
375 feature = "all",
376 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
377 )))
378 )]
379 pub const PACKET: Domain = Domain(libc::AF_PACKET);
380
381 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
383 #[cfg_attr(
384 docsrs,
385 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
386 )]
387 pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
388}
389
390impl_debug!(
391 Domain,
392 libc::AF_INET,
393 libc::AF_INET6,
394 libc::AF_UNIX,
395 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
396 #[cfg_attr(
397 docsrs,
398 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
399 )]
400 libc::AF_PACKET,
401 #[cfg(any(target_os = "android", target_os = "linux"))]
402 #[cfg_attr(docsrs, doc(cfg(any(target_os = "android", target_os = "linux"))))]
403 libc::AF_VSOCK,
404 libc::AF_UNSPEC, );
406
407impl Type {
409 #[cfg(all(
411 feature = "all",
412 any(
413 target_os = "android",
414 target_os = "dragonfly",
415 target_os = "freebsd",
416 target_os = "fuchsia",
417 target_os = "illumos",
418 target_os = "linux",
419 target_os = "netbsd",
420 target_os = "openbsd"
421 )
422 ))]
423 #[cfg_attr(
424 docsrs,
425 doc(cfg(all(
426 feature = "all",
427 any(
428 target_os = "android",
429 target_os = "dragonfly",
430 target_os = "freebsd",
431 target_os = "fuchsia",
432 target_os = "illumos",
433 target_os = "linux",
434 target_os = "netbsd",
435 target_os = "openbsd"
436 )
437 )))
438 )]
439 pub const fn nonblocking(self) -> Type {
440 Type(self.0 | libc::SOCK_NONBLOCK)
441 }
442
443 #[cfg(all(
445 feature = "all",
446 any(
447 target_os = "android",
448 target_os = "dragonfly",
449 target_os = "freebsd",
450 target_os = "fuchsia",
451 target_os = "hurd",
452 target_os = "illumos",
453 target_os = "linux",
454 target_os = "netbsd",
455 target_os = "openbsd",
456 target_os = "redox",
457 target_os = "solaris",
458 )
459 ))]
460 #[cfg_attr(
461 docsrs,
462 doc(cfg(all(
463 feature = "all",
464 any(
465 target_os = "android",
466 target_os = "dragonfly",
467 target_os = "freebsd",
468 target_os = "fuchsia",
469 target_os = "hurd",
470 target_os = "illumos",
471 target_os = "linux",
472 target_os = "netbsd",
473 target_os = "openbsd",
474 target_os = "redox",
475 target_os = "solaris",
476 )
477 )))
478 )]
479 pub const fn cloexec(self) -> Type {
480 self._cloexec()
481 }
482
483 #[cfg(any(
484 target_os = "android",
485 target_os = "dragonfly",
486 target_os = "freebsd",
487 target_os = "fuchsia",
488 target_os = "hurd",
489 target_os = "illumos",
490 target_os = "linux",
491 target_os = "netbsd",
492 target_os = "openbsd",
493 target_os = "redox",
494 target_os = "solaris",
495 ))]
496 pub(crate) const fn _cloexec(self) -> Type {
497 Type(self.0 | libc::SOCK_CLOEXEC)
498 }
499}
500
501impl_debug!(
502 Type,
503 libc::SOCK_STREAM,
504 libc::SOCK_DGRAM,
505 #[cfg(all(feature = "all", target_os = "linux"))]
506 libc::SOCK_DCCP,
507 #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
508 libc::SOCK_RAW,
509 #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "espidf")))]
510 libc::SOCK_RDM,
511 #[cfg(not(target_os = "espidf"))]
512 libc::SOCK_SEQPACKET,
513 );
536
537impl_debug!(
538 Protocol,
539 libc::IPPROTO_ICMP,
540 libc::IPPROTO_ICMPV6,
541 libc::IPPROTO_TCP,
542 libc::IPPROTO_UDP,
543 #[cfg(target_os = "linux")]
544 libc::IPPROTO_MPTCP,
545 #[cfg(all(feature = "all", target_os = "linux"))]
546 libc::IPPROTO_DCCP,
547 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
548 libc::IPPROTO_SCTP,
549 #[cfg(all(
550 feature = "all",
551 any(
552 target_os = "android",
553 target_os = "freebsd",
554 target_os = "fuchsia",
555 target_os = "linux",
556 )
557 ))]
558 libc::IPPROTO_UDPLITE,
559 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
560 libc::IPPROTO_DIVERT,
561);
562
563#[cfg(not(target_os = "redox"))]
565impl RecvFlags {
566 #[cfg(not(target_os = "espidf"))]
576 pub const fn is_end_of_record(self) -> bool {
577 self.0 & libc::MSG_EOR != 0
578 }
579
580 pub const fn is_out_of_band(self) -> bool {
587 self.0 & libc::MSG_OOB != 0
588 }
589
590 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
598 #[cfg_attr(
599 docsrs,
600 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
601 )]
602 pub const fn is_confirm(self) -> bool {
603 self.0 & libc::MSG_CONFIRM != 0
604 }
605
606 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
613 #[cfg_attr(
614 docsrs,
615 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
616 )]
617 pub const fn is_dontroute(self) -> bool {
618 self.0 & libc::MSG_DONTROUTE != 0
619 }
620}
621
622#[cfg(not(target_os = "redox"))]
623impl std::fmt::Debug for RecvFlags {
624 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
625 let mut s = f.debug_struct("RecvFlags");
626 #[cfg(not(target_os = "espidf"))]
627 s.field("is_end_of_record", &self.is_end_of_record());
628 s.field("is_out_of_band", &self.is_out_of_band());
629 #[cfg(not(target_os = "espidf"))]
630 s.field("is_truncated", &self.is_truncated());
631 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
632 s.field("is_confirm", &self.is_confirm());
633 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
634 s.field("is_dontroute", &self.is_dontroute());
635 s.finish()
636 }
637}
638
639#[repr(transparent)]
640pub struct MaybeUninitSlice<'a> {
641 vec: libc::iovec,
642 _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
643}
644
645unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
646
647unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
648
649impl<'a> MaybeUninitSlice<'a> {
650 pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
651 MaybeUninitSlice {
652 vec: libc::iovec {
653 iov_base: buf.as_mut_ptr().cast(),
654 iov_len: buf.len(),
655 },
656 _lifetime: PhantomData,
657 }
658 }
659
660 pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
661 unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
662 }
663
664 pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
665 unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
666 }
667}
668
669pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize {
671 let base = storage as *const _ as usize;
672 let path = ptr::addr_of!(storage.sun_path) as usize;
673 path - base
674}
675
676#[allow(unsafe_op_in_unsafe_fn)]
677pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
678 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
680 let len = {
681 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<libc::sockaddr_un>() };
682
683 let bytes = path.as_os_str().as_bytes();
684 let too_long = match bytes.first() {
685 None => false,
686 Some(&0) => bytes.len() > storage.sun_path.len(),
688 Some(_) => bytes.len() >= storage.sun_path.len(),
689 };
690 if too_long {
691 return Err(io::Error::new(
692 io::ErrorKind::InvalidInput,
693 "path must be shorter than SUN_LEN",
694 ));
695 }
696
697 storage.sun_family = libc::AF_UNIX as sa_family_t;
698 unsafe {
703 ptr::copy_nonoverlapping(
704 bytes.as_ptr(),
705 storage.sun_path.as_mut_ptr().cast(),
706 bytes.len(),
707 );
708 }
709
710 let sun_path_offset = offset_of_path(storage);
711 sun_path_offset
712 + bytes.len()
713 + match bytes.first() {
714 Some(&0) | None => 0,
715 Some(_) => 1,
716 }
717 };
718 Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
719}
720
721#[cfg(not(target_os = "redox"))]
723pub(crate) use libc::msghdr;
724
725#[cfg(not(any(
726 target_os = "freebsd",
727 target_os = "fuchsia",
728 target_os = "hurd",
729 target_os = "redox",
730 target_os = "vita",
731)))]
732pub(crate) use libc::cmsghdr;
733
734#[cfg(not(target_os = "redox"))]
735pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
736 msg.msg_name = name.as_ptr() as *mut _;
737 msg.msg_namelen = name.len();
738}
739
740#[cfg(not(target_os = "redox"))]
741#[allow(clippy::unnecessary_cast)] pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) {
743 msg.msg_iov = ptr;
744 msg.msg_iovlen = min(len, IovLen::MAX as usize) as IovLen;
745}
746
747#[cfg(not(target_os = "redox"))]
748pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) {
749 msg.msg_control = ptr;
750 msg.msg_controllen = len as _;
751}
752
753#[cfg(not(target_os = "redox"))]
754pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: libc::c_int) {
755 msg.msg_flags = flags;
756}
757
758#[cfg(not(target_os = "redox"))]
759pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
760 RecvFlags(msg.msg_flags)
761}
762
763#[cfg(not(target_os = "redox"))]
764pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
765 msg.msg_controllen as _
766}
767
768impl SockAddr {
770 #[allow(unsafe_op_in_unsafe_fn)]
777 #[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 vsock(cid: u32, port: u32) -> SockAddr {
783 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
785 {
786 let storage: &mut libc::sockaddr_vm =
787 unsafe { &mut *((&mut storage as *mut sockaddr_storage).cast()) };
788 storage.svm_family = libc::AF_VSOCK as sa_family_t;
789 storage.svm_cid = cid;
790 storage.svm_port = port;
791 }
792 unsafe { SockAddr::new(storage, mem::size_of::<libc::sockaddr_vm>() as socklen_t) }
793 }
794
795 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
798 #[cfg_attr(
799 docsrs,
800 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
801 )]
802 pub fn as_vsock_address(&self) -> Option<(u32, u32)> {
803 if self.family() == libc::AF_VSOCK as sa_family_t {
804 let addr = unsafe { &*(self.as_ptr() as *const libc::sockaddr_vm) };
806 Some((addr.svm_cid, addr.svm_port))
807 } else {
808 None
809 }
810 }
811
812 pub fn is_unnamed(&self) -> bool {
815 self.as_sockaddr_un()
816 .map(|storage| {
817 self.len() == offset_of_path(storage) as _
818 || (cfg!(not(any(target_os = "linux", target_os = "android")))
823 && storage.sun_path[0] == 0)
824 })
825 .unwrap_or_default()
826 }
827
828 pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> {
831 self.is_unix().then(|| {
832 unsafe { &*self.as_ptr().cast::<libc::sockaddr_un>() }
835 })
836 }
837
838 fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
843 debug_assert!(!self.is_unnamed());
844 self.len() as usize - offset_of_path(storage) - 1
845 }
846
847 fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] {
851 debug_assert!(!self.is_unnamed());
852 unsafe {
860 slice::from_raw_parts(
861 (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize),
862 self.path_len(storage),
863 )
864 }
865 }
866
867 pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
870 let path = self.as_pathname()?;
871 Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
874 }
875
876 pub fn as_pathname(&self) -> Option<&Path> {
879 self.as_sockaddr_un().and_then(|storage| {
880 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] != 0).then(|| {
881 let path_slice = self.path_bytes(storage, false);
882 Path::new::<OsStr>(OsStrExt::from_bytes(path_slice))
883 })
884 })
885 }
886
887 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
893 #[cfg(any(target_os = "linux", target_os = "android"))]
896 {
897 self.as_sockaddr_un().and_then(|storage| {
898 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] == 0)
899 .then(|| self.path_bytes(storage, true))
900 })
901 }
902 #[cfg(not(any(target_os = "linux", target_os = "android")))]
903 None
904 }
905}
906
907pub(crate) type Socket = c_int;
908
909pub(crate) unsafe fn socket_from_raw(socket: Socket) -> crate::socket::Inner {
910 crate::socket::Inner::from_raw_fd(socket)
911}
912
913pub(crate) fn socket_as_raw(socket: &crate::socket::Inner) -> Socket {
914 socket.as_raw_fd()
915}
916
917pub(crate) fn socket_into_raw(socket: crate::socket::Inner) -> Socket {
918 socket.into_raw_fd()
919}
920
921pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> {
922 syscall!(socket(family, ty, protocol))
923}
924
925#[cfg(all(feature = "all", unix))]
926#[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
927pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[Socket; 2]> {
928 let mut fds = [0, 0];
929 syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds)
930}
931
932pub(crate) fn bind(fd: Socket, addr: &SockAddr) -> io::Result<()> {
933 syscall!(bind(fd, addr.as_ptr(), addr.len() as _)).map(|_| ())
934}
935
936pub(crate) fn connect(fd: Socket, addr: &SockAddr) -> io::Result<()> {
937 syscall!(connect(fd, addr.as_ptr(), addr.len())).map(|_| ())
938}
939
940pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
941 let start = Instant::now();
942
943 let mut pollfd = libc::pollfd {
944 fd: socket.as_raw(),
945 events: libc::POLLIN | libc::POLLOUT,
946 revents: 0,
947 };
948
949 loop {
950 let elapsed = start.elapsed();
951 if elapsed >= timeout {
952 return Err(io::ErrorKind::TimedOut.into());
953 }
954
955 let timeout = (timeout - elapsed).as_millis();
956 let timeout = timeout.clamp(1, c_int::MAX as u128) as c_int;
957
958 match syscall!(poll(&mut pollfd, 1, timeout)) {
959 Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
960 Ok(_) => {
961 if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0 {
963 match socket.take_error() {
964 Ok(Some(err)) | Err(err) => return Err(err),
965 Ok(None) => {
966 return Err(io::Error::new(
967 io::ErrorKind::Other,
968 "no error set after POLLHUP",
969 ))
970 }
971 }
972 }
973 return Ok(());
974 }
975 Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
977 Err(err) => return Err(err),
978 }
979 }
980}
981
982pub(crate) fn listen(fd: Socket, backlog: c_int) -> io::Result<()> {
983 syscall!(listen(fd, backlog)).map(|_| ())
984}
985
986pub(crate) fn accept(fd: Socket) -> io::Result<(Socket, SockAddr)> {
987 unsafe { SockAddr::try_init(|storage, len| syscall!(accept(fd, storage.cast(), len))) }
989}
990
991pub(crate) fn getsockname(fd: Socket) -> io::Result<SockAddr> {
992 unsafe { SockAddr::try_init(|storage, len| syscall!(getsockname(fd, storage.cast(), len))) }
994 .map(|(_, addr)| addr)
995}
996
997pub(crate) fn getpeername(fd: Socket) -> io::Result<SockAddr> {
998 unsafe { SockAddr::try_init(|storage, len| syscall!(getpeername(fd, storage.cast(), len))) }
1000 .map(|(_, addr)| addr)
1001}
1002
1003pub(crate) fn try_clone(fd: Socket) -> io::Result<Socket> {
1004 syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0))
1005}
1006
1007#[cfg(all(feature = "all", unix, not(target_os = "vita")))]
1008pub(crate) fn nonblocking(fd: Socket) -> io::Result<bool> {
1009 let file_status_flags = fcntl_get(fd, libc::F_GETFL)?;
1010 Ok((file_status_flags & libc::O_NONBLOCK) != 0)
1011}
1012
1013#[cfg(all(feature = "all", target_os = "vita"))]
1014pub(crate) fn nonblocking(fd: Socket) -> io::Result<bool> {
1015 unsafe {
1016 getsockopt::<Bool>(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK).map(|non_block| non_block != 0)
1017 }
1018}
1019
1020#[cfg(not(target_os = "vita"))]
1021pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> {
1022 if nonblocking {
1023 fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1024 } else {
1025 fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1026 }
1027}
1028
1029#[cfg(target_os = "vita")]
1030pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> {
1031 unsafe {
1032 setsockopt(
1033 fd,
1034 libc::SOL_SOCKET,
1035 libc::SO_NONBLOCK,
1036 nonblocking as libc::c_int,
1037 )
1038 }
1039}
1040
1041pub(crate) fn shutdown(fd: Socket, how: Shutdown) -> io::Result<()> {
1042 let how = match how {
1043 Shutdown::Write => libc::SHUT_WR,
1044 Shutdown::Read => libc::SHUT_RD,
1045 Shutdown::Both => libc::SHUT_RDWR,
1046 };
1047 syscall!(shutdown(fd, how)).map(|_| ())
1048}
1049
1050pub(crate) fn recv(fd: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
1051 syscall!(recv(
1052 fd,
1053 buf.as_mut_ptr().cast(),
1054 min(buf.len(), MAX_BUF_LEN),
1055 flags,
1056 ))
1057 .map(|n| n as usize)
1058}
1059
1060pub(crate) fn recv_from(
1061 fd: Socket,
1062 buf: &mut [MaybeUninit<u8>],
1063 flags: c_int,
1064) -> io::Result<(usize, SockAddr)> {
1065 unsafe {
1067 SockAddr::try_init(|addr, addrlen| {
1068 syscall!(recvfrom(
1069 fd,
1070 buf.as_mut_ptr().cast(),
1071 min(buf.len(), MAX_BUF_LEN),
1072 flags,
1073 addr.cast(),
1074 addrlen
1075 ))
1076 .map(|n| n as usize)
1077 })
1078 }
1079}
1080
1081pub(crate) fn peek_sender(fd: Socket) -> io::Result<SockAddr> {
1082 let (_, sender) = recv_from(fd, &mut [MaybeUninit::uninit(); 8], MSG_PEEK)?;
1087 Ok(sender)
1088}
1089
1090#[cfg(not(target_os = "redox"))]
1091pub(crate) fn recv_vectored(
1092 fd: Socket,
1093 bufs: &mut [crate::MaybeUninitSlice<'_>],
1094 flags: c_int,
1095) -> io::Result<(usize, RecvFlags)> {
1096 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1097 let n = recvmsg(fd, &mut msg, flags)?;
1098 Ok((n, msg.flags()))
1099}
1100
1101#[cfg(not(target_os = "redox"))]
1102pub(crate) fn recv_from_vectored(
1103 fd: Socket,
1104 bufs: &mut [crate::MaybeUninitSlice<'_>],
1105 flags: c_int,
1106) -> io::Result<(usize, RecvFlags, SockAddr)> {
1107 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1108 let (n, addr) = unsafe {
1111 SockAddr::try_init(|storage, len| {
1112 msg.inner.msg_name = storage.cast();
1113 msg.inner.msg_namelen = *len;
1114 let n = recvmsg(fd, &mut msg, flags)?;
1115 *len = msg.inner.msg_namelen;
1117 Ok(n)
1118 })?
1119 };
1120 Ok((n, msg.flags(), addr))
1121}
1122
1123#[cfg(not(target_os = "redox"))]
1124pub(crate) fn recvmsg(
1125 fd: Socket,
1126 msg: &mut MsgHdrMut<'_, '_, '_>,
1127 flags: c_int,
1128) -> io::Result<usize> {
1129 syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|n| n as usize)
1130}
1131
1132#[cfg(not(any(
1133 target_os = "freebsd",
1134 target_os = "fuchsia",
1135 target_os = "hurd",
1136 target_os = "redox",
1137 target_os = "vita",
1138)))]
1139use crate::{CMsgHdrOps, MsgHdrInit, MsgHdrOps};
1140
1141#[cfg(not(any(
1142 target_os = "freebsd",
1143 target_os = "fuchsia",
1144 target_os = "hurd",
1145 target_os = "redox",
1146 target_os = "vita",
1147)))]
1148use libc::{CMSG_DATA, CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_SPACE};
1149
1150#[cfg(not(any(
1151 target_os = "freebsd",
1152 target_os = "fuchsia",
1153 target_os = "hurd",
1154 target_os = "redox",
1155 target_os = "vita",
1156)))]
1157pub(crate) fn recvmsg_init(
1158 fd: Socket,
1159 msg: &mut MsgHdrInit<'_, '_, '_>,
1160 flags: c_int,
1161) -> io::Result<usize> {
1162 syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|length| {
1163 if let Some(src) = msg.src.as_mut() {
1164 unsafe { src.set_length(msg.inner.msg_namelen) }
1166 }
1167 length as usize
1168 })
1169}
1170
1171#[cfg(not(any(
1172 target_os = "freebsd",
1173 target_os = "fuchsia",
1174 target_os = "hurd",
1175 target_os = "redox",
1176 target_os = "vita",
1177)))]
1178impl MsgHdrOps for msghdr {
1179 fn cmsg_first_hdr(&self) -> *mut cmsghdr {
1180 unsafe { CMSG_FIRSTHDR(self) }
1181 }
1182
1183 fn cmsg_next_hdr(&self, cmsg: &cmsghdr) -> *mut cmsghdr {
1184 unsafe { CMSG_NXTHDR(self, cmsg) }
1185 }
1186}
1187
1188#[cfg(not(any(
1189 target_os = "freebsd",
1190 target_os = "fuchsia",
1191 target_os = "hurd",
1192 target_os = "redox",
1193 target_os = "vita",
1194)))]
1195impl CMsgHdrOps for cmsghdr {
1196 fn cmsg_data(&self) -> *mut u8 {
1197 unsafe { CMSG_DATA(self) }
1198 }
1199}
1200
1201#[cfg(not(any(
1204 target_os = "freebsd",
1205 target_os = "fuchsia",
1206 target_os = "hurd",
1207 target_os = "redox",
1208 target_os = "vita",
1209)))]
1210pub(crate) const fn _cmsg_space(data_len: usize) -> usize {
1211 unsafe { CMSG_SPACE(data_len as _) as usize }
1212}
1213
1214pub(crate) fn send(fd: Socket, buf: &[u8], flags: c_int) -> io::Result<usize> {
1215 syscall!(send(
1216 fd,
1217 buf.as_ptr().cast(),
1218 min(buf.len(), MAX_BUF_LEN),
1219 flags,
1220 ))
1221 .map(|n| n as usize)
1222}
1223
1224#[cfg(not(target_os = "redox"))]
1225pub(crate) fn send_vectored(fd: Socket, bufs: &[IoSlice<'_>], flags: c_int) -> io::Result<usize> {
1226 let msg = MsgHdr::new().with_buffers(bufs);
1227 sendmsg(fd, &msg, flags)
1228}
1229
1230pub(crate) fn send_to(fd: Socket, buf: &[u8], addr: &SockAddr, flags: c_int) -> io::Result<usize> {
1231 syscall!(sendto(
1232 fd,
1233 buf.as_ptr().cast(),
1234 min(buf.len(), MAX_BUF_LEN),
1235 flags,
1236 addr.as_ptr(),
1237 addr.len(),
1238 ))
1239 .map(|n| n as usize)
1240}
1241
1242#[cfg(not(target_os = "redox"))]
1243pub(crate) fn send_to_vectored(
1244 fd: Socket,
1245 bufs: &[IoSlice<'_>],
1246 addr: &SockAddr,
1247 flags: c_int,
1248) -> io::Result<usize> {
1249 let msg = MsgHdr::new().with_addr(addr).with_buffers(bufs);
1250 sendmsg(fd, &msg, flags)
1251}
1252
1253#[cfg(not(target_os = "redox"))]
1254pub(crate) fn sendmsg(fd: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
1255 syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
1256}
1257
1258pub(crate) fn timeout_opt(fd: Socket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
1260 unsafe { getsockopt(fd, opt, val).map(from_timeval) }
1261}
1262
1263const fn from_timeval(duration: libc::timeval) -> Option<Duration> {
1264 if duration.tv_sec == 0 && duration.tv_usec == 0 {
1265 None
1266 } else {
1267 let sec = duration.tv_sec as u64;
1268 let nsec = (duration.tv_usec as u32) * 1000;
1269 Some(Duration::new(sec, nsec))
1270 }
1271}
1272
1273pub(crate) fn set_timeout_opt(
1275 fd: Socket,
1276 opt: c_int,
1277 val: c_int,
1278 duration: Option<Duration>,
1279) -> io::Result<()> {
1280 let duration = into_timeval(duration);
1281 unsafe { setsockopt(fd, opt, val, duration) }
1282}
1283
1284fn into_timeval(duration: Option<Duration>) -> libc::timeval {
1285 match duration {
1286 #[cfg_attr(target_env = "musl", allow(deprecated))]
1288 Some(duration) => libc::timeval {
1289 tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
1290 tv_usec: duration.subsec_micros() as libc::suseconds_t,
1291 },
1292 None => libc::timeval {
1293 tv_sec: 0,
1294 tv_usec: 0,
1295 },
1296 }
1297}
1298
1299#[cfg(all(
1300 feature = "all",
1301 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1302))]
1303#[cfg_attr(
1304 docsrs,
1305 doc(cfg(all(
1306 feature = "all",
1307 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1308 )))
1309)]
1310pub(crate) fn keepalive_time(fd: Socket) -> io::Result<Duration> {
1311 unsafe {
1312 getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
1313 .map(|secs| Duration::from_secs(secs as u64))
1314 }
1315}
1316
1317#[allow(unused_variables)]
1318pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()> {
1319 #[cfg(not(any(
1320 target_os = "haiku",
1321 target_os = "openbsd",
1322 target_os = "nto",
1323 target_os = "vita"
1324 )))]
1325 if let Some(time) = keepalive.time {
1326 let secs = into_secs(time);
1327 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1328 }
1329
1330 #[cfg(any(
1331 target_os = "aix",
1332 target_os = "android",
1333 target_os = "dragonfly",
1334 target_os = "freebsd",
1335 target_os = "fuchsia",
1336 target_os = "hurd",
1337 target_os = "illumos",
1338 target_os = "ios",
1339 target_os = "linux",
1340 target_os = "macos",
1341 target_os = "netbsd",
1342 target_os = "tvos",
1343 target_os = "watchos",
1344 ))]
1345 {
1346 if let Some(interval) = keepalive.interval {
1347 let secs = into_secs(interval);
1348 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
1349 }
1350
1351 if let Some(retries) = keepalive.retries {
1352 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
1353 }
1354 }
1355
1356 #[cfg(target_os = "nto")]
1357 if let Some(time) = keepalive.time {
1358 let secs = into_timeval(Some(time));
1359 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1360 }
1361
1362 Ok(())
1363}
1364
1365#[cfg(not(any(
1366 target_os = "haiku",
1367 target_os = "openbsd",
1368 target_os = "nto",
1369 target_os = "vita"
1370)))]
1371fn into_secs(duration: Duration) -> c_int {
1372 min(duration.as_secs(), c_int::MAX as u64) as c_int
1373}
1374
1375#[cfg(not(target_os = "vita"))]
1377fn fcntl_get(fd: Socket, cmd: c_int) -> io::Result<c_int> {
1378 syscall!(fcntl(fd, cmd))
1379}
1380
1381#[cfg(not(target_os = "vita"))]
1383fn fcntl_add(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1384 let previous = fcntl_get(fd, get_cmd)?;
1385 let new = previous | flag;
1386 if new != previous {
1387 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1388 } else {
1389 Ok(())
1391 }
1392}
1393
1394#[cfg(not(target_os = "vita"))]
1396fn fcntl_remove(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1397 let previous = fcntl_get(fd, get_cmd)?;
1398 let new = previous & !flag;
1399 if new != previous {
1400 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1401 } else {
1402 Ok(())
1404 }
1405}
1406
1407pub(crate) unsafe fn getsockopt<T>(fd: Socket, opt: c_int, val: c_int) -> io::Result<T> {
1409 let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
1410 let mut len = size_of::<T>() as libc::socklen_t;
1411 syscall!(getsockopt(
1412 fd,
1413 opt,
1414 val,
1415 payload.as_mut_ptr().cast(),
1416 &mut len,
1417 ))
1418 .map(|_| {
1419 debug_assert_eq!(len as usize, size_of::<T>());
1420 payload.assume_init()
1422 })
1423}
1424
1425pub(crate) unsafe fn setsockopt<T>(
1427 fd: Socket,
1428 opt: c_int,
1429 val: c_int,
1430 payload: T,
1431) -> io::Result<()> {
1432 let payload = ptr::addr_of!(payload).cast();
1433 syscall!(setsockopt(
1434 fd,
1435 opt,
1436 val,
1437 payload,
1438 mem::size_of::<T>() as libc::socklen_t,
1439 ))
1440 .map(|_| ())
1441}
1442
1443pub(crate) const fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
1444 in_addr {
1448 s_addr: u32::from_ne_bytes(addr.octets()),
1449 }
1450}
1451
1452pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
1453 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1454}
1455
1456pub(crate) const fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
1457 in6_addr {
1458 s6_addr: addr.octets(),
1459 }
1460}
1461
1462pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
1463 Ipv6Addr::from(addr.s6_addr)
1464}
1465
1466#[cfg(not(any(
1467 target_os = "aix",
1468 target_os = "haiku",
1469 target_os = "illumos",
1470 target_os = "netbsd",
1471 target_os = "openbsd",
1472 target_os = "redox",
1473 target_os = "solaris",
1474 target_os = "nto",
1475 target_os = "espidf",
1476 target_os = "vita",
1477)))]
1478pub(crate) const fn to_mreqn(
1479 multiaddr: &Ipv4Addr,
1480 interface: &crate::socket::InterfaceIndexOrAddress,
1481) -> libc::ip_mreqn {
1482 match interface {
1483 crate::socket::InterfaceIndexOrAddress::Index(interface) => libc::ip_mreqn {
1484 imr_multiaddr: to_in_addr(multiaddr),
1485 imr_address: to_in_addr(&Ipv4Addr::UNSPECIFIED),
1486 imr_ifindex: *interface as _,
1487 },
1488 crate::socket::InterfaceIndexOrAddress::Address(interface) => libc::ip_mreqn {
1489 imr_multiaddr: to_in_addr(multiaddr),
1490 imr_address: to_in_addr(interface),
1491 imr_ifindex: 0,
1492 },
1493 }
1494}
1495
1496impl crate::Socket {
1498 #[doc = man_links!(unix: accept4(2))]
1506 #[cfg(all(
1507 feature = "all",
1508 any(
1509 target_os = "android",
1510 target_os = "dragonfly",
1511 target_os = "freebsd",
1512 target_os = "fuchsia",
1513 target_os = "illumos",
1514 target_os = "linux",
1515 target_os = "netbsd",
1516 target_os = "openbsd",
1517 )
1518 ))]
1519 #[cfg_attr(
1520 docsrs,
1521 doc(cfg(all(
1522 feature = "all",
1523 any(
1524 target_os = "android",
1525 target_os = "dragonfly",
1526 target_os = "freebsd",
1527 target_os = "fuchsia",
1528 target_os = "illumos",
1529 target_os = "linux",
1530 target_os = "netbsd",
1531 target_os = "openbsd",
1532 )
1533 )))
1534 )]
1535 pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1536 self._accept4(flags)
1537 }
1538
1539 #[cfg(any(
1540 target_os = "android",
1541 target_os = "dragonfly",
1542 target_os = "freebsd",
1543 target_os = "fuchsia",
1544 target_os = "illumos",
1545 target_os = "linux",
1546 target_os = "netbsd",
1547 target_os = "openbsd",
1548 ))]
1549 pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1550 unsafe {
1552 SockAddr::try_init(|storage, len| {
1553 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1554 .map(crate::Socket::from_raw)
1555 })
1556 }
1557 }
1558
1559 #[cfg_attr(
1565 any(
1566 target_os = "ios",
1567 target_os = "macos",
1568 target_os = "tvos",
1569 target_os = "watchos"
1570 ),
1571 allow(rustdoc::broken_intra_doc_links)
1572 )]
1573 #[cfg(all(feature = "all", not(target_os = "vita")))]
1574 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
1575 pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1576 self._set_cloexec(close_on_exec)
1577 }
1578
1579 #[cfg(not(target_os = "vita"))]
1580 pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1581 if close_on_exec {
1582 fcntl_add(
1583 self.as_raw(),
1584 libc::F_GETFD,
1585 libc::F_SETFD,
1586 libc::FD_CLOEXEC,
1587 )
1588 } else {
1589 fcntl_remove(
1590 self.as_raw(),
1591 libc::F_GETFD,
1592 libc::F_SETFD,
1593 libc::FD_CLOEXEC,
1594 )
1595 }
1596 }
1597
1598 #[cfg(all(
1600 feature = "all",
1601 any(
1602 target_os = "ios",
1603 target_os = "macos",
1604 target_os = "tvos",
1605 target_os = "watchos",
1606 )
1607 ))]
1608 #[cfg_attr(
1609 docsrs,
1610 doc(cfg(all(
1611 feature = "all",
1612 any(
1613 target_os = "ios",
1614 target_os = "macos",
1615 target_os = "tvos",
1616 target_os = "watchos",
1617 )
1618 )))
1619 )]
1620 pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1621 self._set_nosigpipe(nosigpipe)
1622 }
1623
1624 #[cfg(any(
1625 target_os = "ios",
1626 target_os = "macos",
1627 target_os = "tvos",
1628 target_os = "watchos",
1629 ))]
1630 pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1631 unsafe {
1632 setsockopt(
1633 self.as_raw(),
1634 libc::SOL_SOCKET,
1635 libc::SO_NOSIGPIPE,
1636 nosigpipe as c_int,
1637 )
1638 }
1639 }
1640
1641 #[cfg(all(feature = "all", not(target_os = "redox")))]
1647 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
1648 pub fn mss(&self) -> io::Result<u32> {
1649 unsafe {
1650 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1651 .map(|mss| mss as u32)
1652 }
1653 }
1654
1655 #[cfg(all(feature = "all", not(target_os = "redox")))]
1660 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
1661 pub fn set_mss(&self, mss: u32) -> io::Result<()> {
1662 unsafe {
1663 setsockopt(
1664 self.as_raw(),
1665 libc::IPPROTO_TCP,
1666 libc::TCP_MAXSEG,
1667 mss as c_int,
1668 )
1669 }
1670 }
1671
1672 #[cfg(all(
1675 feature = "all",
1676 any(
1677 target_os = "aix",
1678 target_os = "android",
1679 target_os = "freebsd",
1680 target_os = "fuchsia",
1681 target_os = "linux",
1682 )
1683 ))]
1684 #[cfg_attr(
1685 docsrs,
1686 doc(cfg(all(
1687 feature = "all",
1688 any(
1689 target_os = "aix",
1690 target_os = "android",
1691 target_os = "freebsd",
1692 target_os = "fuchsia",
1693 target_os = "linux",
1694 )
1695 )))
1696 )]
1697 pub fn is_listener(&self) -> io::Result<bool> {
1698 unsafe {
1699 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1700 .map(|v| v != 0)
1701 }
1702 }
1703
1704 #[cfg(all(
1707 feature = "all",
1708 any(
1709 target_os = "android",
1710 target_os = "fuchsia",
1713 target_os = "linux",
1714 )
1715 ))]
1716 #[cfg_attr(docsrs, doc(cfg(all(
1717 feature = "all",
1718 any(
1719 target_os = "android",
1720 target_os = "fuchsia",
1723 target_os = "linux",
1724 )
1725 ))))]
1726 pub fn domain(&self) -> io::Result<Domain> {
1727 unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1728 }
1729
1730 #[cfg(all(
1733 feature = "all",
1734 any(
1735 target_os = "android",
1736 target_os = "freebsd",
1737 target_os = "fuchsia",
1738 target_os = "linux",
1739 )
1740 ))]
1741 #[cfg_attr(
1742 docsrs,
1743 doc(cfg(all(
1744 feature = "all",
1745 any(
1746 target_os = "android",
1747 target_os = "freebsd",
1748 target_os = "fuchsia",
1749 target_os = "linux",
1750 )
1751 )))
1752 )]
1753 pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1754 unsafe {
1755 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1756 {
1757 0 => None,
1758 p => Some(Protocol(p)),
1759 })
1760 }
1761 }
1762
1763 #[cfg(all(
1770 feature = "all",
1771 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1772 ))]
1773 #[cfg_attr(
1774 docsrs,
1775 doc(cfg(all(
1776 feature = "all",
1777 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1778 )))
1779 )]
1780 pub fn mark(&self) -> io::Result<u32> {
1781 unsafe {
1782 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1783 .map(|mark| mark as u32)
1784 }
1785 }
1786
1787 #[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_mark(&self, mark: u32) -> io::Result<()> {
1806 unsafe {
1807 setsockopt::<c_int>(
1808 self.as_raw(),
1809 libc::SOL_SOCKET,
1810 libc::SO_MARK,
1811 mark 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 cork(&self) -> io::Result<bool> {
1833 unsafe {
1834 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK)
1835 .map(|cork| cork != 0)
1836 }
1837 }
1838
1839 #[cfg(all(
1846 feature = "all",
1847 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1848 ))]
1849 #[cfg_attr(
1850 docsrs,
1851 doc(cfg(all(
1852 feature = "all",
1853 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1854 )))
1855 )]
1856 pub fn set_cork(&self, cork: bool) -> io::Result<()> {
1857 unsafe {
1858 setsockopt(
1859 self.as_raw(),
1860 libc::IPPROTO_TCP,
1861 libc::TCP_CORK,
1862 cork as c_int,
1863 )
1864 }
1865 }
1866
1867 #[cfg(all(
1873 feature = "all",
1874 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1875 ))]
1876 #[cfg_attr(
1877 docsrs,
1878 doc(cfg(all(
1879 feature = "all",
1880 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1881 )))
1882 )]
1883 pub fn quickack(&self) -> io::Result<bool> {
1884 unsafe {
1885 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK)
1886 .map(|quickack| quickack != 0)
1887 }
1888 }
1889
1890 #[cfg(all(
1897 feature = "all",
1898 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1899 ))]
1900 #[cfg_attr(
1901 docsrs,
1902 doc(cfg(all(
1903 feature = "all",
1904 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1905 )))
1906 )]
1907 pub fn set_quickack(&self, quickack: bool) -> io::Result<()> {
1908 unsafe {
1909 setsockopt(
1910 self.as_raw(),
1911 libc::IPPROTO_TCP,
1912 libc::TCP_QUICKACK,
1913 quickack as c_int,
1914 )
1915 }
1916 }
1917
1918 #[cfg(all(
1924 feature = "all",
1925 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1926 ))]
1927 #[cfg_attr(
1928 docsrs,
1929 doc(cfg(all(
1930 feature = "all",
1931 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1932 )))
1933 )]
1934 pub fn thin_linear_timeouts(&self) -> io::Result<bool> {
1935 unsafe {
1936 getsockopt::<Bool>(
1937 self.as_raw(),
1938 libc::IPPROTO_TCP,
1939 libc::TCP_THIN_LINEAR_TIMEOUTS,
1940 )
1941 .map(|timeouts| timeouts != 0)
1942 }
1943 }
1944
1945 #[cfg(all(
1951 feature = "all",
1952 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1953 ))]
1954 #[cfg_attr(
1955 docsrs,
1956 doc(cfg(all(
1957 feature = "all",
1958 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1959 )))
1960 )]
1961 pub fn set_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> {
1962 unsafe {
1963 setsockopt(
1964 self.as_raw(),
1965 libc::IPPROTO_TCP,
1966 libc::TCP_THIN_LINEAR_TIMEOUTS,
1967 timeouts as c_int,
1968 )
1969 }
1970 }
1971
1972 #[cfg(all(
1976 feature = "all",
1977 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1978 ))]
1979 #[cfg_attr(
1980 docsrs,
1981 doc(cfg(all(
1982 feature = "all",
1983 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1984 )))
1985 )]
1986 pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1987 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1989 unsafe { MaybeUninit::uninit().assume_init() };
1990 let mut len = buf.len() as libc::socklen_t;
1991 syscall!(getsockopt(
1992 self.as_raw(),
1993 libc::SOL_SOCKET,
1994 libc::SO_BINDTODEVICE,
1995 buf.as_mut_ptr().cast(),
1996 &mut len,
1997 ))?;
1998 if len == 0 {
1999 Ok(None)
2000 } else {
2001 let buf = &buf[..len as usize - 1];
2002 Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
2004 }
2005 }
2006
2007 #[cfg(all(
2015 feature = "all",
2016 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2017 ))]
2018 #[cfg_attr(
2019 docsrs,
2020 doc(cfg(all(
2021 feature = "all",
2022 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2023 )))
2024 )]
2025 pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
2026 let (value, len) = if let Some(interface) = interface {
2027 (interface.as_ptr(), interface.len())
2028 } else {
2029 (ptr::null(), 0)
2030 };
2031 syscall!(setsockopt(
2032 self.as_raw(),
2033 libc::SOL_SOCKET,
2034 libc::SO_BINDTODEVICE,
2035 value.cast(),
2036 len as libc::socklen_t,
2037 ))
2038 .map(|_| ())
2039 }
2040
2041 #[cfg(all(feature = "all", target_os = "freebsd"))]
2045 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "freebsd"))))]
2046 pub fn set_fib(&self, fib: u32) -> io::Result<()> {
2047 syscall!(setsockopt(
2048 self.as_raw(),
2049 libc::SOL_SOCKET,
2050 libc::SO_SETFIB,
2051 (&fib as *const u32).cast(),
2052 mem::size_of::<u32>() as libc::socklen_t,
2053 ))
2054 .map(|_| ())
2055 }
2056
2057 #[cfg(all(
2059 feature = "all",
2060 any(
2061 target_os = "ios",
2062 target_os = "macos",
2063 target_os = "tvos",
2064 target_os = "watchos",
2065 )
2066 ))]
2067 #[cfg_attr(
2068 docsrs,
2069 doc(cfg(all(
2070 feature = "all",
2071 any(
2072 target_os = "ios",
2073 target_os = "macos",
2074 target_os = "tvos",
2075 target_os = "watchos",
2076 )
2077 )))
2078 )]
2079 #[deprecated = "Use `Socket::bind_device_by_index_v4` instead"]
2080 pub fn bind_device_by_index(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2081 self.bind_device_by_index_v4(interface)
2082 }
2083
2084 #[cfg(all(
2095 feature = "all",
2096 any(
2097 target_os = "ios",
2098 target_os = "macos",
2099 target_os = "tvos",
2100 target_os = "watchos",
2101 )
2102 ))]
2103 #[cfg_attr(
2104 docsrs,
2105 doc(cfg(all(
2106 feature = "all",
2107 any(
2108 target_os = "ios",
2109 target_os = "macos",
2110 target_os = "tvos",
2111 target_os = "watchos",
2112 )
2113 )))
2114 )]
2115 pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2116 let index = interface.map_or(0, NonZeroU32::get);
2117 unsafe { setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index) }
2118 }
2119
2120 #[cfg(all(
2131 feature = "all",
2132 any(
2133 target_os = "ios",
2134 target_os = "macos",
2135 target_os = "tvos",
2136 target_os = "watchos",
2137 )
2138 ))]
2139 #[cfg_attr(
2140 docsrs,
2141 doc(cfg(all(
2142 feature = "all",
2143 any(
2144 target_os = "ios",
2145 target_os = "macos",
2146 target_os = "tvos",
2147 target_os = "watchos",
2148 )
2149 )))
2150 )]
2151 pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2152 let index = interface.map_or(0, NonZeroU32::get);
2153 unsafe { setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index) }
2154 }
2155
2156 #[cfg(all(
2162 feature = "all",
2163 any(
2164 target_os = "ios",
2165 target_os = "macos",
2166 target_os = "tvos",
2167 target_os = "watchos",
2168 )
2169 ))]
2170 #[cfg_attr(
2171 docsrs,
2172 doc(cfg(all(
2173 feature = "all",
2174 any(
2175 target_os = "ios",
2176 target_os = "macos",
2177 target_os = "tvos",
2178 target_os = "watchos",
2179 )
2180 )))
2181 )]
2182 pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
2183 let index =
2184 unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
2185 Ok(NonZeroU32::new(index))
2186 }
2187
2188 #[cfg(all(
2190 feature = "all",
2191 any(
2192 target_os = "ios",
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 = "macos",
2205 target_os = "tvos",
2206 target_os = "watchos",
2207 )
2208 )))
2209 )]
2210 #[deprecated = "Use `Socket::device_index_v4` instead"]
2211 pub fn device_index(&self) -> io::Result<Option<NonZeroU32>> {
2212 self.device_index_v4()
2213 }
2214
2215 #[cfg(all(
2221 feature = "all",
2222 any(
2223 target_os = "ios",
2224 target_os = "macos",
2225 target_os = "tvos",
2226 target_os = "watchos",
2227 )
2228 ))]
2229 #[cfg_attr(
2230 docsrs,
2231 doc(cfg(all(
2232 feature = "all",
2233 any(
2234 target_os = "ios",
2235 target_os = "macos",
2236 target_os = "tvos",
2237 target_os = "watchos",
2238 )
2239 )))
2240 )]
2241 pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
2242 let index = unsafe {
2243 getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)?
2244 };
2245 Ok(NonZeroU32::new(index))
2246 }
2247
2248 #[cfg(all(feature = "all", target_os = "linux"))]
2254 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2255 pub fn cpu_affinity(&self) -> io::Result<usize> {
2256 unsafe {
2257 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
2258 .map(|cpu| cpu as usize)
2259 }
2260 }
2261
2262 #[cfg(all(feature = "all", target_os = "linux"))]
2266 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2267 pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
2268 unsafe {
2269 setsockopt(
2270 self.as_raw(),
2271 libc::SOL_SOCKET,
2272 libc::SO_INCOMING_CPU,
2273 cpu as c_int,
2274 )
2275 }
2276 }
2277
2278 #[cfg(all(
2284 feature = "all",
2285 not(any(target_os = "solaris", target_os = "illumos"))
2286 ))]
2287 #[cfg_attr(
2288 docsrs,
2289 doc(cfg(all(
2290 feature = "all",
2291 unix,
2292 not(any(target_os = "solaris", target_os = "illumos"))
2293 )))
2294 )]
2295 pub fn reuse_port(&self) -> io::Result<bool> {
2296 unsafe {
2297 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
2298 .map(|reuse| reuse != 0)
2299 }
2300 }
2301
2302 #[cfg(all(
2308 feature = "all",
2309 not(any(target_os = "solaris", target_os = "illumos"))
2310 ))]
2311 #[cfg_attr(
2312 docsrs,
2313 doc(cfg(all(
2314 feature = "all",
2315 unix,
2316 not(any(target_os = "solaris", target_os = "illumos"))
2317 )))
2318 )]
2319 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
2320 unsafe {
2321 setsockopt(
2322 self.as_raw(),
2323 libc::SOL_SOCKET,
2324 libc::SO_REUSEPORT,
2325 reuse as c_int,
2326 )
2327 }
2328 }
2329
2330 #[cfg(all(feature = "all", target_os = "freebsd"))]
2336 pub fn reuse_port_lb(&self) -> io::Result<bool> {
2337 unsafe {
2338 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT_LB)
2339 .map(|reuse| reuse != 0)
2340 }
2341 }
2342
2343 #[cfg(all(feature = "all", target_os = "freebsd"))]
2348 pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
2349 unsafe {
2350 setsockopt(
2351 self.as_raw(),
2352 libc::SOL_SOCKET,
2353 libc::SO_REUSEPORT_LB,
2354 reuse as c_int,
2355 )
2356 }
2357 }
2358
2359 #[cfg(all(
2365 feature = "all",
2366 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2367 ))]
2368 #[cfg_attr(
2369 docsrs,
2370 doc(cfg(all(
2371 feature = "all",
2372 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2373 )))
2374 )]
2375 pub fn freebind(&self) -> io::Result<bool> {
2376 unsafe {
2377 getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
2378 .map(|freebind| freebind != 0)
2379 }
2380 }
2381
2382 #[cfg(all(
2390 feature = "all",
2391 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2392 ))]
2393 #[cfg_attr(
2394 docsrs,
2395 doc(cfg(all(
2396 feature = "all",
2397 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2398 )))
2399 )]
2400 pub fn set_freebind(&self, freebind: bool) -> io::Result<()> {
2401 unsafe {
2402 setsockopt(
2403 self.as_raw(),
2404 libc::SOL_IP,
2405 libc::IP_FREEBIND,
2406 freebind as c_int,
2407 )
2408 }
2409 }
2410
2411 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2419 #[cfg_attr(
2420 docsrs,
2421 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2422 )]
2423 pub fn freebind_ipv6(&self) -> io::Result<bool> {
2424 unsafe {
2425 getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
2426 .map(|freebind| freebind != 0)
2427 }
2428 }
2429
2430 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2461 #[cfg_attr(
2462 docsrs,
2463 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2464 )]
2465 pub fn set_freebind_ipv6(&self, freebind: bool) -> io::Result<()> {
2466 unsafe {
2467 setsockopt(
2468 self.as_raw(),
2469 libc::SOL_IPV6,
2470 libc::IPV6_FREEBIND,
2471 freebind as c_int,
2472 )
2473 }
2474 }
2475
2476 #[cfg(all(
2481 feature = "all",
2482 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2483 ))]
2484 #[cfg_attr(
2485 docsrs,
2486 doc(cfg(all(
2487 feature = "all",
2488 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2489 )))
2490 )]
2491 pub fn original_dst(&self) -> io::Result<SockAddr> {
2492 unsafe {
2494 SockAddr::try_init(|storage, len| {
2495 syscall!(getsockopt(
2496 self.as_raw(),
2497 libc::SOL_IP,
2498 libc::SO_ORIGINAL_DST,
2499 storage.cast(),
2500 len
2501 ))
2502 })
2503 }
2504 .map(|(_, addr)| addr)
2505 }
2506
2507 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2512 #[cfg_attr(
2513 docsrs,
2514 doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
2515 )]
2516 pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
2517 unsafe {
2519 SockAddr::try_init(|storage, len| {
2520 syscall!(getsockopt(
2521 self.as_raw(),
2522 libc::SOL_IPV6,
2523 libc::IP6T_SO_ORIGINAL_DST,
2524 storage.cast(),
2525 len
2526 ))
2527 })
2528 }
2529 .map(|(_, addr)| addr)
2530 }
2531
2532 #[doc = man_links!(unix: sendfile(2))]
2542 #[cfg(all(
2552 feature = "all",
2553 any(
2554 target_os = "aix",
2555 target_os = "android",
2556 target_os = "freebsd",
2557 target_os = "ios",
2558 target_os = "linux",
2559 target_os = "macos",
2560 target_os = "tvos",
2561 target_os = "watchos",
2562 )
2563 ))]
2564 #[cfg_attr(
2565 docsrs,
2566 doc(cfg(all(
2567 feature = "all",
2568 any(
2569 target_os = "aix",
2570 target_os = "android",
2571 target_os = "freebsd",
2572 target_os = "ios",
2573 target_os = "linux",
2574 target_os = "macos",
2575 target_os = "tvos",
2576 target_os = "watchos",
2577 )
2578 )))
2579 )]
2580 pub fn sendfile<F>(
2581 &self,
2582 file: &F,
2583 offset: usize,
2584 length: Option<NonZeroUsize>,
2585 ) -> io::Result<usize>
2586 where
2587 F: AsRawFd,
2588 {
2589 self._sendfile(file.as_raw_fd(), offset as _, length)
2590 }
2591
2592 #[cfg(all(
2593 feature = "all",
2594 any(
2595 target_os = "ios",
2596 target_os = "macos",
2597 target_os = "tvos",
2598 target_os = "watchos",
2599 )
2600 ))]
2601 fn _sendfile(
2602 &self,
2603 file: RawFd,
2604 offset: libc::off_t,
2605 length: Option<NonZeroUsize>,
2606 ) -> io::Result<usize> {
2607 let mut length = match length {
2610 Some(n) => n.get() as libc::off_t,
2611 None => 0,
2613 };
2614 syscall!(sendfile(
2615 file,
2616 self.as_raw(),
2617 offset,
2618 &mut length,
2619 ptr::null_mut(),
2620 0,
2621 ))
2622 .map(|_| length as usize)
2623 }
2624
2625 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2626 fn _sendfile(
2627 &self,
2628 file: RawFd,
2629 offset: libc::off_t,
2630 length: Option<NonZeroUsize>,
2631 ) -> io::Result<usize> {
2632 let count = match length {
2633 Some(n) => n.get() as libc::size_t,
2634 None => 0x7ffff000, };
2637 let mut offset = offset;
2638 syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
2639 }
2640
2641 #[cfg(all(feature = "all", target_os = "freebsd"))]
2642 fn _sendfile(
2643 &self,
2644 file: RawFd,
2645 offset: libc::off_t,
2646 length: Option<NonZeroUsize>,
2647 ) -> io::Result<usize> {
2648 let nbytes = match length {
2649 Some(n) => n.get() as libc::size_t,
2650 None => 0,
2652 };
2653 let mut sbytes: libc::off_t = 0;
2654 syscall!(sendfile(
2655 file,
2656 self.as_raw(),
2657 offset,
2658 nbytes,
2659 ptr::null_mut(),
2660 &mut sbytes,
2661 0,
2662 ))
2663 .map(|_| sbytes as usize)
2664 }
2665
2666 #[cfg(all(feature = "all", target_os = "aix"))]
2667 fn _sendfile(
2668 &self,
2669 file: RawFd,
2670 offset: libc::off_t,
2671 length: Option<NonZeroUsize>,
2672 ) -> io::Result<usize> {
2673 let nbytes = match length {
2674 Some(n) => n.get() as i64,
2675 None => -1,
2676 };
2677 let mut params = libc::sf_parms {
2678 header_data: ptr::null_mut(),
2679 header_length: 0,
2680 file_descriptor: file,
2681 file_size: 0,
2682 file_offset: offset as u64,
2683 file_bytes: nbytes,
2684 trailer_data: ptr::null_mut(),
2685 trailer_length: 0,
2686 bytes_sent: 0,
2687 };
2688 syscall!(send_file(
2690 &mut self.as_raw() as *mut _,
2691 &mut params as *mut _,
2692 libc::SF_CLOSE as libc::c_uint,
2693 ))
2694 .map(|_| params.bytes_sent as usize)
2695 }
2696
2697 #[cfg(all(
2708 feature = "all",
2709 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2710 ))]
2711 #[cfg_attr(
2712 docsrs,
2713 doc(cfg(all(
2714 feature = "all",
2715 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2716 )))
2717 )]
2718 pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
2719 let timeout = timeout.map_or(0, |to| {
2720 min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint
2721 });
2722 unsafe {
2723 setsockopt(
2724 self.as_raw(),
2725 libc::IPPROTO_TCP,
2726 libc::TCP_USER_TIMEOUT,
2727 timeout,
2728 )
2729 }
2730 }
2731
2732 #[cfg(all(
2738 feature = "all",
2739 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2740 ))]
2741 #[cfg_attr(
2742 docsrs,
2743 doc(cfg(all(
2744 feature = "all",
2745 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2746 )))
2747 )]
2748 pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
2749 unsafe {
2750 getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
2751 .map(|millis| {
2752 if millis == 0 {
2753 None
2754 } else {
2755 Some(Duration::from_millis(millis as u64))
2756 }
2757 })
2758 }
2759 }
2760
2761 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2768 pub fn attach_filter(&self, filters: &[libc::sock_filter]) -> io::Result<()> {
2769 let prog = libc::sock_fprog {
2770 len: filters.len() as u16,
2771 filter: filters.as_ptr() as *mut _,
2772 };
2773
2774 unsafe {
2775 setsockopt(
2776 self.as_raw(),
2777 libc::SOL_SOCKET,
2778 libc::SO_ATTACH_FILTER,
2779 prog,
2780 )
2781 }
2782 }
2783
2784 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2790 pub fn detach_filter(&self) -> io::Result<()> {
2791 unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) }
2792 }
2793
2794 #[cfg(all(feature = "all", target_os = "linux"))]
2801 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2802 pub fn cookie(&self) -> io::Result<u64> {
2803 unsafe { getsockopt::<libc::c_ulonglong>(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) }
2804 }
2805
2806 #[cfg(all(
2812 feature = "all",
2813 any(
2814 target_os = "android",
2815 target_os = "dragonfly",
2816 target_os = "freebsd",
2817 target_os = "fuchsia",
2818 target_os = "linux",
2819 target_os = "macos",
2820 target_os = "netbsd",
2821 target_os = "openbsd"
2822 )
2823 ))]
2824 #[cfg_attr(
2825 docsrs,
2826 doc(cfg(all(
2827 feature = "all",
2828 any(
2829 target_os = "android",
2830 target_os = "dragonfly",
2831 target_os = "freebsd",
2832 target_os = "fuchsia",
2833 target_os = "linux",
2834 target_os = "macos",
2835 target_os = "netbsd",
2836 target_os = "openbsd"
2837 )
2838 )))
2839 )]
2840 pub fn tclass_v6(&self) -> io::Result<u32> {
2841 unsafe {
2842 getsockopt::<c_int>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS)
2843 .map(|tclass| tclass as u32)
2844 }
2845 }
2846
2847 #[cfg(all(
2852 feature = "all",
2853 any(
2854 target_os = "android",
2855 target_os = "dragonfly",
2856 target_os = "freebsd",
2857 target_os = "fuchsia",
2858 target_os = "linux",
2859 target_os = "macos",
2860 target_os = "netbsd",
2861 target_os = "openbsd"
2862 )
2863 ))]
2864 #[cfg_attr(
2865 docsrs,
2866 doc(cfg(all(
2867 feature = "all",
2868 any(
2869 target_os = "android",
2870 target_os = "dragonfly",
2871 target_os = "freebsd",
2872 target_os = "fuchsia",
2873 target_os = "linux",
2874 target_os = "macos",
2875 target_os = "netbsd",
2876 target_os = "openbsd"
2877 )
2878 )))
2879 )]
2880 pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
2881 unsafe {
2882 setsockopt(
2883 self.as_raw(),
2884 IPPROTO_IPV6,
2885 libc::IPV6_TCLASS,
2886 tclass as c_int,
2887 )
2888 }
2889 }
2890
2891 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2897 #[cfg_attr(
2898 docsrs,
2899 doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux"))))
2900 )]
2901 pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
2902 let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX];
2903 let mut len = payload.len() as libc::socklen_t;
2904 syscall!(getsockopt(
2905 self.as_raw(),
2906 IPPROTO_TCP,
2907 libc::TCP_CONGESTION,
2908 payload.as_mut_ptr().cast(),
2909 &mut len,
2910 ))
2911 .map(|_| payload[..len as usize].to_vec())
2912 }
2913
2914 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2921 #[cfg_attr(
2922 docsrs,
2923 doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux"))))
2924 )]
2925 pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
2926 syscall!(setsockopt(
2927 self.as_raw(),
2928 IPPROTO_TCP,
2929 libc::TCP_CONGESTION,
2930 tcp_ca_name.as_ptr() as *const _,
2931 tcp_ca_name.len() as libc::socklen_t,
2932 ))
2933 .map(|_| ())
2934 }
2935
2936 #[cfg(all(feature = "all", target_os = "linux"))]
2947 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2948 pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
2949 unsafe {
2950 setsockopt(
2951 self.as_raw(),
2952 libc::SOL_DCCP,
2953 libc::DCCP_SOCKOPT_SERVICE,
2954 code,
2955 )
2956 }
2957 }
2958
2959 #[cfg(all(feature = "all", target_os = "linux"))]
2965 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2966 pub fn dccp_service(&self) -> io::Result<u32> {
2967 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) }
2968 }
2969
2970 #[cfg(all(feature = "all", target_os = "linux"))]
2974 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2975 pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
2976 unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) }
2977 }
2978
2979 #[cfg(all(feature = "all", target_os = "linux"))]
2985 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2986 pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
2987 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) }
2988 }
2989
2990 #[cfg(all(feature = "all", target_os = "linux"))]
2996 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
2997 pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
2998 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) }
2999 }
3000
3001 #[cfg(all(feature = "all", target_os = "linux"))]
3006 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3007 pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> {
3008 unsafe {
3009 setsockopt(
3010 self.as_raw(),
3011 libc::SOL_DCCP,
3012 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
3013 hold_timewait as c_int,
3014 )
3015 }
3016 }
3017
3018 #[cfg(all(feature = "all", target_os = "linux"))]
3024 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3025 pub fn dccp_server_timewait(&self) -> io::Result<bool> {
3026 unsafe {
3027 getsockopt(
3028 self.as_raw(),
3029 libc::SOL_DCCP,
3030 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
3031 )
3032 }
3033 }
3034
3035 #[cfg(all(feature = "all", target_os = "linux"))]
3043 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3044 pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
3045 unsafe {
3046 setsockopt(
3047 self.as_raw(),
3048 libc::SOL_DCCP,
3049 libc::DCCP_SOCKOPT_SEND_CSCOV,
3050 level,
3051 )
3052 }
3053 }
3054
3055 #[cfg(all(feature = "all", target_os = "linux"))]
3061 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3062 pub fn dccp_send_cscov(&self) -> io::Result<u32> {
3063 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) }
3064 }
3065
3066 #[cfg(all(feature = "all", target_os = "linux"))]
3072 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3073 pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
3074 unsafe {
3075 setsockopt(
3076 self.as_raw(),
3077 libc::SOL_DCCP,
3078 libc::DCCP_SOCKOPT_RECV_CSCOV,
3079 level,
3080 )
3081 }
3082 }
3083
3084 #[cfg(all(feature = "all", target_os = "linux"))]
3090 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3091 pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
3092 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) }
3093 }
3094
3095 #[cfg(all(feature = "all", target_os = "linux"))]
3100 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3101 pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
3102 unsafe {
3103 setsockopt(
3104 self.as_raw(),
3105 libc::SOL_DCCP,
3106 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
3107 length,
3108 )
3109 }
3110 }
3111
3112 #[cfg(all(feature = "all", target_os = "linux"))]
3118 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3119 pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
3120 unsafe {
3121 getsockopt(
3122 self.as_raw(),
3123 libc::SOL_DCCP,
3124 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
3125 )
3126 }
3127 }
3128
3129 #[cfg(all(feature = "all", target_os = "linux"))]
3139 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3140 pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEndpoints<N>> {
3141 let mut endpoints = [0; N];
3142 let mut length = endpoints.len() as libc::socklen_t;
3143 syscall!(getsockopt(
3144 self.as_raw(),
3145 libc::SOL_DCCP,
3146 libc::DCCP_SOCKOPT_AVAILABLE_CCIDS,
3147 endpoints.as_mut_ptr().cast(),
3148 &mut length,
3149 ))?;
3150 Ok(CcidEndpoints { endpoints, length })
3151 }
3152
3153 #[cfg(all(feature = "all", target_os = "linux"))]
3158 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3159 pub fn dccp_cur_mps(&self) -> io::Result<u32> {
3160 unsafe {
3161 getsockopt(
3162 self.as_raw(),
3163 libc::SOL_DCCP,
3164 libc::DCCP_SOCKOPT_GET_CUR_MPS,
3165 )
3166 }
3167 }
3168}
3169
3170#[cfg(all(feature = "all", target_os = "linux"))]
3172#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3173#[derive(Debug)]
3174pub struct CcidEndpoints<const N: usize> {
3175 endpoints: [u8; N],
3176 length: u32,
3177}
3178
3179#[cfg(all(feature = "all", target_os = "linux"))]
3180#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
3181impl<const N: usize> std::ops::Deref for CcidEndpoints<N> {
3182 type Target = [u8];
3183
3184 fn deref(&self) -> &[u8] {
3185 &self.endpoints[0..self.length as usize]
3186 }
3187}
3188
3189#[cfg_attr(docsrs, doc(cfg(unix)))]
3190impl AsFd for crate::Socket {
3191 fn as_fd(&self) -> BorrowedFd<'_> {
3192 unsafe { BorrowedFd::borrow_raw(self.as_raw()) }
3194 }
3195}
3196
3197#[cfg_attr(docsrs, doc(cfg(unix)))]
3198impl AsRawFd for crate::Socket {
3199 fn as_raw_fd(&self) -> c_int {
3200 self.as_raw()
3201 }
3202}
3203
3204#[cfg_attr(docsrs, doc(cfg(unix)))]
3205impl From<crate::Socket> for OwnedFd {
3206 fn from(sock: crate::Socket) -> OwnedFd {
3207 unsafe { OwnedFd::from_raw_fd(sock.into_raw()) }
3209 }
3210}
3211
3212#[cfg_attr(docsrs, doc(cfg(unix)))]
3213impl IntoRawFd for crate::Socket {
3214 fn into_raw_fd(self) -> c_int {
3215 self.into_raw()
3216 }
3217}
3218
3219#[cfg_attr(docsrs, doc(cfg(unix)))]
3220impl From<OwnedFd> for crate::Socket {
3221 fn from(fd: OwnedFd) -> crate::Socket {
3222 unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) }
3224 }
3225}
3226
3227#[cfg_attr(docsrs, doc(cfg(unix)))]
3228impl FromRawFd for crate::Socket {
3229 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
3230 crate::Socket::from_raw(fd)
3231 }
3232}
3233
3234#[cfg(feature = "all")]
3235from!(UnixStream, crate::Socket);
3236#[cfg(feature = "all")]
3237from!(UnixListener, crate::Socket);
3238#[cfg(feature = "all")]
3239from!(UnixDatagram, crate::Socket);
3240#[cfg(feature = "all")]
3241from!(crate::Socket, UnixStream);
3242#[cfg(feature = "all")]
3243from!(crate::Socket, UnixListener);
3244#[cfg(feature = "all")]
3245from!(crate::Socket, UnixDatagram);
3246
3247#[test]
3248fn in_addr_convertion() {
3249 let ip = Ipv4Addr::new(127, 0, 0, 1);
3250 let raw = to_in_addr(&ip);
3251 let a = raw.s_addr;
3253 assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
3254 assert_eq!(from_in_addr(raw), ip);
3255
3256 let ip = Ipv4Addr::new(127, 34, 4, 12);
3257 let raw = to_in_addr(&ip);
3258 let a = raw.s_addr;
3259 assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
3260 assert_eq!(from_in_addr(raw), ip);
3261}
3262
3263#[test]
3264fn in6_addr_convertion() {
3265 let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
3266 let raw = to_in6_addr(&ip);
3267 let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
3268 assert_eq!(raw.s6_addr, want);
3269 assert_eq!(from_in6_addr(raw), ip);
3270}