1use std::cmp::min;
10#[cfg(not(target_os = "wasi"))]
11use std::ffi::OsStr;
12#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
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")))]
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(target_os = "redox", target_os = "espidf", target_os = "wasi"))
88))]
89pub(crate) use libc::SOCK_RAW;
90#[cfg(all(feature = "all", not(any(target_os = "espidf", target_os = "wasi"))))]
91pub(crate) use libc::SOCK_SEQPACKET;
92pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM};
93#[cfg(all(feature = "all", target_os = "linux"))]
95pub(crate) use libc::IPPROTO_DCCP;
96#[cfg(target_os = "linux")]
97pub(crate) use libc::IPPROTO_MPTCP;
98#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
99pub(crate) use libc::IPPROTO_SCTP;
100#[cfg(all(
101 feature = "all",
102 any(
103 target_os = "android",
104 target_os = "freebsd",
105 target_os = "fuchsia",
106 target_os = "linux",
107 )
108))]
109pub(crate) use libc::IPPROTO_UDPLITE;
110#[cfg(not(target_os = "wasi"))]
111pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6};
112pub(crate) use libc::{IPPROTO_TCP, IPPROTO_UDP};
113#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
115pub(crate) use libc::IPPROTO_DIVERT;
116pub(crate) use libc::{
117 sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t,
118};
119#[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "wasi")))]
121pub(crate) use libc::MSG_TRUNC;
122#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
123pub(crate) use libc::SO_OOBINLINE;
124#[cfg(not(target_os = "nto"))]
126pub(crate) use libc::ipv6_mreq as Ipv6Mreq;
127#[cfg(all(feature = "all", target_os = "linux"))]
128pub(crate) use libc::IPV6_HDRINCL;
129#[cfg(all(
130 feature = "all",
131 not(any(
132 target_os = "dragonfly",
133 target_os = "fuchsia",
134 target_os = "hurd",
135 target_os = "illumos",
136 target_os = "netbsd",
137 target_os = "openbsd",
138 target_os = "redox",
139 target_os = "solaris",
140 target_os = "haiku",
141 target_os = "espidf",
142 target_os = "vita",
143 target_os = "wasi",
144 target_os = "cygwin",
145 ))
146))]
147pub(crate) use libc::IPV6_RECVHOPLIMIT;
148#[cfg(not(any(
149 target_os = "dragonfly",
150 target_os = "fuchsia",
151 target_os = "hurd",
152 target_os = "illumos",
153 target_os = "netbsd",
154 target_os = "openbsd",
155 target_os = "redox",
156 target_os = "solaris",
157 target_os = "haiku",
158 target_os = "espidf",
159 target_os = "vita",
160 target_os = "wasi",
161)))]
162pub(crate) use libc::IPV6_RECVTCLASS;
163#[cfg(all(
164 feature = "all",
165 not(any(target_os = "redox", target_os = "espidf", target_os = "wasi"))
166))]
167pub(crate) use libc::IP_HDRINCL;
168#[cfg(not(any(
169 target_os = "aix",
170 target_os = "dragonfly",
171 target_os = "fuchsia",
172 target_os = "illumos",
173 target_os = "netbsd",
174 target_os = "openbsd",
175 target_os = "redox",
176 target_os = "solaris",
177 target_os = "haiku",
178 target_os = "hurd",
179 target_os = "nto",
180 target_os = "espidf",
181 target_os = "vita",
182 target_os = "wasi",
183 target_os = "cygwin",
184)))]
185pub(crate) use libc::IP_RECVTOS;
186#[cfg(not(any(
187 target_os = "fuchsia",
188 target_os = "redox",
189 target_os = "solaris",
190 target_os = "haiku",
191 target_os = "illumos",
192 target_os = "wasi",
193)))]
194pub(crate) use libc::IP_TOS;
195#[cfg(not(any(
196 target_os = "ios",
197 target_os = "visionos",
198 target_os = "macos",
199 target_os = "tvos",
200 target_os = "watchos",
201)))]
202pub(crate) use libc::SO_LINGER;
203#[cfg(any(
204 target_os = "ios",
205 target_os = "visionos",
206 target_os = "macos",
207 target_os = "tvos",
208 target_os = "watchos",
209))]
210pub(crate) use libc::SO_LINGER_SEC as SO_LINGER;
211#[cfg(any(target_os = "linux", target_os = "cygwin"))]
212pub(crate) use libc::SO_PASSCRED;
213#[cfg(all(
214 feature = "all",
215 any(target_os = "linux", target_os = "android", target_os = "fuchsia")
216))]
217pub(crate) use libc::SO_PRIORITY;
218pub(crate) use libc::{
219 ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS,
220 IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
221 IP_TTL, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO,
222 SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
223};
224#[cfg(not(any(
225 target_os = "dragonfly",
226 target_os = "haiku",
227 target_os = "hurd",
228 target_os = "netbsd",
229 target_os = "openbsd",
230 target_os = "redox",
231 target_os = "fuchsia",
232 target_os = "nto",
233 target_os = "espidf",
234 target_os = "vita",
235 target_os = "wasi",
236)))]
237pub(crate) use libc::{
238 ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
239};
240#[cfg(not(any(
241 target_os = "dragonfly",
242 target_os = "freebsd",
243 target_os = "haiku",
244 target_os = "illumos",
245 target_os = "ios",
246 target_os = "visionos",
247 target_os = "macos",
248 target_os = "netbsd",
249 target_os = "nto",
250 target_os = "openbsd",
251 target_os = "solaris",
252 target_os = "tvos",
253 target_os = "watchos",
254 target_os = "wasi",
255)))]
256pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
257#[cfg(any(
258 target_os = "dragonfly",
259 target_os = "freebsd",
260 target_os = "haiku",
261 target_os = "illumos",
262 target_os = "ios",
263 target_os = "visionos",
264 target_os = "macos",
265 target_os = "netbsd",
266 target_os = "openbsd",
267 target_os = "solaris",
268 target_os = "tvos",
269 target_os = "watchos",
270 all(target_os = "wasi", not(target_env = "p1")),
271))]
272pub(crate) use libc::{
273 IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP,
274};
275#[cfg(not(target_os = "wasi"))]
276pub(crate) use libc::{IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IP_MULTICAST_IF, MSG_OOB};
277#[cfg(all(
278 feature = "all",
279 any(
280 target_os = "android",
281 target_os = "dragonfly",
282 target_os = "freebsd",
283 target_os = "fuchsia",
284 target_os = "illumos",
285 target_os = "ios",
286 target_os = "visionos",
287 target_os = "linux",
288 target_os = "macos",
289 target_os = "netbsd",
290 target_os = "tvos",
291 target_os = "watchos",
292 target_os = "cygwin",
293 all(target_os = "wasi", not(target_env = "p1")),
294 )
295))]
296pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
297
298pub(crate) type Bool = c_int;
300
301#[cfg(any(
302 target_os = "ios",
303 target_os = "visionos",
304 target_os = "macos",
305 target_os = "nto",
306 target_os = "tvos",
307 target_os = "watchos",
308))]
309use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
310#[cfg(not(any(
311 target_os = "haiku",
312 target_os = "ios",
313 target_os = "visionos",
314 target_os = "macos",
315 target_os = "nto",
316 target_os = "openbsd",
317 target_os = "tvos",
318 target_os = "watchos",
319 target_os = "vita",
320)))]
321use libc::TCP_KEEPIDLE as KEEPALIVE_TIME;
322
323macro_rules! syscall {
325 ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
326 #[allow(unused_unsafe)]
327 let res = unsafe { libc::$fn($($arg, )*) };
328 if res == -1 {
329 Err(std::io::Error::last_os_error())
330 } else {
331 Ok(res)
332 }
333 }};
334}
335
336#[cfg(not(any(
338 target_os = "ios",
339 target_os = "visionos",
340 target_os = "macos",
341 target_os = "tvos",
342 target_os = "watchos",
343 target_os = "cygwin",
344)))]
345const MAX_BUF_LEN: usize = ssize_t::MAX as usize;
346
347#[cfg(any(
356 target_os = "ios",
357 target_os = "visionos",
358 target_os = "macos",
359 target_os = "tvos",
360 target_os = "watchos",
361 target_os = "cygwin",
362))]
363const MAX_BUF_LEN: usize = c_int::MAX as usize - 1;
364
365#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
367const TCP_CA_NAME_MAX: usize = 16;
368
369#[cfg(any(
370 all(
371 target_os = "linux",
372 any(
373 target_env = "gnu",
374 all(target_env = "uclibc", target_pointer_width = "64")
375 )
376 ),
377 target_os = "android",
378))]
379type IovLen = usize;
380
381#[cfg(any(
382 all(
383 target_os = "linux",
384 any(
385 target_env = "musl",
386 target_env = "ohos",
387 all(target_env = "uclibc", target_pointer_width = "32")
388 )
389 ),
390 target_os = "aix",
391 target_os = "dragonfly",
392 target_os = "freebsd",
393 target_os = "fuchsia",
394 target_os = "haiku",
395 target_os = "hurd",
396 target_os = "illumos",
397 target_os = "ios",
398 target_os = "visionos",
399 target_os = "macos",
400 target_os = "netbsd",
401 target_os = "nto",
402 target_os = "openbsd",
403 target_os = "solaris",
404 target_os = "tvos",
405 target_os = "watchos",
406 target_os = "espidf",
407 target_os = "vita",
408 target_os = "cygwin",
409))]
410type IovLen = c_int;
411
412impl Domain {
414 #[cfg(all(
416 feature = "all",
417 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
418 ))]
419 pub const PACKET: Domain = Domain(libc::AF_PACKET);
420
421 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
423 pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
424}
425
426impl_debug!(
427 Domain,
428 libc::AF_INET,
429 libc::AF_INET6,
430 #[cfg(not(target_os = "wasi"))]
431 libc::AF_UNIX,
432 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
433 libc::AF_PACKET,
434 #[cfg(any(target_os = "android", target_os = "linux"))]
435 libc::AF_VSOCK,
436 libc::AF_UNSPEC, );
438
439impl Type {
441 #[cfg(all(
443 feature = "all",
444 any(
445 target_os = "android",
446 target_os = "dragonfly",
447 target_os = "freebsd",
448 target_os = "fuchsia",
449 target_os = "illumos",
450 target_os = "linux",
451 target_os = "netbsd",
452 target_os = "openbsd",
453 target_os = "cygwin",
454 all(target_os = "wasi", not(target_env = "p1")),
455 )
456 ))]
457 pub const fn nonblocking(self) -> Type {
458 Type(self.0 | libc::SOCK_NONBLOCK)
459 }
460
461 #[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 target_os = "cygwin",
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 target_os = "cygwin",
496 ))]
497 pub(crate) const fn _cloexec(self) -> Type {
498 Type(self.0 | libc::SOCK_CLOEXEC)
499 }
500}
501
502impl_debug!(
503 Type,
504 libc::SOCK_STREAM,
505 libc::SOCK_DGRAM,
506 #[cfg(all(feature = "all", target_os = "linux"))]
507 libc::SOCK_DCCP,
508 #[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "wasi")))]
509 libc::SOCK_RAW,
510 #[cfg(not(any(
511 target_os = "redox",
512 target_os = "haiku",
513 target_os = "espidf",
514 target_os = "wasi"
515 )))]
516 libc::SOCK_RDM,
517 #[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
518 libc::SOCK_SEQPACKET,
519 );
542
543impl_debug!(
544 Protocol,
545 #[cfg(not(target_os = "wasi"))]
546 libc::IPPROTO_ICMP,
547 #[cfg(not(target_os = "wasi"))]
548 libc::IPPROTO_ICMPV6,
549 libc::IPPROTO_TCP,
550 libc::IPPROTO_UDP,
551 #[cfg(target_os = "linux")]
552 libc::IPPROTO_MPTCP,
553 #[cfg(all(feature = "all", target_os = "linux"))]
554 libc::IPPROTO_DCCP,
555 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
556 libc::IPPROTO_SCTP,
557 #[cfg(all(
558 feature = "all",
559 any(
560 target_os = "android",
561 target_os = "freebsd",
562 target_os = "fuchsia",
563 target_os = "linux",
564 )
565 ))]
566 libc::IPPROTO_UDPLITE,
567 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
568 libc::IPPROTO_DIVERT,
569);
570
571#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
573impl RecvFlags {
574 #[cfg(not(target_os = "espidf"))]
584 pub const fn is_end_of_record(self) -> bool {
585 self.0 & libc::MSG_EOR != 0
586 }
587
588 pub const fn is_out_of_band(self) -> bool {
595 self.0 & libc::MSG_OOB != 0
596 }
597
598 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
606 pub const fn is_confirm(self) -> bool {
607 self.0 & libc::MSG_CONFIRM != 0
608 }
609
610 #[cfg(all(
617 feature = "all",
618 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
619 ))]
620 pub const fn is_dontroute(self) -> bool {
621 self.0 & libc::MSG_DONTROUTE != 0
622 }
623}
624
625#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
626impl std::fmt::Debug for RecvFlags {
627 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
628 let mut s = f.debug_struct("RecvFlags");
629 #[cfg(not(target_os = "espidf"))]
630 s.field("is_end_of_record", &self.is_end_of_record());
631 s.field("is_out_of_band", &self.is_out_of_band());
632 #[cfg(not(target_os = "espidf"))]
633 s.field("is_truncated", &self.is_truncated());
634 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
635 s.field("is_confirm", &self.is_confirm());
636 #[cfg(all(
637 feature = "all",
638 any(target_os = "android", target_os = "linux", target_os = "cygwin"),
639 ))]
640 s.field("is_dontroute", &self.is_dontroute());
641 s.finish()
642 }
643}
644
645#[repr(transparent)]
646pub struct MaybeUninitSlice<'a> {
647 vec: libc::iovec,
648 _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
649}
650
651unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
652
653unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
654
655impl<'a> MaybeUninitSlice<'a> {
656 pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
657 MaybeUninitSlice {
658 vec: libc::iovec {
659 iov_base: buf.as_mut_ptr().cast(),
660 iov_len: buf.len(),
661 },
662 _lifetime: PhantomData,
663 }
664 }
665
666 pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
667 unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
668 }
669
670 pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
671 unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
672 }
673}
674
675#[cfg(not(target_os = "wasi"))]
677pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize {
678 let base = storage as *const _ as usize;
679 let path = ptr::addr_of!(storage.sun_path) as usize;
680 path - base
681}
682
683#[cfg(not(target_os = "wasi"))]
684#[allow(unsafe_op_in_unsafe_fn)]
685pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
686 let mut storage = SockAddrStorage::zeroed();
687 let len = {
688 let storage = unsafe { storage.view_as::<libc::sockaddr_un>() };
690
691 let bytes = path.as_os_str().as_bytes();
692 let too_long = match bytes.first() {
693 None => false,
694 Some(&0) => bytes.len() > storage.sun_path.len(),
696 Some(_) => bytes.len() >= storage.sun_path.len(),
697 };
698 if too_long {
699 return Err(io::Error::new(
700 io::ErrorKind::InvalidInput,
701 "path must be shorter than SUN_LEN",
702 ));
703 }
704
705 storage.sun_family = libc::AF_UNIX as sa_family_t;
706 unsafe {
711 ptr::copy_nonoverlapping(
712 bytes.as_ptr(),
713 storage.sun_path.as_mut_ptr().cast(),
714 bytes.len(),
715 );
716 }
717
718 let sun_path_offset = offset_of_path(storage);
719 sun_path_offset
720 + bytes.len()
721 + match bytes.first() {
722 Some(&0) | None => 0,
723 Some(_) => 1,
724 }
725 };
726 Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
727}
728
729#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
731pub(crate) use libc::msghdr;
732
733#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
734pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
735 msg.msg_name = name.as_ptr() as *mut _;
736 msg.msg_namelen = name.len();
737}
738
739#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
740#[allow(clippy::unnecessary_cast)] pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) {
742 msg.msg_iov = ptr;
743 msg.msg_iovlen = min(len, IovLen::MAX as usize) as IovLen;
744}
745
746#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
747pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) {
748 msg.msg_control = ptr;
749 msg.msg_controllen = len as _;
750}
751
752#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
753pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: c_int) {
754 msg.msg_flags = flags;
755}
756
757#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
758pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags {
759 RecvFlags(msg.msg_flags)
760}
761
762#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
763pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize {
764 msg.msg_controllen as _
765}
766
767impl SockAddr {
769 #[allow(unsafe_op_in_unsafe_fn)]
776 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
777 pub fn vsock(cid: u32, port: u32) -> SockAddr {
778 let mut storage = SockAddrStorage::zeroed();
779 {
780 let storage = unsafe { storage.view_as::<libc::sockaddr_vm>() };
782 storage.svm_family = libc::AF_VSOCK as sa_family_t;
783 storage.svm_cid = cid;
784 storage.svm_port = port;
785 }
786 unsafe { SockAddr::new(storage, mem::size_of::<libc::sockaddr_vm>() as socklen_t) }
787 }
788
789 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
792 pub fn as_vsock_address(&self) -> Option<(u32, u32)> {
793 if self.family() == libc::AF_VSOCK as sa_family_t {
794 let addr = unsafe { &*(self.as_ptr() as *const libc::sockaddr_vm) };
796 Some((addr.svm_cid, addr.svm_port))
797 } else {
798 None
799 }
800 }
801}
802
803#[cfg(not(target_os = "wasi"))]
805impl SockAddr {
806 pub fn is_unnamed(&self) -> bool {
809 self.as_sockaddr_un()
810 .map(|storage| {
811 self.len() == offset_of_path(storage) as _
812 || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))
817 && storage.sun_path[0] == 0)
818 })
819 .unwrap_or_default()
820 }
821
822 pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> {
825 self.is_unix().then(|| {
826 unsafe { &*self.as_ptr().cast::<libc::sockaddr_un>() }
829 })
830 }
831
832 fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
837 debug_assert!(!self.is_unnamed());
838 self.len() as usize - offset_of_path(storage) - 1
839 }
840
841 fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] {
845 debug_assert!(!self.is_unnamed());
846 unsafe {
854 slice::from_raw_parts(
855 (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize),
856 self.path_len(storage),
857 )
858 }
859 }
860
861 pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
864 let path = self.as_pathname()?;
865 Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
868 }
869
870 pub fn as_pathname(&self) -> Option<&Path> {
873 self.as_sockaddr_un().and_then(|storage| {
874 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] != 0).then(|| {
875 let path_slice = self.path_bytes(storage, false);
876 Path::new::<OsStr>(OsStrExt::from_bytes(path_slice))
877 })
878 })
879 }
880
881 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
887 #[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
890 {
891 self.as_sockaddr_un().and_then(|storage| {
892 (self.len() > offset_of_path(storage) as _ && storage.sun_path[0] == 0)
893 .then(|| self.path_bytes(storage, true))
894 })
895 }
896 #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))]
897 None
898 }
899}
900
901pub(crate) type Socket = std::os::fd::OwnedFd;
902pub(crate) type RawSocket = c_int;
903
904pub(crate) unsafe fn socket_from_raw(socket: RawSocket) -> Socket {
905 Socket::from_raw_fd(socket)
906}
907
908pub(crate) fn socket_as_raw(socket: &Socket) -> RawSocket {
909 socket.as_raw_fd()
910}
911
912pub(crate) fn socket_into_raw(socket: Socket) -> RawSocket {
913 socket.into_raw_fd()
914}
915
916pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<RawSocket> {
917 syscall!(socket(family, ty, protocol))
918}
919
920#[cfg(all(feature = "all", unix))]
921pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[RawSocket; 2]> {
922 let mut fds = [0, 0];
923 syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds)
924}
925
926pub(crate) fn bind(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
927 syscall!(bind(fd, addr.as_ptr().cast::<sockaddr>(), addr.len() as _)).map(|_| ())
928}
929
930pub(crate) fn connect(fd: RawSocket, addr: &SockAddr) -> io::Result<()> {
931 syscall!(connect(fd, addr.as_ptr().cast::<sockaddr>(), addr.len())).map(|_| ())
932}
933
934pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
935 let start = Instant::now();
936
937 let mut pollfd = libc::pollfd {
938 fd: socket.as_raw(),
939 events: libc::POLLIN | libc::POLLOUT,
940 revents: 0,
941 };
942
943 loop {
944 let elapsed = start.elapsed();
945 if elapsed >= timeout {
946 return Err(io::ErrorKind::TimedOut.into());
947 }
948
949 let timeout = (timeout - elapsed).as_millis();
950 let timeout = timeout.clamp(1, c_int::MAX as u128) as c_int;
951
952 match syscall!(poll(&mut pollfd, 1, timeout)) {
953 Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
954 Ok(_) => {
955 if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0 {
957 match socket.take_error() {
958 Ok(Some(err)) | Err(err) => return Err(err),
959 Ok(None) => {
960 return Err(io::Error::new(
961 io::ErrorKind::Other,
962 "no error set after POLLHUP",
963 ))
964 }
965 }
966 }
967 return Ok(());
968 }
969 Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
971 Err(err) => return Err(err),
972 }
973 }
974}
975
976pub(crate) fn listen(fd: RawSocket, backlog: c_int) -> io::Result<()> {
977 syscall!(listen(fd, backlog)).map(|_| ())
978}
979
980pub(crate) fn accept(fd: RawSocket) -> io::Result<(RawSocket, SockAddr)> {
981 unsafe { SockAddr::try_init(|storage, len| syscall!(accept(fd, storage.cast(), len))) }
983}
984
985pub(crate) fn getsockname(fd: RawSocket) -> io::Result<SockAddr> {
986 unsafe { SockAddr::try_init(|storage, len| syscall!(getsockname(fd, storage.cast(), len))) }
988 .map(|(_, addr)| addr)
989}
990
991pub(crate) fn getpeername(fd: RawSocket) -> io::Result<SockAddr> {
992 unsafe { SockAddr::try_init(|storage, len| syscall!(getpeername(fd, storage.cast(), len))) }
994 .map(|(_, addr)| addr)
995}
996
997#[cfg(not(target_os = "wasi"))]
998pub(crate) fn try_clone(fd: RawSocket) -> io::Result<RawSocket> {
999 syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0))
1000}
1001
1002#[cfg(all(
1003 feature = "all",
1004 any(unix, all(target_os = "wasi", not(target_env = "p1"))),
1005 not(target_os = "vita")
1006))]
1007pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
1008 let file_status_flags = fcntl_get(fd, libc::F_GETFL)?;
1009 Ok((file_status_flags & libc::O_NONBLOCK) != 0)
1010}
1011
1012#[cfg(all(feature = "all", target_os = "vita"))]
1013pub(crate) fn nonblocking(fd: RawSocket) -> io::Result<bool> {
1014 unsafe {
1015 getsockopt::<Bool>(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK).map(|non_block| non_block != 0)
1016 }
1017}
1018
1019#[cfg(not(target_os = "vita"))]
1020pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::Result<()> {
1021 if nonblocking {
1022 fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1023 } else {
1024 fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
1025 }
1026}
1027
1028#[cfg(target_os = "vita")]
1029pub(crate) fn set_nonblocking(fd: RawSocket, nonblocking: bool) -> io::Result<()> {
1030 unsafe {
1031 setsockopt(
1032 fd,
1033 libc::SOL_SOCKET,
1034 libc::SO_NONBLOCK,
1035 nonblocking as c_int,
1036 )
1037 }
1038}
1039
1040pub(crate) fn shutdown(fd: RawSocket, how: Shutdown) -> io::Result<()> {
1041 let how = match how {
1042 Shutdown::Write => libc::SHUT_WR,
1043 Shutdown::Read => libc::SHUT_RD,
1044 Shutdown::Both => libc::SHUT_RDWR,
1045 };
1046 syscall!(shutdown(fd, how)).map(|_| ())
1047}
1048
1049pub(crate) fn recv(fd: RawSocket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
1050 syscall!(recv(
1051 fd,
1052 buf.as_mut_ptr().cast(),
1053 min(buf.len(), MAX_BUF_LEN),
1054 flags,
1055 ))
1056 .map(|n| n as usize)
1057}
1058
1059pub(crate) fn recv_from(
1060 fd: RawSocket,
1061 buf: &mut [MaybeUninit<u8>],
1062 flags: c_int,
1063) -> io::Result<(usize, SockAddr)> {
1064 unsafe {
1066 SockAddr::try_init(|addr, addrlen| {
1067 syscall!(recvfrom(
1068 fd,
1069 buf.as_mut_ptr().cast(),
1070 min(buf.len(), MAX_BUF_LEN),
1071 flags,
1072 addr.cast(),
1073 addrlen
1074 ))
1075 .map(|n| n as usize)
1076 })
1077 }
1078}
1079
1080pub(crate) fn peek_sender(fd: RawSocket) -> io::Result<SockAddr> {
1081 let (_, sender) = recv_from(fd, &mut [MaybeUninit::uninit(); 8], MSG_PEEK)?;
1086 Ok(sender)
1087}
1088
1089#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
1090pub(crate) fn recv_vectored(
1091 fd: RawSocket,
1092 bufs: &mut [crate::MaybeUninitSlice<'_>],
1093 flags: c_int,
1094) -> io::Result<(usize, RecvFlags)> {
1095 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1096 let n = recvmsg(fd, &mut msg, flags)?;
1097 Ok((n, msg.flags()))
1098}
1099
1100#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
1101pub(crate) fn recv_from_vectored(
1102 fd: RawSocket,
1103 bufs: &mut [crate::MaybeUninitSlice<'_>],
1104 flags: c_int,
1105) -> io::Result<(usize, RecvFlags, SockAddr)> {
1106 let mut msg = MsgHdrMut::new().with_buffers(bufs);
1107 let (n, addr) = unsafe {
1110 SockAddr::try_init(|storage, len| {
1111 msg.inner.msg_name = storage.cast();
1112 msg.inner.msg_namelen = *len;
1113 let n = recvmsg(fd, &mut msg, flags)?;
1114 *len = msg.inner.msg_namelen;
1116 Ok(n)
1117 })?
1118 };
1119 Ok((n, msg.flags(), addr))
1120}
1121
1122#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
1123pub(crate) fn recvmsg(
1124 fd: RawSocket,
1125 msg: &mut MsgHdrMut<'_, '_, '_>,
1126 flags: c_int,
1127) -> io::Result<usize> {
1128 syscall!(recvmsg(fd, &mut msg.inner, flags)).map(|n| n as usize)
1129}
1130
1131pub(crate) fn send(fd: RawSocket, buf: &[u8], flags: c_int) -> io::Result<usize> {
1132 syscall!(send(
1133 fd,
1134 buf.as_ptr().cast(),
1135 min(buf.len(), MAX_BUF_LEN),
1136 flags,
1137 ))
1138 .map(|n| n as usize)
1139}
1140
1141#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
1142pub(crate) fn send_vectored(
1143 fd: RawSocket,
1144 bufs: &[IoSlice<'_>],
1145 flags: c_int,
1146) -> io::Result<usize> {
1147 let msg = MsgHdr::new().with_buffers(bufs);
1148 sendmsg(fd, &msg, flags)
1149}
1150
1151pub(crate) fn send_to(
1152 fd: RawSocket,
1153 buf: &[u8],
1154 addr: &SockAddr,
1155 flags: c_int,
1156) -> io::Result<usize> {
1157 syscall!(sendto(
1158 fd,
1159 buf.as_ptr().cast(),
1160 min(buf.len(), MAX_BUF_LEN),
1161 flags,
1162 addr.as_ptr().cast::<sockaddr>(),
1163 addr.len(),
1164 ))
1165 .map(|n| n as usize)
1166}
1167
1168#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
1169pub(crate) fn send_to_vectored(
1170 fd: RawSocket,
1171 bufs: &[IoSlice<'_>],
1172 addr: &SockAddr,
1173 flags: c_int,
1174) -> io::Result<usize> {
1175 let msg = MsgHdr::new().with_addr(addr).with_buffers(bufs);
1176 sendmsg(fd, &msg, flags)
1177}
1178
1179#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
1180pub(crate) fn sendmsg(fd: RawSocket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io::Result<usize> {
1181 syscall!(sendmsg(fd, &msg.inner, flags)).map(|n| n as usize)
1182}
1183
1184pub(crate) fn timeout_opt(fd: RawSocket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
1186 unsafe { getsockopt(fd, opt, val).map(from_timeval) }
1187}
1188
1189const fn from_timeval(duration: libc::timeval) -> Option<Duration> {
1190 if duration.tv_sec == 0 && duration.tv_usec == 0 {
1191 None
1192 } else {
1193 let sec = duration.tv_sec as u64;
1194 let nsec = (duration.tv_usec as u32) * 1000;
1195 Some(Duration::new(sec, nsec))
1196 }
1197}
1198
1199pub(crate) fn set_timeout_opt(
1201 fd: RawSocket,
1202 opt: c_int,
1203 val: c_int,
1204 duration: Option<Duration>,
1205) -> io::Result<()> {
1206 let duration = into_timeval(duration);
1207 unsafe { setsockopt(fd, opt, val, duration) }
1208}
1209
1210fn into_timeval(duration: Option<Duration>) -> libc::timeval {
1211 match duration {
1212 #[cfg_attr(target_env = "musl", allow(deprecated))]
1214 Some(duration) => libc::timeval {
1215 tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t,
1216 tv_usec: duration.subsec_micros() as libc::suseconds_t,
1217 },
1218 None => libc::timeval {
1219 tv_sec: 0,
1220 tv_usec: 0,
1221 },
1222 }
1223}
1224
1225#[cfg(all(
1226 feature = "all",
1227 not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita"))
1228))]
1229pub(crate) fn tcp_keepalive_time(fd: RawSocket) -> io::Result<Duration> {
1230 unsafe {
1231 getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
1232 .map(|secs| Duration::from_secs(secs as u64))
1233 }
1234}
1235
1236#[allow(unused_variables)]
1237pub(crate) fn set_tcp_keepalive(fd: RawSocket, keepalive: &TcpKeepalive) -> io::Result<()> {
1238 #[cfg(not(any(
1239 target_os = "haiku",
1240 target_os = "openbsd",
1241 target_os = "nto",
1242 target_os = "vita"
1243 )))]
1244 if let Some(time) = keepalive.time {
1245 let secs = into_secs(time);
1246 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1247 }
1248
1249 #[cfg(any(
1250 target_os = "aix",
1251 target_os = "android",
1252 target_os = "dragonfly",
1253 target_os = "freebsd",
1254 target_os = "fuchsia",
1255 target_os = "hurd",
1256 target_os = "illumos",
1257 target_os = "ios",
1258 target_os = "visionos",
1259 target_os = "linux",
1260 target_os = "macos",
1261 target_os = "netbsd",
1262 target_os = "tvos",
1263 target_os = "watchos",
1264 target_os = "cygwin",
1265 all(target_os = "wasi", not(target_env = "p1")),
1266 ))]
1267 {
1268 if let Some(interval) = keepalive.interval {
1269 let secs = into_secs(interval);
1270 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
1271 }
1272
1273 if let Some(retries) = keepalive.retries {
1274 unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
1275 }
1276 }
1277
1278 #[cfg(target_os = "nto")]
1279 if let Some(time) = keepalive.time {
1280 let secs = into_timeval(Some(time));
1281 unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
1282 }
1283
1284 Ok(())
1285}
1286
1287#[cfg(not(any(
1288 target_os = "haiku",
1289 target_os = "openbsd",
1290 target_os = "nto",
1291 target_os = "vita"
1292)))]
1293fn into_secs(duration: Duration) -> c_int {
1294 min(duration.as_secs(), c_int::MAX as u64) as c_int
1295}
1296
1297#[cfg(not(target_os = "vita"))]
1299fn fcntl_get(fd: RawSocket, cmd: c_int) -> io::Result<c_int> {
1300 syscall!(fcntl(fd, cmd))
1301}
1302
1303#[cfg(not(target_os = "vita"))]
1305fn fcntl_add(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1306 let previous = fcntl_get(fd, get_cmd)?;
1307 let new = previous | flag;
1308 if new != previous {
1309 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1310 } else {
1311 Ok(())
1313 }
1314}
1315
1316#[cfg(not(target_os = "vita"))]
1318fn fcntl_remove(fd: RawSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
1319 let previous = fcntl_get(fd, get_cmd)?;
1320 let new = previous & !flag;
1321 if new != previous {
1322 syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
1323 } else {
1324 Ok(())
1326 }
1327}
1328
1329pub(crate) unsafe fn getsockopt<T>(fd: RawSocket, opt: c_int, val: c_int) -> io::Result<T> {
1331 let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
1332 let mut len = size_of::<T>() as libc::socklen_t;
1333 syscall!(getsockopt(
1334 fd,
1335 opt,
1336 val,
1337 payload.as_mut_ptr().cast(),
1338 &mut len,
1339 ))
1340 .map(|_| {
1341 debug_assert_eq!(len as usize, size_of::<T>());
1342 payload.assume_init()
1344 })
1345}
1346
1347pub(crate) unsafe fn setsockopt<T>(
1349 fd: RawSocket,
1350 opt: c_int,
1351 val: c_int,
1352 payload: T,
1353) -> io::Result<()> {
1354 let payload = ptr::addr_of!(payload).cast();
1355 syscall!(setsockopt(
1356 fd,
1357 opt,
1358 val,
1359 payload,
1360 mem::size_of::<T>() as libc::socklen_t,
1361 ))
1362 .map(|_| ())
1363}
1364
1365pub(crate) const fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
1366 in_addr {
1370 s_addr: u32::from_ne_bytes(addr.octets()),
1371 }
1372}
1373
1374pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
1375 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1376}
1377
1378pub(crate) const fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
1379 in6_addr {
1380 s6_addr: addr.octets(),
1381 }
1382}
1383
1384pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
1385 Ipv6Addr::from(addr.s6_addr)
1386}
1387
1388#[cfg(not(any(
1389 target_os = "aix",
1390 target_os = "haiku",
1391 target_os = "illumos",
1392 target_os = "netbsd",
1393 target_os = "openbsd",
1394 target_os = "redox",
1395 target_os = "solaris",
1396 target_os = "nto",
1397 target_os = "espidf",
1398 target_os = "vita",
1399 target_os = "cygwin",
1400 target_os = "wasi",
1401)))]
1402pub(crate) const fn to_mreqn(
1403 multiaddr: &Ipv4Addr,
1404 interface: &crate::socket::InterfaceIndexOrAddress,
1405) -> libc::ip_mreqn {
1406 match interface {
1407 crate::socket::InterfaceIndexOrAddress::Index(interface) => libc::ip_mreqn {
1408 imr_multiaddr: to_in_addr(multiaddr),
1409 imr_address: to_in_addr(&Ipv4Addr::UNSPECIFIED),
1410 imr_ifindex: *interface as _,
1411 },
1412 crate::socket::InterfaceIndexOrAddress::Address(interface) => libc::ip_mreqn {
1413 imr_multiaddr: to_in_addr(multiaddr),
1414 imr_address: to_in_addr(interface),
1415 imr_ifindex: 0,
1416 },
1417 }
1418}
1419
1420#[cfg(all(
1421 feature = "all",
1422 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1423))]
1424pub(crate) fn original_dst_v4(fd: RawSocket) -> io::Result<SockAddr> {
1425 unsafe {
1427 SockAddr::try_init(|storage, len| {
1428 syscall!(getsockopt(
1429 fd,
1430 libc::SOL_IP,
1431 libc::SO_ORIGINAL_DST,
1432 storage.cast(),
1433 len
1434 ))
1435 })
1436 }
1437 .map(|(_, addr)| addr)
1438}
1439
1440#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1445pub(crate) fn original_dst_v6(fd: RawSocket) -> io::Result<SockAddr> {
1446 unsafe {
1448 SockAddr::try_init(|storage, len| {
1449 syscall!(getsockopt(
1450 fd,
1451 libc::SOL_IPV6,
1452 libc::IP6T_SO_ORIGINAL_DST,
1453 storage.cast(),
1454 len
1455 ))
1456 })
1457 }
1458 .map(|(_, addr)| addr)
1459}
1460
1461impl crate::Socket {
1463 #[doc = man_links!(unix: accept4(2))]
1471 #[cfg(all(
1472 feature = "all",
1473 any(
1474 target_os = "android",
1475 target_os = "dragonfly",
1476 target_os = "freebsd",
1477 target_os = "fuchsia",
1478 target_os = "illumos",
1479 target_os = "linux",
1480 target_os = "netbsd",
1481 target_os = "openbsd",
1482 target_os = "cygwin",
1483 )
1484 ))]
1485 pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1486 self._accept4(flags)
1487 }
1488
1489 #[cfg(any(
1490 target_os = "android",
1491 target_os = "dragonfly",
1492 target_os = "freebsd",
1493 target_os = "fuchsia",
1494 target_os = "illumos",
1495 target_os = "linux",
1496 target_os = "netbsd",
1497 target_os = "openbsd",
1498 target_os = "cygwin",
1499 ))]
1500 pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1501 unsafe {
1503 SockAddr::try_init(|storage, len| {
1504 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1505 .map(crate::Socket::from_raw)
1506 })
1507 }
1508 }
1509
1510 #[cfg_attr(
1516 any(
1517 target_os = "ios",
1518 target_os = "visionos",
1519 target_os = "macos",
1520 target_os = "tvos",
1521 target_os = "watchos",
1522 target_os = "wasi",
1523 ),
1524 allow(rustdoc::broken_intra_doc_links)
1525 )]
1526 #[cfg(all(feature = "all", not(target_os = "vita")))]
1527 pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1528 self._set_cloexec(close_on_exec)
1529 }
1530
1531 #[cfg(not(target_os = "vita"))]
1532 pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1533 if close_on_exec {
1534 fcntl_add(
1535 self.as_raw(),
1536 libc::F_GETFD,
1537 libc::F_SETFD,
1538 libc::FD_CLOEXEC,
1539 )
1540 } else {
1541 fcntl_remove(
1542 self.as_raw(),
1543 libc::F_GETFD,
1544 libc::F_SETFD,
1545 libc::FD_CLOEXEC,
1546 )
1547 }
1548 }
1549
1550 #[cfg(target_os = "cygwin")]
1563 #[cfg(any(doc, target_os = "cygwin"))]
1564 pub fn set_no_peercred(&self) -> io::Result<()> {
1565 syscall!(setsockopt(
1566 self.as_raw(),
1567 libc::SOL_SOCKET,
1568 libc::SO_PEERCRED,
1569 ptr::null_mut(),
1570 0,
1571 ))
1572 .map(|_| ())
1573 }
1574
1575 #[cfg(all(
1577 feature = "all",
1578 any(
1579 target_os = "ios",
1580 target_os = "visionos",
1581 target_os = "macos",
1582 target_os = "tvos",
1583 target_os = "watchos",
1584 )
1585 ))]
1586 pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1587 self._set_nosigpipe(nosigpipe)
1588 }
1589
1590 #[cfg(any(
1591 target_os = "ios",
1592 target_os = "visionos",
1593 target_os = "macos",
1594 target_os = "tvos",
1595 target_os = "watchos",
1596 ))]
1597 pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1598 unsafe {
1599 setsockopt(
1600 self.as_raw(),
1601 libc::SOL_SOCKET,
1602 libc::SO_NOSIGPIPE,
1603 nosigpipe as c_int,
1604 )
1605 }
1606 }
1607
1608 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))]
1614 pub fn tcp_mss(&self) -> io::Result<u32> {
1615 unsafe {
1616 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1617 .map(|mss| mss as u32)
1618 }
1619 }
1620
1621 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "wasi"))))]
1626 pub fn set_tcp_mss(&self, mss: u32) -> io::Result<()> {
1627 unsafe {
1628 setsockopt(
1629 self.as_raw(),
1630 libc::IPPROTO_TCP,
1631 libc::TCP_MAXSEG,
1632 mss as c_int,
1633 )
1634 }
1635 }
1636
1637 #[cfg(all(
1640 feature = "all",
1641 any(
1642 target_os = "aix",
1643 target_os = "android",
1644 target_os = "freebsd",
1645 target_os = "fuchsia",
1646 target_os = "linux",
1647 target_os = "cygwin",
1648 )
1649 ))]
1650 pub fn is_listener(&self) -> io::Result<bool> {
1651 unsafe {
1652 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1653 .map(|v| v != 0)
1654 }
1655 }
1656
1657 #[cfg(all(
1660 feature = "all",
1661 any(
1662 target_os = "android",
1663 target_os = "fuchsia",
1666 target_os = "linux",
1667 )
1668 ))]
1669 pub fn domain(&self) -> io::Result<Domain> {
1670 unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1671 }
1672
1673 #[cfg(all(
1676 feature = "all",
1677 any(
1678 target_os = "android",
1679 target_os = "freebsd",
1680 target_os = "fuchsia",
1681 target_os = "linux",
1682 )
1683 ))]
1684 pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1685 unsafe {
1686 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1687 {
1688 0 => None,
1689 p => Some(Protocol(p)),
1690 })
1691 }
1692 }
1693
1694 #[cfg(all(
1701 feature = "all",
1702 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1703 ))]
1704 pub fn mark(&self) -> io::Result<u32> {
1705 unsafe {
1706 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1707 .map(|mark| mark as u32)
1708 }
1709 }
1710
1711 #[cfg(all(
1719 feature = "all",
1720 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1721 ))]
1722 pub fn set_mark(&self, mark: u32) -> io::Result<()> {
1723 unsafe {
1724 setsockopt::<c_int>(
1725 self.as_raw(),
1726 libc::SOL_SOCKET,
1727 libc::SO_MARK,
1728 mark as c_int,
1729 )
1730 }
1731 }
1732
1733 #[cfg(all(
1739 feature = "all",
1740 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1741 ))]
1742 pub fn tcp_cork(&self) -> io::Result<bool> {
1743 unsafe {
1744 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK)
1745 .map(|cork| cork != 0)
1746 }
1747 }
1748
1749 #[cfg(all(
1756 feature = "all",
1757 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1758 ))]
1759 pub fn set_tcp_cork(&self, cork: bool) -> io::Result<()> {
1760 unsafe {
1761 setsockopt(
1762 self.as_raw(),
1763 libc::IPPROTO_TCP,
1764 libc::TCP_CORK,
1765 cork as c_int,
1766 )
1767 }
1768 }
1769
1770 #[cfg(all(
1776 feature = "all",
1777 any(
1778 target_os = "android",
1779 target_os = "fuchsia",
1780 target_os = "linux",
1781 target_os = "cygwin",
1782 )
1783 ))]
1784 pub fn tcp_quickack(&self) -> io::Result<bool> {
1785 unsafe {
1786 getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK)
1787 .map(|quickack| quickack != 0)
1788 }
1789 }
1790
1791 #[cfg(all(
1798 feature = "all",
1799 any(
1800 target_os = "android",
1801 target_os = "fuchsia",
1802 target_os = "linux",
1803 target_os = "cygwin",
1804 )
1805 ))]
1806 pub fn set_tcp_quickack(&self, quickack: bool) -> io::Result<()> {
1807 unsafe {
1808 setsockopt(
1809 self.as_raw(),
1810 libc::IPPROTO_TCP,
1811 libc::TCP_QUICKACK,
1812 quickack as c_int,
1813 )
1814 }
1815 }
1816
1817 #[cfg(all(
1823 feature = "all",
1824 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1825 ))]
1826 pub fn tcp_thin_linear_timeouts(&self) -> io::Result<bool> {
1827 unsafe {
1828 getsockopt::<Bool>(
1829 self.as_raw(),
1830 libc::IPPROTO_TCP,
1831 libc::TCP_THIN_LINEAR_TIMEOUTS,
1832 )
1833 .map(|timeouts| timeouts != 0)
1834 }
1835 }
1836
1837 #[cfg(all(
1843 feature = "all",
1844 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1845 ))]
1846 pub fn set_tcp_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> {
1847 unsafe {
1848 setsockopt(
1849 self.as_raw(),
1850 libc::IPPROTO_TCP,
1851 libc::TCP_THIN_LINEAR_TIMEOUTS,
1852 timeouts as c_int,
1853 )
1854 }
1855 }
1856
1857 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1863 pub fn tcp_notsent_lowat(&self) -> io::Result<u32> {
1864 unsafe {
1865 getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_NOTSENT_LOWAT)
1866 .map(|lowat| lowat as u32)
1867 }
1868 }
1869
1870 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1875 pub fn set_tcp_notsent_lowat(&self, lowat: u32) -> io::Result<()> {
1876 unsafe {
1877 setsockopt(
1878 self.as_raw(),
1879 libc::IPPROTO_TCP,
1880 libc::TCP_NOTSENT_LOWAT,
1881 lowat as c_int,
1882 )
1883 }
1884 }
1885
1886 #[cfg(all(
1890 feature = "all",
1891 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1892 ))]
1893 pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1894 let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1896 unsafe { MaybeUninit::uninit().assume_init() };
1897 let mut len = buf.len() as libc::socklen_t;
1898 syscall!(getsockopt(
1899 self.as_raw(),
1900 libc::SOL_SOCKET,
1901 libc::SO_BINDTODEVICE,
1902 buf.as_mut_ptr().cast(),
1903 &mut len,
1904 ))?;
1905 if len == 0 {
1906 Ok(None)
1907 } else {
1908 let buf = &buf[..len as usize - 1];
1909 Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
1911 }
1912 }
1913
1914 #[cfg(all(
1922 feature = "all",
1923 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1924 ))]
1925 pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
1926 let (value, len) = if let Some(interface) = interface {
1927 (interface.as_ptr(), interface.len())
1928 } else {
1929 (ptr::null(), 0)
1930 };
1931 syscall!(setsockopt(
1932 self.as_raw(),
1933 libc::SOL_SOCKET,
1934 libc::SO_BINDTODEVICE,
1935 value.cast(),
1936 len as libc::socklen_t,
1937 ))
1938 .map(|_| ())
1939 }
1940
1941 #[cfg(all(feature = "all", target_os = "freebsd"))]
1945 pub fn set_fib(&self, fib: u32) -> io::Result<()> {
1946 syscall!(setsockopt(
1947 self.as_raw(),
1948 libc::SOL_SOCKET,
1949 libc::SO_SETFIB,
1950 (&fib as *const u32).cast(),
1951 mem::size_of::<u32>() as libc::socklen_t,
1952 ))
1953 .map(|_| ())
1954 }
1955
1956 #[cfg(all(
1967 feature = "all",
1968 any(
1969 target_os = "ios",
1970 target_os = "visionos",
1971 target_os = "macos",
1972 target_os = "tvos",
1973 target_os = "watchos",
1974 target_os = "illumos",
1975 target_os = "solaris",
1976 target_os = "linux",
1977 target_os = "android",
1978 )
1979 ))]
1980 pub fn bind_device_by_index_v4(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
1981 let index = interface.map_or(0, NonZeroU32::get);
1982
1983 #[cfg(any(
1984 target_os = "ios",
1985 target_os = "visionos",
1986 target_os = "macos",
1987 target_os = "tvos",
1988 target_os = "watchos",
1989 target_os = "illumos",
1990 target_os = "solaris",
1991 ))]
1992 unsafe {
1993 setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index)
1994 }
1995
1996 #[cfg(any(target_os = "linux", target_os = "android",))]
1997 unsafe {
1998 setsockopt(
1999 self.as_raw(),
2000 libc::SOL_SOCKET,
2001 libc::SO_BINDTOIFINDEX,
2002 index,
2003 )
2004 }
2005 }
2006
2007 #[cfg(all(
2018 feature = "all",
2019 any(
2020 target_os = "ios",
2021 target_os = "visionos",
2022 target_os = "macos",
2023 target_os = "tvos",
2024 target_os = "watchos",
2025 target_os = "illumos",
2026 target_os = "solaris",
2027 target_os = "linux",
2028 target_os = "android",
2029 )
2030 ))]
2031 pub fn bind_device_by_index_v6(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
2032 let index = interface.map_or(0, NonZeroU32::get);
2033
2034 #[cfg(any(
2035 target_os = "ios",
2036 target_os = "visionos",
2037 target_os = "macos",
2038 target_os = "tvos",
2039 target_os = "watchos",
2040 target_os = "illumos",
2041 target_os = "solaris",
2042 ))]
2043 unsafe {
2044 setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index)
2045 }
2046
2047 #[cfg(any(target_os = "linux", target_os = "android",))]
2048 unsafe {
2049 setsockopt(
2050 self.as_raw(),
2051 libc::SOL_SOCKET,
2052 libc::SO_BINDTOIFINDEX,
2053 index,
2054 )
2055 }
2056 }
2057
2058 #[cfg(all(
2064 feature = "all",
2065 any(
2066 target_os = "ios",
2067 target_os = "visionos",
2068 target_os = "macos",
2069 target_os = "tvos",
2070 target_os = "watchos",
2071 target_os = "illumos",
2072 target_os = "solaris",
2073 target_os = "linux",
2074 target_os = "android",
2075 )
2076 ))]
2077 pub fn device_index_v4(&self) -> io::Result<Option<NonZeroU32>> {
2078 #[cfg(any(
2079 target_os = "ios",
2080 target_os = "visionos",
2081 target_os = "macos",
2082 target_os = "tvos",
2083 target_os = "watchos",
2084 target_os = "illumos",
2085 target_os = "solaris",
2086 ))]
2087 let index =
2088 unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
2089
2090 #[cfg(any(target_os = "linux", target_os = "android",))]
2091 let index = unsafe {
2092 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2093 };
2094
2095 Ok(NonZeroU32::new(index))
2096 }
2097
2098 #[cfg(all(
2104 feature = "all",
2105 any(
2106 target_os = "ios",
2107 target_os = "visionos",
2108 target_os = "macos",
2109 target_os = "tvos",
2110 target_os = "watchos",
2111 target_os = "illumos",
2112 target_os = "solaris",
2113 target_os = "linux",
2114 target_os = "android",
2115 )
2116 ))]
2117 pub fn device_index_v6(&self) -> io::Result<Option<NonZeroU32>> {
2118 #[cfg(any(
2119 target_os = "ios",
2120 target_os = "visionos",
2121 target_os = "macos",
2122 target_os = "tvos",
2123 target_os = "watchos",
2124 target_os = "illumos",
2125 target_os = "solaris",
2126 ))]
2127 let index = unsafe {
2128 getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)?
2129 };
2130
2131 #[cfg(any(target_os = "linux", target_os = "android",))]
2132 let index = unsafe {
2133 getsockopt::<libc::c_uint>(self.as_raw(), libc::SOL_SOCKET, libc::SO_BINDTOIFINDEX)?
2134 };
2135
2136 Ok(NonZeroU32::new(index))
2137 }
2138
2139 #[cfg(all(feature = "all", target_os = "linux"))]
2145 pub fn cpu_affinity(&self) -> io::Result<usize> {
2146 unsafe {
2147 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
2148 .map(|cpu| cpu as usize)
2149 }
2150 }
2151
2152 #[cfg(all(feature = "all", target_os = "linux"))]
2156 pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
2157 unsafe {
2158 setsockopt(
2159 self.as_raw(),
2160 libc::SOL_SOCKET,
2161 libc::SO_INCOMING_CPU,
2162 cpu as c_int,
2163 )
2164 }
2165 }
2166
2167 #[cfg(all(
2173 feature = "all",
2174 not(any(
2175 target_os = "solaris",
2176 target_os = "illumos",
2177 target_os = "cygwin",
2178 target_os = "wasi"
2179 ))
2180 ))]
2181 pub fn reuse_port(&self) -> io::Result<bool> {
2182 unsafe {
2183 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
2184 .map(|reuse| reuse != 0)
2185 }
2186 }
2187
2188 #[cfg(all(
2194 feature = "all",
2195 not(any(
2196 target_os = "solaris",
2197 target_os = "illumos",
2198 target_os = "cygwin",
2199 target_os = "wasi"
2200 ))
2201 ))]
2202 pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
2203 unsafe {
2204 setsockopt(
2205 self.as_raw(),
2206 libc::SOL_SOCKET,
2207 libc::SO_REUSEPORT,
2208 reuse as c_int,
2209 )
2210 }
2211 }
2212
2213 #[cfg(all(feature = "all", target_os = "freebsd"))]
2219 pub fn reuse_port_lb(&self) -> io::Result<bool> {
2220 unsafe {
2221 getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT_LB)
2222 .map(|reuse| reuse != 0)
2223 }
2224 }
2225
2226 #[cfg(all(feature = "all", target_os = "freebsd"))]
2231 pub fn set_reuse_port_lb(&self, reuse: bool) -> io::Result<()> {
2232 unsafe {
2233 setsockopt(
2234 self.as_raw(),
2235 libc::SOL_SOCKET,
2236 libc::SO_REUSEPORT_LB,
2237 reuse as c_int,
2238 )
2239 }
2240 }
2241
2242 #[cfg(all(
2248 feature = "all",
2249 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2250 ))]
2251 pub fn freebind_v4(&self) -> io::Result<bool> {
2252 unsafe {
2253 getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
2254 .map(|freebind| freebind != 0)
2255 }
2256 }
2257
2258 #[cfg(all(
2266 feature = "all",
2267 any(target_os = "android", target_os = "fuchsia", target_os = "linux")
2268 ))]
2269 pub fn set_freebind_v4(&self, freebind: bool) -> io::Result<()> {
2270 unsafe {
2271 setsockopt(
2272 self.as_raw(),
2273 libc::SOL_IP,
2274 libc::IP_FREEBIND,
2275 freebind as c_int,
2276 )
2277 }
2278 }
2279
2280 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2288 pub fn freebind_v6(&self) -> io::Result<bool> {
2289 unsafe {
2290 getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
2291 .map(|freebind| freebind != 0)
2292 }
2293 }
2294
2295 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2326 pub fn set_freebind_v6(&self, freebind: bool) -> io::Result<()> {
2327 unsafe {
2328 setsockopt(
2329 self.as_raw(),
2330 libc::SOL_IPV6,
2331 libc::IPV6_FREEBIND,
2332 freebind as c_int,
2333 )
2334 }
2335 }
2336
2337 #[doc = man_links!(unix: sendfile(2))]
2347 #[cfg(all(
2357 feature = "all",
2358 any(
2359 target_os = "aix",
2360 target_os = "android",
2361 target_os = "freebsd",
2362 target_os = "ios",
2363 target_os = "visionos",
2364 target_os = "linux",
2365 target_os = "macos",
2366 target_os = "tvos",
2367 target_os = "watchos",
2368 )
2369 ))]
2370 pub fn sendfile<F>(
2371 &self,
2372 file: &F,
2373 offset: usize,
2374 length: Option<NonZeroUsize>,
2375 ) -> io::Result<usize>
2376 where
2377 F: AsRawFd,
2378 {
2379 self._sendfile(file.as_raw_fd(), offset as _, length)
2380 }
2381
2382 #[cfg(all(
2383 feature = "all",
2384 any(
2385 target_os = "ios",
2386 target_os = "visionos",
2387 target_os = "macos",
2388 target_os = "tvos",
2389 target_os = "watchos",
2390 )
2391 ))]
2392 fn _sendfile(
2393 &self,
2394 file: RawFd,
2395 offset: libc::off_t,
2396 length: Option<NonZeroUsize>,
2397 ) -> io::Result<usize> {
2398 let mut length = match length {
2401 Some(n) => n.get() as libc::off_t,
2402 None => 0,
2404 };
2405 syscall!(sendfile(
2406 file,
2407 self.as_raw(),
2408 offset,
2409 &mut length,
2410 ptr::null_mut(),
2411 0,
2412 ))
2413 .map(|_| length as usize)
2414 }
2415
2416 #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
2417 fn _sendfile(
2418 &self,
2419 file: RawFd,
2420 offset: libc::off_t,
2421 length: Option<NonZeroUsize>,
2422 ) -> io::Result<usize> {
2423 let count = match length {
2424 Some(n) => n.get() as libc::size_t,
2425 None => 0x7ffff000, };
2428 let mut offset = offset;
2429 syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
2430 }
2431
2432 #[cfg(all(feature = "all", target_os = "freebsd"))]
2433 fn _sendfile(
2434 &self,
2435 file: RawFd,
2436 offset: libc::off_t,
2437 length: Option<NonZeroUsize>,
2438 ) -> io::Result<usize> {
2439 let nbytes = match length {
2440 Some(n) => n.get() as libc::size_t,
2441 None => 0,
2443 };
2444 let mut sbytes: libc::off_t = 0;
2445 syscall!(sendfile(
2446 file,
2447 self.as_raw(),
2448 offset,
2449 nbytes,
2450 ptr::null_mut(),
2451 &mut sbytes,
2452 0,
2453 ))
2454 .map(|_| sbytes as usize)
2455 }
2456
2457 #[cfg(all(feature = "all", target_os = "aix"))]
2458 fn _sendfile(
2459 &self,
2460 file: RawFd,
2461 offset: libc::off_t,
2462 length: Option<NonZeroUsize>,
2463 ) -> io::Result<usize> {
2464 let nbytes = match length {
2465 Some(n) => n.get() as i64,
2466 None => -1,
2467 };
2468 let mut params = libc::sf_parms {
2469 header_data: ptr::null_mut(),
2470 header_length: 0,
2471 file_descriptor: file,
2472 file_size: 0,
2473 file_offset: offset as u64,
2474 file_bytes: nbytes,
2475 trailer_data: ptr::null_mut(),
2476 trailer_length: 0,
2477 bytes_sent: 0,
2478 };
2479 syscall!(send_file(
2481 &mut self.as_raw() as *mut _,
2482 &mut params as *mut _,
2483 libc::SF_CLOSE as libc::c_uint,
2484 ))
2485 .map(|_| params.bytes_sent as usize)
2486 }
2487
2488 #[cfg(all(
2499 feature = "all",
2500 any(
2501 target_os = "android",
2502 target_os = "fuchsia",
2503 target_os = "linux",
2504 target_os = "cygwin",
2505 )
2506 ))]
2507 pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
2508 let timeout = timeout.map_or(0, |to| {
2509 min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint
2510 });
2511 unsafe {
2512 setsockopt(
2513 self.as_raw(),
2514 libc::IPPROTO_TCP,
2515 libc::TCP_USER_TIMEOUT,
2516 timeout,
2517 )
2518 }
2519 }
2520
2521 #[cfg(all(
2527 feature = "all",
2528 any(
2529 target_os = "android",
2530 target_os = "fuchsia",
2531 target_os = "linux",
2532 target_os = "cygwin",
2533 )
2534 ))]
2535 pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
2536 unsafe {
2537 getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
2538 .map(|millis| {
2539 if millis == 0 {
2540 None
2541 } else {
2542 Some(Duration::from_millis(millis as u64))
2543 }
2544 })
2545 }
2546 }
2547
2548 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2555 pub fn attach_filter(&self, filters: &[SockFilter]) -> io::Result<()> {
2556 let prog = libc::sock_fprog {
2557 len: filters.len() as u16,
2558 filter: filters.as_ptr() as *mut _,
2560 };
2561
2562 unsafe {
2563 setsockopt(
2564 self.as_raw(),
2565 libc::SOL_SOCKET,
2566 libc::SO_ATTACH_FILTER,
2567 prog,
2568 )
2569 }
2570 }
2571
2572 #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2578 pub fn detach_filter(&self) -> io::Result<()> {
2579 unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) }
2580 }
2581
2582 #[cfg(all(feature = "all", target_os = "linux"))]
2589 pub fn cookie(&self) -> io::Result<u64> {
2590 unsafe { getsockopt::<libc::c_ulonglong>(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) }
2591 }
2592
2593 #[cfg(all(
2599 feature = "all",
2600 any(
2601 target_os = "android",
2602 target_os = "dragonfly",
2603 target_os = "freebsd",
2604 target_os = "fuchsia",
2605 target_os = "linux",
2606 target_os = "macos",
2607 target_os = "netbsd",
2608 target_os = "openbsd",
2609 target_os = "cygwin",
2610 )
2611 ))]
2612 pub fn tclass_v6(&self) -> io::Result<u32> {
2613 unsafe {
2614 getsockopt::<c_int>(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS)
2615 .map(|tclass| tclass as u32)
2616 }
2617 }
2618
2619 #[cfg(all(
2624 feature = "all",
2625 any(
2626 target_os = "android",
2627 target_os = "dragonfly",
2628 target_os = "freebsd",
2629 target_os = "fuchsia",
2630 target_os = "linux",
2631 target_os = "macos",
2632 target_os = "netbsd",
2633 target_os = "openbsd",
2634 target_os = "cygwin",
2635 )
2636 ))]
2637 pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> {
2638 unsafe {
2639 setsockopt(
2640 self.as_raw(),
2641 IPPROTO_IPV6,
2642 libc::IPV6_TCLASS,
2643 tclass as c_int,
2644 )
2645 }
2646 }
2647
2648 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2654 pub fn tcp_congestion(&self) -> io::Result<Vec<u8>> {
2655 let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX];
2656 let mut len = payload.len() as libc::socklen_t;
2657 syscall!(getsockopt(
2658 self.as_raw(),
2659 IPPROTO_TCP,
2660 libc::TCP_CONGESTION,
2661 payload.as_mut_ptr().cast(),
2662 &mut len,
2663 ))
2664 .map(|_| payload[..len as usize].to_vec())
2665 }
2666
2667 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
2674 pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> {
2675 syscall!(setsockopt(
2676 self.as_raw(),
2677 IPPROTO_TCP,
2678 libc::TCP_CONGESTION,
2679 tcp_ca_name.as_ptr() as *const _,
2680 tcp_ca_name.len() as libc::socklen_t,
2681 ))
2682 .map(|_| ())
2683 }
2684
2685 #[cfg(all(feature = "all", target_os = "linux"))]
2696 pub fn set_dccp_service(&self, code: u32) -> io::Result<()> {
2697 unsafe {
2698 setsockopt(
2699 self.as_raw(),
2700 libc::SOL_DCCP,
2701 libc::DCCP_SOCKOPT_SERVICE,
2702 code,
2703 )
2704 }
2705 }
2706
2707 #[cfg(all(feature = "all", target_os = "linux"))]
2713 pub fn dccp_service(&self) -> io::Result<u32> {
2714 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) }
2715 }
2716
2717 #[cfg(all(feature = "all", target_os = "linux"))]
2721 pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> {
2722 unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) }
2723 }
2724
2725 #[cfg(all(feature = "all", target_os = "linux"))]
2731 pub fn dccp_tx_ccid(&self) -> io::Result<u32> {
2732 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) }
2733 }
2734
2735 #[cfg(all(feature = "all", target_os = "linux"))]
2741 pub fn dccp_xx_ccid(&self) -> io::Result<u32> {
2742 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) }
2743 }
2744
2745 #[cfg(all(feature = "all", target_os = "linux"))]
2750 pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> {
2751 unsafe {
2752 setsockopt(
2753 self.as_raw(),
2754 libc::SOL_DCCP,
2755 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2756 hold_timewait as c_int,
2757 )
2758 }
2759 }
2760
2761 #[cfg(all(feature = "all", target_os = "linux"))]
2767 pub fn dccp_server_timewait(&self) -> io::Result<bool> {
2768 unsafe {
2769 getsockopt(
2770 self.as_raw(),
2771 libc::SOL_DCCP,
2772 libc::DCCP_SOCKOPT_SERVER_TIMEWAIT,
2773 )
2774 }
2775 }
2776
2777 #[cfg(all(feature = "all", target_os = "linux"))]
2785 pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> {
2786 unsafe {
2787 setsockopt(
2788 self.as_raw(),
2789 libc::SOL_DCCP,
2790 libc::DCCP_SOCKOPT_SEND_CSCOV,
2791 level,
2792 )
2793 }
2794 }
2795
2796 #[cfg(all(feature = "all", target_os = "linux"))]
2802 pub fn dccp_send_cscov(&self) -> io::Result<u32> {
2803 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) }
2804 }
2805
2806 #[cfg(all(feature = "all", target_os = "linux"))]
2812 pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> {
2813 unsafe {
2814 setsockopt(
2815 self.as_raw(),
2816 libc::SOL_DCCP,
2817 libc::DCCP_SOCKOPT_RECV_CSCOV,
2818 level,
2819 )
2820 }
2821 }
2822
2823 #[cfg(all(feature = "all", target_os = "linux"))]
2829 pub fn dccp_recv_cscov(&self) -> io::Result<u32> {
2830 unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) }
2831 }
2832
2833 #[cfg(all(feature = "all", target_os = "linux"))]
2838 pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> {
2839 unsafe {
2840 setsockopt(
2841 self.as_raw(),
2842 libc::SOL_DCCP,
2843 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2844 length,
2845 )
2846 }
2847 }
2848
2849 #[cfg(all(feature = "all", target_os = "linux"))]
2855 pub fn dccp_qpolicy_txqlen(&self) -> io::Result<u32> {
2856 unsafe {
2857 getsockopt(
2858 self.as_raw(),
2859 libc::SOL_DCCP,
2860 libc::DCCP_SOCKOPT_QPOLICY_TXQLEN,
2861 )
2862 }
2863 }
2864
2865 #[cfg(all(feature = "all", target_os = "linux"))]
2875 pub fn dccp_available_ccids<const N: usize>(&self) -> io::Result<CcidEndpoints<N>> {
2876 let mut endpoints = [0; N];
2877 let mut length = endpoints.len() as libc::socklen_t;
2878 syscall!(getsockopt(
2879 self.as_raw(),
2880 libc::SOL_DCCP,
2881 libc::DCCP_SOCKOPT_AVAILABLE_CCIDS,
2882 endpoints.as_mut_ptr().cast(),
2883 &mut length,
2884 ))?;
2885 Ok(CcidEndpoints { endpoints, length })
2886 }
2887
2888 #[cfg(all(feature = "all", target_os = "linux"))]
2893 pub fn dccp_cur_mps(&self) -> io::Result<u32> {
2894 unsafe {
2895 getsockopt(
2896 self.as_raw(),
2897 libc::SOL_DCCP,
2898 libc::DCCP_SOCKOPT_GET_CUR_MPS,
2899 )
2900 }
2901 }
2902
2903 #[cfg(all(feature = "all", target_os = "linux"))]
2907 pub fn busy_poll(&self) -> io::Result<u32> {
2908 unsafe { getsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_BUSY_POLL) }
2909 }
2910
2911 #[cfg(all(feature = "all", target_os = "linux"))]
2915 pub fn set_busy_poll(&self, busy_poll: u32) -> io::Result<()> {
2916 unsafe {
2917 setsockopt(
2918 self.as_raw(),
2919 libc::SOL_SOCKET,
2920 libc::SO_BUSY_POLL,
2921 busy_poll as c_int,
2922 )
2923 }
2924 }
2925}
2926
2927#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2933#[repr(transparent)]
2934pub struct SockFilter {
2935 #[allow(dead_code)]
2938 filter: libc::sock_filter,
2939}
2940
2941#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2942impl SockFilter {
2943 pub const fn new(code: u16, jt: u8, jf: u8, k: u32) -> SockFilter {
2945 SockFilter {
2946 filter: libc::sock_filter { code, jt, jf, k },
2947 }
2948 }
2949}
2950
2951#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
2952impl std::fmt::Debug for SockFilter {
2953 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2954 f.debug_struct("SockFilter").finish_non_exhaustive()
2955 }
2956}
2957
2958#[cfg(all(feature = "all", target_os = "linux"))]
2962#[derive(Debug)]
2963pub struct CcidEndpoints<const N: usize> {
2964 endpoints: [u8; N],
2965 length: u32,
2966}
2967
2968#[cfg(all(feature = "all", target_os = "linux"))]
2969impl<const N: usize> std::ops::Deref for CcidEndpoints<N> {
2970 type Target = [u8];
2971
2972 fn deref(&self) -> &[u8] {
2973 &self.endpoints[0..self.length as usize]
2974 }
2975}
2976
2977impl AsFd for crate::Socket {
2978 fn as_fd(&self) -> BorrowedFd<'_> {
2979 unsafe { BorrowedFd::borrow_raw(self.as_raw()) }
2981 }
2982}
2983
2984impl AsRawFd for crate::Socket {
2985 fn as_raw_fd(&self) -> RawFd {
2986 self.as_raw()
2987 }
2988}
2989
2990impl From<crate::Socket> for OwnedFd {
2991 fn from(sock: crate::Socket) -> OwnedFd {
2992 unsafe { OwnedFd::from_raw_fd(sock.into_raw()) }
2994 }
2995}
2996
2997impl IntoRawFd for crate::Socket {
2998 fn into_raw_fd(self) -> c_int {
2999 self.into_raw()
3000 }
3001}
3002
3003impl From<OwnedFd> for crate::Socket {
3004 fn from(fd: OwnedFd) -> crate::Socket {
3005 unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) }
3007 }
3008}
3009
3010impl FromRawFd for crate::Socket {
3011 unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
3012 crate::Socket::from_raw(fd)
3013 }
3014}
3015
3016#[cfg(all(feature = "all", unix))]
3017from!(UnixStream, crate::Socket);
3018#[cfg(all(feature = "all", unix))]
3019from!(UnixListener, crate::Socket);
3020#[cfg(all(feature = "all", unix))]
3021from!(UnixDatagram, crate::Socket);
3022#[cfg(all(feature = "all", unix))]
3023from!(crate::Socket, UnixStream);
3024#[cfg(all(feature = "all", unix))]
3025from!(crate::Socket, UnixListener);
3026#[cfg(all(feature = "all", unix))]
3027from!(crate::Socket, UnixDatagram);
3028
3029#[test]
3030fn in_addr_convertion() {
3031 let ip = Ipv4Addr::new(127, 0, 0, 1);
3032 let raw = to_in_addr(&ip);
3033 let a = raw.s_addr;
3035 assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
3036 assert_eq!(from_in_addr(raw), ip);
3037
3038 let ip = Ipv4Addr::new(127, 34, 4, 12);
3039 let raw = to_in_addr(&ip);
3040 let a = raw.s_addr;
3041 assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
3042 assert_eq!(from_in_addr(raw), ip);
3043}
3044
3045#[test]
3046fn in6_addr_convertion() {
3047 let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
3048 let raw = to_in6_addr(&ip);
3049 let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
3050 assert_eq!(raw.s6_addr, want);
3051 assert_eq!(from_in6_addr(raw), ip);
3052}