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 //! Utilities for creating and using sockets.
10 //!
11 //! The goal of this crate is to create and use a socket using advanced
12 //! configuration options (those that are not available in the types in the
13 //! standard library) without using any unsafe code.
14 //!
15 //! This crate provides as direct as possible access to the system's
16 //! functionality for sockets, this means little effort to provide
17 //! cross-platform utilities. It is up to the user to know how to use sockets
18 //! when using this crate. *If you don't know how to create a socket using
19 //! libc/system calls then this crate is not for you*. Most, if not all,
20 //! functions directly relate to the equivalent system call with no error
21 //! handling applied, so no handling errors such as [`EINTR`]. As a result using
22 //! this crate can be a little wordy, but it should give you maximal flexibility
23 //! over configuration of sockets.
24 //!
25 //! [`EINTR`]: std::io::ErrorKind::Interrupted
26 //!
27 //! # Examples
28 //!
29 //! ```no_run
30 //! # fn main() -> std::io::Result<()> {
31 //! use std::net::{SocketAddr, TcpListener};
32 //! use socket2::{Socket, Domain, Type};
33 //!
34 //! // Create a TCP listener bound to two addresses.
35 //! let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
36 //!
37 //! socket.set_only_v6(false)?;
38 //! let address: SocketAddr = "[::1]:12345".parse().unwrap();
39 //! socket.bind(&address.into())?;
40 //! socket.listen(128)?;
41 //!
42 //! let listener: TcpListener = socket.into();
43 //! // ...
44 //! # drop(listener);
45 //! # Ok(()) }
46 //! ```
47 //!
48 //! ## Features
49 //!
50 //! This crate has a single feature `all`, which enables all functions even ones
51 //! that are not available on all OSs.
52 
53 #![doc(html_root_url = "https://docs.rs/socket2/0.3")]
54 #![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
55 // Show required OS/features on docs.rs.
56 #![cfg_attr(docsrs, feature(doc_cfg))]
57 // Disallow warnings when running tests.
58 #![cfg_attr(test, deny(warnings))]
59 // Disallow warnings in examples.
60 #![doc(test(attr(deny(warnings))))]
61 
62 use std::fmt;
63 use std::mem::MaybeUninit;
64 use std::net::SocketAddr;
65 use std::ops::{Deref, DerefMut};
66 use std::time::Duration;
67 
68 /// Macro to implement `fmt::Debug` for a type, printing the constant names
69 /// rather than a number.
70 ///
71 /// Note this is used in the `sys` module and thus must be defined before
72 /// defining the modules.
73 macro_rules! impl_debug {
74     (
75         // Type name for which to implement `fmt::Debug`.
76         $type: path,
77         $(
78             $(#[$target: meta])*
79             // The flag(s) to check.
80             // Need to specific the libc crate because Windows doesn't use
81             // `libc` but `winapi`.
82             $libc: ident :: $flag: ident
83         ),+ $(,)*
84     ) => {
85         impl std::fmt::Debug for $type {
86             fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87                 let string = match self.0 {
88                     $(
89                         $(#[$target])*
90                         $libc :: $flag => stringify!($flag),
91                     )+
92                     n => return write!(f, "{}", n),
93                 };
94                 f.write_str(string)
95             }
96         }
97     };
98 }
99 
100 /// Macro to convert from one network type to another.
101 macro_rules! from {
102     ($from: ty, $for: ty) => {
103         impl From<$from> for $for {
104             fn from(socket: $from) -> $for {
105                 #[cfg(unix)]
106                 unsafe {
107                     <$for>::from_raw_fd(socket.into_raw_fd())
108                 }
109                 #[cfg(windows)]
110                 unsafe {
111                     <$for>::from_raw_socket(socket.into_raw_socket())
112                 }
113             }
114         }
115     };
116 }
117 
118 mod sockaddr;
119 mod socket;
120 mod sockref;
121 
122 #[cfg(unix)]
123 #[path = "sys/unix.rs"]
124 mod sys;
125 #[cfg(windows)]
126 #[path = "sys/windows.rs"]
127 mod sys;
128 
129 use sys::c_int;
130 
131 pub use sockaddr::SockAddr;
132 pub use socket::Socket;
133 pub use sockref::SockRef;
134 
135 /// Specification of the communication domain for a socket.
136 ///
137 /// This is a newtype wrapper around an integer which provides a nicer API in
138 /// addition to an injection point for documentation. Convenience constants such
139 /// as [`Domain::IPV4`], [`Domain::IPV6`], etc, are provided to avoid reaching
140 /// into libc for various constants.
141 ///
142 /// This type is freely interconvertible with C's `int` type, however, if a raw
143 /// value needs to be provided.
144 #[derive(Copy, Clone, Eq, PartialEq)]
145 pub struct Domain(c_int);
146 
147 impl Domain {
148     /// Domain for IPv4 communication, corresponding to `AF_INET`.
149     pub const IPV4: Domain = Domain(sys::AF_INET);
150 
151     /// Domain for IPv6 communication, corresponding to `AF_INET6`.
152     pub const IPV6: Domain = Domain(sys::AF_INET6);
153 
154     /// Returns the correct domain for `address`.
for_address(address: SocketAddr) -> Domain155     pub const fn for_address(address: SocketAddr) -> Domain {
156         match address {
157             SocketAddr::V4(_) => Domain::IPV4,
158             SocketAddr::V6(_) => Domain::IPV6,
159         }
160     }
161 }
162 
163 impl From<c_int> for Domain {
from(d: c_int) -> Domain164     fn from(d: c_int) -> Domain {
165         Domain(d)
166     }
167 }
168 
169 impl From<Domain> for c_int {
from(d: Domain) -> c_int170     fn from(d: Domain) -> c_int {
171         d.0
172     }
173 }
174 
175 /// Specification of communication semantics on a socket.
176 ///
177 /// This is a newtype wrapper around an integer which provides a nicer API in
178 /// addition to an injection point for documentation. Convenience constants such
179 /// as [`Type::STREAM`], [`Type::DGRAM`], etc, are provided to avoid reaching
180 /// into libc for various constants.
181 ///
182 /// This type is freely interconvertible with C's `int` type, however, if a raw
183 /// value needs to be provided.
184 #[derive(Copy, Clone, Eq, PartialEq)]
185 pub struct Type(c_int);
186 
187 impl Type {
188     /// Type corresponding to `SOCK_STREAM`.
189     ///
190     /// Used for protocols such as TCP.
191     pub const STREAM: Type = Type(sys::SOCK_STREAM);
192 
193     /// Type corresponding to `SOCK_DGRAM`.
194     ///
195     /// Used for protocols such as UDP.
196     pub const DGRAM: Type = Type(sys::SOCK_DGRAM);
197 
198     /// Type corresponding to `SOCK_SEQPACKET`.
199     #[cfg(feature = "all")]
200     #[cfg_attr(docsrs, doc(cfg(feature = "all")))]
201     pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
202 
203     /// Type corresponding to `SOCK_RAW`.
204     #[cfg(all(feature = "all", not(target_os = "redox")))]
205     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "redox")))))]
206     pub const RAW: Type = Type(sys::SOCK_RAW);
207 }
208 
209 impl From<c_int> for Type {
from(t: c_int) -> Type210     fn from(t: c_int) -> Type {
211         Type(t)
212     }
213 }
214 
215 impl From<Type> for c_int {
from(t: Type) -> c_int216     fn from(t: Type) -> c_int {
217         t.0
218     }
219 }
220 
221 /// Protocol specification used for creating sockets via `Socket::new`.
222 ///
223 /// This is a newtype wrapper around an integer which provides a nicer API in
224 /// addition to an injection point for documentation.
225 ///
226 /// This type is freely interconvertible with C's `int` type, however, if a raw
227 /// value needs to be provided.
228 #[derive(Copy, Clone, Eq, PartialEq)]
229 pub struct Protocol(c_int);
230 
231 impl Protocol {
232     /// Protocol corresponding to `ICMPv4`.
233     pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP);
234 
235     /// Protocol corresponding to `ICMPv6`.
236     pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6);
237 
238     /// Protocol corresponding to `TCP`.
239     pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP);
240 
241     /// Protocol corresponding to `UDP`.
242     pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP);
243 }
244 
245 impl From<c_int> for Protocol {
from(p: c_int) -> Protocol246     fn from(p: c_int) -> Protocol {
247         Protocol(p)
248     }
249 }
250 
251 impl From<Protocol> for c_int {
from(p: Protocol) -> c_int252     fn from(p: Protocol) -> c_int {
253         p.0
254     }
255 }
256 
257 /// Flags for incoming messages.
258 ///
259 /// Flags provide additional information about incoming messages.
260 #[cfg(not(target_os = "redox"))]
261 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
262 #[derive(Copy, Clone, Eq, PartialEq)]
263 pub struct RecvFlags(c_int);
264 
265 #[cfg(not(target_os = "redox"))]
266 impl RecvFlags {
267     /// Check if the message contains a truncated datagram.
268     ///
269     /// This flag is only used for datagram-based sockets,
270     /// not for stream sockets.
271     ///
272     /// On Unix this corresponds to the `MSG_TRUNC` flag.
273     /// On Windows this corresponds to the `WSAEMSGSIZE` error code.
is_truncated(self) -> bool274     pub const fn is_truncated(self) -> bool {
275         self.0 & sys::MSG_TRUNC != 0
276     }
277 }
278 
279 /// A version of [`IoSliceMut`] that allows the buffer to be uninitialised.
280 ///
281 /// [`IoSliceMut`]: std::io::IoSliceMut
282 #[repr(transparent)]
283 pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
284 
285 unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
286 
287 unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
288 
289 impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result290     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
291         fmt::Debug::fmt(self.0.as_slice(), fmt)
292     }
293 }
294 
295 impl<'a> MaybeUninitSlice<'a> {
296     /// Creates a new `MaybeUninitSlice` wrapping a byte slice.
297     ///
298     /// # Panics
299     ///
300     /// Panics on Windows if the slice is larger than 4GB.
new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a>301     pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
302         MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
303     }
304 }
305 
306 impl<'a> Deref for MaybeUninitSlice<'a> {
307     type Target = [MaybeUninit<u8>];
308 
deref(&self) -> &[MaybeUninit<u8>]309     fn deref(&self) -> &[MaybeUninit<u8>] {
310         self.0.as_slice()
311     }
312 }
313 
314 impl<'a> DerefMut for MaybeUninitSlice<'a> {
deref_mut(&mut self) -> &mut [MaybeUninit<u8>]315     fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
316         self.0.as_mut_slice()
317     }
318 }
319 
320 /// Configures a socket's TCP keepalive parameters.
321 ///
322 /// See [`Socket::set_tcp_keepalive`].
323 #[derive(Debug, Clone)]
324 pub struct TcpKeepalive {
325     time: Option<Duration>,
326     #[cfg_attr(target_os = "redox", allow(dead_code))]
327     interval: Option<Duration>,
328     #[cfg_attr(target_os = "redox", allow(dead_code))]
329     retries: Option<u32>,
330 }
331 
332 impl TcpKeepalive {
333     /// Returns a new, empty set of TCP keepalive parameters.
new() -> TcpKeepalive334     pub const fn new() -> TcpKeepalive {
335         TcpKeepalive {
336             time: None,
337             interval: None,
338             retries: None,
339         }
340     }
341 
342     /// Set the amount of time after which TCP keepalive probes will be sent on
343     /// idle connections.
344     ///
345     /// This will set `TCP_KEEPALIVE` on macOS and iOS, and
346     /// `TCP_KEEPIDLE` on all other Unix operating systems, except
347     /// OpenBSD and Haiku which don't support any way to set this
348     /// option. On Windows, this sets the value of the `tcp_keepalive`
349     /// struct's `keepalivetime` field.
350     ///
351     /// Some platforms specify this value in seconds, so sub-second
352     /// specifications may be omitted.
with_time(self, time: Duration) -> Self353     pub const fn with_time(self, time: Duration) -> Self {
354         Self {
355             time: Some(time),
356             ..self
357         }
358     }
359 
360     /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the
361     /// value of the `tcp_keepalive` struct's `keepaliveinterval` field.
362     ///
363     /// Sets the time interval between TCP keepalive probes.
364     ///
365     /// Some platforms specify this value in seconds, so sub-second
366     /// specifications may be omitted.
367     #[cfg(all(
368         feature = "all",
369         any(
370             target_os = "dragonfly",
371             target_os = "freebsd",
372             target_os = "fuchsia",
373             target_os = "linux",
374             target_os = "netbsd",
375             target_vendor = "apple",
376             windows,
377         )
378     ))]
379     #[cfg_attr(
380         docsrs,
381         doc(cfg(all(
382             feature = "all",
383             any(
384                 target_os = "freebsd",
385                 target_os = "fuchsia",
386                 target_os = "linux",
387                 target_os = "netbsd",
388                 target_vendor = "apple",
389                 windows,
390             )
391         )))
392     )]
with_interval(self, interval: Duration) -> Self393     pub const fn with_interval(self, interval: Duration) -> Self {
394         Self {
395             interval: Some(interval),
396             ..self
397         }
398     }
399 
400     /// Set the value of the `TCP_KEEPCNT` option.
401     ///
402     /// Set the maximum number of TCP keepalive probes that will be sent before
403     /// dropping a connection, if TCP keepalive is enabled on this socket.
404     #[cfg(all(
405         feature = "all",
406         any(
407             doc,
408             target_os = "dragonfly",
409             target_os = "freebsd",
410             target_os = "fuchsia",
411             target_os = "linux",
412             target_os = "netbsd",
413             target_vendor = "apple",
414         )
415     ))]
416     #[cfg_attr(
417         docsrs,
418         doc(cfg(all(
419             feature = "all",
420             any(
421                 target_os = "freebsd",
422                 target_os = "fuchsia",
423                 target_os = "linux",
424                 target_os = "netbsd",
425                 target_vendor = "apple",
426             )
427         )))
428     )]
with_retries(self, retries: u32) -> Self429     pub const fn with_retries(self, retries: u32) -> Self {
430         Self {
431             retries: Some(retries),
432             ..self
433         }
434     }
435 }
436