1use std::cmp::min;
10#[cfg(not(target_os = "wasi"))]
11use std::ffi::OsStr;
12#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
13use std::io::IoSlice;
14use std::marker::PhantomData;
15use std::mem::{self, size_of, MaybeUninit};
16use std::net::Shutdown;
17use std::net::{Ipv4Addr, Ipv6Addr};
18#[cfg(all(
19 feature = "all",
20 any(
21 target_os = "ios",
22 target_os = "visionos",
23 target_os = "macos",
24 target_os = "tvos",
25 target_os = "watchos",
26 target_os = "illumos",
27 target_os = "solaris",
28 target_os = "linux",
29 target_os = "android",
30 )
31))]
32use std::num::NonZeroU32;
33#[cfg(all(
34 feature = "all",
35 any(
36 target_os = "aix",
37 target_os = "android",
38 target_os = "freebsd",
39 target_os = "ios",
40 target_os = "visionos",
41 target_os = "linux",
42 target_os = "macos",
43 target_os = "tvos",
44 target_os = "watchos",
45 )
46))]
47use std::num::NonZeroUsize;
48use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
49#[cfg(not(target_os = "wasi"))]
50use std::os::unix::ffi::OsStrExt;
51#[cfg(all(feature = "all", unix))]
52use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
53#[cfg(not(target_os = "wasi"))]
54use std::path::Path;
55use std::ptr;
56use std::time::{Duration, Instant};
57use std::{io, slice};
58
59#[cfg(not(any(
60 target_os = "ios",
61 target_os = "visionos",
62 target_os = "macos",
63 target_os = "tvos",
64 target_os = "watchos",
65 target_os = "cygwin",
66)))]
67use libc::ssize_t;
68use libc::{in6_addr, in_addr};
69
70#[cfg(not(target_os = "wasi"))]
71use crate::SockAddrStorage;
72use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
73#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
74use crate::{MsgHdr, MsgHdrMut, RecvFlags};
75
76pub(crate) use std::ffi::c_int;
77
78#[cfg(not(target_os = "wasi"))]
80pub(crate) use libc::AF_UNIX;
81pub(crate) use libc::{AF_INET, AF_INET6};
82#[cfg(all(feature = "all", target_os = "linux"))]
84pub(crate) use libc::SOCK_DCCP;
85#[cfg(all(
86 feature = "all",
87 not(any(
88 target_os = "redox",
89 target_os = "espidf",
90 target_os = "wasi",
91 target_os = "horizon"
92 ))
93))]
94pub(crate) use libc::SOCK_RAW;
95#[cfg(all(
96 feature = "all",
97 not(any(target_os = "espidf", target_os = "wasi", target_os = "horizon"))
98))]
99pub(crate) use libc::SOCK_SEQPACKET;
100pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM};
101#[cfg(all(feature = "all", target_os = "linux"))]
103pub(crate) use libc::IPPROTO_DCCP;
104#[cfg(target_os = "linux")]
105pub(crate) use libc::IPPROTO_MPTCP;
106#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
107pub(crate) use libc::IPPROTO_SCTP;
108#[cfg(all(
109 feature = "all",
110 any(
111 target_os = "android",
112 target_os = "freebsd",
113 target_os = "fuchsia",
114 target_os = "linux",
115 )
116))]
117pub(crate) use libc::IPPROTO_UDPLITE;
118#[cfg(not(target_os = "wasi"))]
119pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6};
120pub(crate) use libc::{IPPROTO_TCP, IPPROTO_UDP};
121#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
123pub(crate) use libc::IPPROTO_DIVERT;
124pub(crate) use libc::{
125 sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t,
126};
127#[cfg(not(any(
129 target_os = "redox",
130 target_os = "espidf",
131 target_os = "wasi",
132 target_os = "horizon"
133)))]
134pub(crate) use libc::MSG_TRUNC;
135#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
136pub(crate) use libc::SO_OOBINLINE;
137#[cfg(not(any(target_os = "nto", target_os = "nuttx")))]
139pub(crate) use libc::ipv6_mreq as Ipv6Mreq;
140#[cfg(all(feature = "all", target_os = "linux"))]
141pub(crate) use libc::IPV6_HDRINCL;
142#[cfg(all(
143 feature = "all",
144 not(any(
145 target_os = "dragonfly",
146 target_os = "fuchsia",
147 target_os = "hurd",
148 target_os = "illumos",
149 target_os = "netbsd",
150 target_os = "openbsd",
151 target_os = "redox",
152 target_os = "solaris",
153 target_os = "haiku",
154 target_os = "espidf",
155 target_os = "vita",
156 target_os = "wasi",
157 target_os = "cygwin",
158 target_os = "horizon"
159 ))
160))]
161pub(crate) use libc::IPV6_RECVHOPLIMIT;
162#[cfg(not(any(
163 target_os = "dragonfly",
164 target_os = "fuchsia",
165 target_os = "hurd",
166 target_os = "illumos",
167 target_os = "netbsd",
168 target_os = "openbsd",
169 target_os = "redox",
170 target_os = "solaris",
171 target_os = "haiku",
172 target_os = "espidf",
173 target_os = "nuttx",
174 target_os = "vita",
175 target_os = "wasi",
176 target_os = "horizon"
177)))]
178pub(crate) use libc::IPV6_RECVTCLASS;
179#[cfg(all(
180 feature = "all",
181 not(any(
182 target_os = "redox",
183 target_os = "espidf",
184 target_os = "nuttx",
185 target_os = "wasi",
186 target_os = "horizon"
187 ))
188))]
189pub(crate) use libc::IP_HDRINCL;
190#[cfg(not(any(
191 target_os = "aix",
192 target_os = "dragonfly",
193 target_os = "fuchsia",
194 target_os = "illumos",
195 target_os = "netbsd",
196 target_os = "openbsd",
197 target_os = "redox",
198 target_os = "solaris",
199 target_os = "haiku",
200 target_os = "hurd",
201 target_os = "nto",
202 target_os = "espidf",
203 target_os = "nuttx",
204 target_os = "vita",
205 target_os = "wasi",
206 target_os = "cygwin",
207 target_os = "horizon"
208)))]
209pub(crate) use libc::IP_RECVTOS;
210#[cfg(not(any(
211 target_os = "fuchsia",
212 target_os = "redox",
213 target_os = "solaris",
214 target_os = "haiku",
215 target_os = "wasi",
216)))]
217pub(crate) use libc::IP_TOS;
218#[cfg(not(any(
219 target_os = "ios",
220 target_os = "visionos",
221 target_os = "macos",
222 target_os = "tvos",
223 target_os = "watchos",
224)))]
225pub(crate) use libc::SO_LINGER;
226#[cfg(any(
227 target_os = "ios",
228 target_os = "visionos",
229 target_os = "macos",
230 target_os = "tvos",
231 target_os = "watchos",
232))]
233pub(crate) use libc::SO_LINGER_SEC as SO_LINGER;
234#[cfg(any(target_os = "linux", target_os = "cygwin"))]
235pub(crate) use libc::SO_PASSCRED;
236#[cfg(all(
237 feature = "all",
238 any(target_os = "linux", target_os = "android", target_os = "fuchsia")
239))]
240pub(crate) use libc::SO_PRIORITY;
241pub(crate) use libc::{
242 ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS,
243 IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
244 IP_TTL, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO,
245 SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
246};
247#[cfg(not(any(
248 target_os = "dragonfly",
249 target_os = "haiku",
250 target_os = "hurd",
251 target_os = "netbsd",
252 target_os = "openbsd",
253 target_os = "redox",
254 target_os = "fuchsia",
255 target_os = "nto",
256 target_os = "espidf",
257 target_os = "vita",
258 target_os = "wasi",
259 target_os = "horizon"
260)))]
261pub(crate) use libc::{
262 ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
263};
264#[cfg(not(any(
265 target_os = "dragonfly",
266 target_os = "freebsd",
267 target_os = "haiku",
268 target_os = "illumos",
269 target_os = "ios",
270 target_os = "visionos",
271 target_os = "macos",
272 target_os = "netbsd",
273 target_os = "nto",
274 target_os = "openbsd",
275 target_os = "solaris",
276 target_os = "tvos",
277 target_os = "watchos",
278 target_os = "nuttx",
279 target_os = "wasi",
280)))]
281pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
282#[cfg(any(
283 target_os = "dragonfly",
284 target_os = "freebsd",
285 target_os = "haiku",
286 target_os = "illumos",
287 target_os = "ios",
288 target_os = "visionos",
289 target_os = "macos",
290 target_os = "netbsd",
291 target_os = "openbsd",
292 target_os = "solaris",
293 target_os = "tvos",
294 target_os = "watchos",
295 all(target_os = "wasi", not(target_env = "p1")),
296))]
297pub(crate) use libc::{
298 IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP,
299};
300#[cfg(not(target_os = "wasi"))]
301pub(crate) use libc::{IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IP_MULTICAST_IF, MSG_OOB};
302#[cfg(all(
303 feature = "all",
304 any(
305 target_os = "android",
306 target_os = "dragonfly",
307 target_os = "emscripten",
308 target_os = "freebsd",
309 target_os = "fuchsia",
310 target_os = "illumos",
311 target_os = "ios",
312 target_os = "visionos",
313 target_os = "linux",
314 target_os = "macos",
315 target_os = "netbsd",
316 target_os = "tvos",
317 target_os = "watchos",
318 target_os = "cygwin",
319 target_os = "nuttx",
320 all(target_os = "wasi", not(target_env = "p1")),
321 )
322))]
323pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
324
325pub(crate) type Bool = c_int;
327
328#[cfg(any(
329 target_os = "ios",
330 target_os = "visionos",
331 target_os = "macos",
332 all(target_os = "nto", any(target_env = "nto70", target_env = "nto71"),),
333 target_os = "tvos",
334 target_os = "watchos",
335))]
336use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
337#[cfg(not(any(
338 target_os = "haiku",
339 target_os = "ios",
340 target_os = "visionos",
341 target_os = "macos",
342 all(target_os = "nto", any(target_env = "nto70", target_env = "nto71"),),
343 target_os = "openbsd",
344 target_os = "tvos",
345 target_os = "watchos",
346 target_os = "vita",
347)))]
348use libc::TCP_KEEPIDLE as KEEPALIVE_TIME;
349
350macro_rules! syscall {
352 ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
353 #[allow(unused_unsafe)]
354 let res = unsafe { libc::$fn($($arg, )*) };
355 if res == -1 {
356 Err(std::io::Error::last_os_error())
357 } else {
358 Ok(res)
359 }
360 }};
361}
362
363#[cfg(not(any(
365 target_os = "ios",
366 target_os = "visionos",
367 target_os = "macos",
368 target_os = "tvos",
369 target_os = "watchos",
370 target_os = "cygwin",
371)))]
372const MAX_BUF_LEN: usize = ssize_t::MAX as usize;
373
374#[cfg(any(
383 target_os = "ios",
384 target_os = "visionos",
385 target_os = "macos",
386 target_os = "tvos",
387 target_os = "watchos",
388 target_os = "cygwin",
389))]
390const MAX_BUF_LEN: usize = c_int::MAX as usize - 1;
391
392#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
394const TCP_CA_NAME_MAX: usize = 16;
395
396#[cfg(any(
397 all(
398 target_os = "linux",
399 any(
400 target_env = "gnu",
401 all(target_env = "uclibc", target_pointer_width = "64")
402 )
403 ),
404 target_os = "android",
405))]
406type IovLen = usize;
407
408#[cfg(any(
409 all(
410 target_os = "linux",
411 any(
412 target_env = "musl",
413 target_env = "ohos",
414 all(target_env = "uclibc", target_pointer_width = "32")
415 )
416 ),
417 target_os = "aix",
418 target_os = "dragonfly",
419 target_os = "emscripten",
420 target_os = "freebsd",
421 target_os = "fuchsia",
422 target_os = "haiku",
423 target_os = "hurd",
424 target_os = "illumos",
425 target_os = "ios",
426 target_os = "visionos",
427 target_os = "macos",
428 target_os = "netbsd",
429 target_os = "nto",
430 target_os = "openbsd",
431 target_os = "solaris",
432 target_os = "tvos",
433 target_os = "watchos",
434 target_os = "espidf",
435 target_os = "vita",
436 target_os = "cygwin",
437))]
438type IovLen = c_int;
439#[cfg(target_os = "nuttx")]
440type IovLen = libc::c_ulong;
441
442impl Domain {
444 #[cfg(all(
446 feature = "all",
447 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
448 ))]
449 pub const PACKET: Domain = Domain(libc::AF_PACKET);
450
451 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
453 pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
454}
455
456impl_debug!(
457 Domain,
458 libc::AF_INET,
459 libc::AF_INET6,
460 #[cfg(not(target_os = "wasi"))]
461 libc::AF_UNIX,
462 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
463 libc::AF_PACKET,
464 #[cfg(any(target_os = "android", target_os = "linux"))]
465 libc::AF_VSOCK,
466 libc::AF_UNSPEC, );
468
469impl Type {
471 #[cfg(all(
473 feature = "all",
474 any(
475 target_os = "android",
476 target_os = "dragonfly",
477 target_os = "emscripten",
478 target_os = "freebsd",
479 target_os = "fuchsia",
480 target_os = "illumos",
481 target_os = "linux",
482 target_os = "netbsd",
483 target_os = "openbsd",
484 target_os = "cygwin",
485 all(target_os = "wasi", not(target_env = "p1")),
486 )
487 ))]
488 pub const fn nonblocking(self) -> Type {
489 Type(self.0 | libc::SOCK_NONBLOCK)
490 }
491
492 #[cfg(all(
494 feature = "all",
495 any(
496 target_os = "android",
497 target_os = "dragonfly",
498 target_os = "emscripten",
499 target_os = "freebsd",
500 target_os = "fuchsia",
501 target_os = "hurd",
502 target_os = "illumos",
503 target_os = "linux",
504 target_os = "netbsd",
505 target_os = "openbsd",
506 target_os = "redox",
507 target_os = "solaris",
508 target_os = "cygwin",
509 )
510 ))]
511 pub const fn cloexec(self) -> Type {
512 self._cloexec()
513 }
514
515 #[cfg(any(
516 target_os = "android",
517 target_os = "dragonfly",
518 target_os = "emscripten",
519 target_os = "freebsd",
520 target_os = "fuchsia",
521 target_os = "hurd",
522 target_os = "illumos",
523 target_os = "linux",
524 target_os = "netbsd",
525 target_os = "openbsd",
526 target_os = "redox",
527 target_os = "solaris",
528 target_os = "cygwin",
529 ))]
530 pub(crate) const fn _cloexec(self) -> Type {
531 Type(self.0 | libc::SOCK_CLOEXEC)
532 }
533}
534
535impl_debug!(
536 Type,
537 libc::SOCK_STREAM,
538 libc::SOCK_DGRAM,
539 #[cfg(all(feature = "all", target_os = "linux"))]
540 libc::SOCK_DCCP,
541 #[cfg(not(any(
542 target_os = "redox",
543 target_os = "espidf",
544 target_os = "wasi",
545 target_os = "horizon"
546 )))]
547 libc::SOCK_RAW,
548 #[cfg(not(any(
549 target_os = "redox",
550 target_os = "haiku",
551 target_os = "espidf",
552 target_os = "wasi",
553 target_os = "horizon"
554 )))]
555 libc::SOCK_RDM,
556 #[cfg(not(any(target_os = "espidf", target_os = "wasi", target_os = "horizon")))]
557 libc::SOCK_SEQPACKET,
558 );
581
582impl_debug!(
583 Protocol,
584 #[cfg(not(target_os = "wasi"))]
585 libc::IPPROTO_ICMP,
586 #[cfg(not(target_os = "wasi"))]
587 libc::IPPROTO_ICMPV6,
588 libc::IPPROTO_TCP,
589 libc::IPPROTO_UDP,
590 #[cfg(target_os = "linux")]
591 libc::IPPROTO_MPTCP,
592 #[cfg(all(feature = "all", target_os = "linux"))]
593 libc::IPPROTO_DCCP,
594 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
595 libc::IPPROTO_SCTP,
596 #[cfg(all(
597 feature = "all",
598 any(
599 target_os = "android",
600 target_os = "freebsd",
601 target_os = "fuchsia",
602 target_os = "linux",
603 )
604 ))]
605 libc::IPPROTO_UDPLITE,
606 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
607 libc::IPPROTO_DIVERT,
608);
609
610#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
612impl RecvFlags {
613 #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
623 pub const fn is_end_of_record(self) -> bool {
624 self.0 & libc::MSG_EOR != 0
625 }
626
627 pub const fn is_out_of_band(self) -> bool {
634 self.0 & libc::MSG_OOB != 0
635 }
636
637 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
645 pub const fn is_confirm(self) -> bool {
646 self.0 & libc::MSG_CONFIRM != 0
647 }
648
649 #[cfg(all(
656 feature = "all",
657 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
658 ))]
659 pub const fn is_dontroute(self) -> bool {
660 self.0 & libc::MSG_DONTROUTE != 0
661 }
662}
663
664#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
665impl std::fmt::Debug for RecvFlags {
666 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
667 let mut s = f.debug_struct("RecvFlags");
668 #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
669 s.field("is_end_of_record", &self.is_end_of_record());
670 s.field("is_out_of_band", &self.is_out_of_band());
671 #[cfg(not(target_os = "espidf"))]
672 s.field("is_truncated", &self.is_truncated());
673 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
674 s.field("is_confirm", &self.is_confirm());
675 #[cfg(all(
676 feature = "all",
677 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
678 ))]
679 s.field("is_dontroute", &self.is_dontroute());
680 s.finish()
681 }
682}
683
684#[repr(transparent)]
685pub struct MaybeUninitSlice<'a> {
686 vec: libc::iovec,
687 _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
688}
689
690unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
691
692unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
693
694impl<'a> MaybeUninitSlice<'a> {
695 pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
696 MaybeUninitSlice {
697 vec: libc::iovec {
698 iov_base: buf.as_mut_ptr().cast(),
699 iov_len: buf.len(),
700 },
701 _lifetime: PhantomData,
702 }
703 }
704
705 pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
706 unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
707 }
708
709 pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
710 unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
711 }
712}
713
714#[cfg(not(target_os = "wasi"))]
716pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize {
717 let base = storage as *const _ as usize;
718 let path = ptr::addr_of!(storage.sun_path) as usize;
719 path - base
720}
721
722#[cfg(not(target_os = "wasi"))]
723#[allow(unsafe_op_in_unsafe_fn)]
724pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
725 let mut storage = SockAddrStorage::zeroed();
726 let len = {
727 let storage = unsafe { storage.view_as::<libc::sockaddr_un>() };
729
730 let bytes = path.as_os_str().as_bytes();
731 let too_long = match bytes.first() {
732 None => false,
733 Some(&0) => bytes.len() > storage.sun_path.len(),
735 Some(_) => bytes.len() >= storage.sun_path.len(),
736 };
737 if too_long {
738 return Err(io::Error::new(
739 io::ErrorKind::InvalidInput,
740 "path must be shorter than SUN_LEN",
741 ));
742 }
743
744 storage.sun_family = libc::AF_UNIX as sa_family_t;
745 unsafe {
750 ptr::copy_nonoverlapping(
751 bytes.as_ptr(),
752 storage.sun_path.as_mut_ptr().cast(),
753 bytes.len(),
754 );
755 }
756
757 let sun_path_offset = offset_of_path(storage);
758 sun_path_offset
759 + bytes.len()
760 + match bytes.first() {
761 Some(&0) | None => 0,
762 Some(_) => 1,
763 }
764 };
765 Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
766}
767
768#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
770pub(crate) use libc::msghdr;
771
772#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
773pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
774 msg.msg_name = name.as_ptr() as *mut _;
775 msg.msg_namelen = name.len();
776}
777
778#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
779#[allow(clippy::unnecessary_cast)] pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) {
781 msg.msg_iov = ptr;
782 msg.msg_iovlen = min(len, IovLen::MAX as usize) as IovLen;
783}
784
785#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
786pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) {
787 msg.msg_control = ptr;
788 msg.msg_controllen = len as _;
789}
790
791#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
792pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: c_int) {
793 msg.msg_flags = flags;
794}
795
796#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
797pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
798 RecvFlags(msg.msg_flags)
799}
800
801#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
802pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
803 msg.msg_controllen as _
804}
805
806impl SockAddr {
808 #[allow(unsafe_op_in_unsafe_fn)]
815 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
816 pub fn vsock(cid: u32, port: u32) -> SockAddr {
817 let mut storage = SockAddrStorage::zeroed();
818 {
819 let storage = unsafe { storage.view_as::<libc::sockaddr_vm>() };
821 storage.svm_family = libc::AF_VSOCK as sa_family_t;
822 storage.svm_cid = cid;
823 storage.svm_port = port;
824 }
825 unsafe { SockAddr::new(storage, mem::size_of::<libc::sockaddr_vm>() as socklen_t) }
826 }
827
828 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
831 pub fn as_vsock_address(&self) -> Option<(u32, u32)> {
832 if self.family() == libc::AF_VSOCK as sa_family_t {
833 let addr = unsafe { &*(self.as_ptr() as *const libc::sockaddr_vm) };
835 Some((addr.svm_cid, addr.svm_port))
836 } else {
837 None
838 }
839 }
840}
841
842#[cfg(not(target_os = "wasi"))]
844impl SockAddr {
845 pub fn is_unnamed(&self) -> bool {
848 self.as_sockaddr_un()
849 .map(|storage| {
850 self.len() == offset_of_path(storage) as _
851 || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))
856 && storage.sun_path[0] == 0)
857 })
858 .unwrap_or_default()
859 }
860
861 pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> {
864 self.is_unix().then(|| {
865 unsafe { &*self.as_ptr().cast::<libc::sockaddr_un>() }
868 })
869 }
870
871 fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
876 debug_assert!(!self.is_unnamed());
877 self.len() as usize - offset_of_path(storage) - 1
878 }
879
880 fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] {
884 debug_assert!(!self.is_unnamed());
885 unsafe {
893 slice::from_raw_parts(
894 (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize),
895 self.path_len(storage),
896 )
897 }
898 }
899
900 pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
903 let path = self.as_pathname()?;
904 Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
907 }
908
909 pub fn as_pathname(&self) -> Option<&Path> {
912 self.as_sockaddr_un().and_then(|storage| {
913 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] != 0).then(|| {
914 let path_slice = self.path_bytes(storage, false);
915 Path::new::<OsStr>(OsStrExt::from_bytes(path_slice))
916 })
917 })
918 }
919
920 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
926 #[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
929 {
930 self.as_sockaddr_un().and_then(|storage| {
931 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] == 0)
932 .then(|| self.path_bytes(storage, true))
933 })
934 }
935 #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))]
936 None
937 }
938}
939
940pub(crate) type Socket = std::os::fd::OwnedFd;
941pub(crate) type RawSocket = c_int;
942
943pub(crate) unsafe fn socket_from_raw(socket: RawSocket) -> Socket {
944 Socket::from_raw_fd(socket)
945}
946
947pub(crate) fn socket_as_raw(socket: &Socket) -> RawSocket {
948 socket.as_raw_fd()
949}
950
951pub(crate) fn socket_into_raw(socket: Socket) -> RawSocket {
952 socket.into_raw_fd()
953}
954
955pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<RawSocket> {
956 syscall!(socket(family, ty, protocol))
957}
958
959#[cfg(all(feature = "all", unix))]
960pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[RawSocket; 2]> {
961 let mut fds = [0, 0];
962 syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds)
963}
964
965pub(crate) fn bind(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
966 syscall!(bind(fd, addr.as_ptr().cast::<sockaddr>(), addr.len() as _)).map(|_| ())
967}
968
969pub(crate) fn connect(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
970 syscall!(connect(fd, addr.as_ptr().cast::<sockaddr>(), addr.len())).map(|_| ())
971}
972
973pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
974 let start = Instant::now();
975
976 let mut pollfd = libc::pollfd {
977 fd: socket.as_raw(),
978 events: libc::POLLIN | libc::POLLOUT,
979 revents: 0,
980 };
981
982 loop {
983 let elapsed = start.elapsed();
984 if elapsed >= timeout {
985 return Err(io::ErrorKind::TimedOut.into());
986 }
987
988 let timeout = (timeout - elapsed).as_millis();
989 let timeout = timeout.clamp(1, c_int::MAX as u128) as c_int;
990
991 match syscall!(poll(&mut pollfd, 1, timeout)) {
992 Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
993 Ok(_) => {
994 if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0 {
996 match socket.take_error() {
997 Ok(Some(err)) | Err(err) => return Err(err),
998 Ok(None) => {
999 return Err(io::Error::new(
1000 io::ErrorKind::Other,
1001 "no error set after POLLHUP",
1002 ))
1003 }
1004 }
1005 }
1006 return Ok(());
1007 }
1008 Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
1010 Err(err) => return Err(err),
1011 }
1012 }
1013}
1014
1015pub(crate) fn listen(fd: RawSocket, backlog: c_int) -> io::Result<()> {
1016 syscall!(listen(fd, backlog)).map(|_| ())
1017}
1018
1019pub(crate) fn accept(fd: RawSocket) -> io::Result<(RawSocket, SockAddr)> {
1020 unsafe { SockAddr::try_init(|storage, len| syscall!(accept(fd, storage.cast(), len))) }
1022}
1023
1024pub(crate) fn getsockname(fd: RawSocket) -> io::Result<SockAddr> {
1025 unsafe { SockAddr::try_init(|storage, len| syscall!(getsockname(fd, storage.cast(), len))) }
1027 .map(|(_, addr)| addr)
1028}
1029
1030pub(crate) fn getpeername(fd: RawSocket) -> io::Result<SockAddr> {
1031 unsafe { SockAddr::try_init(|storage, len| syscall!(getpeername(fd, storage.cast(), len))) }
1033 .map(|(_, addr)| addr)
1034}
1035
1036#[cfg(not(target_os = "wasi"))]
1037pub(crate) fn try_clone(fd: RawSocket) -> io::Result<RawSocket> {
1038 syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0))
1039}
1040
1041#[cfg(all(
1042 feature = "all",
1043 any(unix, all(target_os = "wasi", not(target_env = "p1"))),
1044 not(target_os = "vita")
1045))]
1046pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
1047 let file_status_flags = fcntl_get(fd, libc::F_GETFL)?;
1048 Ok((file_status_flags & libc::O_NONBLOCK) != 0)
1049}
1050
1051#[cfg(all(feature = "all", target_os = "vita"))]
1052pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
1053 unsafe {
1054 getsockopt::<Bool>(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK).map(|non_block| non_block != 0)
1055 }
1056}
1057
1058#[cfg(not(target_os = "vita"))]
1059pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::Result<()> {
1060 if nonblocking {
1061 fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1062 } else {
1063 fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1064 }
1065}
1066
1067#[cfg(target_os = "vita")]
1068pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::Result<()> {
1069 unsafe {
1070 setsockopt(
1071 fd,
1072 libc::SOL_SOCKET,
1073 libc::SO_NONBLOCK,
1074 nonblocking as c_int,
1075 )
1076 }
1077}
1078
1079pub(crate) fn shutdown(fd: RawSocket, how: Shutdown) -> io::Result<()> {
1080 let how = match how {
1081 Shutdown::Write => libc::SHUT_WR,
1082 Shutdown::Read => libc::SHUT_RD,
1083 Shutdown::Both => libc::SHUT_RDWR,
1084 };
1085 syscall!(shutdown(fd, how)).map(|_| ())
1086}
1087
1088pub(crate) fn recv(fd: RawSocket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
1089 syscall!(recv(
1090 fd,
1091 buf.as_mut_ptr().cast(),
1092 min(buf.len(), MAX_BUF_LEN),
1093 flags,
1094 ))
1095 .map(|n| n as usize)
1096}
1097
1098pub(crate) fn recv_from(
1099 fd: RawSocket,
1100 buf: &mut [MaybeUninit<u8>],
1101 flags: c_int,
1102) -> io::Result<(usize, SockAddr)> {
1103 unsafe {
1105 SockAddr::try_init(|addr, addrlen| {
1106 syscall!(recvfrom(
1107 fd,
1108 buf.as_mut_ptr().cast(),
1109 min(buf.len(), MAX_BUF_LEN),
1110 flags,
1111 addr.cast(),
1112 addrlen
1113 ))
1114 .map(|n| n as usize)
1115 })
1116 }
1117}
1118
1119pub(crate) fn peek_sender(fd: RawSocket) -> io::Result<SockAddr> {
1120 let (_, sender) = recv_from(fd, &mut [MaybeUninit::uninit(); 8], MSG_PEEK)?;
1125 Ok(sender)
1126}
1127
1128#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1129pub(crate) fn recv_vectored(
1130 fd: RawSocket,
1131 bufs: &mut [crate::MaybeUninitSlice<'_>],
1132 flags: c_int,
1133) -> io::Result<(usize, RecvFlags)> {
1134 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1135 let n = recvmsg(fd, &mut msg, flags)?;
1136 Ok((n, msg.flags()))
1137}
1138
1139#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1140pub(crate) fn recv_from_vectored(
1141 fd: RawSocket,
1142 bufs: &mut [crate::MaybeUninitSlice<'_>],
1143 flags: c_int,
1144) -> io::Result<(usize, RecvFlags, SockAddr)> {
1145 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1146 let (n, addr) = unsafe {
1149 SockAddr::try_init(|storage, len| {
1150 msg.inner.msg_name = storage.cast();
1151 msg.inner.msg_namelen = *len;
1152 let n = recvmsg(fd, &mut msg, flags)?;
1153 *len = msg.inner.msg_namelen;
1155 Ok(n)
1156 })?
1157 };
1158 Ok((n, msg.flags(), addr))
1159}
1160
1161#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1162pub(crate) fn recvmsg(
1163 fd: RawSocket,
1164 msg: &mut MsgHdrMut<'_, '_, '_>,
1165 flags: c_int,
1166) -> io::Result<usize> {
1167 syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|n| n as usize)
1168}
1169
1170pub(crate) fn send(fd: RawSocket, buf: &[u8], flags: c_int) -> io::Result<usize> {
1171 syscall!(send(
1172 fd,
1173 buf.as_ptr().cast(),
1174 min(buf.len(), MAX_BUF_LEN),
1175 flags,
1176 ))
1177 .map(|n| n as usize)
1178}
1179
1180#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1181pub(crate) fn send_vectored(
1182 fd: RawSocket,
1183 bufs: &[IoSlice<'_>],
1184 flags: c_int,
1185) -> io::Result<usize> {
1186 let msg = MsgHdr::new().with_buffers(bufs);
1187 sendmsg(fd, &msg, flags)
1188}
1189
1190pub(crate) fn send_to(
1191 fd: RawSocket,
1192 buf: &[u8],
1193 addr: &SockAddr,
1194 flags: c_int,
1195) -> io::Result<usize> {
1196 syscall!(sendto(
1197 fd,
1198 buf.as_ptr().cast(),
1199 min(buf.len(), MAX_BUF_LEN),
1200 flags,
1201 addr.as_ptr().cast::<sockaddr>(),
1202 addr.len(),
1203 ))
1204 .map(|n| n as usize)
1205}
1206
1207#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1208pub(crate) fn send_to_vectored(
1209 fd: RawSocket,
1210 bufs: &[IoSlice<'_>],
1211 addr: &SockAddr,
1212 flags: c_int,
1213) -> io::Result<usize> {
1214 let msg = MsgHdr::new().with_addr(addr).with_buffers(bufs);
1215 sendmsg(fd, &msg, flags)
1216}
1217
1218#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
1219pub(crate) fn sendmsg(fd: RawSocket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
1220 syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
1221}
1222
1223pub(crate) fn timeout_opt(fd: RawSocket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
1225 unsafe { getsockopt(fd, opt, val).map(from_timeval) }
1226}
1227
1228const fn from_timeval(duration: libc::timeval) -> Option<Duration> {
1229 if duration.tv_sec == 0 && duration.tv_usec == 0 {
1230 None
1231 } else {
1232 let sec = duration.tv_sec as u64;
1233 let nsec = (duration.tv_usec as u32) * 1000;
1234 Some(Duration::new(sec, nsec))
1235 }
1236}
1237
1238pub(crate) fn set_timeout_opt(
1240 fd: RawSocket,
1241 opt: c_int,
1242 val: c_int,
1243 duration: Option<Duration>,
1244) -> io::Result<()> {
1245 let duration = into_timeval(duration);
1246 unsafe { setsockopt(fd, opt, val, duration) }
1247}
1248
1249fn into_timeval(duration: Option<Duration>) -> libc::timeval {
1250 match duration {
1251 #[cfg_attr(target_env = "musl", allow(deprecated))]
1253 Some(duration) => libc::timeval {
1254 tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
1255 tv_usec: duration.subsec_micros() as libc::suseconds_t,
1256 },
1257 None => libc::timeval {
1258 tv_sec: 0,
1259 tv_usec: 0,
1260 },
1261 }
1262}
1263
1264#[cfg(all(
1265 feature = "all",
1266 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1267))]
1268pub(crate) fn tcp_keepalive_time(fd: RawSocket) -> io::Result<Duration> {
1269 unsafe {
1270 getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
1271 .map(|secs| Duration::from_secs(secs as u64))
1272 }
1273}
1274
1275#[allow(unused_variables)]
1276pub(crate) fn set_tcp_keepalive(fd: RawSocket, keepalive: &TcpKeepalive) -> io::Result<()> {
1277 #[cfg(not(any(
1278 target_os = "haiku",
1279 target_os = "openbsd",
1280 target_os = "nto",
1281 target_os = "vita"
1282 )))]
1283 if let Some(time) = keepalive.time {
1284 let secs = into_secs(time);
1285 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1286 }
1287
1288 #[cfg(any(
1289 target_os = "aix",
1290 target_os = "android",
1291 target_os = "dragonfly",
1292 target_os = "emscripten",
1293 target_os = "freebsd",
1294 target_os = "fuchsia",
1295 target_os = "hurd",
1296 target_os = "illumos",
1297 target_os = "ios",
1298 target_os = "visionos",
1299 target_os = "linux",
1300 target_os = "macos",
1301 target_os = "netbsd",
1302 target_os = "tvos",
1303 target_os = "watchos",
1304 target_os = "cygwin",
1305 target_os = "nuttx",
1306 all(target_os = "wasi", not(target_env = "p1")),
1307 ))]
1308 {
1309 if let Some(interval) = keepalive.interval {
1310 let secs = into_secs(interval);
1311 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
1312 }
1313
1314 if let Some(retries) = keepalive.retries {
1315 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
1316 }
1317 }
1318
1319 #[cfg(target_os = "nto")]
1320 if let Some(time) = keepalive.time {
1321 let secs = into_timeval(Some(time));
1322 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1323 }
1324
1325 Ok(())
1326}
1327
1328#[cfg(not(any(
1329 target_os = "haiku",
1330 target_os = "openbsd",
1331 target_os = "nto",
1332 target_os = "vita"
1333)))]
1334fn into_secs(duration: Duration) -> c_int {
1335 min(duration.as_secs(), c_int::MAX as u64) as c_int
1336}
1337
1338#[cfg(not(target_os = "vita"))]
1340fn fcntl_get(fd: RawSocket, cmd: c_int) -> io::Result<c_int> {
1341 syscall!(fcntl(fd, cmd))
1342}
1343
1344#[cfg(not(target_os = "vita"))]
1346fn fcntl_add(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1347 let previous = fcntl_get(fd, get_cmd)?;
1348 let new = previous | flag;
1349 if new != previous {
1350 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1351 } else {
1352 Ok(())
1354 }
1355}
1356
1357#[cfg(not(target_os = "vita"))]
1359fn fcntl_remove(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1360 let previous = fcntl_get(fd, get_cmd)?;
1361 let new = previous & !flag;
1362 if new != previous {
1363 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1364 } else {
1365 Ok(())
1367 }
1368}
1369
1370pub(crate) unsafe fn getsockopt<T>(fd: RawSocket, opt: c_int, val: c_int) -> io::Result<T> {
1372 let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
1373 let mut len = size_of::<T>() as libc::socklen_t;
1374 syscall!(getsockopt(
1375 fd,
1376 opt,
1377 val,
1378 payload.as_mut_ptr().cast(),
1379 &mut len,
1380 ))
1381 .map(|_| {
1382 debug_assert_eq!(len as usize, size_of::<T>());
1383 payload.assume_init()
1385 })
1386}
1387
1388pub(crate) unsafe fn setsockopt<T>(
1390 fd: RawSocket,
1391 opt: c_int,
1392 val: c_int,
1393 payload: T,
1394) -> io::Result<()> {
1395 let payload = ptr::addr_of!(payload).cast();
1396 syscall!(setsockopt(
1397 fd,
1398 opt,
1399 val,
1400 payload,
1401 mem::size_of::<T>() as libc::socklen_t,
1402 ))
1403 .map(|_| ())
1404}
1405
1406pub(crate) const fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
1407 in_addr {
1411 s_addr: u32::from_ne_bytes(addr.octets()),
1412 }
1413}
1414
1415pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
1416 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1417}
1418
1419pub(crate) const fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
1420 in6_addr {
1421 s6_addr: addr.octets(),
1422 }
1423}
1424
1425pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
1426 Ipv6Addr::from(addr.s6_addr)
1427}
1428
1429#[cfg(not(any(
1430 target_os = "aix",
1431 target_os = "haiku",
1432 target_os = "illumos",
1433 target_os = "netbsd",
1434 target_os = "openbsd",
1435 target_os = "redox",
1436 target_os = "solaris",
1437 target_os = "nto",
1438 target_os = "espidf",
1439 target_os = "vita",
1440 target_os = "cygwin",
1441 target_os = "wasi",
1442 target_os = "horizon"
1443)))]
1444pub(crate) const fn to_mreqn(
1445 multiaddr: &Ipv4Addr,
1446 interface: &crate::socket::InterfaceIndexOrAddress,
1447) -> libc::ip_mreqn {
1448 match interface {
1449 crate::socket::InterfaceIndexOrAddress::Index(interface) => libc::ip_mreqn {
1450 imr_multiaddr: to_in_addr(multiaddr),
1451 imr_address: to_in_addr(&Ipv4Addr::UNSPECIFIED),
1452 imr_ifindex: *interface as _,
1453 },
1454 crate::socket::InterfaceIndexOrAddress::Address(interface) => libc::ip_mreqn {
1455 imr_multiaddr: to_in_addr(multiaddr),
1456 imr_address: to_in_addr(interface),
1457 imr_ifindex: 0,
1458 },
1459 }
1460}
1461
1462#[cfg(all(
1463 feature = "all",
1464 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1465))]
1466pub(crate) fn original_dst_v4(fd: RawSocket) -> io::Result<SockAddr> {
1467 unsafe {
1469 SockAddr::try_init(|storage, len| {
1470 syscall!(getsockopt(
1471 fd,
1472 libc::SOL_IP,
1473 libc::SO_ORIGINAL_DST,
1474 storage.cast(),
1475 len
1476 ))
1477 })
1478 }
1479 .map(|(_, addr)| addr)
1480}
1481
1482#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1487pub(crate) fn original_dst_v6(fd: RawSocket) -> io::Result<SockAddr> {
1488 unsafe {
1490 SockAddr::try_init(|storage, len| {
1491 syscall!(getsockopt(
1492 fd,
1493 libc::SOL_IPV6,
1494 libc::IP6T_SO_ORIGINAL_DST,
1495 storage.cast(),
1496 len
1497 ))
1498 })
1499 }
1500 .map(|(_, addr)| addr)
1501}
1502
1503impl crate::Socket {
1505 #[doc = man_links!(unix: accept4(2))]
1513 #[cfg(all(
1514 feature = "all",
1515 any(
1516 target_os = "android",
1517 target_os = "dragonfly",
1518 target_os = "freebsd",
1519 target_os = "fuchsia",
1520 target_os = "illumos",
1521 target_os = "linux",
1522 target_os = "netbsd",
1523 target_os = "openbsd",
1524 target_os = "cygwin",
1525 )
1526 ))]
1527 pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1528 self._accept4(flags)
1529 }
1530
1531 #[cfg(any(
1532 target_os = "android",
1533 target_os = "dragonfly",
1534 target_os = "freebsd",
1535 target_os = "fuchsia",
1536 target_os = "illumos",
1537 target_os = "linux",
1538 target_os = "netbsd",
1539 target_os = "openbsd",
1540 target_os = "cygwin",
1541 ))]
1542 pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1543 unsafe {
1545 SockAddr::try_init(|storage, len| {
1546 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1547 .map(crate::Socket::from_raw)
1548 })
1549 }
1550 }
1551
1552 #[cfg_attr(
1558 any(
1559 target_os = "ios",
1560 target_os = "visionos",
1561 target_os = "macos",
1562 target_os = "tvos",
1563 target_os = "watchos",
1564 target_os = "wasi",
1565 target_os = "horizon"
1566 ),
1567 allow(rustdoc::broken_intra_doc_links)
1568 )]
1569 #[cfg(all(feature = "all", not(target_os = "vita")))]
1570 pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1571 self._set_cloexec(close_on_exec)
1572 }
1573
1574 #[cfg(not(target_os = "vita"))]
1575 pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1576 if close_on_exec {
1577 fcntl_add(
1578 self.as_raw(),
1579 libc::F_GETFD,
1580 libc::F_SETFD,
1581 libc::FD_CLOEXEC,
1582 )
1583 } else {
1584 fcntl_remove(
1585 self.as_raw(),
1586 libc::F_GETFD,
1587 libc::F_SETFD,
1588 libc::FD_CLOEXEC,
1589 )
1590 }
1591 }
1592
1593 #[cfg(target_os = "cygwin")]
1606 #[cfg(any(doc, target_os = "cygwin"))]
1607 pub fn set_no_peercred(&self) -> io::Result<()> {
1608 syscall!(setsockopt(
1609 self.as_raw(),
1610 libc::SOL_SOCKET,
1611 libc::SO_PEERCRED,
1612 ptr::null_mut(),
1613 0,
1614 ))
1615 .map(|_| ())
1616 }
1617
1618 #[cfg(all(
1620 feature = "all",
1621 any(
1622 target_os = "ios",
1623 target_os = "visionos",
1624 target_os = "macos",
1625 target_os = "tvos",
1626 target_os = "watchos",
1627 )
1628 ))]
1629 pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1630 self._set_nosigpipe(nosigpipe)
1631 }
1632
1633 #[cfg(any(
1634 target_os = "ios",
1635 target_os = "visionos",
1636 target_os = "macos",
1637 target_os = "tvos",
1638 target_os = "watchos",
1639 ))]
1640 pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1641 unsafe {
1642 setsockopt(
1643 self.as_raw(),
1644 libc::SOL_SOCKET,
1645 libc::SO_NOSIGPIPE,
1646 nosigpipe as c_int,
1647 )
1648 }
1649 }
1650
1651 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))]
1657 pub fn tcp_mss(&self) -> io::Result<u32> {
1658 unsafe {
1659 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1660 .map(|mss| mss as u32)
1661 }
1662 }
1663
1664 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))]
1669 pub fn set_tcp_mss(&self, mss: u32) -> io::Result<()> {
1670 unsafe {
1671 setsockopt(
1672 self.as_raw(),
1673 libc::IPPROTO_TCP,
1674 libc::TCP_MAXSEG,
1675 mss as c_int,
1676 )
1677 }
1678 }
1679
1680 #[cfg(all(
1683 feature = "all",
1684 any(
1685 target_os = "aix",
1686 target_os = "android",
1687 target_os = "freebsd",
1688 target_os = "fuchsia",
1689 target_os = "linux",
1690 target_os = "cygwin",
1691 )
1692 ))]
1693 pub fn is_listener(&self) -> io::Result<bool> {
1694 unsafe {
1695 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1696 .map(|v| v != 0)
1697 }
1698 }
1699
1700 #[cfg(all(
1703 feature = "all",
1704 any(
1705 target_os = "android",
1706 target_os = "fuchsia",
1709 target_os = "linux",
1710 )
1711 ))]
1712 pub fn domain(&self) -> io::Result<Domain> {
1713 unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1714 }
1715
1716 #[cfg(all(
1719 feature = "all",
1720 any(
1721 target_os = "android",
1722 target_os = "freebsd",
1723 target_os = "fuchsia",
1724 target_os = "linux",
1725 )
1726 ))]
1727 pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1728 unsafe {
1729 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1730 {
1731 0 => None,
1732 p => Some(Protocol(p)),
1733 })
1734 }
1735 }
1736
1737 #[cfg(all(
1744 feature = "all",
1745 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1746 ))]
1747 pub fn mark(&self) -> io::Result<u32> {
1748 unsafe {
1749 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1750 .map(|mark| mark as u32)
1751 }
1752 }
1753
1754 #[cfg(all(
1762 feature = "all",
1763 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1764 ))]
1765 pub fn set_mark(&self, mark: u32) -> io::Result<()> {
1766 unsafe {
1767 setsockopt::<c_int>(
1768 self.as_raw(),
1769 libc::SOL_SOCKET,
1770 libc::SO_MARK,
1771 mark as c_int,
1772 )
1773 }
1774 }
1775
1776 #[cfg(all(
1782 feature = "all",
1783 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1784 ))]
1785 pub fn tcp_cork(&self) -> io::Result<bool> {
1786 unsafe {
1787 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK)
1788 .map(|cork| cork != 0)
1789 }
1790 }
1791
1792 #[cfg(all(
1799 feature = "all",
1800 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1801 ))]
1802 pub fn set_tcp_cork(&self, cork: bool) -> io::Result<()> {
1803 unsafe {
1804 setsockopt(
1805 self.as_raw(),
1806 libc::IPPROTO_TCP,
1807 libc::TCP_CORK,
1808 cork as c_int,
1809 )
1810 }
1811 }
1812
1813 #[cfg(all(
1819 feature = "all",
1820 any(
1821 target_os = "android",
1822 target_os = "fuchsia",
1823 target_os = "linux",
1824 target_os = "cygwin",
1825 )
1826 ))]
1827 pub fn tcp_quickack(&self) -> io::Result<bool> {
1828 unsafe {
1829 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK)
1830 .map(|quickack| quickack != 0)
1831 }
1832 }
1833
1834 #[cfg(all(
1841 feature = "all",
1842 any(
1843 target_os = "android",
1844 target_os = "fuchsia",
1845 target_os = "linux",
1846 target_os = "cygwin",
1847 )
1848 ))]
1849 pub fn set_tcp_quickack(&self, quickack: bool) -> io::Result<()> {
1850 unsafe {
1851 setsockopt(
1852 self.as_raw(),
1853 libc::IPPROTO_TCP,
1854 libc::TCP_QUICKACK,
1855 quickack as c_int,
1856 )
1857 }
1858 }
1859
1860 #[cfg(all(
1866 feature = "all",
1867 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1868 ))]
1869 pub fn tcp_thin_linear_timeouts(&self) -> io::Result<bool> {
1870 unsafe {
1871 getsockopt::<Bool>(
1872 self.as_raw(),
1873 libc::IPPROTO_TCP,
1874 libc::TCP_THIN_LINEAR_TIMEOUTS,
1875 )
1876 .map(|timeouts| timeouts != 0)
1877 }
1878 }
1879
1880 #[cfg(all(
1886 feature = "all",
1887 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1888 ))]
1889 pub fn set_tcp_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> {
1890 unsafe {
1891 setsockopt(
1892 self.as_raw(),
1893 libc::IPPROTO_TCP,
1894 libc::TCP_THIN_LINEAR_TIMEOUTS,
1895 timeouts as c_int,
1896 )
1897 }
1898 }
1899
1900 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1906 pub fn tcp_notsent_lowat(&self) -> io::Result<u32> {
1907 unsafe {
1908 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_NOTSENT_LOWAT)
1909 .map(|lowat| lowat as u32)
1910 }
1911 }
1912
1913 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1918 pub fn set_tcp_notsent_lowat(&self, lowat: u32) -> io::Result<()> {
1919 unsafe {
1920 setsockopt(
1921 self.as_raw(),
1922 libc::IPPROTO_TCP,
1923 libc::TCP_NOTSENT_LOWAT,
1924 lowat as c_int,
1925 )
1926 }
1927 }
1928
1929 #[cfg(all(
1933 feature = "all",
1934 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1935 ))]
1936 pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1937 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1939 unsafe { MaybeUninit::uninit().assume_init() };
1940 let mut len = buf.len() as libc::socklen_t;
1941 syscall!(getsockopt(
1942 self.as_raw(),
1943 libc::SOL_SOCKET,
1944 libc::SO_BINDTODEVICE,
1945 buf.as_mut_ptr().cast(),
1946 &mut len,
1947 ))?;
1948 if len == 0 {
1949 Ok(None)
1950 } else {
1951 let buf = &buf[..len as usize - 1];
1952 Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
1954 }
1955 }
1956
1957 #[cfg(all(
1965 feature = "all",
1966 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1967 ))]
1968 pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
1969 let (value, len) = if let Some(interface) = interface {
1970 (interface.as_ptr(), interface.len())
1971 } else {
1972 (ptr::null(), 0)
1973 };
1974 syscall!(setsockopt(
1975 self.as_raw(),
1976 libc::SOL_SOCKET,
1977 libc::SO_BINDTODEVICE,
1978 value.cast(),
1979 len as libc::socklen_t,
1980 ))
1981 .map(|_| ())
1982 }
1983
1984 #[cfg(all(feature = "all", target_os = "freebsd"))]
1988 pub fn set_fib(&self, fib: u32) -> io::Result<()> {
1989 syscall!(setsockopt(
1990 self.as_raw(),
1991 libc::SOL_SOCKET,
1992 libc::SO_SETFIB,
1993 (&fib as *const u32).cast(),
1994 mem::size_of::<u32>() as libc::socklen_t,
1995 ))
1996 .map(|_| ())
1997 }
1998
1999 #[cfg(all(
2010 feature = "all",
2011 any(
2012 target_os = "ios",
2013 target_os = "visionos",
2014 target_os = "macos",
2015 target_os = "tvos",
2016 target_os = "watchos",
2017 target_os = "illumos",
2018 target_os = "solaris",
2019 target_os = "linux",
2020 target_os = "android",
2021 )
2022 ))]
2023 pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2024 let index = interface.map_or(0, NonZeroU32::get);
2025
2026 #[cfg(any(
2027 target_os = "ios",
2028 target_os = "visionos",
2029 target_os = "macos",
2030 target_os = "tvos",
2031 target_os = "watchos",
2032 target_os = "illumos",
2033 target_os = "solaris",
2034 ))]
2035 unsafe {
2036 setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index)
2037 }
2038
2039 #[cfg(any(target_os = "linux", target_os = "android",))]
2040 unsafe {
2041 setsockopt(
2042 self.as_raw(),
2043 libc::SOL_SOCKET,
2044 libc::SO_BINDTOIFINDEX,
2045 index,
2046 )
2047 }
2048 }
2049
2050 #[cfg(all(
2061 feature = "all",
2062 any(
2063 target_os = "ios",
2064 target_os = "visionos",
2065 target_os = "macos",
2066 target_os = "tvos",
2067 target_os = "watchos",
2068 target_os = "illumos",
2069 target_os = "solaris",
2070 target_os = "linux",
2071 target_os = "android",
2072 )
2073 ))]
2074 pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2075 let index = interface.map_or(0, NonZeroU32::get);
2076
2077 #[cfg(any(
2078 target_os = "ios",
2079 target_os = "visionos",
2080 target_os = "macos",
2081 target_os = "tvos",
2082 target_os = "watchos",
2083 target_os = "illumos",
2084 target_os = "solaris",
2085 ))]
2086 unsafe {
2087 setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index)
2088 }
2089
2090 #[cfg(any(target_os = "linux", target_os = "android",))]
2091 unsafe {
2092 setsockopt(
2093 self.as_raw(),
2094 libc::SOL_SOCKET,
2095 libc::SO_BINDTOIFINDEX,
2096 index,
2097 )
2098 }
2099 }
2100
2101 #[cfg(all(
2107 feature = "all",
2108 any(
2109 target_os = "ios",
2110 target_os = "visionos",
2111 target_os = "macos",
2112 target_os = "tvos",
2113 target_os = "watchos",
2114 target_os = "illumos",
2115 target_os = "solaris",
2116 target_os = "linux",
2117 target_os = "android",
2118 )
2119 ))]
2120 pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
2121 #[cfg(any(
2122 target_os = "ios",
2123 target_os = "visionos",
2124 target_os = "macos",
2125 target_os = "tvos",
2126 target_os = "watchos",
2127 target_os = "illumos",
2128 target_os = "solaris",
2129 ))]
2130 let index =
2131 unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
2132
2133 #[cfg(any(target_os = "linux", target_os = "android",))]
2134 let index = unsafe {
2135 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2136 };
2137
2138 Ok(NonZeroU32::new(index))
2139 }
2140
2141 #[cfg(all(
2147 feature = "all",
2148 any(
2149 target_os = "ios",
2150 target_os = "visionos",
2151 target_os = "macos",
2152 target_os = "tvos",
2153 target_os = "watchos",
2154 target_os = "illumos",
2155 target_os = "solaris",
2156 target_os = "linux",
2157 target_os = "android",
2158 )
2159 ))]
2160 pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
2161 #[cfg(any(
2162 target_os = "ios",
2163 target_os = "visionos",
2164 target_os = "macos",
2165 target_os = "tvos",
2166 target_os = "watchos",
2167 target_os = "illumos",
2168 target_os = "solaris",
2169 ))]
2170 let index = unsafe {
2171 getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)?
2172 };
2173
2174 #[cfg(any(target_os = "linux", target_os = "android",))]
2175 let index = unsafe {
2176 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2177 };
2178
2179 Ok(NonZeroU32::new(index))
2180 }
2181
2182 #[cfg(all(feature = "all", target_os = "linux"))]
2188 pub fn cpu_affinity(&self) -> io::Result<usize> {
2189 unsafe {
2190 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
2191 .map(|cpu| cpu as usize)
2192 }
2193 }
2194
2195 #[cfg(all(feature = "all", target_os = "linux"))]
2199 pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
2200 unsafe {
2201 setsockopt(
2202 self.as_raw(),
2203 libc::SOL_SOCKET,
2204 libc::SO_INCOMING_CPU,
2205 cpu as c_int,
2206 )
2207 }
2208 }
2209
2210 #[cfg(all(
2216 feature = "all",
2217 not(any(
2218 target_os = "solaris",
2219 target_os = "illumos",
2220 target_os = "cygwin",
2221 target_os = "nuttx",
2222 target_os = "wasi"
2223 ))
2224 ))]
2225 pub fn reuse_port(&self) -> io::Result<bool> {
2226 unsafe {
2227 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
2228 .map(|reuse| reuse != 0)
2229 }
2230 }
2231
2232 #[cfg(all(
2238 feature = "all",
2239 not(any(
2240 target_os = "solaris",
2241 target_os = "illumos",
2242 target_os = "cygwin",
2243 target_os = "nuttx",
2244 target_os = "wasi"
2245 ))
2246 ))]
2247 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
2248 unsafe {
2249 setsockopt(
2250 self.as_raw(),
2251 libc::SOL_SOCKET,
2252 libc::SO_REUSEPORT,
2253 reuse as c_int,
2254 )
2255 }
2256 }
2257
2258 #[cfg(all(feature = "all", target_os = "freebsd"))]
2264 pub fn reuse_port_lb(&self) -> io::Result<bool> {
2265 unsafe {
2266 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT_LB)
2267 .map(|reuse| reuse != 0)
2268 }
2269 }
2270
2271 #[cfg(all(feature = "all", target_os = "freebsd"))]
2276 pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
2277 unsafe {
2278 setsockopt(
2279 self.as_raw(),
2280 libc::SOL_SOCKET,
2281 libc::SO_REUSEPORT_LB,
2282 reuse as c_int,
2283 )
2284 }
2285 }
2286
2287 #[cfg(all(
2293 feature = "all",
2294 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2295 ))]
2296 pub fn freebind_v4(&self) -> io::Result<bool> {
2297 unsafe {
2298 getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
2299 .map(|freebind| freebind != 0)
2300 }
2301 }
2302
2303 #[cfg(all(
2311 feature = "all",
2312 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2313 ))]
2314 pub fn set_freebind_v4(&self, freebind: bool) -> io::Result<()> {
2315 unsafe {
2316 setsockopt(
2317 self.as_raw(),
2318 libc::SOL_IP,
2319 libc::IP_FREEBIND,
2320 freebind as c_int,
2321 )
2322 }
2323 }
2324
2325 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2333 pub fn freebind_v6(&self) -> io::Result<bool> {
2334 unsafe {
2335 getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
2336 .map(|freebind| freebind != 0)
2337 }
2338 }
2339
2340 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2371 pub fn set_freebind_v6(&self, freebind: bool) -> io::Result<()> {
2372 unsafe {
2373 setsockopt(
2374 self.as_raw(),
2375 libc::SOL_IPV6,
2376 libc::IPV6_FREEBIND,
2377 freebind as c_int,
2378 )
2379 }
2380 }
2381
2382 #[doc = man_links!(unix: sendfile(2))]
2392 #[cfg(all(
2402 feature = "all",
2403 any(
2404 target_os = "aix",
2405 target_os = "android",
2406 target_os = "freebsd",
2407 target_os = "ios",
2408 target_os = "visionos",
2409 target_os = "linux",
2410 target_os = "macos",
2411 target_os = "tvos",
2412 target_os = "watchos",
2413 )
2414 ))]
2415 pub fn sendfile<F>(
2416 &self,
2417 file: &F,
2418 offset: usize,
2419 length: Option<NonZeroUsize>,
2420 ) -> io::Result<usize>
2421 where
2422 F: AsRawFd,
2423 {
2424 self._sendfile(file.as_raw_fd(), offset as _, length)
2425 }
2426
2427 #[cfg(all(
2428 feature = "all",
2429 any(
2430 target_os = "ios",
2431 target_os = "visionos",
2432 target_os = "macos",
2433 target_os = "tvos",
2434 target_os = "watchos",
2435 )
2436 ))]
2437 fn _sendfile(
2438 &self,
2439 file: RawFd,
2440 offset: libc::off_t,
2441 length: Option<NonZeroUsize>,
2442 ) -> io::Result<usize> {
2443 let mut length = match length {
2446 Some(n) => n.get() as libc::off_t,
2447 None => 0,
2449 };
2450 syscall!(sendfile(
2451 file,
2452 self.as_raw(),
2453 offset,
2454 &mut length,
2455 ptr::null_mut(),
2456 0,
2457 ))
2458 .map(|_| length as usize)
2459 }
2460
2461 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2462 fn _sendfile(
2463 &self,
2464 file: RawFd,
2465 offset: libc::off_t,
2466 length: Option<NonZeroUsize>,
2467 ) -> io::Result<usize> {
2468 let count = match length {
2469 Some(n) => n.get() as libc::size_t,
2470 None => 0x7ffff000, };
2473 let mut offset = offset;
2474 syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
2475 }
2476
2477 #[cfg(all(feature = "all", target_os = "freebsd"))]
2478 fn _sendfile(
2479 &self,
2480 file: RawFd,
2481 offset: libc::off_t,
2482 length: Option<NonZeroUsize>,
2483 ) -> io::Result<usize> {
2484 let nbytes = match length {
2485 Some(n) => n.get() as libc::size_t,
2486 None => 0,
2488 };
2489 let mut sbytes: libc::off_t = 0;
2490 syscall!(sendfile(
2491 file,
2492 self.as_raw(),
2493 offset,
2494 nbytes,
2495 ptr::null_mut(),
2496 &mut sbytes,
2497 0,
2498 ))
2499 .map(|_| sbytes as usize)
2500 }
2501
2502 #[cfg(all(feature = "all", target_os = "aix"))]
2503 fn _sendfile(
2504 &self,
2505 file: RawFd,
2506 offset: libc::off_t,
2507 length: Option<NonZeroUsize>,
2508 ) -> io::Result<usize> {
2509 let nbytes = match length {
2510 Some(n) => n.get() as i64,
2511 None => -1,
2512 };
2513 let mut params = libc::sf_parms {
2514 header_data: ptr::null_mut(),
2515 header_length: 0,
2516 file_descriptor: file,
2517 file_size: 0,
2518 file_offset: offset as u64,
2519 file_bytes: nbytes,
2520 trailer_data: ptr::null_mut(),
2521 trailer_length: 0,
2522 bytes_sent: 0,
2523 };
2524 syscall!(send_file(
2526 &mut self.as_raw() as *mut _,
2527 &mut params as *mut _,
2528 libc::SF_CLOSE as libc::c_uint,
2529 ))
2530 .map(|_| params.bytes_sent as usize)
2531 }
2532
2533 #[cfg(all(
2544 feature = "all",
2545 any(
2546 target_os = "android",
2547 target_os = "fuchsia",
2548 target_os = "linux",
2549 target_os = "cygwin",
2550 )
2551 ))]
2552 pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
2553 let timeout = timeout.map_or(0, |to| {
2554 min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint
2555 });
2556 unsafe {
2557 setsockopt(
2558 self.as_raw(),
2559 libc::IPPROTO_TCP,
2560 libc::TCP_USER_TIMEOUT,
2561 timeout,
2562 )
2563 }
2564 }
2565
2566 #[cfg(all(
2572 feature = "all",
2573 any(
2574 target_os = "android",
2575 target_os = "fuchsia",
2576 target_os = "linux",
2577 target_os = "cygwin",
2578 )
2579 ))]
2580 pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
2581 unsafe {
2582 getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
2583 .map(|millis| {
2584 if millis == 0 {
2585 None
2586 } else {
2587 Some(Duration::from_millis(millis as u64))
2588 }
2589 })
2590 }
2591 }
2592
2593 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2600 pub fn attach_filter(&self, filters: &[SockFilter]) -> io::Result<()> {
2601 let prog = libc::sock_fprog {
2602 len: filters.len() as u16,
2603 filter: filters.as_ptr() as *mut _,
2605 };
2606
2607 unsafe {
2608 setsockopt(
2609 self.as_raw(),
2610 libc::SOL_SOCKET,
2611 libc::SO_ATTACH_FILTER,
2612 prog,
2613 )
2614 }
2615 }
2616
2617 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2623 pub fn detach_filter(&self) -> io::Result<()> {
2624 unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) }
2625 }
2626
2627 #[cfg(all(feature = "all", target_os = "linux"))]
2634 pub fn cookie(&self) -> io::Result<u64> {
2635 unsafe { getsockopt::<libc::c_ulonglong>(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) }
2636 }
2637
2638 #[cfg(all(
2644 feature = "all",
2645 any(
2646 target_os = "android",
2647 target_os = "dragonfly",
2648 target_os = "freebsd",
2649 target_os = "fuchsia",
2650 target_os = "linux",
2651 target_os = "macos",
2652 target_os = "netbsd",
2653 target_os = "openbsd",
2654 target_os = "cygwin",
2655 target_os = "illumos",
2656 )
2657 ))]
2658 pub fn tclass_v6(&self) -> io::Result<u32> {
2659 unsafe {
2660 getsockopt::<c_int>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS)
2661 .map(|tclass| tclass as u32)
2662 }
2663 }
2664
2665 #[cfg(all(
2670 feature = "all",
2671 any(
2672 target_os = "android",
2673 target_os = "dragonfly",
2674 target_os = "freebsd",
2675 target_os = "fuchsia",
2676 target_os = "linux",
2677 target_os = "macos",
2678 target_os = "netbsd",
2679 target_os = "openbsd",
2680 target_os = "cygwin",
2681 target_os = "illumos",
2682 )
2683 ))]
2684 pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
2685 unsafe {
2686 setsockopt(
2687 self.as_raw(),
2688 IPPROTO_IPV6,
2689 libc::IPV6_TCLASS,
2690 tclass as c_int,
2691 )
2692 }
2693 }
2694
2695 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2701 pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
2702 let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX];
2703 let mut len = payload.len() as libc::socklen_t;
2704 syscall!(getsockopt(
2705 self.as_raw(),
2706 IPPROTO_TCP,
2707 libc::TCP_CONGESTION,
2708 payload.as_mut_ptr().cast(),
2709 &mut len,
2710 ))
2711 .map(|_| payload[..len as usize].to_vec())
2712 }
2713
2714 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2721 pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
2722 syscall!(setsockopt(
2723 self.as_raw(),
2724 IPPROTO_TCP,
2725 libc::TCP_CONGESTION,
2726 tcp_ca_name.as_ptr() as *const _,
2727 tcp_ca_name.len() as libc::socklen_t,
2728 ))
2729 .map(|_| ())
2730 }
2731
2732 #[cfg(all(feature = "all", target_os = "linux"))]
2743 pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
2744 unsafe {
2745 setsockopt(
2746 self.as_raw(),
2747 libc::SOL_DCCP,
2748 libc::DCCP_SOCKOPT_SERVICE,
2749 code,
2750 )
2751 }
2752 }
2753
2754 #[cfg(all(feature = "all", target_os = "linux"))]
2760 pub fn dccp_service(&self) -> io::Result<u32> {
2761 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) }
2762 }
2763
2764 #[cfg(all(feature = "all", target_os = "linux"))]
2768 pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
2769 unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) }
2770 }
2771
2772 #[cfg(all(feature = "all", target_os = "linux"))]
2778 pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
2779 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) }
2780 }
2781
2782 #[cfg(all(feature = "all", target_os = "linux"))]
2788 pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
2789 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) }
2790 }
2791
2792 #[cfg(all(feature = "all", target_os = "linux"))]
2797 pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> {
2798 unsafe {
2799 setsockopt(
2800 self.as_raw(),
2801 libc::SOL_DCCP,
2802 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2803 hold_timewait as c_int,
2804 )
2805 }
2806 }
2807
2808 #[cfg(all(feature = "all", target_os = "linux"))]
2814 pub fn dccp_server_timewait(&self) -> io::Result<bool> {
2815 unsafe {
2816 getsockopt(
2817 self.as_raw(),
2818 libc::SOL_DCCP,
2819 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2820 )
2821 }
2822 }
2823
2824 #[cfg(all(feature = "all", target_os = "linux"))]
2832 pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
2833 unsafe {
2834 setsockopt(
2835 self.as_raw(),
2836 libc::SOL_DCCP,
2837 libc::DCCP_SOCKOPT_SEND_CSCOV,
2838 level,
2839 )
2840 }
2841 }
2842
2843 #[cfg(all(feature = "all", target_os = "linux"))]
2849 pub fn dccp_send_cscov(&self) -> io::Result<u32> {
2850 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) }
2851 }
2852
2853 #[cfg(all(feature = "all", target_os = "linux"))]
2859 pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
2860 unsafe {
2861 setsockopt(
2862 self.as_raw(),
2863 libc::SOL_DCCP,
2864 libc::DCCP_SOCKOPT_RECV_CSCOV,
2865 level,
2866 )
2867 }
2868 }
2869
2870 #[cfg(all(feature = "all", target_os = "linux"))]
2876 pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
2877 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) }
2878 }
2879
2880 #[cfg(all(feature = "all", target_os = "linux"))]
2885 pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
2886 unsafe {
2887 setsockopt(
2888 self.as_raw(),
2889 libc::SOL_DCCP,
2890 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2891 length,
2892 )
2893 }
2894 }
2895
2896 #[cfg(all(feature = "all", target_os = "linux"))]
2902 pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
2903 unsafe {
2904 getsockopt(
2905 self.as_raw(),
2906 libc::SOL_DCCP,
2907 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2908 )
2909 }
2910 }
2911
2912 #[cfg(all(feature = "all", target_os = "linux"))]
2922 pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEndpoints<N>> {
2923 let mut endpoints = [0; N];
2924 let mut length = endpoints.len() as libc::socklen_t;
2925 syscall!(getsockopt(
2926 self.as_raw(),
2927 libc::SOL_DCCP,
2928 libc::DCCP_SOCKOPT_AVAILABLE_CCIDS,
2929 endpoints.as_mut_ptr().cast(),
2930 &mut length,
2931 ))?;
2932 Ok(CcidEndpoints { endpoints, length })
2933 }
2934
2935 #[cfg(all(feature = "all", target_os = "linux"))]
2940 pub fn dccp_cur_mps(&self) -> io::Result<u32> {
2941 unsafe {
2942 getsockopt(
2943 self.as_raw(),
2944 libc::SOL_DCCP,
2945 libc::DCCP_SOCKOPT_GET_CUR_MPS,
2946 )
2947 }
2948 }
2949
2950 #[cfg(all(feature = "all", target_os = "linux"))]
2954 pub fn busy_poll(&self) -> io::Result<u32> {
2955 unsafe { getsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_BUSY_POLL) }
2956 }
2957
2958 #[cfg(all(feature = "all", target_os = "linux"))]
2962 pub fn set_busy_poll(&self, busy_poll: u32) -> io::Result<()> {
2963 unsafe {
2964 setsockopt(
2965 self.as_raw(),
2966 libc::SOL_SOCKET,
2967 libc::SO_BUSY_POLL,
2968 busy_poll as c_int,
2969 )
2970 }
2971 }
2972}
2973
2974#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2980#[repr(transparent)]
2981pub struct SockFilter {
2982 #[allow(dead_code)]
2985 filter: libc::sock_filter,
2986}
2987
2988#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2989impl SockFilter {
2990 pub const fn new(code: u16, jt: u8, jf: u8, k: u32) -> SockFilter {
2992 SockFilter {
2993 filter: libc::sock_filter { code, jt, jf, k },
2994 }
2995 }
2996}
2997
2998#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2999impl std::fmt::Debug for SockFilter {
3000 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3001 f.debug_struct("SockFilter").finish_non_exhaustive()
3002 }
3003}
3004
3005#[cfg(all(feature = "all", target_os = "linux"))]
3009#[derive(Debug)]
3010pub struct CcidEndpoints<const N: usize> {
3011 endpoints: [u8; N],
3012 length: u32,
3013}
3014
3015#[cfg(all(feature = "all", target_os = "linux"))]
3016impl<const N: usize> std::ops::Deref for CcidEndpoints<N> {
3017 type Target = [u8];
3018
3019 fn deref(&self) -> &[u8] {
3020 &self.endpoints[0..self.length as usize]
3021 }
3022}
3023
3024impl AsFd for crate::Socket {
3025 fn as_fd(&self) -> BorrowedFd<'_> {
3026 unsafe { BorrowedFd::borrow_raw(self.as_raw()) }
3028 }
3029}
3030
3031impl AsRawFd for crate::Socket {
3032 fn as_raw_fd(&self) -> RawFd {
3033 self.as_raw()
3034 }
3035}
3036
3037impl From<crate::Socket> for OwnedFd {
3038 fn from(sock: crate::Socket) -> OwnedFd {
3039 unsafe { OwnedFd::from_raw_fd(sock.into_raw()) }
3041 }
3042}
3043
3044impl IntoRawFd for crate::Socket {
3045 fn into_raw_fd(self) -> c_int {
3046 self.into_raw()
3047 }
3048}
3049
3050impl From<OwnedFd> for crate::Socket {
3051 fn from(fd: OwnedFd) -> crate::Socket {
3052 unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) }
3054 }
3055}
3056
3057impl FromRawFd for crate::Socket {
3058 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
3059 crate::Socket::from_raw(fd)
3060 }
3061}
3062
3063#[cfg(all(feature = "all", unix))]
3064from!(UnixStream, crate::Socket);
3065#[cfg(all(feature = "all", unix))]
3066from!(UnixListener, crate::Socket);
3067#[cfg(all(feature = "all", unix))]
3068from!(UnixDatagram, crate::Socket);
3069#[cfg(all(feature = "all", unix))]
3070from!(crate::Socket, UnixStream);
3071#[cfg(all(feature = "all", unix))]
3072from!(crate::Socket, UnixListener);
3073#[cfg(all(feature = "all", unix))]
3074from!(crate::Socket, UnixDatagram);
3075
3076#[test]
3077fn in_addr_convertion() {
3078 let ip = Ipv4Addr::new(127, 0, 0, 1);
3079 let raw = to_in_addr(&ip);
3080 let a = raw.s_addr;
3082 assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
3083 assert_eq!(from_in_addr(raw), ip);
3084
3085 let ip = Ipv4Addr::new(127, 34, 4, 12);
3086 let raw = to_in_addr(&ip);
3087 let a = raw.s_addr;
3088 assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
3089 assert_eq!(from_in_addr(raw), ip);
3090}
3091
3092#[test]
3093fn in6_addr_convertion() {
3094 let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
3095 let raw = to_in6_addr(&ip);
3096 let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
3097 assert_eq!(raw.s6_addr, want);
3098 assert_eq!(from_in6_addr(raw), ip);
3099}