• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Rust Project Developers.
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or https://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.4")]
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_attr(unix, path = "sys/unix.rs")]
123 #[cfg_attr(windows, path = "sys/windows.rs")]
124 mod sys;
125 
126 #[cfg(not(any(windows, unix)))]
127 compile_error!("Socket2 doesn't support the compile target");
128 
129 use sys::c_int;
130 
131 pub use sockaddr::SockAddr;
132 pub use socket::Socket;
133 pub use sockref::SockRef;
134 
135 #[cfg(not(any(
136     target_os = "haiku",
137     target_os = "illumos",
138     target_os = "netbsd",
139     target_os = "redox",
140     target_os = "solaris",
141 )))]
142 pub use socket::InterfaceIndexOrAddress;
143 
144 /// Specification of the communication domain for a socket.
145 ///
146 /// This is a newtype wrapper around an integer which provides a nicer API in
147 /// addition to an injection point for documentation. Convenience constants such
148 /// as [`Domain::IPV4`], [`Domain::IPV6`], etc, are provided to avoid reaching
149 /// into libc for various constants.
150 ///
151 /// This type is freely interconvertible with C's `int` type, however, if a raw
152 /// value needs to be provided.
153 #[derive(Copy, Clone, Eq, PartialEq)]
154 pub struct Domain(c_int);
155 
156 impl Domain {
157     /// Domain for IPv4 communication, corresponding to `AF_INET`.
158     pub const IPV4: Domain = Domain(sys::AF_INET);
159 
160     /// Domain for IPv6 communication, corresponding to `AF_INET6`.
161     pub const IPV6: Domain = Domain(sys::AF_INET6);
162 
163     /// Returns the correct domain for `address`.
for_address(address: SocketAddr) -> Domain164     pub const fn for_address(address: SocketAddr) -> Domain {
165         match address {
166             SocketAddr::V4(_) => Domain::IPV4,
167             SocketAddr::V6(_) => Domain::IPV6,
168         }
169     }
170 }
171 
172 impl From<c_int> for Domain {
from(d: c_int) -> Domain173     fn from(d: c_int) -> Domain {
174         Domain(d)
175     }
176 }
177 
178 impl From<Domain> for c_int {
from(d: Domain) -> c_int179     fn from(d: Domain) -> c_int {
180         d.0
181     }
182 }
183 
184 /// Specification of communication semantics on a socket.
185 ///
186 /// This is a newtype wrapper around an integer which provides a nicer API in
187 /// addition to an injection point for documentation. Convenience constants such
188 /// as [`Type::STREAM`], [`Type::DGRAM`], etc, are provided to avoid reaching
189 /// into libc for various constants.
190 ///
191 /// This type is freely interconvertible with C's `int` type, however, if a raw
192 /// value needs to be provided.
193 #[derive(Copy, Clone, Eq, PartialEq)]
194 pub struct Type(c_int);
195 
196 impl Type {
197     /// Type corresponding to `SOCK_STREAM`.
198     ///
199     /// Used for protocols such as TCP.
200     pub const STREAM: Type = Type(sys::SOCK_STREAM);
201 
202     /// Type corresponding to `SOCK_DGRAM`.
203     ///
204     /// Used for protocols such as UDP.
205     pub const DGRAM: Type = Type(sys::SOCK_DGRAM);
206 
207     /// Type corresponding to `SOCK_SEQPACKET`.
208     #[cfg(feature = "all")]
209     #[cfg_attr(docsrs, doc(cfg(feature = "all")))]
210     pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
211 
212     /// Type corresponding to `SOCK_RAW`.
213     #[cfg(all(feature = "all", not(target_os = "redox")))]
214     #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "redox")))))]
215     pub const RAW: Type = Type(sys::SOCK_RAW);
216 }
217 
218 impl From<c_int> for Type {
from(t: c_int) -> Type219     fn from(t: c_int) -> Type {
220         Type(t)
221     }
222 }
223 
224 impl From<Type> for c_int {
from(t: Type) -> c_int225     fn from(t: Type) -> c_int {
226         t.0
227     }
228 }
229 
230 /// Protocol specification used for creating sockets via `Socket::new`.
231 ///
232 /// This is a newtype wrapper around an integer which provides a nicer API in
233 /// addition to an injection point for documentation.
234 ///
235 /// This type is freely interconvertible with C's `int` type, however, if a raw
236 /// value needs to be provided.
237 #[derive(Copy, Clone, Eq, PartialEq)]
238 pub struct Protocol(c_int);
239 
240 impl Protocol {
241     /// Protocol corresponding to `ICMPv4`.
242     pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP);
243 
244     /// Protocol corresponding to `ICMPv6`.
245     pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6);
246 
247     /// Protocol corresponding to `TCP`.
248     pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP);
249 
250     /// Protocol corresponding to `UDP`.
251     pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP);
252 }
253 
254 impl From<c_int> for Protocol {
from(p: c_int) -> Protocol255     fn from(p: c_int) -> Protocol {
256         Protocol(p)
257     }
258 }
259 
260 impl From<Protocol> for c_int {
from(p: Protocol) -> c_int261     fn from(p: Protocol) -> c_int {
262         p.0
263     }
264 }
265 
266 /// Flags for incoming messages.
267 ///
268 /// Flags provide additional information about incoming messages.
269 #[cfg(not(target_os = "redox"))]
270 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
271 #[derive(Copy, Clone, Eq, PartialEq)]
272 pub struct RecvFlags(c_int);
273 
274 #[cfg(not(target_os = "redox"))]
275 impl RecvFlags {
276     /// Check if the message contains a truncated datagram.
277     ///
278     /// This flag is only used for datagram-based sockets,
279     /// not for stream sockets.
280     ///
281     /// On Unix this corresponds to the `MSG_TRUNC` flag.
282     /// On Windows this corresponds to the `WSAEMSGSIZE` error code.
is_truncated(self) -> bool283     pub const fn is_truncated(self) -> bool {
284         self.0 & sys::MSG_TRUNC != 0
285     }
286 }
287 
288 /// A version of [`IoSliceMut`] that allows the buffer to be uninitialised.
289 ///
290 /// [`IoSliceMut`]: std::io::IoSliceMut
291 #[repr(transparent)]
292 pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
293 
294 impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result295     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
296         fmt::Debug::fmt(self.0.as_slice(), fmt)
297     }
298 }
299 
300 impl<'a> MaybeUninitSlice<'a> {
301     /// Creates a new `MaybeUninitSlice` wrapping a byte slice.
302     ///
303     /// # Panics
304     ///
305     /// Panics on Windows if the slice is larger than 4GB.
new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a>306     pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
307         MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
308     }
309 }
310 
311 impl<'a> Deref for MaybeUninitSlice<'a> {
312     type Target = [MaybeUninit<u8>];
313 
deref(&self) -> &[MaybeUninit<u8>]314     fn deref(&self) -> &[MaybeUninit<u8>] {
315         self.0.as_slice()
316     }
317 }
318 
319 impl<'a> DerefMut for MaybeUninitSlice<'a> {
deref_mut(&mut self) -> &mut [MaybeUninit<u8>]320     fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
321         self.0.as_mut_slice()
322     }
323 }
324 
325 /// Configures a socket's TCP keepalive parameters.
326 ///
327 /// See [`Socket::set_tcp_keepalive`].
328 #[derive(Debug, Clone)]
329 pub struct TcpKeepalive {
330     #[cfg_attr(target_os = "openbsd", allow(dead_code))]
331     time: Option<Duration>,
332     #[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "solaris")))]
333     interval: Option<Duration>,
334     #[cfg(not(any(
335         target_os = "openbsd",
336         target_os = "redox",
337         target_os = "solaris",
338         target_os = "windows"
339     )))]
340     retries: Option<u32>,
341 }
342 
343 impl TcpKeepalive {
344     /// Returns a new, empty set of TCP keepalive parameters.
new() -> TcpKeepalive345     pub const fn new() -> TcpKeepalive {
346         TcpKeepalive {
347             time: None,
348             #[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "solaris")))]
349             interval: None,
350             #[cfg(not(any(
351                 target_os = "openbsd",
352                 target_os = "redox",
353                 target_os = "solaris",
354                 target_os = "windows"
355             )))]
356             retries: None,
357         }
358     }
359 
360     /// Set the amount of time after which TCP keepalive probes will be sent on
361     /// idle connections.
362     ///
363     /// This will set `TCP_KEEPALIVE` on macOS and iOS, and
364     /// `TCP_KEEPIDLE` on all other Unix operating systems, except
365     /// OpenBSD and Haiku which don't support any way to set this
366     /// option. On Windows, this sets the value of the `tcp_keepalive`
367     /// struct's `keepalivetime` field.
368     ///
369     /// Some platforms specify this value in seconds, so sub-second
370     /// specifications may be omitted.
with_time(self, time: Duration) -> Self371     pub const fn with_time(self, time: Duration) -> Self {
372         Self {
373             time: Some(time),
374             ..self
375         }
376     }
377 
378     /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the
379     /// value of the `tcp_keepalive` struct's `keepaliveinterval` field.
380     ///
381     /// Sets the time interval between TCP keepalive probes.
382     ///
383     /// Some platforms specify this value in seconds, so sub-second
384     /// specifications may be omitted.
385     #[cfg(all(
386         feature = "all",
387         any(
388             target_os = "android",
389             target_os = "dragonfly",
390             target_os = "freebsd",
391             target_os = "fuchsia",
392             target_os = "illumos",
393             target_os = "linux",
394             target_os = "netbsd",
395             target_vendor = "apple",
396             windows,
397         )
398     ))]
399     #[cfg_attr(
400         docsrs,
401         doc(cfg(all(
402             feature = "all",
403             any(
404                 target_os = "android",
405                 target_os = "dragonfly",
406                 target_os = "freebsd",
407                 target_os = "fuchsia",
408                 target_os = "illumos",
409                 target_os = "linux",
410                 target_os = "netbsd",
411                 target_vendor = "apple",
412                 windows,
413             )
414         )))
415     )]
with_interval(self, interval: Duration) -> Self416     pub const fn with_interval(self, interval: Duration) -> Self {
417         Self {
418             interval: Some(interval),
419             ..self
420         }
421     }
422 
423     /// Set the value of the `TCP_KEEPCNT` option.
424     ///
425     /// Set the maximum number of TCP keepalive probes that will be sent before
426     /// dropping a connection, if TCP keepalive is enabled on this socket.
427     #[cfg(all(
428         feature = "all",
429         any(
430             doc,
431             target_os = "android",
432             target_os = "dragonfly",
433             target_os = "freebsd",
434             target_os = "fuchsia",
435             target_os = "illumos",
436             target_os = "linux",
437             target_os = "netbsd",
438             target_vendor = "apple",
439         )
440     ))]
441     #[cfg_attr(
442         docsrs,
443         doc(cfg(all(
444             feature = "all",
445             any(
446                 target_os = "android",
447                 target_os = "dragonfly",
448                 target_os = "freebsd",
449                 target_os = "fuchsia",
450                 target_os = "illumos",
451                 target_os = "linux",
452                 target_os = "netbsd",
453                 target_vendor = "apple",
454             )
455         )))
456     )]
with_retries(self, retries: u32) -> Self457     pub const fn with_retries(self, retries: u32) -> Self {
458         Self {
459             retries: Some(retries),
460             ..self
461         }
462     }
463 }
464