// 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.
#![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; #[cfg(not(target_os = "redox"))] use std::io::IoSlice; #[cfg(not(target_os = "redox"))] use std::marker::PhantomData; #[cfg(not(target_os = "redox"))] use std::mem; 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 `windows_sys`.
$libc: ident :: $flag: ident
),+ $(,)*
) => { impl std::fmt::Debug for $type { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let string = matchself.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())
}
}
}
};
}
/// Link to online documentation for (almost) all supported OSs. #[rustfmt::skip]
macro_rules! man_links { // Links to all OSs.
($syscall: tt ( $section: tt ) ) => {
concat!(
man_links!(__ intro),
man_links!(__ unix $syscall($section)),
man_links!(__ windows $syscall($section)),
)
}; // Links to Unix-like OSs.
(unix: $syscall: tt ( $section: tt ) ) => {
concat!(
man_links!(__ intro),
man_links!(__ unix $syscall($section)),
)
}; // Links to Windows only.
(windows: $syscall: tt ( $section: tt ) ) => {
concat!(
man_links!(__ intro),
man_links!(__ windows $syscall($section)),
)
}; // Internals.
(__ intro) => { "\n\nAdditional documentation can be found in manual of the OS:\n\n"
}; // List for Unix-like OSs.
(__ unix $syscall: tt ( $section: tt ) ) => {
concat!( " * DragonFly BSD: <https://man.dragonflybsd.org/?command=", stringify!($syscall), "§ion=", stringify!($section), ">\n", " * FreeBSD: <https://www.freebsd.org/cgi/man.cgi?query=", stringify!($syscall), "&sektion=", stringify!($section), ">\n", " * Linux: <https://man7.org/linux/man-pages/man", stringify!($section), "/", stringify!($syscall), ".", stringify!($section), ".html>\n", " * macOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived, actually for iOS)\n", " * NetBSD: <https://man.netbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n", " * OpenBSD: <https://man.openbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n", " * iOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived)\n", " * illumos: <https://illumos.org/man/3SOCKET/", stringify!($syscall), ">\n",
)
}; // List for Window (so just Windows).
(__ windows $syscall: tt ( $section: tt ) ) => {
concat!( " * Windows: <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-", stringify!($syscall), ">\n",
)
};
}
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");
/// 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)] pubstruct Domain(c_int);
impl Domain { /// Domain for IPv4 communication, corresponding to `AF_INET`. pubconst IPV4: Domain = Domain(sys::AF_INET);
/// Domain for IPv6 communication, corresponding to `AF_INET6`. pubconst IPV6: Domain = Domain(sys::AF_INET6);
/// Domain for Unix socket communication, corresponding to `AF_UNIX`. pubconst UNIX: Domain = Domain(sys::AF_UNIX);
/// Returns the correct domain for `address`. pubconstfn for_address(address: SocketAddr) -> Domain { match address {
SocketAddr::V4(_) => Domain::IPV4,
SocketAddr::V6(_) => Domain::IPV6,
}
}
}
/// 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)] pubstructType(c_int);
implType { /// Type corresponding to `SOCK_STREAM`. /// /// Used for protocols such as TCP. pubconst STREAM: Type = Type(sys::SOCK_STREAM);
/// Type corresponding to `SOCK_DGRAM`. /// /// Used for protocols such as UDP. pubconst DGRAM: Type = Type(sys::SOCK_DGRAM);
/// Type corresponding to `SOCK_DCCP`. /// /// Used for the DCCP protocol. #[cfg(all(feature = "all", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pubconst DCCP: Type = Type(sys::SOCK_DCCP);
/// Type corresponding to `SOCK_SEQPACKET`. #[cfg(all(feature = "all", not(target_os = "espidf")))] #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "espidf")))))] pubconst SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
/// 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)] pubstruct Protocol(c_int);
/// 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)] pubstruct 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. #[cfg(not(target_os = "espidf"))] pubconstfn 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)] pubstruct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
impl<'a> MaybeUninitSlice<'a> { /// Creates a new `MaybeUninitSlice` wrapping a byte slice. /// /// # Panics /// /// Panics on Windows if the slice is larger than 4GB. pubfn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
}
}
impl<'a> Deref for MaybeUninitSlice<'a> { type Target = [MaybeUninit<u8>];
/// 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. pubconstfn 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(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
target_os = "windows",
))] #[cfg_attr(
docsrs,
doc(cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
target_os = "windows",
)))
)] pubconstfn 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(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
)
))] #[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 = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
)
)))
)] pubconstfn with_retries(self, retries: u32) -> Self { Self {
retries: Some(retries),
..self
}
}
}
/// Configuration of a `sendmsg(2)` system call. /// /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdrMut`] /// for the variant used by `recvmsg(2)`. #[cfg(not(target_os = "redox"))] pubstruct MsgHdr<'addr, 'bufs, 'control> {
inner: sys::msghdr, #[allow(clippy::type_complexity)]
_lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>,
}
#[cfg(not(target_os = "redox"))] impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> { /// Create a new `MsgHdr` with all empty/zero fields. #[allow(clippy::new_without_default)] pubfn new() -> MsgHdr<'addr, 'bufs, 'control> { // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
MsgHdr {
inner: unsafe { mem::zeroed() },
_lifetimes: PhantomData,
}
}
/// Set the address (name) of the message. /// /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name` /// and `namelen` on Windows. pubfn with_addr(mutself, addr: &'addr SockAddr) -> Self {
sys::set_msghdr_name(&mutself.inner, addr); self
}
/// Set the buffer(s) of the message. /// /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers` /// and `dwBufferCount` on Windows. pubfn with_buffers(mutself, bufs: &'bufs [IoSlice<'_>]) -> Self { let ptr = bufs.as_ptr() as *mut _;
sys::set_msghdr_iov(&mutself.inner, ptr, bufs.len()); self
}
/// Set the control buffer of the message. /// /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and /// `Control` on Windows. pubfn with_control(mutself, buf: &'control [u8]) -> Self { let ptr = buf.as_ptr() as *mut _;
sys::set_msghdr_control(&mutself.inner, ptr, buf.len()); self
}
/// Set the flags of the message. /// /// Corresponds to setting `msg_flags` on Unix and `dwFlags` on Windows. pubfn with_flags(mutself, flags: sys::c_int) -> Self {
sys::set_msghdr_flags(&mutself.inner, flags); self
}
}
/// Configuration of a `recvmsg(2)` system call. /// /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdr`] for /// the variant used by `sendmsg(2)`. #[cfg(not(target_os = "redox"))] pubstruct MsgHdrMut<'addr, 'bufs, 'control> {
inner: sys::msghdr, #[allow(clippy::type_complexity)]
_lifetimes: PhantomData<(
&'addr mut SockAddr,
&'bufs mut MaybeUninitSlice<'bufs>,
&'control mut [u8],
)>,
}
#[cfg(not(target_os = "redox"))] impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> { /// Create a new `MsgHdrMut` with all empty/zero fields. #[allow(clippy::new_without_default)] pubfn new() -> MsgHdrMut<'addr, 'bufs, 'control> { // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
MsgHdrMut {
inner: unsafe { mem::zeroed() },
_lifetimes: PhantomData,
}
}
/// Set the mutable address (name) of the message. /// /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name` /// and `namelen` on Windows. #[allow(clippy::needless_pass_by_ref_mut)] pubfn with_addr(mutself, addr: &'addr mut SockAddr) -> Self {
sys::set_msghdr_name(&mutself.inner, addr); self
}
/// Set the mutable buffer(s) of the message. /// /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers` /// and `dwBufferCount` on Windows. pubfn with_buffers(mutself, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
sys::set_msghdr_iov(&mutself.inner, bufs.as_mut_ptr().cast(), bufs.len()); self
}
/// Set the mutable control buffer of the message. /// /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and /// `Control` on Windows. pubfn with_control(mutself, buf: &'control mut [MaybeUninit<u8>]) -> Self {
sys::set_msghdr_control(&mutself.inner, buf.as_mut_ptr().cast(), buf.len()); self
}
/// Returns the flags of the message. pubfn flags(&self) -> RecvFlags {
sys::msghdr_flags(&self.inner)
}
/// Gets the length of the control buffer. /// /// Can be used to determine how much, if any, of the control buffer was filled by `recvmsg`. /// /// Corresponds to `msg_controllen` on Unix and `Control.len` on Windows. pubfn control_len(&self) -> usize {
sys::msghdr_control_len(&self.inner)
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.