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
62use std::fmt;
63use std::mem::MaybeUninit;
64use std::net::SocketAddr;
65use std::ops::{Deref, DerefMut};
66use 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.
73macro_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.
101macro_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
118mod sockaddr;
119mod socket;
120mod sockref;
121
122#[cfg_attr(unix, path = "sys/unix.rs")]
123#[cfg_attr(windows, path = "sys/windows.rs")]
124mod sys;
125
126#[cfg(not(any(windows, unix)))]
127compile_error!("Socket2 doesn't support the compile target");
128
129use sys::c_int;
130
131pub use sockaddr::SockAddr;
132pub use socket::Socket;
133pub 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)))]
142pub 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)]
154pub struct Domain(c_int);
155
156impl 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
172impl From<c_int> for Domain {
173 fn from(d: c_int) -> Domain {
174 Domain(d)
175 }
176}
177
178impl 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)]
194pub struct Type(c_int);
195
196impl 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
221impl From<c_int> for Type {
222 fn from(t: c_int) -> Type {
223 Type(t)
224 }
225}
226
227impl 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)]
241pub struct Protocol(c_int);
242
243impl 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
257impl From<c_int> for Protocol {
258 fn from(p: c_int) -> Protocol {
259 Protocol(p)
260 }
261}
262
263impl 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)]
275pub struct RecvFlags(c_int);
276
277#[cfg(not(target_os = "redox"))]
278impl 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)]
296pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
297
298impl<'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
304impl<'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
315impl<'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
323impl<'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)]
333pub 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
357impl 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