diff options
Diffstat (limited to 'third_party/rust/socket2/src/lib.rs')
-rw-r--r-- | third_party/rust/socket2/src/lib.rs | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/third_party/rust/socket2/src/lib.rs b/third_party/rust/socket2/src/lib.rs new file mode 100644 index 0000000000..a2e2ffcb8f --- /dev/null +++ b/third_party/rust/socket2/src/lib.rs @@ -0,0 +1,475 @@ +// Copyright 2015 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Utilities for creating and using sockets. +//! +//! The goal of this crate is to create and use a socket using advanced +//! configuration options (those that are not available in the types in the +//! standard library) without using any unsafe code. +//! +//! This crate provides as direct as possible access to the system's +//! functionality for sockets, this means little effort to provide +//! cross-platform utilities. It is up to the user to know how to use sockets +//! when using this crate. *If you don't know how to create a socket using +//! libc/system calls then this crate is not for you*. Most, if not all, +//! functions directly relate to the equivalent system call with no error +//! handling applied, so no handling errors such as [`EINTR`]. As a result using +//! this crate can be a little wordy, but it should give you maximal flexibility +//! over configuration of sockets. +//! +//! [`EINTR`]: std::io::ErrorKind::Interrupted +//! +//! # Examples +//! +//! ```no_run +//! # fn main() -> std::io::Result<()> { +//! use std::net::{SocketAddr, TcpListener}; +//! use socket2::{Socket, Domain, Type}; +//! +//! // Create a TCP listener bound to two addresses. +//! let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?; +//! +//! socket.set_only_v6(false)?; +//! let address: SocketAddr = "[::1]:12345".parse().unwrap(); +//! socket.bind(&address.into())?; +//! socket.listen(128)?; +//! +//! let listener: TcpListener = socket.into(); +//! // ... +//! # drop(listener); +//! # Ok(()) } +//! ``` +//! +//! ## Features +//! +//! This crate has a single feature `all`, which enables all functions even ones +//! that are not available on all OSs. + +#![doc(html_root_url = "https://docs.rs/socket2/0.4")] +#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)] +// Show required OS/features on docs.rs. +#![cfg_attr(docsrs, feature(doc_cfg))] +// Disallow warnings when running tests. +#![cfg_attr(test, deny(warnings))] +// Disallow warnings in examples. +#![doc(test(attr(deny(warnings))))] + +use std::fmt; +use std::mem::MaybeUninit; +use std::net::SocketAddr; +use std::ops::{Deref, DerefMut}; +use std::time::Duration; + +/// Macro to implement `fmt::Debug` for a type, printing the constant names +/// rather than a number. +/// +/// Note this is used in the `sys` module and thus must be defined before +/// defining the modules. +macro_rules! impl_debug { + ( + // Type name for which to implement `fmt::Debug`. + $type: path, + $( + $(#[$target: meta])* + // The flag(s) to check. + // Need to specific the libc crate because Windows doesn't use + // `libc` but `winapi`. + $libc: ident :: $flag: ident + ),+ $(,)* + ) => { + impl std::fmt::Debug for $type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let string = match self.0 { + $( + $(#[$target])* + $libc :: $flag => stringify!($flag), + )+ + n => return write!(f, "{}", n), + }; + f.write_str(string) + } + } + }; +} + +/// Macro to convert from one network type to another. +macro_rules! from { + ($from: ty, $for: ty) => { + impl From<$from> for $for { + fn from(socket: $from) -> $for { + #[cfg(unix)] + unsafe { + <$for>::from_raw_fd(socket.into_raw_fd()) + } + #[cfg(windows)] + unsafe { + <$for>::from_raw_socket(socket.into_raw_socket()) + } + } + } + }; +} + +mod sockaddr; +mod socket; +mod sockref; + +#[cfg_attr(unix, path = "sys/unix.rs")] +#[cfg_attr(windows, path = "sys/windows.rs")] +mod sys; + +#[cfg(not(any(windows, unix)))] +compile_error!("Socket2 doesn't support the compile target"); + +use sys::c_int; + +pub use sockaddr::SockAddr; +pub use socket::Socket; +pub use sockref::SockRef; + +#[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "netbsd", + target_os = "redox", + target_os = "solaris", +)))] +pub use socket::InterfaceIndexOrAddress; + +/// Specification of the communication domain for a socket. +/// +/// This is a newtype wrapper around an integer which provides a nicer API in +/// addition to an injection point for documentation. Convenience constants such +/// as [`Domain::IPV4`], [`Domain::IPV6`], etc, are provided to avoid reaching +/// into libc for various constants. +/// +/// This type is freely interconvertible with C's `int` type, however, if a raw +/// value needs to be provided. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Domain(c_int); + +impl Domain { + /// Domain for IPv4 communication, corresponding to `AF_INET`. + pub const IPV4: Domain = Domain(sys::AF_INET); + + /// Domain for IPv6 communication, corresponding to `AF_INET6`. + pub const IPV6: Domain = Domain(sys::AF_INET6); + + /// Returns the correct domain for `address`. + pub const fn for_address(address: SocketAddr) -> Domain { + match address { + SocketAddr::V4(_) => Domain::IPV4, + SocketAddr::V6(_) => Domain::IPV6, + } + } +} + +impl From<c_int> for Domain { + fn from(d: c_int) -> Domain { + Domain(d) + } +} + +impl From<Domain> for c_int { + fn from(d: Domain) -> c_int { + d.0 + } +} + +/// Specification of communication semantics on a socket. +/// +/// This is a newtype wrapper around an integer which provides a nicer API in +/// addition to an injection point for documentation. Convenience constants such +/// as [`Type::STREAM`], [`Type::DGRAM`], etc, are provided to avoid reaching +/// into libc for various constants. +/// +/// This type is freely interconvertible with C's `int` type, however, if a raw +/// value needs to be provided. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Type(c_int); + +impl Type { + /// Type corresponding to `SOCK_STREAM`. + /// + /// Used for protocols such as TCP. + pub const STREAM: Type = Type(sys::SOCK_STREAM); + + /// Type corresponding to `SOCK_DGRAM`. + /// + /// Used for protocols such as UDP. + pub const DGRAM: Type = Type(sys::SOCK_DGRAM); + + /// Type corresponding to `SOCK_SEQPACKET`. + #[cfg(feature = "all")] + #[cfg_attr(docsrs, doc(cfg(feature = "all")))] + pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET); + + /// Type corresponding to `SOCK_RAW`. + #[cfg(all(feature = "all", not(target_os = "redox")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "redox")))))] + pub const RAW: Type = Type(sys::SOCK_RAW); +} + +impl From<c_int> for Type { + fn from(t: c_int) -> Type { + Type(t) + } +} + +impl From<Type> for c_int { + fn from(t: Type) -> c_int { + t.0 + } +} + +/// Protocol specification used for creating sockets via `Socket::new`. +/// +/// This is a newtype wrapper around an integer which provides a nicer API in +/// addition to an injection point for documentation. +/// +/// This type is freely interconvertible with C's `int` type, however, if a raw +/// value needs to be provided. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Protocol(c_int); + +impl Protocol { + /// Protocol corresponding to `ICMPv4`. + pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP); + + /// Protocol corresponding to `ICMPv6`. + pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6); + + /// Protocol corresponding to `TCP`. + pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP); + + /// Protocol corresponding to `UDP`. + pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP); +} + +impl From<c_int> for Protocol { + fn from(p: c_int) -> Protocol { + Protocol(p) + } +} + +impl From<Protocol> for c_int { + fn from(p: Protocol) -> c_int { + p.0 + } +} + +/// Flags for incoming messages. +/// +/// Flags provide additional information about incoming messages. +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct RecvFlags(c_int); + +#[cfg(not(target_os = "redox"))] +impl RecvFlags { + /// Check if the message contains a truncated datagram. + /// + /// This flag is only used for datagram-based sockets, + /// not for stream sockets. + /// + /// On Unix this corresponds to the `MSG_TRUNC` flag. + /// On Windows this corresponds to the `WSAEMSGSIZE` error code. + pub const fn is_truncated(self) -> bool { + self.0 & sys::MSG_TRUNC != 0 + } +} + +/// A version of [`IoSliceMut`] that allows the buffer to be uninitialised. +/// +/// [`IoSliceMut`]: std::io::IoSliceMut +#[repr(transparent)] +pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>); + +impl<'a> fmt::Debug for MaybeUninitSlice<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.0.as_slice(), fmt) + } +} + +impl<'a> MaybeUninitSlice<'a> { + /// Creates a new `MaybeUninitSlice` wrapping a byte slice. + /// + /// # Panics + /// + /// Panics on Windows if the slice is larger than 4GB. + pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> { + MaybeUninitSlice(sys::MaybeUninitSlice::new(buf)) + } +} + +impl<'a> Deref for MaybeUninitSlice<'a> { + type Target = [MaybeUninit<u8>]; + + fn deref(&self) -> &[MaybeUninit<u8>] { + self.0.as_slice() + } +} + +impl<'a> DerefMut for MaybeUninitSlice<'a> { + fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] { + self.0.as_mut_slice() + } +} + +/// Configures a socket's TCP keepalive parameters. +/// +/// See [`Socket::set_tcp_keepalive`]. +#[derive(Debug, Clone)] +pub struct TcpKeepalive { + #[cfg_attr(target_os = "openbsd", allow(dead_code))] + time: Option<Duration>, + #[cfg(not(any( + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "nto", + )))] + interval: Option<Duration>, + #[cfg(not(any( + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "windows", + target_os = "nto", + )))] + retries: Option<u32>, +} + +impl TcpKeepalive { + /// Returns a new, empty set of TCP keepalive parameters. + pub const fn new() -> TcpKeepalive { + TcpKeepalive { + time: None, + #[cfg(not(any( + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "nto", + )))] + interval: None, + #[cfg(not(any( + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "windows", + target_os = "nto", + )))] + retries: None, + } + } + + /// Set the amount of time after which TCP keepalive probes will be sent on + /// idle connections. + /// + /// This will set `TCP_KEEPALIVE` on macOS and iOS, and + /// `TCP_KEEPIDLE` on all other Unix operating systems, except + /// OpenBSD and Haiku which don't support any way to set this + /// option. On Windows, this sets the value of the `tcp_keepalive` + /// struct's `keepalivetime` field. + /// + /// Some platforms specify this value in seconds, so sub-second + /// specifications may be omitted. + pub const fn with_time(self, time: Duration) -> Self { + Self { + time: Some(time), + ..self + } + } + + /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the + /// value of the `tcp_keepalive` struct's `keepaliveinterval` field. + /// + /// Sets the time interval between TCP keepalive probes. + /// + /// Some platforms specify this value in seconds, so sub-second + /// specifications may be omitted. + #[cfg(all( + feature = "all", + any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + windows, + ) + ))] + #[cfg_attr( + docsrs, + doc(cfg(all( + feature = "all", + any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + windows, + ) + ))) + )] + pub const fn with_interval(self, interval: Duration) -> Self { + Self { + interval: Some(interval), + ..self + } + } + + /// Set the value of the `TCP_KEEPCNT` option. + /// + /// Set the maximum number of TCP keepalive probes that will be sent before + /// dropping a connection, if TCP keepalive is enabled on this socket. + #[cfg(all( + feature = "all", + any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + ) + ))] + #[cfg_attr( + docsrs, + doc(cfg(all( + feature = "all", + any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + ) + ))) + )] + pub const fn with_retries(self, retries: u32) -> Self { + Self { + retries: Some(retries), + ..self + } + } +} |