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")]
keepalive_time(fd: Socket) -> io::Result<Duration>869 pub(crate) fn keepalive_time(fd: Socket) -> io::Result<Duration> {
870     unsafe {
871         getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME)
872             .map(|secs| Duration::from_secs(secs as u64))
873     }
874 }
875 
876 #[allow(unused_variables)]
set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()>877 pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()> {
878     #[cfg(not(any(target_os = "haiku", target_os = "openbsd")))]
879     if let Some(time) = keepalive.time {
880         let secs = into_secs(time);
881         unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? }
882     }
883 
884     #[cfg(any(
885         target_os = "android",
886         target_os = "dragonfly",
887         target_os = "freebsd",
888         target_os = "fuchsia",
889         target_os = "illumos",
890         target_os = "linux",
891         target_os = "netbsd",
892         target_vendor = "apple",
893     ))]
894     {
895         if let Some(interval) = keepalive.interval {
896             let secs = into_secs(interval);
897             unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, secs)? }
898         }
899 
900         if let Some(retries) = keepalive.retries {
901             unsafe { setsockopt(fd, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, retries as c_int)? }
902         }
903     }
904 
905     Ok(())
906 }
907 
908 #[cfg(not(any(target_os = "haiku", target_os = "openbsd")))]
into_secs(duration: Duration) -> c_int909 fn into_secs(duration: Duration) -> c_int {
910     min(duration.as_secs(), c_int::max_value() as u64) as c_int
911 }
912 
913 /// 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<()>914 fn fcntl_add(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
915     let previous = syscall!(fcntl(fd, get_cmd))?;
916     let new = previous | flag;
917     if new != previous {
918         syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
919     } else {
920         // Flag was already set.
921         Ok(())
922     }
923 }
924 
925 /// 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<()>926 fn fcntl_remove(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> {
927     let previous = syscall!(fcntl(fd, get_cmd))?;
928     let new = previous & !flag;
929     if new != previous {
930         syscall!(fcntl(fd, set_cmd, new)).map(|_| ())
931     } else {
932         // Flag was already set.
933         Ok(())
934     }
935 }
936 
937 /// 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>938 pub(crate) unsafe fn getsockopt<T>(fd: Socket, opt: c_int, val: c_int) -> io::Result<T> {
939     let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
940     let mut len = size_of::<T>() as libc::socklen_t;
941     syscall!(getsockopt(
942         fd,
943         opt,
944         val,
945         payload.as_mut_ptr().cast(),
946         &mut len,
947     ))
948     .map(|_| {
949         debug_assert_eq!(len as usize, size_of::<T>());
950         // Safety: `getsockopt` initialised `payload` for us.
951         payload.assume_init()
952     })
953 }
954 
955 /// 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<()>956 pub(crate) unsafe fn setsockopt<T>(
957     fd: Socket,
958     opt: c_int,
959     val: c_int,
960     payload: T,
961 ) -> io::Result<()> {
962     let payload = &payload as *const T as *const c_void;
963     syscall!(setsockopt(
964         fd,
965         opt,
966         val,
967         payload,
968         mem::size_of::<T>() as libc::socklen_t,
969     ))
970     .map(|_| ())
971 }
972 
to_in_addr(addr: &Ipv4Addr) -> in_addr973 pub(crate) fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
974     // `s_addr` is stored as BE on all machines, and the array is in BE order.
975     // So the native endian conversion method is used so that it's never
976     // swapped.
977     in_addr {
978         s_addr: u32::from_ne_bytes(addr.octets()),
979     }
980 }
981 
from_in_addr(in_addr: in_addr) -> Ipv4Addr982 pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
983     Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
984 }
985 
to_in6_addr(addr: &Ipv6Addr) -> in6_addr986 pub(crate) fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
987     in6_addr {
988         s6_addr: addr.octets(),
989     }
990 }
991 
from_in6_addr(addr: in6_addr) -> Ipv6Addr992 pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
993     Ipv6Addr::from(addr.s6_addr)
994 }
995 
996 /// Unix only API.
997 impl crate::Socket {
998     /// Accept a new incoming connection from this listener.
999     ///
1000     /// This function directly corresponds to the `accept4(2)` function.
1001     ///
1002     /// This function will block the calling thread until a new connection is
1003     /// established. When established, the corresponding `Socket` and the remote
1004     /// peer's address will be returned.
1005     #[cfg(all(
1006         feature = "all",
1007         any(
1008             target_os = "android",
1009             target_os = "dragonfly",
1010             target_os = "freebsd",
1011             target_os = "fuchsia",
1012             target_os = "illumos",
1013             target_os = "linux",
1014             target_os = "netbsd",
1015             target_os = "openbsd"
1016         )
1017     ))]
1018     #[cfg_attr(
1019         docsrs,
1020         doc(cfg(all(
1021             feature = "all",
1022             any(
1023                 target_os = "android",
1024                 target_os = "dragonfly",
1025                 target_os = "freebsd",
1026                 target_os = "fuchsia",
1027                 target_os = "illumos",
1028                 target_os = "linux",
1029                 target_os = "netbsd",
1030                 target_os = "openbsd"
1031             )
1032         )))
1033     )]
accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)>1034     pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1035         self._accept4(flags)
1036     }
1037 
1038     #[cfg(any(
1039         target_os = "android",
1040         target_os = "dragonfly",
1041         target_os = "freebsd",
1042         target_os = "fuchsia",
1043         target_os = "illumos",
1044         target_os = "linux",
1045         target_os = "netbsd",
1046         target_os = "openbsd"
1047     ))]
_accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)>1048     pub(crate) fn _accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> {
1049         // Safety: `accept4` initialises the `SockAddr` for us.
1050         unsafe {
1051             SockAddr::init(|storage, len| {
1052                 syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
1053                     .map(crate::Socket::from_raw)
1054             })
1055         }
1056     }
1057 
1058     /// Sets `CLOEXEC` on the socket.
1059     ///
1060     /// # Notes
1061     ///
1062     /// On supported platforms you can use [`Type::cloexec`].
1063     #[cfg(feature = "all")]
1064     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
set_cloexec(&self, close_on_exec: bool) -> io::Result<()>1065     pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1066         self._set_cloexec(close_on_exec)
1067     }
1068 
_set_cloexec(&self, close_on_exec: bool) -> io::Result<()>1069     pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
1070         if close_on_exec {
1071             fcntl_add(
1072                 self.as_raw(),
1073                 libc::F_GETFD,
1074                 libc::F_SETFD,
1075                 libc::FD_CLOEXEC,
1076             )
1077         } else {
1078             fcntl_remove(
1079                 self.as_raw(),
1080                 libc::F_GETFD,
1081                 libc::F_SETFD,
1082                 libc::FD_CLOEXEC,
1083             )
1084         }
1085     }
1086 
1087     /// Sets `SO_NOSIGPIPE` on the socket.
1088     #[cfg(all(feature = "all", any(doc, target_vendor = "apple")))]
1089     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_vendor = "apple"))))]
set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()>1090     pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1091         self._set_nosigpipe(nosigpipe)
1092     }
1093 
1094     #[cfg(target_vendor = "apple")]
_set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()>1095     pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
1096         unsafe {
1097             setsockopt(
1098                 self.as_raw(),
1099                 libc::SOL_SOCKET,
1100                 libc::SO_NOSIGPIPE,
1101                 nosigpipe as c_int,
1102             )
1103         }
1104     }
1105 
1106     /// Gets the value of the `TCP_MAXSEG` option on this socket.
1107     ///
1108     /// For more information about this option, see [`set_mss`].
1109     ///
1110     /// [`set_mss`]: crate::Socket::set_mss
1111     #[cfg(all(feature = "all", not(target_os = "redox")))]
1112     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
mss(&self) -> io::Result<u32>1113     pub fn mss(&self) -> io::Result<u32> {
1114         unsafe {
1115             getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
1116                 .map(|mss| mss as u32)
1117         }
1118     }
1119 
1120     /// Sets the value of the `TCP_MAXSEG` option on this socket.
1121     ///
1122     /// The `TCP_MAXSEG` option denotes the TCP Maximum Segment Size and is only
1123     /// available on TCP sockets.
1124     #[cfg(all(feature = "all", not(target_os = "redox")))]
1125     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))]
set_mss(&self, mss: u32) -> io::Result<()>1126     pub fn set_mss(&self, mss: u32) -> io::Result<()> {
1127         unsafe {
1128             setsockopt(
1129                 self.as_raw(),
1130                 libc::IPPROTO_TCP,
1131                 libc::TCP_MAXSEG,
1132                 mss as c_int,
1133             )
1134         }
1135     }
1136 
1137     /// Returns `true` if `listen(2)` was called on this socket by checking the
1138     /// `SO_ACCEPTCONN` option on this socket.
1139     #[cfg(all(
1140         feature = "all",
1141         any(
1142             target_os = "android",
1143             target_os = "freebsd",
1144             target_os = "fuchsia",
1145             target_os = "linux",
1146         )
1147     ))]
1148     #[cfg_attr(
1149         docsrs,
1150         doc(cfg(all(
1151             feature = "all",
1152             any(
1153                 target_os = "android",
1154                 target_os = "freebsd",
1155                 target_os = "fuchsia",
1156                 target_os = "linux",
1157             )
1158         )))
1159     )]
is_listener(&self) -> io::Result<bool>1160     pub fn is_listener(&self) -> io::Result<bool> {
1161         unsafe {
1162             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
1163                 .map(|v| v != 0)
1164         }
1165     }
1166 
1167     /// Returns the [`Domain`] of this socket by checking the `SO_DOMAIN` option
1168     /// on this socket.
1169     #[cfg(all(
1170         feature = "all",
1171         any(
1172             target_os = "android",
1173             // TODO: add FreeBSD.
1174             // target_os = "freebsd",
1175             target_os = "fuchsia",
1176             target_os = "linux",
1177         )
1178     ))]
1179     #[cfg_attr(docsrs, doc(cfg(all(
1180         feature = "all",
1181         any(
1182             target_os = "android",
1183             // TODO: add FreeBSD.
1184             // target_os = "freebsd",
1185             target_os = "fuchsia",
1186             target_os = "linux",
1187         )
1188     ))))]
domain(&self) -> io::Result<Domain>1189     pub fn domain(&self) -> io::Result<Domain> {
1190         unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
1191     }
1192 
1193     /// Returns the [`Protocol`] of this socket by checking the `SO_PROTOCOL`
1194     /// option on this socket.
1195     #[cfg(all(
1196         feature = "all",
1197         any(
1198             target_os = "android",
1199             target_os = "freebsd",
1200             target_os = "fuchsia",
1201             target_os = "linux",
1202         )
1203     ))]
1204     #[cfg_attr(
1205         docsrs,
1206         doc(cfg(all(
1207             feature = "all",
1208             any(
1209                 target_os = "android",
1210                 target_os = "freebsd",
1211                 target_os = "fuchsia",
1212                 target_os = "linux",
1213             )
1214         )))
1215     )]
protocol(&self) -> io::Result<Option<Protocol>>1216     pub fn protocol(&self) -> io::Result<Option<Protocol>> {
1217         unsafe {
1218             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
1219             {
1220                 0 => None,
1221                 p => Some(Protocol(p)),
1222             })
1223         }
1224     }
1225 
1226     /// Gets the value for the `SO_MARK` option on this socket.
1227     ///
1228     /// This value gets the socket mark field for each packet sent through
1229     /// this socket.
1230     ///
1231     /// On Linux this function requires the `CAP_NET_ADMIN` capability.
1232     #[cfg(all(
1233         feature = "all",
1234         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1235     ))]
1236     #[cfg_attr(
1237         docsrs,
1238         doc(cfg(all(
1239             feature = "all",
1240             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1241         )))
1242     )]
mark(&self) -> io::Result<u32>1243     pub fn mark(&self) -> io::Result<u32> {
1244         unsafe {
1245             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
1246                 .map(|mark| mark as u32)
1247         }
1248     }
1249 
1250     /// Sets the value for the `SO_MARK` option on this socket.
1251     ///
1252     /// This value sets the socket mark field for each packet sent through
1253     /// this socket. Changing the mark can be used for mark-based routing
1254     /// without netfilter or for packet filtering.
1255     ///
1256     /// On Linux this function requires the `CAP_NET_ADMIN` capability.
1257     #[cfg(all(
1258         feature = "all",
1259         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1260     ))]
1261     #[cfg_attr(
1262         docsrs,
1263         doc(cfg(all(
1264             feature = "all",
1265             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1266         )))
1267     )]
set_mark(&self, mark: u32) -> io::Result<()>1268     pub fn set_mark(&self, mark: u32) -> io::Result<()> {
1269         unsafe {
1270             setsockopt::<c_int>(
1271                 self.as_raw(),
1272                 libc::SOL_SOCKET,
1273                 libc::SO_MARK,
1274                 mark as c_int,
1275             )
1276         }
1277     }
1278 
1279     /// Gets the value for the `SO_BINDTODEVICE` option on this socket.
1280     ///
1281     /// This value gets the socket binded device's interface name.
1282     #[cfg(all(
1283         feature = "all",
1284         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1285     ))]
1286     #[cfg_attr(
1287         docsrs,
1288         doc(cfg(all(
1289             feature = "all",
1290             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1291         )))
1292     )]
device(&self) -> io::Result<Option<Vec<u8>>>1293     pub fn device(&self) -> io::Result<Option<Vec<u8>>> {
1294         // TODO: replace with `MaybeUninit::uninit_array` once stable.
1295         let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] =
1296             unsafe { MaybeUninit::uninit().assume_init() };
1297         let mut len = buf.len() as libc::socklen_t;
1298         unsafe {
1299             syscall!(getsockopt(
1300                 self.as_raw(),
1301                 libc::SOL_SOCKET,
1302                 libc::SO_BINDTODEVICE,
1303                 buf.as_mut_ptr().cast(),
1304                 &mut len,
1305             ))?;
1306         }
1307         if len == 0 {
1308             Ok(None)
1309         } else {
1310             let buf = &buf[..len as usize - 1];
1311             // TODO: use `MaybeUninit::slice_assume_init_ref` once stable.
1312             Ok(Some(unsafe { &*(buf as *const [_] as *const [u8]) }.into()))
1313         }
1314     }
1315 
1316     /// Sets the value for the `SO_BINDTODEVICE` option on this socket.
1317     ///
1318     /// If a socket is bound to an interface, only packets received from that
1319     /// particular interface are processed by the socket. Note that this only
1320     /// works for some socket types, particularly `AF_INET` sockets.
1321     ///
1322     /// If `interface` is `None` or an empty string it removes the binding.
1323     #[cfg(all(
1324         feature = "all",
1325         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1326     ))]
1327     #[cfg_attr(
1328         docsrs,
1329         doc(cfg(all(
1330             feature = "all",
1331             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1332         )))
1333     )]
bind_device(&self, interface: Option<&[u8]>) -> io::Result<()>1334     pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> {
1335         let (value, len) = if let Some(interface) = interface {
1336             (interface.as_ptr(), interface.len())
1337         } else {
1338             (ptr::null(), 0)
1339         };
1340         syscall!(setsockopt(
1341             self.as_raw(),
1342             libc::SOL_SOCKET,
1343             libc::SO_BINDTODEVICE,
1344             value.cast(),
1345             len as libc::socklen_t,
1346         ))
1347         .map(|_| ())
1348     }
1349 
1350     /// Sets the value for `IP_BOUND_IF` option on this socket.
1351     ///
1352     /// If a socket is bound to an interface, only packets received from that
1353     /// particular interface are processed by the socket.
1354     ///
1355     /// If `interface` is `None`, the binding is removed. If the `interface`
1356     /// index is not valid, an error is returned.
1357     ///
1358     /// One can use `libc::if_nametoindex` to convert an interface alias to an
1359     /// index.
1360     #[cfg(all(feature = "all", target_vendor = "apple"))]
1361     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_vendor = "apple"))))]
bind_device_by_index(&self, interface: Option<NonZeroU32>) -> io::Result<()>1362     pub fn bind_device_by_index(&self, interface: Option<NonZeroU32>) -> io::Result<()> {
1363         let index = interface.map(NonZeroU32::get).unwrap_or(0);
1364         unsafe { setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index) }
1365     }
1366 
1367     /// Gets the value for `IP_BOUND_IF` option on this socket, i.e. the index
1368     /// for the interface to which the socket is bound.
1369     ///
1370     /// Returns `None` if the socket is not bound to any interface, otherwise
1371     /// returns an interface index.
1372     #[cfg(all(feature = "all", target_vendor = "apple"))]
1373     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_vendor = "apple"))))]
device_index(&self) -> io::Result<Option<NonZeroU32>>1374     pub fn device_index(&self) -> io::Result<Option<NonZeroU32>> {
1375         let index =
1376             unsafe { getsockopt::<libc::c_uint>(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? };
1377         Ok(NonZeroU32::new(index))
1378     }
1379 
1380     /// Get the value of the `SO_INCOMING_CPU` option on this socket.
1381     ///
1382     /// For more information about this option, see [`set_cpu_affinity`].
1383     ///
1384     /// [`set_cpu_affinity`]: crate::Socket::set_cpu_affinity
1385     #[cfg(all(feature = "all", target_os = "linux"))]
1386     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
cpu_affinity(&self) -> io::Result<usize>1387     pub fn cpu_affinity(&self) -> io::Result<usize> {
1388         unsafe {
1389             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
1390                 .map(|cpu| cpu as usize)
1391         }
1392     }
1393 
1394     /// Set value for the `SO_INCOMING_CPU` option on this socket.
1395     ///
1396     /// Sets the CPU affinity of the socket.
1397     #[cfg(all(feature = "all", target_os = "linux"))]
1398     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
set_cpu_affinity(&self, cpu: usize) -> io::Result<()>1399     pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
1400         unsafe {
1401             setsockopt(
1402                 self.as_raw(),
1403                 libc::SOL_SOCKET,
1404                 libc::SO_INCOMING_CPU,
1405                 cpu as c_int,
1406             )
1407         }
1408     }
1409 
1410     /// Get the value of the `SO_REUSEPORT` option on this socket.
1411     ///
1412     /// For more information about this option, see [`set_reuse_port`].
1413     ///
1414     /// [`set_reuse_port`]: crate::Socket::set_reuse_port
1415     #[cfg(all(
1416         feature = "all",
1417         not(any(target_os = "solaris", target_os = "illumos"))
1418     ))]
1419     #[cfg_attr(
1420         docsrs,
1421         doc(cfg(all(
1422             feature = "all",
1423             unix,
1424             not(any(target_os = "solaris", target_os = "illumos"))
1425         )))
1426     )]
reuse_port(&self) -> io::Result<bool>1427     pub fn reuse_port(&self) -> io::Result<bool> {
1428         unsafe {
1429             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
1430                 .map(|reuse| reuse != 0)
1431         }
1432     }
1433 
1434     /// Set value for the `SO_REUSEPORT` option on this socket.
1435     ///
1436     /// This indicates that further calls to `bind` may allow reuse of local
1437     /// addresses. For IPv4 sockets this means that a socket may bind even when
1438     /// there's a socket already listening on this port.
1439     #[cfg(all(
1440         feature = "all",
1441         not(any(target_os = "solaris", target_os = "illumos"))
1442     ))]
1443     #[cfg_attr(
1444         docsrs,
1445         doc(cfg(all(
1446             feature = "all",
1447             unix,
1448             not(any(target_os = "solaris", target_os = "illumos"))
1449         )))
1450     )]
set_reuse_port(&self, reuse: bool) -> io::Result<()>1451     pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
1452         unsafe {
1453             setsockopt(
1454                 self.as_raw(),
1455                 libc::SOL_SOCKET,
1456                 libc::SO_REUSEPORT,
1457                 reuse as c_int,
1458             )
1459         }
1460     }
1461 
1462     /// Get the value of the `IP_FREEBIND` option on this socket.
1463     ///
1464     /// For more information about this option, see [`set_freebind`].
1465     ///
1466     /// [`set_freebind`]: crate::Socket::set_freebind
1467     #[cfg(all(
1468         feature = "all",
1469         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1470     ))]
1471     #[cfg_attr(
1472         docsrs,
1473         doc(cfg(all(
1474             feature = "all",
1475             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1476         )))
1477     )]
freebind(&self) -> io::Result<bool>1478     pub fn freebind(&self) -> io::Result<bool> {
1479         unsafe {
1480             getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::IP_FREEBIND)
1481                 .map(|reuse| reuse != 0)
1482         }
1483     }
1484 
1485     /// Set value for the `IP_FREEBIND` option on this socket.
1486     ///
1487     /// If enabled, this boolean option allows binding to an IP address that is
1488     /// nonlocal or does not (yet) exist.  This permits listening on a socket,
1489     /// without requiring the underlying network interface or the specified
1490     /// dynamic IP address to be up at the time that the application is trying
1491     /// to bind to it.
1492     #[cfg(all(
1493         feature = "all",
1494         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1495     ))]
1496     #[cfg_attr(
1497         docsrs,
1498         doc(cfg(all(
1499             feature = "all",
1500             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1501         )))
1502     )]
set_freebind(&self, reuse: bool) -> io::Result<()>1503     pub fn set_freebind(&self, reuse: bool) -> io::Result<()> {
1504         unsafe {
1505             setsockopt(
1506                 self.as_raw(),
1507                 libc::SOL_SOCKET,
1508                 libc::IP_FREEBIND,
1509                 reuse as c_int,
1510             )
1511         }
1512     }
1513 
1514     /// Copies data between a `file` and this socket using the `sendfile(2)`
1515     /// system call. Because this copying is done within the kernel,
1516     /// `sendfile()` is more efficient than the combination of `read(2)` and
1517     /// `write(2)`, which would require transferring data to and from user
1518     /// space.
1519     ///
1520     /// Different OSs support different kinds of `file`s, see the OS
1521     /// documentation for what kind of files are supported. Generally *regular*
1522     /// files are supported by all OSs.
1523     ///
1524     /// The `offset` is the absolute offset into the `file` to use as starting
1525     /// point.
1526     ///
1527     /// Depending on the OS this function *may* change the offset of `file`. For
1528     /// the best results reset the offset of the file before using it again.
1529     ///
1530     /// The `length` determines how many bytes to send, where a length of `None`
1531     /// means it will try to send all bytes.
1532     #[cfg(all(
1533         feature = "all",
1534         any(
1535             target_os = "android",
1536             target_os = "freebsd",
1537             target_os = "linux",
1538             target_vendor = "apple",
1539         )
1540     ))]
1541     #[cfg_attr(
1542         docsrs,
1543         doc(cfg(all(
1544             feature = "all",
1545             any(
1546                 target_os = "android",
1547                 target_os = "freebsd",
1548                 target_os = "linux",
1549                 target_vendor = "apple",
1550             )
1551         )))
1552     )]
sendfile<F>( &self, file: &F, offset: usize, length: Option<NonZeroUsize>, ) -> io::Result<usize> where F: AsRawFd,1553     pub fn sendfile<F>(
1554         &self,
1555         file: &F,
1556         offset: usize,
1557         length: Option<NonZeroUsize>,
1558     ) -> io::Result<usize>
1559     where
1560         F: AsRawFd,
1561     {
1562         self._sendfile(file.as_raw_fd(), offset as _, length)
1563     }
1564 
1565     #[cfg(all(feature = "all", target_vendor = "apple"))]
_sendfile( &self, file: RawFd, offset: libc::off_t, length: Option<NonZeroUsize>, ) -> io::Result<usize>1566     fn _sendfile(
1567         &self,
1568         file: RawFd,
1569         offset: libc::off_t,
1570         length: Option<NonZeroUsize>,
1571     ) -> io::Result<usize> {
1572         // On macOS `length` is value-result parameter. It determines the number
1573         // of bytes to write and returns the number of bytes written.
1574         let mut length = match length {
1575             Some(n) => n.get() as libc::off_t,
1576             // A value of `0` means send all bytes.
1577             None => 0,
1578         };
1579         syscall!(sendfile(
1580             file,
1581             self.as_raw(),
1582             offset,
1583             &mut length,
1584             ptr::null_mut(),
1585             0,
1586         ))
1587         .map(|_| length as usize)
1588     }
1589 
1590     #[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>1591     fn _sendfile(
1592         &self,
1593         file: RawFd,
1594         offset: libc::off_t,
1595         length: Option<NonZeroUsize>,
1596     ) -> io::Result<usize> {
1597         let count = match length {
1598             Some(n) => n.get() as libc::size_t,
1599             // The maximum the Linux kernel will write in a single call.
1600             None => 0x7ffff000, // 2,147,479,552 bytes.
1601         };
1602         let mut offset = offset;
1603         syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
1604     }
1605 
1606     #[cfg(all(feature = "all", target_os = "freebsd"))]
_sendfile( &self, file: RawFd, offset: libc::off_t, length: Option<NonZeroUsize>, ) -> io::Result<usize>1607     fn _sendfile(
1608         &self,
1609         file: RawFd,
1610         offset: libc::off_t,
1611         length: Option<NonZeroUsize>,
1612     ) -> io::Result<usize> {
1613         let nbytes = match length {
1614             Some(n) => n.get() as libc::size_t,
1615             // A value of `0` means send all bytes.
1616             None => 0,
1617         };
1618         let mut sbytes: libc::off_t = 0;
1619         syscall!(sendfile(
1620             file,
1621             self.as_raw(),
1622             offset,
1623             nbytes,
1624             ptr::null_mut(),
1625             &mut sbytes,
1626             0,
1627         ))
1628         .map(|_| sbytes as usize)
1629     }
1630 
1631     /// Set the value of the `TCP_USER_TIMEOUT` option on this socket.
1632     ///
1633     /// If set, this specifies the maximum amount of time that transmitted data may remain
1634     /// unacknowledged or buffered data may remain untransmitted before TCP will forcibly close the
1635     /// corresponding connection.
1636     ///
1637     /// Setting `timeout` to `None` or a zero duration causes the system default timeouts to
1638     /// be used. If `timeout` in milliseconds is larger than `c_uint::MAX`, the timeout is clamped
1639     /// to `c_uint::MAX`. For example, when `c_uint` is a 32-bit value, this limits the timeout to
1640     /// approximately 49.71 days.
1641     #[cfg(all(
1642         feature = "all",
1643         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1644     ))]
1645     #[cfg_attr(
1646         docsrs,
1647         doc(cfg(all(
1648             feature = "all",
1649             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1650         )))
1651     )]
set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()>1652     pub fn set_tcp_user_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
1653         let timeout = timeout
1654             .map(|to| min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint)
1655             .unwrap_or(0);
1656         unsafe {
1657             setsockopt(
1658                 self.as_raw(),
1659                 libc::IPPROTO_TCP,
1660                 libc::TCP_USER_TIMEOUT,
1661                 timeout,
1662             )
1663         }
1664     }
1665 
1666     /// Get the value of the `TCP_USER_TIMEOUT` option on this socket.
1667     ///
1668     /// For more information about this option, see [`set_tcp_user_timeout`].
1669     ///
1670     /// [`set_tcp_user_timeout`]: Socket::set_tcp_user_timeout
1671     #[cfg(all(
1672         feature = "all",
1673         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1674     ))]
1675     #[cfg_attr(
1676         docsrs,
1677         doc(cfg(all(
1678             feature = "all",
1679             any(target_os = "android", target_os = "fuchsia", target_os = "linux")
1680         )))
1681     )]
tcp_user_timeout(&self) -> io::Result<Option<Duration>>1682     pub fn tcp_user_timeout(&self) -> io::Result<Option<Duration>> {
1683         unsafe {
1684             getsockopt::<libc::c_uint>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT)
1685                 .map(|millis| {
1686                     if millis == 0 {
1687                         None
1688                     } else {
1689                         Some(Duration::from_millis(millis as u64))
1690                     }
1691                 })
1692         }
1693     }
1694 }
1695 
1696 #[cfg_attr(docsrs, doc(cfg(unix)))]
1697 impl AsRawFd for crate::Socket {
as_raw_fd(&self) -> c_int1698     fn as_raw_fd(&self) -> c_int {
1699         self.as_raw()
1700     }
1701 }
1702 
1703 #[cfg_attr(docsrs, doc(cfg(unix)))]
1704 impl IntoRawFd for crate::Socket {
into_raw_fd(self) -> c_int1705     fn into_raw_fd(self) -> c_int {
1706         self.into_raw()
1707     }
1708 }
1709 
1710 #[cfg_attr(docsrs, doc(cfg(unix)))]
1711 impl FromRawFd for crate::Socket {
from_raw_fd(fd: c_int) -> crate::Socket1712     unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
1713         crate::Socket::from_raw(fd)
1714     }
1715 }
1716 
1717 #[cfg(feature = "all")]
1718 from!(UnixStream, crate::Socket);
1719 #[cfg(feature = "all")]
1720 from!(UnixListener, crate::Socket);
1721 #[cfg(feature = "all")]
1722 from!(UnixDatagram, crate::Socket);
1723 #[cfg(feature = "all")]
1724 from!(crate::Socket, UnixStream);
1725 #[cfg(feature = "all")]
1726 from!(crate::Socket, UnixListener);
1727 #[cfg(feature = "all")]
1728 from!(crate::Socket, UnixDatagram);
1729 
1730 #[test]
in_addr_convertion()1731 fn in_addr_convertion() {
1732     let ip = Ipv4Addr::new(127, 0, 0, 1);
1733     let raw = to_in_addr(&ip);
1734     // NOTE: `in_addr` is packed on NetBSD and it's unsafe to borrow.
1735     let a = raw.s_addr;
1736     assert_eq!(a, u32::from_ne_bytes([127, 0, 0, 1]));
1737     assert_eq!(from_in_addr(raw), ip);
1738 
1739     let ip = Ipv4Addr::new(127, 34, 4, 12);
1740     let raw = to_in_addr(&ip);
1741     let a = raw.s_addr;
1742     assert_eq!(a, u32::from_ne_bytes([127, 34, 4, 12]));
1743     assert_eq!(from_in_addr(raw), ip);
1744 }
1745 
1746 #[test]
in6_addr_convertion()1747 fn in6_addr_convertion() {
1748     let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
1749     let raw = to_in6_addr(&ip);
1750     let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
1751     assert_eq!(raw.s6_addr, want);
1752     assert_eq!(from_in6_addr(raw), ip);
1753 }
1754