1 // Copyright 2015 The Rust Project Developers.
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 use std::cmp::min;
10 #[cfg(not(target_os = "redox"))]
11 use std::io::IoSlice;
12 use std::marker::PhantomData;
13 use std::mem::{self, size_of, MaybeUninit};
14 use std::net::Shutdown;
15 use std::net::{Ipv4Addr, Ipv6Addr};
16 #[cfg(all(feature = "all", target_vendor = "apple"))]
17 use std::num::NonZeroU32;
18 #[cfg(all(
19     feature = "all",
20     any(
21         target_os = "android",
22         target_os = "freebsd",
23         target_os = "linux",
24         target_vendor = "apple",
25     )
26 ))]
27 use std::num::NonZeroUsize;
28 #[cfg(feature = "all")]
29 use std::os::unix::ffi::OsStrExt;
30 #[cfg(all(
31     feature = "all",
32     any(
33         target_os = "android",
34         target_os = "freebsd",
35         target_os = "linux",
36         target_vendor = "apple",
37     )
38 ))]
39 use std::os::unix::io::RawFd;
40 use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
41 #[cfg(feature = "all")]
42 use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
43 #[cfg(feature = "all")]
44 use std::path::Path;
45 #[cfg(not(all(target_os = "redox", not(feature = "all"))))]
46 use std::ptr;
47 use std::time::{Duration, Instant};
48 use std::{io, slice};
49 
50 #[cfg(not(target_vendor = "apple"))]
51 use libc::ssize_t;
52 use libc::{c_void, in6_addr, in_addr};
53 
54 #[cfg(not(target_os = "redox"))]
55 use crate::RecvFlags;
56 use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
57 
58 pub(crate) use libc::c_int;
59 
60 // Used in `Domain`.
61 pub(crate) use libc::{AF_INET, AF_INET6};
62 // Used in `Type`.
63 #[cfg(all(feature = "all", not(target_os = "redox")))]
64 pub(crate) use libc::SOCK_RAW;
65 #[cfg(feature = "all")]
66 pub(crate) use libc::SOCK_SEQPACKET;
67 pub(crate) use libc::{SOCK_DGRAM, SOCK_STREAM};
68 // Used in `Protocol`.
69 pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP};
70 // Used in `SockAddr`.
71 pub(crate) use libc::{
72     sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t,
73 };
74 // Used in `RecvFlags`.
75 #[cfg(not(target_os = "redox"))]
76 pub(crate) use libc::{MSG_TRUNC, SO_OOBINLINE};
77 // Used in `Socket`.
78 #[cfg(not(any(
79     target_os = "fuschia",
80     target_os = "redox",
81     target_os = "solaris",
82     target_os = "illumos",
83 )))]
84 pub(crate) use libc::IP_TOS;
85 #[cfg(not(target_vendor = "apple"))]
86 pub(crate) use libc::SO_LINGER;
87 #[cfg(target_vendor = "apple")]
88 pub(crate) use libc::SO_LINGER_SEC as SO_LINGER;
89 pub(crate) use libc::{
90     ip_mreq as IpMreq, ipv6_mreq as Ipv6Mreq, linger, IPPROTO_IP, IPPROTO_IPV6,
91     IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY,
92     IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
93     IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF,
94     SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
95 };
96 #[cfg(not(any(
97     target_os = "dragonfly",
98     target_os = "freebsd",
99     target_os = "haiku",
100     target_os = "illumos",
101     target_os = "netbsd",
102     target_os = "openbsd",
103     target_os = "solaris",
104     target_vendor = "apple"
105 )))]
106 pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
107 #[cfg(any(
108     target_os = "dragonfly",
109     target_os = "freebsd",
110     target_os = "haiku",
111     target_os = "illumos",
112     target_os = "netbsd",
113     target_os = "openbsd",
114     target_os = "solaris",
115     target_vendor = "apple",
116 ))]
117 pub(crate) use libc::{
118     IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP,
119 };
120 #[cfg(all(
121     feature = "all",
122     any(
123         target_os = "android",
124         target_os = "dragonfly",
125         target_os = "freebsd",
126         target_os = "fuchsia",
127         target_os = "illumos",
128         target_os = "linux",
129         target_os = "netbsd",
130         target_vendor = "apple",
131     )
132 ))]
133 pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL};
134 
135 // See this type in the Windows file.
136 pub(crate) type Bool = c_int;
137 
138 #[cfg(target_vendor = "apple")]
139 use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
140 #[cfg(not(any(target_vendor = "apple", target_os = "haiku", target_os = "openbsd")))]
141 use libc::TCP_KEEPIDLE as KEEPALIVE_TIME;
142 
143 /// Helper macro to execute a system call that returns an `io::Result`.
144 macro_rules! syscall {
145     ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
146         #[allow(unused_unsafe)]
147         let res = unsafe { libc::$fn($($arg, )*) };
148         if res == -1 {
149             Err(std::io::Error::last_os_error())
150         } else {
151             Ok(res)
152         }
153     }};
154 }
155 
156 /// Maximum size of a buffer passed to system call like `recv` and `send`.
157 #[cfg(not(target_vendor = "apple"))]
158 const MAX_BUF_LEN: usize = <ssize_t>::max_value() as usize;
159 
160 // The maximum read limit on most posix-like systems is `SSIZE_MAX`, with the
161 // man page quoting that if the count of bytes to read is greater than
162 // `SSIZE_MAX` the result is "unspecified".
163 //
164 // On macOS, however, apparently the 64-bit libc is either buggy or
165 // intentionally showing odd behavior by rejecting any read with a size larger
166 // than or equal to INT_MAX. To handle both of these the read size is capped on
167 // both platforms.
168 #[cfg(target_vendor = "apple")]
169 const MAX_BUF_LEN: usize = <c_int>::max_value() as usize - 1;
170 
171 #[cfg(any(
172     all(
173         target_os = "linux",
174         any(
175             target_env = "gnu",
176             all(target_env = "uclibc", target_pointer_width = "64")
177         )
178     ),
179     target_os = "android",
180 ))]
181 type IovLen = usize;
182 
183 #[cfg(any(
184     all(
185         target_os = "linux",
186         any(
187             target_env = "musl",
188             all(target_env = "uclibc", target_pointer_width = "32")
189         )
190     ),
191     target_os = "dragonfly",
192     target_os = "freebsd",
193     target_os = "fuchsia",
194     target_os = "haiku",
195     target_os = "illumos",
196     target_os = "netbsd",
197     target_os = "openbsd",
198     target_os = "solaris",
199     target_vendor = "apple",
200 ))]
201 type IovLen = c_int;
202 
203 /// Unix only API.
204 impl Domain {
205     /// Domain for Unix socket communication, corresponding to `AF_UNIX`.
206     #[cfg_attr(docsrs, doc(cfg(unix)))]
207     pub const UNIX: Domain = Domain(libc::AF_UNIX);
208 
209     /// Domain for low-level packet interface, corresponding to `AF_PACKET`.
210     #[cfg(all(
211         feature = "all",
212         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
213     ))]
214     #[cfg_attr(
215         docsrs,
216         doc(cfg(all(
217             feature = "all",
218             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
219         )))
220     )]
221     pub const PACKET: Domain = Domain(libc::AF_PACKET);
222 
223     /// Domain for low-level VSOCK interface, corresponding to `AF_VSOCK`.
224     #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
225     #[cfg_attr(
226         docsrs,
227         doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
228     )]
229     pub const VSOCK: Domain = Domain(libc::AF_VSOCK);
230 }
231 
232 impl_debug!(
233     Domain,
234     libc::AF_INET,
235     libc::AF_INET6,
236     libc::AF_UNIX,
237     #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
238     #[cfg_attr(
239         docsrs,
240         doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
241     )]
242     libc::AF_PACKET,
243     #[cfg(any(target_os = "android", target_os = "linux"))]
244     #[cfg_attr(docsrs, doc(cfg(any(target_os = "android", target_os = "linux"))))]
245     libc::AF_VSOCK,
246     libc::AF_UNSPEC, // = 0.
247 );
248 
249 /// Unix only API.
250 impl Type {
251     /// Set `SOCK_NONBLOCK` on the `Type`.
252     #[cfg(all(
253         feature = "all",
254         any(
255             target_os = "android",
256             target_os = "dragonfly",
257             target_os = "freebsd",
258             target_os = "fuchsia",
259             target_os = "illumos",
260             target_os = "linux",
261             target_os = "netbsd",
262             target_os = "openbsd"
263         )
264     ))]
265     #[cfg_attr(
266         docsrs,
267         doc(cfg(all(
268             feature = "all",
269             any(
270                 target_os = "android",
271                 target_os = "dragonfly",
272                 target_os = "freebsd",
273                 target_os = "fuchsia",
274                 target_os = "illumos",
275                 target_os = "linux",
276                 target_os = "netbsd",
277                 target_os = "openbsd"
278             )
279         )))
280     )]
nonblocking(self) -> Type281     pub const fn nonblocking(self) -> Type {
282         Type(self.0 | libc::SOCK_NONBLOCK)
283     }
284 
285     /// Set `SOCK_CLOEXEC` on the `Type`.
286     #[cfg(all(
287         feature = "all",
288         any(
289             target_os = "android",
290             target_os = "dragonfly",
291             target_os = "freebsd",
292             target_os = "fuchsia",
293             target_os = "illumos",
294             target_os = "linux",
295             target_os = "netbsd",
296             target_os = "openbsd"
297         )
298     ))]
299     #[cfg_attr(
300         docsrs,
301         doc(cfg(all(
302             feature = "all",
303             any(
304                 target_os = "android",
305                 target_os = "dragonfly",
306                 target_os = "freebsd",
307                 target_os = "fuchsia",
308                 target_os = "illumos",
309                 target_os = "linux",
310                 target_os = "netbsd",
311                 target_os = "openbsd"
312             )
313         )))
314     )]
cloexec(self) -> Type315     pub const fn cloexec(self) -> Type {
316         self._cloexec()
317     }
318 
319     #[cfg(any(
320         target_os = "android",
321         target_os = "dragonfly",
322         target_os = "freebsd",
323         target_os = "fuchsia",
324         target_os = "illumos",
325         target_os = "linux",
326         target_os = "netbsd",
327         target_os = "openbsd"
328     ))]
_cloexec(self) -> Type329     pub(crate) const fn _cloexec(self) -> Type {
330         Type(self.0 | libc::SOCK_CLOEXEC)
331     }
332 }
333 
334 impl_debug!(
335     Type,
336     libc::SOCK_STREAM,
337     libc::SOCK_DGRAM,
338     #[cfg(not(target_os = "redox"))]
339     libc::SOCK_RAW,
340     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
341     libc::SOCK_RDM,
342     libc::SOCK_SEQPACKET,
343     /* TODO: add these optional bit OR-ed flags:
344     #[cfg(any(
345         target_os = "android",
346         target_os = "dragonfly",
347         target_os = "freebsd",
348         target_os = "fuchsia",
349         target_os = "linux",
350         target_os = "netbsd",
351         target_os = "openbsd"
352     ))]
353     libc::SOCK_NONBLOCK,
354     #[cfg(any(
355         target_os = "android",
356         target_os = "dragonfly",
357         target_os = "freebsd",
358         target_os = "fuchsia",
359         target_os = "linux",
360         target_os = "netbsd",
361         target_os = "openbsd"
362     ))]
363     libc::SOCK_CLOEXEC,
364     */
365 );
366 
367 impl_debug!(
368     Protocol,
369     libc::IPPROTO_ICMP,
370     libc::IPPROTO_ICMPV6,
371     libc::IPPROTO_TCP,
372     libc::IPPROTO_UDP,
373 );
374 
375 /// Unix-only API.
376 #[cfg(not(target_os = "redox"))]
377 impl RecvFlags {
378     /// Check if the message terminates a record.
379     ///
380     /// Not all socket types support the notion of records.
381     /// For socket types that do support it (such as [`SEQPACKET`][Type::SEQPACKET]),
382     /// a record is terminated by sending a message with the end-of-record flag set.
383     ///
384     /// On Unix this corresponds to the MSG_EOR flag.
is_end_of_record(self) -> bool385     pub const fn is_end_of_record(self) -> bool {
386         self.0 & libc::MSG_EOR != 0
387     }
388 
389     /// Check if the message contains out-of-band data.
390     ///
391     /// This is useful for protocols where you receive out-of-band data
392     /// mixed in with the normal data stream.
393     ///
394     /// On Unix this corresponds to the MSG_OOB flag.
is_out_of_band(self) -> bool395     pub const fn is_out_of_band(self) -> bool {
396         self.0 & libc::MSG_OOB != 0
397     }
398 }
399 
400 #[cfg(not(target_os = "redox"))]
401 impl std::fmt::Debug for RecvFlags {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result402     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
403         f.debug_struct("RecvFlags")
404             .field("is_end_of_record", &self.is_end_of_record())
405             .field("is_out_of_band", &self.is_out_of_band())
406             .field("is_truncated", &self.is_truncated())
407             .finish()
408     }
409 }
410 
411 #[repr(transparent)]
412 pub struct MaybeUninitSlice<'a> {
413     vec: libc::iovec,
414     _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
415 }
416 
417 impl<'a> MaybeUninitSlice<'a> {
new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a>418     pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
419         MaybeUninitSlice {
420             vec: libc::iovec {
421                 iov_base: buf.as_mut_ptr().cast(),
422                 iov_len: buf.len(),
423             },
424             _lifetime: PhantomData,
425         }
426     }
427 
as_slice(&self) -> &[MaybeUninit<u8>]428     pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
429         unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
430     }
431 
as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>]432     pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
433         unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
434     }
435 }
436 
437 /// Unix only API.
438 impl SockAddr {
439     /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
440     ///
441     /// # Failure
442     ///
443     /// Returns an error if the path is longer than `SUN_LEN`.
444     #[cfg(feature = "all")]
445     #[cfg_attr(docsrs, doc(cfg(all(unix, feature = "all"))))]
446     #[allow(unused_unsafe)] // TODO: replace with `unsafe_op_in_unsafe_fn` once stable.
unix<P>(path: P) -> io::Result<SockAddr> where P: AsRef<Path>,447     pub fn unix<P>(path: P) -> io::Result<SockAddr>
448     where
449         P: AsRef<Path>,
450     {
451         unsafe {
452             SockAddr::init(|storage, len| {
453                 // Safety: `SockAddr::init` zeros the address, which is a valid
454                 // representation.
455                 let storage: &mut libc::sockaddr_un = unsafe { &mut *storage.cast() };
456                 let len: &mut socklen_t = unsafe { &mut *len };
457 
458                 let bytes = path.as_ref().as_os_str().as_bytes();
459                 let too_long = match bytes.first() {
460                     None => false,
461                     // linux abstract namespaces aren't null-terminated
462                     Some(&0) => bytes.len() > storage.sun_path.len(),
463                     Some(_) => bytes.len() >= storage.sun_path.len(),
464                 };
465                 if too_long {
466                     return Err(io::Error::new(
467                         io::ErrorKind::InvalidInput,
468                         "path must be shorter than SUN_LEN",
469                     ));
470                 }
471 
472                 storage.sun_family = libc::AF_UNIX as sa_family_t;
473                 // Safety: `bytes` and `addr.sun_path` are not overlapping and
474                 // both point to valid memory.
475                 // `SockAddr::init` zeroes the memory, so the path is already
476                 // null terminated.
477                 unsafe {
478                     ptr::copy_nonoverlapping(
479                         bytes.as_ptr(),
480                         storage.sun_path.as_mut_ptr() as *mut u8,
481                         bytes.len(),
482                     )
483                 };
484 
485                 let base = storage as *const _ as usize;
486                 let path = &storage.sun_path as *const _ as usize;
487                 let sun_path_offset = path - base;
488                 let length = sun_path_offset
489                     + bytes.len()
490                     + match bytes.first() {
491                         Some(&0) | None => 0,
492                         Some(_) => 1,
493                     };
494                 *len = length as socklen_t;
495 
496                 Ok(())
497             })
498         }
499         .map(|(_, addr)| addr)
500     }
501 }
502 
503 impl SockAddr {
504     /// Constructs a `SockAddr` with the family `AF_VSOCK` and the provided CID/port.
505     ///
506     /// # Errors
507     ///
508     /// This function can never fail. In a future version of this library it will be made
509     /// infallible.
510     #[allow(unused_unsafe)] // TODO: replace with `unsafe_op_in_unsafe_fn` once stable.
511     #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
512     #[cfg_attr(
513         docsrs,
514         doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
515     )]
vsock(cid: u32, port: u32) -> io::Result<SockAddr>516     pub fn vsock(cid: u32, port: u32) -> io::Result<SockAddr> {
517         unsafe {
518             SockAddr::init(|storage, len| {
519                 // Safety: `SockAddr::init` zeros the address, which is a valid
520                 // representation.
521                 let storage: &mut libc::sockaddr_vm = unsafe { &mut *storage.cast() };
522                 let len: &mut socklen_t = unsafe { &mut *len };
523 
524                 storage.svm_family = libc::AF_VSOCK as sa_family_t;
525                 storage.svm_cid = cid;
526                 storage.svm_port = port;
527 
528                 *len = mem::size_of::<libc::sockaddr_vm>() as socklen_t;
529 
530                 Ok(())
531             })
532         }
533         .map(|(_, addr)| addr)
534     }
535 
536     /// Returns this address VSOCK CID/port if it is in the `AF_VSOCK` family,
537     /// otherwise return `None`.
538     #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
539     #[cfg_attr(
540         docsrs,
541         doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
542     )]
vsock_address(&self) -> Option<(u32, u32)>543     pub fn vsock_address(&self) -> Option<(u32, u32)> {
544         if self.family() == libc::AF_VSOCK as sa_family_t {
545             // Safety: if the ss_family field is AF_VSOCK then storage must be a sockaddr_vm.
546             let addr = unsafe { &*(self.as_ptr() as *const libc::sockaddr_vm) };
547             Some((addr.svm_cid, addr.svm_port))
548         } else {
549             None
550         }
551     }
552 }
553 
554 pub(crate) type Socket = c_int;
555 
socket_from_raw(socket: Socket) -> crate::socket::Inner556 pub(crate) unsafe fn socket_from_raw(socket: Socket) -> crate::socket::Inner {
557     crate::socket::Inner::from_raw_fd(socket)
558 }
559 
socket_as_raw(socket: &crate::socket::Inner) -> Socket560 pub(crate) fn socket_as_raw(socket: &crate::socket::Inner) -> Socket {
561     socket.as_raw_fd()
562 }
563 
socket_into_raw(socket: crate::socket::Inner) -> Socket564 pub(crate) fn socket_into_raw(socket: crate::socket::Inner) -> Socket {
565     socket.into_raw_fd()
566 }
567 
socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket>568 pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> {
569     syscall!(socket(family, ty, protocol))
570 }
571 
572 #[cfg(feature = "all")]
socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[Socket; 2]>573 pub(crate) fn socketpair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<[Socket; 2]> {
574     let mut fds = [0, 0];
575     syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds)
576 }
577 
bind(fd: Socket, addr: &SockAddr) -> io::Result<()>578 pub(crate) fn bind(fd: Socket, addr: &SockAddr) -> io::Result<()> {
579     syscall!(bind(fd, addr.as_ptr(), addr.len() as _)).map(|_| ())
580 }
581 
connect(fd: Socket, addr: &SockAddr) -> io::Result<()>582 pub(crate) fn connect(fd: Socket, addr: &SockAddr) -> io::Result<()> {
583     syscall!(connect(fd, addr.as_ptr(), addr.len())).map(|_| ())
584 }
585 
poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()>586 pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
587     let start = Instant::now();
588 
589     let mut pollfd = libc::pollfd {
590         fd: socket.as_raw(),
591         events: libc::POLLIN | libc::POLLOUT,
592         revents: 0,
593     };
594 
595     loop {
596         let elapsed = start.elapsed();
597         if elapsed >= timeout {
598             return Err(io::ErrorKind::TimedOut.into());
599         }
600 
601         let timeout = (timeout - elapsed).as_millis();
602         let timeout = clamp(timeout, 1, c_int::max_value() as u128) as c_int;
603 
604         match syscall!(poll(&mut pollfd, 1, timeout)) {
605             Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
606             Ok(_) => {
607                 // Error or hang up indicates an error (or failure to connect).
608                 if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0 {
609                     match socket.take_error() {
610                         Ok(Some(err)) => return Err(err),
611                         Ok(None) => {
612                             return Err(io::Error::new(
613                                 io::ErrorKind::Other,
614                                 "no error set after POLLHUP",
615                             ))
616                         }
617                         Err(err) => return Err(err),
618                     }
619                 }
620                 return Ok(());
621             }
622             // Got interrupted, try again.
623             Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
624             Err(err) => return Err(err),
625         }
626     }
627 }
628 
629 // TODO: use clamp from std lib, stable since 1.50.
clamp<T>(value: T, min: T, max: T) -> T where T: Ord,630 fn clamp<T>(value: T, min: T, max: T) -> T
631 where
632     T: Ord,
633 {
634     if value <= min {
635         min
636     } else if value >= max {
637         max
638     } else {
639         value
640     }
641 }
642 
listen(fd: Socket, backlog: c_int) -> io::Result<()>643 pub(crate) fn listen(fd: Socket, backlog: c_int) -> io::Result<()> {
644     syscall!(listen(fd, backlog)).map(|_| ())
645 }
646 
accept(fd: Socket) -> io::Result<(Socket, SockAddr)>647 pub(crate) fn accept(fd: Socket) -> io::Result<(Socket, SockAddr)> {
648     // Safety: `accept` initialises the `SockAddr` for us.
649     unsafe { SockAddr::init(|storage, len| syscall!(accept(fd, storage.cast(), len))) }
650 }
651 
getsockname(fd: Socket) -> io::Result<SockAddr>652 pub(crate) fn getsockname(fd: Socket) -> io::Result<SockAddr> {
653     // Safety: `accept` initialises the `SockAddr` for us.
654     unsafe { SockAddr::init(|storage, len| syscall!(getsockname(fd, storage.cast(), len))) }
655         .map(|(_, addr)| addr)
656 }
657 
getpeername(fd: Socket) -> io::Result<SockAddr>658 pub(crate) fn getpeername(fd: Socket) -> io::Result<SockAddr> {
659     // Safety: `accept` initialises the `SockAddr` for us.
660     unsafe { SockAddr::init(|storage, len| syscall!(getpeername(fd, storage.cast(), len))) }
661         .map(|(_, addr)| addr)
662 }
663 
try_clone(fd: Socket) -> io::Result<Socket>664 pub(crate) fn try_clone(fd: Socket) -> io::Result<Socket> {
665     syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0))
666 }
667 
set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()>668 pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> {
669     if nonblocking {
670         fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
671     } else {
672         fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK)
673     }
674 }
675 
shutdown(fd: Socket, how: Shutdown) -> io::Result<()>676 pub(crate) fn shutdown(fd: Socket, how: Shutdown) -> io::Result<()> {
677     let how = match how {
678         Shutdown::Write => libc::SHUT_WR,
679         Shutdown::Read => libc::SHUT_RD,
680         Shutdown::Both => libc::SHUT_RDWR,
681     };
682     syscall!(shutdown(fd, how)).map(|_| ())
683 }
684 
recv(fd: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize>685 pub(crate) fn recv(fd: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
686     syscall!(recv(
687         fd,
688         buf.as_mut_ptr().cast(),
689         min(buf.len(), MAX_BUF_LEN),
690         flags,
691     ))
692     .map(|n| n as usize)
693 }
694 
recv_from( fd: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int, ) -> io::Result<(usize, SockAddr)>695 pub(crate) fn recv_from(
696     fd: Socket,
697     buf: &mut [MaybeUninit<u8>],
698     flags: c_int,
699 ) -> io::Result<(usize, SockAddr)> {
700     // Safety: `recvfrom` initialises the `SockAddr` for us.
701     unsafe {
702         SockAddr::init(|addr, addrlen| {
703             syscall!(recvfrom(
704                 fd,
705                 buf.as_mut_ptr().cast(),
706                 min(buf.len(), MAX_BUF_LEN),
707                 flags,
708                 addr.cast(),
709                 addrlen
710             ))
711             .map(|n| n as usize)
712         })
713     }
714 }
715 
716 #[cfg(not(target_os = "redox"))]
recv_vectored( fd: Socket, bufs: &mut [crate::MaybeUninitSlice<'_>], flags: c_int, ) -> io::Result<(usize, RecvFlags)>717 pub(crate) fn recv_vectored(
718     fd: Socket,
719     bufs: &mut [crate::MaybeUninitSlice<'_>],
720     flags: c_int,
721 ) -> io::Result<(usize, RecvFlags)> {
722     recvmsg(fd, ptr::null_mut(), bufs, flags).map(|(n, _, recv_flags)| (n, recv_flags))
723 }
724 
725 #[cfg(not(target_os = "redox"))]
recv_from_vectored( fd: Socket, bufs: &mut [crate::MaybeUninitSlice<'_>], flags: c_int, ) -> io::Result<(usize, RecvFlags, SockAddr)>726 pub(crate) fn recv_from_vectored(
727     fd: Socket,
728     bufs: &mut [crate::MaybeUninitSlice<'_>],
729     flags: c_int,
730 ) -> io::Result<(usize, RecvFlags, SockAddr)> {
731     // Safety: `recvmsg` initialises the address storage and we set the length
732     // manually.
733     unsafe {
734         SockAddr::init(|storage, len| {
735             recvmsg(fd, storage, bufs, flags).map(|(n, addrlen, recv_flags)| {
736                 // Set the correct address length.
737                 *len = addrlen;
738                 (n, recv_flags)
739             })
740         })
741     }
742     .map(|((n, recv_flags), addr)| (n, recv_flags, addr))
743 }
744 
745 /// Returns the (bytes received, sending address len, `RecvFlags`).
746 #[cfg(not(target_os = "redox"))]
recvmsg( fd: Socket, msg_name: *mut sockaddr_storage, bufs: &mut [crate::MaybeUninitSlice<'_>], flags: c_int, ) -> io::Result<(usize, libc::socklen_t, RecvFlags)>747 fn recvmsg(
748     fd: Socket,
749     msg_name: *mut sockaddr_storage,
750     bufs: &mut [crate::MaybeUninitSlice<'_>],
751     flags: c_int,
752 ) -> io::Result<(usize, libc::socklen_t, RecvFlags)> {
753     let msg_namelen = if msg_name.is_null() {
754         0
755     } else {
756         size_of::<sockaddr_storage>() as libc::socklen_t
757     };
758     // libc::msghdr contains unexported padding fields on Fuchsia.
759     let mut msg: libc::msghdr = unsafe { mem::zeroed() };
760     msg.msg_name = msg_name.cast();
761     msg.msg_namelen = msg_namelen;
762     msg.msg_iov = bufs.as_mut_ptr().cast();
763     msg.msg_iovlen = min(bufs.len(), IovLen::MAX as usize) as IovLen;
764     syscall!(recvmsg(fd, &mut msg, flags))
765         .map(|n| (n as usize, msg.msg_namelen, RecvFlags(msg.msg_flags)))
766 }
767 
send(fd: Socket, buf: &[u8], flags: c_int) -> io::Result<usize>768 pub(crate) fn send(fd: Socket, buf: &[u8], flags: c_int) -> io::Result<usize> {
769     syscall!(send(
770         fd,
771         buf.as_ptr().cast(),
772         min(buf.len(), MAX_BUF_LEN),
773         flags,
774     ))
775     .map(|n| n as usize)
776 }
777 
778 #[cfg(not(target_os = "redox"))]
send_vectored(fd: Socket, bufs: &[IoSlice<'_>], flags: c_int) -> io::Result<usize>779 pub(crate) fn send_vectored(fd: Socket, bufs: &[IoSlice<'_>], flags: c_int) -> io::Result<usize> {
780     sendmsg(fd, ptr::null(), 0, bufs, flags)
781 }
782 
send_to(fd: Socket, buf: &[u8], addr: &SockAddr, flags: c_int) -> io::Result<usize>783 pub(crate) fn send_to(fd: Socket, buf: &[u8], addr: &SockAddr, flags: c_int) -> io::Result<usize> {
784     syscall!(sendto(
785         fd,
786         buf.as_ptr().cast(),
787         min(buf.len(), MAX_BUF_LEN),
788         flags,
789         addr.as_ptr(),
790         addr.len(),
791     ))
792     .map(|n| n as usize)
793 }
794 
795 #[cfg(not(target_os = "redox"))]
send_to_vectored( fd: Socket, bufs: &[IoSlice<'_>], addr: &SockAddr, flags: c_int, ) -> io::Result<usize>796 pub(crate) fn send_to_vectored(
797     fd: Socket,
798     bufs: &[IoSlice<'_>],
799     addr: &SockAddr,
800     flags: c_int,
801 ) -> io::Result<usize> {
802     sendmsg(fd, addr.as_storage_ptr(), addr.len(), bufs, flags)
803 }
804 
805 /// Returns the (bytes received, sending address len, `RecvFlags`).
806 #[cfg(not(target_os = "redox"))]
sendmsg( fd: Socket, msg_name: *const sockaddr_storage, msg_namelen: socklen_t, bufs: &[IoSlice<'_>], flags: c_int, ) -> io::Result<usize>807 fn sendmsg(
808     fd: Socket,
809     msg_name: *const sockaddr_storage,
810     msg_namelen: socklen_t,
811     bufs: &[IoSlice<'_>],
812     flags: c_int,
813 ) -> io::Result<usize> {
814     // libc::msghdr contains unexported padding fields on Fuchsia.
815     let mut msg: libc::msghdr = unsafe { mem::zeroed() };
816     // Safety: we're creating a `*mut` pointer from a reference, which is UB
817     // once actually used. However the OS should not write to it in the
818     // `sendmsg` system call.
819     msg.msg_name = (msg_name as *mut sockaddr_storage).cast();
820     msg.msg_namelen = msg_namelen;
821     // Safety: Same as above about `*const` -> `*mut`.
822     msg.msg_iov = bufs.as_ptr() as *mut _;
823     msg.msg_iovlen = min(bufs.len(), IovLen::MAX as usize) as IovLen;
824     syscall!(sendmsg(fd, &msg, flags)).map(|n| n as usize)
825 }
826 
827 /// Wrapper around `getsockopt` to deal with platform specific timeouts.
timeout_opt(fd: Socket, opt: c_int, val: c_int) -> io::Result<Option<Duration>>828 pub(crate) fn timeout_opt(fd: Socket, opt: c_int, val: c_int) -> io::Result<Option<Duration>> {
829     unsafe { getsockopt(fd, opt, val).map(from_timeval) }
830 }
831 
from_timeval(duration: libc::timeval) -> Option<Duration>832 fn from_timeval(duration: libc::timeval) -> Option<Duration> {
833     if duration.tv_sec == 0 && duration.tv_usec == 0 {
834         None
835     } else {
836         let sec = duration.tv_sec as u64;
837         let nsec = (duration.tv_usec as u32) * 1000;
838         Some(Duration::new(sec, nsec))
839     }
840 }
841 
842 /// Wrapper around `setsockopt` to deal with platform specific timeouts.
set_timeout_opt( fd: Socket, opt: c_int, val: c_int, duration: Option<Duration>, ) -> io::Result<()>843 pub(crate) fn set_timeout_opt(
844     fd: Socket,
845     opt: c_int,
846     val: c_int,
847     duration: Option<Duration>,
848 ) -> io::Result<()> {
849     let duration = into_timeval(duration);
850     unsafe { setsockopt(fd, opt, val, duration) }
851 }
852 
into_timeval(duration: Option<Duration>) -> libc::timeval853 fn into_timeval(duration: Option<Duration>) -> libc::timeval {
854     match duration {
855         // https://github.com/rust-lang/libc/issues/1848
856         #[cfg_attr(target_env = "musl", allow(deprecated))]
857         Some(duration) => libc::timeval {
858             tv_sec: min(duration.as_secs(), libc::time_t::max_value() as u64) as libc::time_t,
859             tv_usec: duration.subsec_micros() as libc::suseconds_t,
860         },
861         None => libc::timeval {
862             tv_sec: 0,
863             tv_usec: 0,
864         },
865     }
866 }
867 
868 #[cfg(feature = "all")]
869 #[cfg(not(any(target_os = "haiku", target_os = "openbsd")))]
keepalive_time(fd: Socket) -> io::Result<Duration>870 pub(crate) fn keepalive_time(fd: Socket) -> io::Result<Duration> {
871     unsafe {
872         getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
873             .map(|secs| Duration::from_secs(secs as u64))
874     }
875 }
876 
877 #[allow(unused_variables)]
set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()>878 pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()> {
879     #[cfg(not(any(target_os = "haiku", target_os = "openbsd")))]
880     if let Some(time) = keepalive.time {
881         let secs = into_secs(time);
882         unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
883     }
884 
885     #[cfg(any(
886         target_os = "android",
887         target_os = "dragonfly",
888         target_os = "freebsd",
889         target_os = "fuchsia",
890         target_os = "illumos",
891         target_os = "linux",
892         target_os = "netbsd",
893         target_vendor = "apple",
894     ))]
895     {
896         if let Some(interval) = keepalive.interval {
897             let secs = into_secs(interval);
898             unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
899         }
900 
901         if let Some(retries) = keepalive.retries {
902             unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
903         }
904     }
905 
906     Ok(())
907 }
908 
909 #[cfg(not(any(target_os = "haiku", target_os = "openbsd")))]
into_secs(duration: Duration) -> c_int910 fn into_secs(duration: Duration) -> c_int {
911     min(duration.as_secs(), c_int::max_value() as u64) as c_int
912 }
913 
914 /// Add `flag` to the current set flags of `F_GETFD`.
fcntl_add(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()>915 fn fcntl_add(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
916     let previous = syscall!(fcntl(fd, get_cmd))?;
917     let new = previous | flag;
918     if new != previous {
919         syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
920     } else {
921         // Flag was already set.
922         Ok(())
923     }
924 }
925 
926 /// Remove `flag` to the current set flags of `F_GETFD`.
fcntl_remove(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()>927 fn fcntl_remove(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
928     let previous = syscall!(fcntl(fd, get_cmd))?;
929     let new = previous & !flag;
930     if new != previous {
931         syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
932     } else {
933         // Flag was already set.
934         Ok(())
935     }
936 }
937 
938 /// Caller must ensure `T` is the correct type for `opt` and `val`.
getsockopt<T>(fd: Socket, opt: c_int, val: c_int) -> io::Result<T>939 pub(crate) unsafe fn getsockopt<T>(fd: Socket, opt: c_int, val: c_int) -> io::Result<T> {
940     let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
941     let mut len = size_of::<T>() as libc::socklen_t;
942     syscall!(getsockopt(
943         fd,
944         opt,
945         val,
946         payload.as_mut_ptr().cast(),
947         &mut len,
948     ))
949     .map(|_| {
950         debug_assert_eq!(len as usize, size_of::<T>());
951         // Safety: `getsockopt` initialised `payload` for us.
952         payload.assume_init()
953     })
954 }
955 
956 /// Caller must ensure `T` is the correct type for `opt` and `val`.
setsockopt<T>( fd: Socket, opt: c_int, val: c_int, payload: T, ) -> io::Result<()>957 pub(crate) unsafe fn setsockopt<T>(
958     fd: Socket,
959     opt: c_int,
960     val: c_int,
961     payload: T,
962 ) -> io::Result<()> {
963     let payload = &payload as *const T as *const c_void;
964     syscall!(setsockopt(
965         fd,
966         opt,
967         val,
968         payload,
969         mem::size_of::<T>() as libc::socklen_t,
970     ))
971     .map(|_| ())
972 }
973 
to_in_addr(addr: &Ipv4Addr) -> in_addr974 pub(crate) fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
975     // `s_addr` is stored as BE on all machines, and the array is in BE order.
976     // So the native endian conversion method is used so that it's never
977     // swapped.
978     in_addr {
979         s_addr: u32::from_ne_bytes(addr.octets()),
980     }
981 }
982 
from_in_addr(in_addr: in_addr) -> Ipv4Addr983 pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
984     Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
985 }
986 
to_in6_addr(addr: &Ipv6Addr) -> in6_addr987 pub(crate) fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
988     in6_addr {
989         s6_addr: addr.octets(),
990     }
991 }
992 
from_in6_addr(addr: in6_addr) -> Ipv6Addr993 pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
994     Ipv6Addr::from(addr.s6_addr)
995 }
996 
997 /// Unix only API.
998 impl crate::Socket {
999     /// Accept a new incoming connection from this listener.
1000     ///
1001     /// This function directly corresponds to the `accept4(2)` function.
1002     ///
1003     /// This function will block the calling thread until a new connection is
1004     /// established. When established, the corresponding `Socket` and the remote
1005     /// peer's address will be returned.
1006     #[cfg(all(
1007         feature = "all",
1008         any(
1009             target_os = "android",
1010             target_os = "dragonfly",
1011             target_os = "freebsd",
1012             target_os = "fuchsia",
1013             target_os = "illumos",
1014             target_os = "linux",
1015             target_os = "netbsd",
1016             target_os = "openbsd"
1017         )
1018     ))]
1019     #[cfg_attr(
1020         docsrs,
1021         doc(cfg(all(
1022             feature = "all",
1023             any(
1024                 target_os = "android",
1025                 target_os = "dragonfly",
1026                 target_os = "freebsd",
1027                 target_os = "fuchsia",
1028                 target_os = "illumos",
1029                 target_os = "linux",
1030                 target_os = "netbsd",
1031                 target_os = "openbsd"
1032             )
1033         )))
1034     )]
accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)>1035     pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1036         self._accept4(flags)
1037     }
1038 
1039     #[cfg(any(
1040         target_os = "android",
1041         target_os = "dragonfly",
1042         target_os = "freebsd",
1043         target_os = "fuchsia",
1044         target_os = "illumos",
1045         target_os = "linux",
1046         target_os = "netbsd",
1047         target_os = "openbsd"
1048     ))]
_accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)>1049     pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1050         // Safety: `accept4` initialises the `SockAddr` for us.
1051         unsafe {
1052             SockAddr::init(|storage, len| {
1053                 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1054                     .map(crate::Socket::from_raw)
1055             })
1056         }
1057     }
1058 
1059     /// Sets `CLOEXEC` on the socket.
1060     ///
1061     /// # Notes
1062     ///
1063     /// On supported platforms you can use [`Type::cloexec`].
1064     #[cfg(feature = "all")]
1065     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
set_cloexec(&self, close_on_exec: bool) -> io::Result<()>1066     pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1067         self._set_cloexec(close_on_exec)
1068     }
1069 
_set_cloexec(&self, close_on_exec: bool) -> io::Result<()>1070     pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1071         if close_on_exec {
1072             fcntl_add(
1073                 self.as_raw(),
1074                 libc::F_GETFD,
1075                 libc::F_SETFD,
1076                 libc::FD_CLOEXEC,
1077             )
1078         } else {
1079             fcntl_remove(
1080                 self.as_raw(),
1081                 libc::F_GETFD,
1082                 libc::F_SETFD,
1083                 libc::FD_CLOEXEC,
1084             )
1085         }
1086     }
1087 
1088     /// Sets `SO_NOSIGPIPE` on the socket.
1089     #[cfg(all(feature = "all", any(doc, target_vendor = "apple")))]
1090     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_vendor = "apple"))))]
set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()>1091     pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1092         self._set_nosigpipe(nosigpipe)
1093     }
1094 
1095     #[cfg(target_vendor = "apple")]
_set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()>1096     pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1097         unsafe {
1098             setsockopt(
1099                 self.as_raw(),
1100                 libc::SOL_SOCKET,
1101                 libc::SO_NOSIGPIPE,
1102                 nosigpipe as c_int,
1103             )
1104         }
1105     }
1106 
1107     /// Gets the value of the `TCP_MAXSEG` option on this socket.
1108     ///
1109     /// For more information about this option, see [`set_mss`].
1110     ///
1111     /// [`set_mss`]: crate::Socket::set_mss
1112     #[cfg(all(feature = "all", not(target_os = "redox")))]
1113     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
mss(&self) -> io::Result<u32>1114     pub fn mss(&self) -> io::Result<u32> {
1115         unsafe {
1116             getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1117                 .map(|mss| mss as u32)
1118         }
1119     }
1120 
1121     /// Sets the value of the `TCP_MAXSEG` option on this socket.
1122     ///
1123     /// The `TCP_MAXSEG` option denotes the TCP Maximum Segment Size and is only
1124     /// available on TCP sockets.
1125     #[cfg(all(feature = "all", not(target_os = "redox")))]
1126     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
set_mss(&self, mss: u32) -> io::Result<()>1127     pub fn set_mss(&self, mss: u32) -> io::Result<()> {
1128         unsafe {
1129             setsockopt(
1130                 self.as_raw(),
1131                 libc::IPPROTO_TCP,
1132                 libc::TCP_MAXSEG,
1133                 mss as c_int,
1134             )
1135         }
1136     }
1137 
1138     /// Returns `true` if `listen(2)` was called on this socket by checking the
1139     /// `SO_ACCEPTCONN` option on this socket.
1140     #[cfg(all(
1141         feature = "all",
1142         any(
1143             target_os = "android",
1144             target_os = "freebsd",
1145             target_os = "fuchsia",
1146             target_os = "linux",
1147         )
1148     ))]
1149     #[cfg_attr(
1150         docsrs,
1151         doc(cfg(all(
1152             feature = "all",
1153             any(
1154                 target_os = "android",
1155                 target_os = "freebsd",
1156                 target_os = "fuchsia",
1157                 target_os = "linux",
1158             )
1159         )))
1160     )]
is_listener(&self) -> io::Result<bool>1161     pub fn is_listener(&self) -> io::Result<bool> {
1162         unsafe {
1163             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1164                 .map(|v| v != 0)
1165         }
1166     }
1167 
1168     /// Returns the [`Domain`] of this socket by checking the `SO_DOMAIN` option
1169     /// on this socket.
1170     #[cfg(all(
1171         feature = "all",
1172         any(
1173             target_os = "android",
1174             // TODO: add FreeBSD.
1175             // target_os = "freebsd",
1176             target_os = "fuchsia",
1177             target_os = "linux",
1178         )
1179     ))]
1180     #[cfg_attr(docsrs, doc(cfg(all(
1181         feature = "all",
1182         any(
1183             target_os = "android",
1184             // TODO: add FreeBSD.
1185             // target_os = "freebsd",
1186             target_os = "fuchsia",
1187             target_os = "linux",
1188         )
1189     ))))]
domain(&self) -> io::Result<Domain>1190     pub fn domain(&self) -> io::Result<Domain> {
1191         unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1192     }
1193 
1194     /// Returns the [`Protocol`] of this socket by checking the `SO_PROTOCOL`
1195     /// option on this socket.
1196     #[cfg(all(
1197         feature = "all",
1198         any(
1199             target_os = "android",
1200             target_os = "freebsd",
1201             target_os = "fuchsia",
1202             target_os = "linux",
1203         )
1204     ))]
1205     #[cfg_attr(
1206         docsrs,
1207         doc(cfg(all(
1208             feature = "all",
1209             any(
1210                 target_os = "android",
1211                 target_os = "freebsd",
1212                 target_os = "fuchsia",
1213                 target_os = "linux",
1214             )
1215         )))
1216     )]
protocol(&self) -> io::Result<Option<Protocol>>1217     pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1218         unsafe {
1219             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1220             {
1221                 0 => None,
1222                 p => Some(Protocol(p)),
1223             })
1224         }
1225     }
1226 
1227     /// Gets the value for the `SO_MARK` option on this socket.
1228     ///
1229     /// This value gets the socket mark field for each packet sent through
1230     /// this socket.
1231     ///
1232     /// On Linux this function requires the `CAP_NET_ADMIN` capability.
1233     #[cfg(all(
1234         feature = "all",
1235         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1236     ))]
1237     #[cfg_attr(
1238         docsrs,
1239         doc(cfg(all(
1240             feature = "all",
1241             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1242         )))
1243     )]
mark(&self) -> io::Result<u32>1244     pub fn mark(&self) -> io::Result<u32> {
1245         unsafe {
1246             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1247                 .map(|mark| mark as u32)
1248         }
1249     }
1250 
1251     /// Sets the value for the `SO_MARK` option on this socket.
1252     ///
1253     /// This value sets the socket mark field for each packet sent through
1254     /// this socket. Changing the mark can be used for mark-based routing
1255     /// without netfilter or for packet filtering.
1256     ///
1257     /// On Linux this function requires the `CAP_NET_ADMIN` capability.
1258     #[cfg(all(
1259         feature = "all",
1260         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1261     ))]
1262     #[cfg_attr(
1263         docsrs,
1264         doc(cfg(all(
1265             feature = "all",
1266             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1267         )))
1268     )]
set_mark(&self, mark: u32) -> io::Result<()>1269     pub fn set_mark(&self, mark: u32) -> io::Result<()> {
1270         unsafe {
1271             setsockopt::<c_int>(
1272                 self.as_raw(),
1273                 libc::SOL_SOCKET,
1274                 libc::SO_MARK,
1275                 mark as c_int,
1276             )
1277         }
1278     }
1279 
1280     /// Gets the value for the `SO_BINDTODEVICE` option on this socket.
1281     ///
1282     /// This value gets the socket binded device's interface name.
1283     #[cfg(all(
1284         feature = "all",
1285         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1286     ))]
1287     #[cfg_attr(
1288         docsrs,
1289         doc(cfg(all(
1290             feature = "all",
1291             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1292         )))
1293     )]
device(&self) -> io::Result<Option<Vec<u8>>>1294     pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1295         // TODO: replace with `MaybeUninit::uninit_array` once stable.
1296         let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1297             unsafe { MaybeUninit::uninit().assume_init() };
1298         let mut len = buf.len() as libc::socklen_t;
1299         unsafe {
1300             syscall!(getsockopt(
1301                 self.as_raw(),
1302                 libc::SOL_SOCKET,
1303                 libc::SO_BINDTODEVICE,
1304                 buf.as_mut_ptr().cast(),
1305                 &mut len,
1306             ))?;
1307         }
1308         if len == 0 {
1309             Ok(None)
1310         } else {
1311             let buf = &buf[..len as usize - 1];
1312             // TODO: use `MaybeUninit::slice_assume_init_ref` once stable.
1313             Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
1314         }
1315     }
1316 
1317     /// Sets the value for the `SO_BINDTODEVICE` option on this socket.
1318     ///
1319     /// If a socket is bound to an interface, only packets received from that
1320     /// particular interface are processed by the socket. Note that this only
1321     /// works for some socket types, particularly `AF_INET` sockets.
1322     ///
1323     /// If `interface` is `None` or an empty string it removes the binding.
1324     #[cfg(all(
1325         feature = "all",
1326         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1327     ))]
1328     #[cfg_attr(
1329         docsrs,
1330         doc(cfg(all(
1331             feature = "all",
1332             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1333         )))
1334     )]
bind_device(&self, interface: Option<&[u8]>) -> io::Result<()>1335     pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
1336         let (value, len) = if let Some(interface) = interface {
1337             (interface.as_ptr(), interface.len())
1338         } else {
1339             (ptr::null(), 0)
1340         };
1341         syscall!(setsockopt(
1342             self.as_raw(),
1343             libc::SOL_SOCKET,
1344             libc::SO_BINDTODEVICE,
1345             value.cast(),
1346             len as libc::socklen_t,
1347         ))
1348         .map(|_| ())
1349     }
1350 
1351     /// Sets the value for `IP_BOUND_IF` option on this socket.
1352     ///
1353     /// If a socket is bound to an interface, only packets received from that
1354     /// particular interface are processed by the socket.
1355     ///
1356     /// If `interface` is `None`, the binding is removed. If the `interface`
1357     /// index is not valid, an error is returned.
1358     ///
1359     /// One can use `libc::if_nametoindex` to convert an interface alias to an
1360     /// index.
1361     #[cfg(all(feature = "all", target_vendor = "apple"))]
1362     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_vendor = "apple"))))]
bind_device_by_index(&self, interface: Option<NonZeroU32>) -> io::Result<()>1363     pub fn bind_device_by_index(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
1364         let index = interface.map(NonZeroU32::get).unwrap_or(0);
1365         unsafe { setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index) }
1366     }
1367 
1368     /// Gets the value for `IP_BOUND_IF` option on this socket, i.e. the index
1369     /// for the interface to which the socket is bound.
1370     ///
1371     /// Returns `None` if the socket is not bound to any interface, otherwise
1372     /// returns an interface index.
1373     #[cfg(all(feature = "all", target_vendor = "apple"))]
1374     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_vendor = "apple"))))]
device_index(&self) -> io::Result<Option<NonZeroU32>>1375     pub fn device_index(&self) -> io::Result<Option<NonZeroU32>> {
1376         let index =
1377             unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
1378         Ok(NonZeroU32::new(index))
1379     }
1380 
1381     /// Get the value of the `SO_INCOMING_CPU` option on this socket.
1382     ///
1383     /// For more information about this option, see [`set_cpu_affinity`].
1384     ///
1385     /// [`set_cpu_affinity`]: crate::Socket::set_cpu_affinity
1386     #[cfg(all(feature = "all", target_os = "linux"))]
1387     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
cpu_affinity(&self) -> io::Result<usize>1388     pub fn cpu_affinity(&self) -> io::Result<usize> {
1389         unsafe {
1390             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
1391                 .map(|cpu| cpu as usize)
1392         }
1393     }
1394 
1395     /// Set value for the `SO_INCOMING_CPU` option on this socket.
1396     ///
1397     /// Sets the CPU affinity of the socket.
1398     #[cfg(all(feature = "all", target_os = "linux"))]
1399     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
set_cpu_affinity(&self, cpu: usize) -> io::Result<()>1400     pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
1401         unsafe {
1402             setsockopt(
1403                 self.as_raw(),
1404                 libc::SOL_SOCKET,
1405                 libc::SO_INCOMING_CPU,
1406                 cpu as c_int,
1407             )
1408         }
1409     }
1410 
1411     /// Get the value of the `SO_REUSEPORT` option on this socket.
1412     ///
1413     /// For more information about this option, see [`set_reuse_port`].
1414     ///
1415     /// [`set_reuse_port`]: crate::Socket::set_reuse_port
1416     #[cfg(all(
1417         feature = "all",
1418         not(any(target_os = "solaris", target_os = "illumos"))
1419     ))]
1420     #[cfg_attr(
1421         docsrs,
1422         doc(cfg(all(
1423             feature = "all",
1424             unix,
1425             not(any(target_os = "solaris", target_os = "illumos"))
1426         )))
1427     )]
reuse_port(&self) -> io::Result<bool>1428     pub fn reuse_port(&self) -> io::Result<bool> {
1429         unsafe {
1430             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
1431                 .map(|reuse| reuse != 0)
1432         }
1433     }
1434 
1435     /// Set value for the `SO_REUSEPORT` option on this socket.
1436     ///
1437     /// This indicates that further calls to `bind` may allow reuse of local
1438     /// addresses. For IPv4 sockets this means that a socket may bind even when
1439     /// there's a socket already listening on this port.
1440     #[cfg(all(
1441         feature = "all",
1442         not(any(target_os = "solaris", target_os = "illumos"))
1443     ))]
1444     #[cfg_attr(
1445         docsrs,
1446         doc(cfg(all(
1447             feature = "all",
1448             unix,
1449             not(any(target_os = "solaris", target_os = "illumos"))
1450         )))
1451     )]
set_reuse_port(&self, reuse: bool) -> io::Result<()>1452     pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
1453         unsafe {
1454             setsockopt(
1455                 self.as_raw(),
1456                 libc::SOL_SOCKET,
1457                 libc::SO_REUSEPORT,
1458                 reuse as c_int,
1459             )
1460         }
1461     }
1462 
1463     /// Get the value of the `IP_FREEBIND` option on this socket.
1464     ///
1465     /// For more information about this option, see [`set_freebind`].
1466     ///
1467     /// [`set_freebind`]: crate::Socket::set_freebind
1468     #[cfg(all(
1469         feature = "all",
1470         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1471     ))]
1472     #[cfg_attr(
1473         docsrs,
1474         doc(cfg(all(
1475             feature = "all",
1476             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1477         )))
1478     )]
freebind(&self) -> io::Result<bool>1479     pub fn freebind(&self) -> io::Result<bool> {
1480         unsafe {
1481             getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND)
1482                 .map(|freebind| freebind != 0)
1483         }
1484     }
1485 
1486     /// Set value for the `IP_FREEBIND` option on this socket.
1487     ///
1488     /// If enabled, this boolean option allows binding to an IP address that is
1489     /// nonlocal or does not (yet) exist.  This permits listening on a socket,
1490     /// without requiring the underlying network interface or the specified
1491     /// dynamic IP address to be up at the time that the application is trying
1492     /// to bind to it.
1493     #[cfg(all(
1494         feature = "all",
1495         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1496     ))]
1497     #[cfg_attr(
1498         docsrs,
1499         doc(cfg(all(
1500             feature = "all",
1501             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1502         )))
1503     )]
set_freebind(&self, freebind: bool) -> io::Result<()>1504     pub fn set_freebind(&self, freebind: bool) -> io::Result<()> {
1505         unsafe {
1506             setsockopt(
1507                 self.as_raw(),
1508                 libc::SOL_IP,
1509                 libc::IP_FREEBIND,
1510                 freebind as c_int,
1511             )
1512         }
1513     }
1514 
1515     /// Get the value of the `IPV6_FREEBIND` option on this socket.
1516     ///
1517     /// This is an IPv6 counterpart of `IP_FREEBIND` socket option on
1518     /// Android/Linux. For more information about this option, see
1519     /// [`set_freebind`].
1520     ///
1521     /// [`set_freebind`]: crate::Socket::set_freebind
1522     #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1523     #[cfg_attr(
1524         docsrs,
1525         doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
1526     )]
freebind_ipv6(&self) -> io::Result<bool>1527     pub fn freebind_ipv6(&self) -> io::Result<bool> {
1528         unsafe {
1529             getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND)
1530                 .map(|freebind| freebind != 0)
1531         }
1532     }
1533 
1534     /// Set value for the `IPV6_FREEBIND` option on this socket.
1535     ///
1536     /// This is an IPv6 counterpart of `IP_FREEBIND` socket option on
1537     /// Android/Linux. For more information about this option, see
1538     /// [`set_freebind`].
1539     ///
1540     /// [`set_freebind`]: crate::Socket::set_freebind
1541     ///
1542     /// # Examples
1543     ///
1544     /// On Linux:
1545     ///
1546     /// ```
1547     /// use socket2::{Domain, Socket, Type};
1548     /// use std::io::{self, Error, ErrorKind};
1549     ///
1550     /// fn enable_freebind(socket: &Socket) -> io::Result<()> {
1551     ///     match socket.domain()? {
1552     ///         Domain::IPV4 => socket.set_freebind(true)?,
1553     ///         Domain::IPV6 => socket.set_freebind_ipv6(true)?,
1554     ///         _ => return Err(Error::new(ErrorKind::Other, "unsupported domain")),
1555     ///     };
1556     ///     Ok(())
1557     /// }
1558     ///
1559     /// # fn main() -> io::Result<()> {
1560     /// #     let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
1561     /// #     enable_freebind(&socket)
1562     /// # }
1563     /// ```
1564     #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1565     #[cfg_attr(
1566         docsrs,
1567         doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
1568     )]
set_freebind_ipv6(&self, freebind: bool) -> io::Result<()>1569     pub fn set_freebind_ipv6(&self, freebind: bool) -> io::Result<()> {
1570         unsafe {
1571             setsockopt(
1572                 self.as_raw(),
1573                 libc::SOL_IPV6,
1574                 libc::IPV6_FREEBIND,
1575                 freebind as c_int,
1576             )
1577         }
1578     }
1579 
1580     /// Copies data between a `file` and this socket using the `sendfile(2)`
1581     /// system call. Because this copying is done within the kernel,
1582     /// `sendfile()` is more efficient than the combination of `read(2)` and
1583     /// `write(2)`, which would require transferring data to and from user
1584     /// space.
1585     ///
1586     /// Different OSs support different kinds of `file`s, see the OS
1587     /// documentation for what kind of files are supported. Generally *regular*
1588     /// files are supported by all OSs.
1589     ///
1590     /// The `offset` is the absolute offset into the `file` to use as starting
1591     /// point.
1592     ///
1593     /// Depending on the OS this function *may* change the offset of `file`. For
1594     /// the best results reset the offset of the file before using it again.
1595     ///
1596     /// The `length` determines how many bytes to send, where a length of `None`
1597     /// means it will try to send all bytes.
1598     #[cfg(all(
1599         feature = "all",
1600         any(
1601             target_os = "android",
1602             target_os = "freebsd",
1603             target_os = "linux",
1604             target_vendor = "apple",
1605         )
1606     ))]
1607     #[cfg_attr(
1608         docsrs,
1609         doc(cfg(all(
1610             feature = "all",
1611             any(
1612                 target_os = "android",
1613                 target_os = "freebsd",
1614                 target_os = "linux",
1615                 target_vendor = "apple",
1616             )
1617         )))
1618     )]
sendfile<F>( &self, file: &F, offset: usize, length: Option<NonZeroUsize>, ) -> io::Result<usize> where F: AsRawFd,1619     pub fn sendfile<F>(
1620         &self,
1621         file: &F,
1622         offset: usize,
1623         length: Option<NonZeroUsize>,
1624     ) -> io::Result<usize>
1625     where
1626         F: AsRawFd,
1627     {
1628         self._sendfile(file.as_raw_fd(), offset as _, length)
1629     }
1630 
1631     #[cfg(all(feature = "all", target_vendor = "apple"))]
_sendfile( &self, file: RawFd, offset: libc::off_t, length: Option<NonZeroUsize>, ) -> io::Result<usize>1632     fn _sendfile(
1633         &self,
1634         file: RawFd,
1635         offset: libc::off_t,
1636         length: Option<NonZeroUsize>,
1637     ) -> io::Result<usize> {
1638         // On macOS `length` is value-result parameter. It determines the number
1639         // of bytes to write and returns the number of bytes written.
1640         let mut length = match length {
1641             Some(n) => n.get() as libc::off_t,
1642             // A value of `0` means send all bytes.
1643             None => 0,
1644         };
1645         syscall!(sendfile(
1646             file,
1647             self.as_raw(),
1648             offset,
1649             &mut length,
1650             ptr::null_mut(),
1651             0,
1652         ))
1653         .map(|_| length as usize)
1654     }
1655 
1656     #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
_sendfile( &self, file: RawFd, offset: libc::off_t, length: Option<NonZeroUsize>, ) -> io::Result<usize>1657     fn _sendfile(
1658         &self,
1659         file: RawFd,
1660         offset: libc::off_t,
1661         length: Option<NonZeroUsize>,
1662     ) -> io::Result<usize> {
1663         let count = match length {
1664             Some(n) => n.get() as libc::size_t,
1665             // The maximum the Linux kernel will write in a single call.
1666             None => 0x7ffff000, // 2,147,479,552 bytes.
1667         };
1668         let mut offset = offset;
1669         syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
1670     }
1671 
1672     #[cfg(all(feature = "all", target_os = "freebsd"))]
_sendfile( &self, file: RawFd, offset: libc::off_t, length: Option<NonZeroUsize>, ) -> io::Result<usize>1673     fn _sendfile(
1674         &self,
1675         file: RawFd,
1676         offset: libc::off_t,
1677         length: Option<NonZeroUsize>,
1678     ) -> io::Result<usize> {
1679         let nbytes = match length {
1680             Some(n) => n.get() as libc::size_t,
1681             // A value of `0` means send all bytes.
1682             None => 0,
1683         };
1684         let mut sbytes: libc::off_t = 0;
1685         syscall!(sendfile(
1686             file,
1687             self.as_raw(),
1688             offset,
1689             nbytes,
1690             ptr::null_mut(),
1691             &mut sbytes,
1692             0,
1693         ))
1694         .map(|_| sbytes as usize)
1695     }
1696 
1697     /// Set the value of the `TCP_USER_TIMEOUT` option on this socket.
1698     ///
1699     /// If set, this specifies the maximum amount of time that transmitted data may remain
1700     /// unacknowledged or buffered data may remain untransmitted before TCP will forcibly close the
1701     /// corresponding connection.
1702     ///
1703     /// Setting `timeout` to `None` or a zero duration causes the system default timeouts to
1704     /// be used. If `timeout` in milliseconds is larger than `c_uint::MAX`, the timeout is clamped
1705     /// to `c_uint::MAX`. For example, when `c_uint` is a 32-bit value, this limits the timeout to
1706     /// approximately 49.71 days.
1707     #[cfg(all(
1708         feature = "all",
1709         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1710     ))]
1711     #[cfg_attr(
1712         docsrs,
1713         doc(cfg(all(
1714             feature = "all",
1715             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1716         )))
1717     )]
set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()>1718     pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
1719         let timeout = timeout
1720             .map(|to| min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint)
1721             .unwrap_or(0);
1722         unsafe {
1723             setsockopt(
1724                 self.as_raw(),
1725                 libc::IPPROTO_TCP,
1726                 libc::TCP_USER_TIMEOUT,
1727                 timeout,
1728             )
1729         }
1730     }
1731 
1732     /// Get the value of the `TCP_USER_TIMEOUT` option on this socket.
1733     ///
1734     /// For more information about this option, see [`set_tcp_user_timeout`].
1735     ///
1736     /// [`set_tcp_user_timeout`]: Socket::set_tcp_user_timeout
1737     #[cfg(all(
1738         feature = "all",
1739         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1740     ))]
1741     #[cfg_attr(
1742         docsrs,
1743         doc(cfg(all(
1744             feature = "all",
1745             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1746         )))
1747     )]
tcp_user_timeout(&self) -> io::Result<Option<Duration>>1748     pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
1749         unsafe {
1750             getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
1751                 .map(|millis| {
1752                     if millis == 0 {
1753                         None
1754                     } else {
1755                         Some(Duration::from_millis(millis as u64))
1756                     }
1757                 })
1758         }
1759     }
1760 }
1761 
1762 #[cfg_attr(docsrs, doc(cfg(unix)))]
1763 impl AsRawFd for crate::Socket {
as_raw_fd(&self) -> c_int1764     fn as_raw_fd(&self) -> c_int {
1765         self.as_raw()
1766     }
1767 }
1768 
1769 #[cfg_attr(docsrs, doc(cfg(unix)))]
1770 impl IntoRawFd for crate::Socket {
into_raw_fd(self) -> c_int1771     fn into_raw_fd(self) -> c_int {
1772         self.into_raw()
1773     }
1774 }
1775 
1776 #[cfg_attr(docsrs, doc(cfg(unix)))]
1777 impl FromRawFd for crate::Socket {
from_raw_fd(fd: c_int) -> crate::Socket1778     unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
1779         crate::Socket::from_raw(fd)
1780     }
1781 }
1782 
1783 #[cfg(feature = "all")]
1784 from!(UnixStream, crate::Socket);
1785 #[cfg(feature = "all")]
1786 from!(UnixListener, crate::Socket);
1787 #[cfg(feature = "all")]
1788 from!(UnixDatagram, crate::Socket);
1789 #[cfg(feature = "all")]
1790 from!(crate::Socket, UnixStream);
1791 #[cfg(feature = "all")]
1792 from!(crate::Socket, UnixListener);
1793 #[cfg(feature = "all")]
1794 from!(crate::Socket, UnixDatagram);
1795 
1796 #[test]
in_addr_convertion()1797 fn in_addr_convertion() {
1798     let ip = Ipv4Addr::new(127, 0, 0, 1);
1799     let raw = to_in_addr(&ip);
1800     // NOTE: `in_addr` is packed on NetBSD and it's unsafe to borrow.
1801     let a = raw.s_addr;
1802     assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
1803     assert_eq!(from_in_addr(raw), ip);
1804 
1805     let ip = Ipv4Addr::new(127, 34, 4, 12);
1806     let raw = to_in_addr(&ip);
1807     let a = raw.s_addr;
1808     assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
1809     assert_eq!(from_in_addr(raw), ip);
1810 }
1811 
1812 #[test]
in6_addr_convertion()1813 fn in6_addr_convertion() {
1814     let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
1815     let raw = to_in6_addr(&ip);
1816     let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
1817     assert_eq!(raw.s6_addr, want);
1818     assert_eq!(from_in6_addr(raw), ip);
1819 }
1820