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`. |
164 | 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 { |
173 | fn from(d: c_int) -> Domain { |
174 | Domain(d) |
175 | } |
176 | } |
177 | |
178 | impl From<Domain> for c_int { |
179 | 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 (all(feature = "all" , not(target_os = "espidf" )))] |
209 | #[cfg_attr (docsrs, doc(cfg(all(feature = "all" , not(target_os = "espidf" )))))] |
210 | pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET); |
211 | |
212 | /// Type corresponding to `SOCK_RAW`. |
213 | #[cfg (all(feature = "all" , not(any(target_os = "redox" , target_os = "espidf" ))))] |
214 | #[cfg_attr ( |
215 | docsrs, |
216 | doc(cfg(all(feature = "all" , not(any(target_os = "redox" , target_os = "espidf" ))))) |
217 | )] |
218 | pub const RAW: Type = Type(sys::SOCK_RAW); |
219 | } |
220 | |
221 | impl From<c_int> for Type { |
222 | fn from(t: c_int) -> Type { |
223 | Type(t) |
224 | } |
225 | } |
226 | |
227 | impl From<Type> for c_int { |
228 | fn from(t: Type) -> c_int { |
229 | t.0 |
230 | } |
231 | } |
232 | |
233 | /// Protocol specification used for creating sockets via `Socket::new`. |
234 | /// |
235 | /// This is a newtype wrapper around an integer which provides a nicer API in |
236 | /// addition to an injection point for documentation. |
237 | /// |
238 | /// This type is freely interconvertible with C's `int` type, however, if a raw |
239 | /// value needs to be provided. |
240 | #[derive (Copy, Clone, Eq, PartialEq)] |
241 | pub struct Protocol(c_int); |
242 | |
243 | impl Protocol { |
244 | /// Protocol corresponding to `ICMPv4`. |
245 | pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP); |
246 | |
247 | /// Protocol corresponding to `ICMPv6`. |
248 | pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6); |
249 | |
250 | /// Protocol corresponding to `TCP`. |
251 | pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP); |
252 | |
253 | /// Protocol corresponding to `UDP`. |
254 | pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP); |
255 | } |
256 | |
257 | impl From<c_int> for Protocol { |
258 | fn from(p: c_int) -> Protocol { |
259 | Protocol(p) |
260 | } |
261 | } |
262 | |
263 | impl From<Protocol> for c_int { |
264 | fn from(p: Protocol) -> c_int { |
265 | p.0 |
266 | } |
267 | } |
268 | |
269 | /// Flags for incoming messages. |
270 | /// |
271 | /// Flags provide additional information about incoming messages. |
272 | #[cfg (not(target_os = "redox" ))] |
273 | #[cfg_attr (docsrs, doc(cfg(not(target_os = "redox" ))))] |
274 | #[derive (Copy, Clone, Eq, PartialEq)] |
275 | pub struct RecvFlags(c_int); |
276 | |
277 | #[cfg (not(target_os = "redox" ))] |
278 | impl RecvFlags { |
279 | /// Check if the message contains a truncated datagram. |
280 | /// |
281 | /// This flag is only used for datagram-based sockets, |
282 | /// not for stream sockets. |
283 | /// |
284 | /// On Unix this corresponds to the `MSG_TRUNC` flag. |
285 | /// On Windows this corresponds to the `WSAEMSGSIZE` error code. |
286 | #[cfg (not(target_os = "espidf" ))] |
287 | pub const fn is_truncated(self) -> bool { |
288 | self.0 & sys::MSG_TRUNC != 0 |
289 | } |
290 | } |
291 | |
292 | /// A version of [`IoSliceMut`] that allows the buffer to be uninitialised. |
293 | /// |
294 | /// [`IoSliceMut`]: std::io::IoSliceMut |
295 | #[repr (transparent)] |
296 | pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>); |
297 | |
298 | impl<'a> fmt::Debug for MaybeUninitSlice<'a> { |
299 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
300 | fmt::Debug::fmt(self.0.as_slice(), f:fmt) |
301 | } |
302 | } |
303 | |
304 | impl<'a> MaybeUninitSlice<'a> { |
305 | /// Creates a new `MaybeUninitSlice` wrapping a byte slice. |
306 | /// |
307 | /// # Panics |
308 | /// |
309 | /// Panics on Windows if the slice is larger than 4GB. |
310 | pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> { |
311 | MaybeUninitSlice(sys::MaybeUninitSlice::new(buf)) |
312 | } |
313 | } |
314 | |
315 | impl<'a> Deref for MaybeUninitSlice<'a> { |
316 | type Target = [MaybeUninit<u8>]; |
317 | |
318 | fn deref(&self) -> &[MaybeUninit<u8>] { |
319 | self.0.as_slice() |
320 | } |
321 | } |
322 | |
323 | impl<'a> DerefMut for MaybeUninitSlice<'a> { |
324 | fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] { |
325 | self.0.as_mut_slice() |
326 | } |
327 | } |
328 | |
329 | /// Configures a socket's TCP keepalive parameters. |
330 | /// |
331 | /// See [`Socket::set_tcp_keepalive`]. |
332 | #[derive (Debug, Clone)] |
333 | pub struct TcpKeepalive { |
334 | #[cfg_attr (any(target_os = "openbsd" , target_os = "vita" ), allow(dead_code))] |
335 | time: Option<Duration>, |
336 | #[cfg (not(any( |
337 | target_os = "openbsd" , |
338 | target_os = "redox" , |
339 | target_os = "solaris" , |
340 | target_os = "nto" , |
341 | target_os = "espidf" , |
342 | target_os = "vita" , |
343 | )))] |
344 | interval: Option<Duration>, |
345 | #[cfg (not(any( |
346 | target_os = "openbsd" , |
347 | target_os = "redox" , |
348 | target_os = "solaris" , |
349 | target_os = "windows" , |
350 | target_os = "nto" , |
351 | target_os = "espidf" , |
352 | target_os = "vita" , |
353 | )))] |
354 | retries: Option<u32>, |
355 | } |
356 | |
357 | impl TcpKeepalive { |
358 | /// Returns a new, empty set of TCP keepalive parameters. |
359 | pub const fn new() -> TcpKeepalive { |
360 | TcpKeepalive { |
361 | time: None, |
362 | #[cfg (not(any( |
363 | target_os = "openbsd" , |
364 | target_os = "redox" , |
365 | target_os = "solaris" , |
366 | target_os = "nto" , |
367 | target_os = "espidf" , |
368 | target_os = "vita" , |
369 | )))] |
370 | interval: None, |
371 | #[cfg (not(any( |
372 | target_os = "openbsd" , |
373 | target_os = "redox" , |
374 | target_os = "solaris" , |
375 | target_os = "windows" , |
376 | target_os = "nto" , |
377 | target_os = "espidf" , |
378 | target_os = "vita" , |
379 | )))] |
380 | retries: None, |
381 | } |
382 | } |
383 | |
384 | /// Set the amount of time after which TCP keepalive probes will be sent on |
385 | /// idle connections. |
386 | /// |
387 | /// This will set `TCP_KEEPALIVE` on macOS and iOS, and |
388 | /// `TCP_KEEPIDLE` on all other Unix operating systems, except |
389 | /// OpenBSD and Haiku which don't support any way to set this |
390 | /// option. On Windows, this sets the value of the `tcp_keepalive` |
391 | /// struct's `keepalivetime` field. |
392 | /// |
393 | /// Some platforms specify this value in seconds, so sub-second |
394 | /// specifications may be omitted. |
395 | pub const fn with_time(self, time: Duration) -> Self { |
396 | Self { |
397 | time: Some(time), |
398 | ..self |
399 | } |
400 | } |
401 | |
402 | /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the |
403 | /// value of the `tcp_keepalive` struct's `keepaliveinterval` field. |
404 | /// |
405 | /// Sets the time interval between TCP keepalive probes. |
406 | /// |
407 | /// Some platforms specify this value in seconds, so sub-second |
408 | /// specifications may be omitted. |
409 | #[cfg (all( |
410 | feature = "all" , |
411 | any( |
412 | target_os = "android" , |
413 | target_os = "dragonfly" , |
414 | target_os = "freebsd" , |
415 | target_os = "fuchsia" , |
416 | target_os = "illumos" , |
417 | target_os = "linux" , |
418 | target_os = "netbsd" , |
419 | target_vendor = "apple" , |
420 | windows, |
421 | ) |
422 | ))] |
423 | #[cfg_attr ( |
424 | docsrs, |
425 | doc(cfg(all( |
426 | feature = "all" , |
427 | any( |
428 | target_os = "android" , |
429 | target_os = "dragonfly" , |
430 | target_os = "freebsd" , |
431 | target_os = "fuchsia" , |
432 | target_os = "illumos" , |
433 | target_os = "linux" , |
434 | target_os = "netbsd" , |
435 | target_vendor = "apple" , |
436 | windows, |
437 | ) |
438 | ))) |
439 | )] |
440 | pub const fn with_interval(self, interval: Duration) -> Self { |
441 | Self { |
442 | interval: Some(interval), |
443 | ..self |
444 | } |
445 | } |
446 | |
447 | /// Set the value of the `TCP_KEEPCNT` option. |
448 | /// |
449 | /// Set the maximum number of TCP keepalive probes that will be sent before |
450 | /// dropping a connection, if TCP keepalive is enabled on this socket. |
451 | #[cfg (all( |
452 | feature = "all" , |
453 | any( |
454 | doc, |
455 | target_os = "android" , |
456 | target_os = "dragonfly" , |
457 | target_os = "freebsd" , |
458 | target_os = "fuchsia" , |
459 | target_os = "illumos" , |
460 | target_os = "linux" , |
461 | target_os = "netbsd" , |
462 | target_vendor = "apple" , |
463 | ) |
464 | ))] |
465 | #[cfg_attr ( |
466 | docsrs, |
467 | doc(cfg(all( |
468 | feature = "all" , |
469 | any( |
470 | target_os = "android" , |
471 | target_os = "dragonfly" , |
472 | target_os = "freebsd" , |
473 | target_os = "fuchsia" , |
474 | target_os = "illumos" , |
475 | target_os = "linux" , |
476 | target_os = "netbsd" , |
477 | target_vendor = "apple" , |
478 | ) |
479 | ))) |
480 | )] |
481 | pub const fn with_retries(self, retries: u32) -> Self { |
482 | Self { |
483 | retries: Some(retries), |
484 | ..self |
485 | } |
486 | } |
487 | } |
488 | |