RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.
This commit is contained in:
442
zeroidc/vendor/socket2/src/lib.rs
vendored
Normal file
442
zeroidc/vendor/socket2/src/lib.rs
vendored
Normal file
@@ -0,0 +1,442 @@
|
||||
// Copyright 2015 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://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.3")]
|
||||
#![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 {
|
||||
time: Option<Duration>,
|
||||
#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
|
||||
interval: Option<Duration>,
|
||||
#[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))]
|
||||
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 = "redox", target_os = "solaris")))]
|
||||
interval: None,
|
||||
#[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))]
|
||||
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 = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_vendor = "apple",
|
||||
windows,
|
||||
)
|
||||
))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(all(
|
||||
feature = "all",
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
target_os = "fuchsia",
|
||||
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 = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_vendor = "apple",
|
||||
)
|
||||
))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(all(
|
||||
feature = "all",
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_vendor = "apple",
|
||||
)
|
||||
)))
|
||||
)]
|
||||
pub const fn with_retries(self, retries: u32) -> Self {
|
||||
Self {
|
||||
retries: Some(retries),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
348
zeroidc/vendor/socket2/src/sockaddr.rs
vendored
Normal file
348
zeroidc/vendor/socket2/src/sockaddr.rs
vendored
Normal file
@@ -0,0 +1,348 @@
|
||||
use std::mem::{self, size_of, MaybeUninit};
|
||||
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::{fmt, io};
|
||||
|
||||
use crate::sys::{
|
||||
sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
|
||||
AF_INET6,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH_u;
|
||||
|
||||
/// The address of a socket.
|
||||
///
|
||||
/// `SockAddr`s may be constructed directly to and from the standard library
|
||||
/// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types.
|
||||
pub struct SockAddr {
|
||||
storage: sockaddr_storage,
|
||||
len: socklen_t,
|
||||
}
|
||||
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
impl SockAddr {
|
||||
/// Create a `SockAddr` from the underlying storage and its length.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Caller must ensure that the address family and length match the type of
|
||||
/// storage address. For example if `storage.ss_family` is set to `AF_INET`
|
||||
/// the `storage` must be initialised as `sockaddr_in`, setting the content
|
||||
/// and length appropriately.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> std::io::Result<()> {
|
||||
/// # #[cfg(unix)] {
|
||||
/// use std::io;
|
||||
/// use std::mem;
|
||||
/// use std::os::unix::io::AsRawFd;
|
||||
///
|
||||
/// use socket2::{SockAddr, Socket, Domain, Type};
|
||||
///
|
||||
/// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
|
||||
///
|
||||
/// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
|
||||
/// let mut addr_storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
|
||||
/// let mut len = mem::size_of_val(&addr_storage) as libc::socklen_t;
|
||||
///
|
||||
/// // The `getsockname(2)` system call will intiliase `storage` for
|
||||
/// // us, setting `len` to the correct length.
|
||||
/// let res = unsafe {
|
||||
/// libc::getsockname(
|
||||
/// socket.as_raw_fd(),
|
||||
/// (&mut addr_storage as *mut libc::sockaddr_storage).cast(),
|
||||
/// &mut len,
|
||||
/// )
|
||||
/// };
|
||||
/// if res == -1 {
|
||||
/// return Err(io::Error::last_os_error());
|
||||
/// }
|
||||
///
|
||||
/// let address = unsafe { SockAddr::new(addr_storage, len) };
|
||||
/// # drop(address);
|
||||
/// # }
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub const unsafe fn new(storage: sockaddr_storage, len: socklen_t) -> SockAddr {
|
||||
SockAddr { storage, len }
|
||||
}
|
||||
|
||||
/// Initialise a `SockAddr` by calling the function `init`.
|
||||
///
|
||||
/// The type of the address storage and length passed to the function `init`
|
||||
/// is OS/architecture specific.
|
||||
///
|
||||
/// The address is zeroed before `init` is called and is thus valid to
|
||||
/// dereference and read from. The length initialised to the maximum length
|
||||
/// of the storage.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Caller must ensure that the address family and length match the type of
|
||||
/// storage address. For example if `storage.ss_family` is set to `AF_INET`
|
||||
/// the `storage` must be initialised as `sockaddr_in`, setting the content
|
||||
/// and length appropriately.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> std::io::Result<()> {
|
||||
/// # #[cfg(unix)] {
|
||||
/// use std::io;
|
||||
/// use std::os::unix::io::AsRawFd;
|
||||
///
|
||||
/// use socket2::{SockAddr, Socket, Domain, Type};
|
||||
///
|
||||
/// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
|
||||
///
|
||||
/// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
|
||||
/// let (_, address) = unsafe {
|
||||
/// SockAddr::init(|addr_storage, len| {
|
||||
/// // The `getsockname(2)` system call will intiliase `storage` for
|
||||
/// // us, setting `len` to the correct length.
|
||||
/// if libc::getsockname(socket.as_raw_fd(), addr_storage.cast(), len) == -1 {
|
||||
/// Err(io::Error::last_os_error())
|
||||
/// } else {
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// })
|
||||
/// }?;
|
||||
/// # drop(address);
|
||||
/// # }
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub unsafe fn init<F, T>(init: F) -> io::Result<(T, SockAddr)>
|
||||
where
|
||||
F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>,
|
||||
{
|
||||
const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t;
|
||||
// NOTE: `SockAddr::unix` depends on the storage being zeroed before
|
||||
// calling `init`.
|
||||
// NOTE: calling `recvfrom` with an empty buffer also depends on the
|
||||
// storage being zeroed before calling `init` as the OS might not
|
||||
// initialise it.
|
||||
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
|
||||
let mut len = STORAGE_SIZE;
|
||||
init(storage.as_mut_ptr(), &mut len).map(|res| {
|
||||
debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
|
||||
let addr = SockAddr {
|
||||
// Safety: zeroed-out `sockaddr_storage` is valid, caller must
|
||||
// ensure at least `len` bytes are valid.
|
||||
storage: storage.assume_init(),
|
||||
len,
|
||||
};
|
||||
(res, addr)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns this address's family.
|
||||
pub const fn family(&self) -> sa_family_t {
|
||||
self.storage.ss_family
|
||||
}
|
||||
|
||||
/// Returns the size of this address in bytes.
|
||||
pub const fn len(&self) -> socklen_t {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the address.
|
||||
pub const fn as_ptr(&self) -> *const sockaddr {
|
||||
&self.storage as *const _ as *const _
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the address storage.
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
pub(crate) const fn as_storage_ptr(&self) -> *const sockaddr_storage {
|
||||
&self.storage
|
||||
}
|
||||
|
||||
/// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4)
|
||||
/// or `AF_INET6` (IPv6) family, otherwise returns `None`.
|
||||
pub fn as_socket(&self) -> Option<SocketAddr> {
|
||||
if self.storage.ss_family == AF_INET as sa_family_t {
|
||||
// Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
|
||||
let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) };
|
||||
|
||||
let ip = crate::sys::from_in_addr(addr.sin_addr);
|
||||
let port = u16::from_be(addr.sin_port);
|
||||
Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
|
||||
} else if self.storage.ss_family == AF_INET6 as sa_family_t {
|
||||
// Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
|
||||
let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) };
|
||||
|
||||
let ip = crate::sys::from_in6_addr(addr.sin6_addr);
|
||||
let port = u16::from_be(addr.sin6_port);
|
||||
Some(SocketAddr::V6(SocketAddrV6::new(
|
||||
ip,
|
||||
port,
|
||||
addr.sin6_flowinfo,
|
||||
#[cfg(unix)]
|
||||
addr.sin6_scope_id,
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
*addr.u.sin6_scope_id()
|
||||
},
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
|
||||
/// family.
|
||||
pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
|
||||
match self.as_socket() {
|
||||
Some(SocketAddr::V4(addr)) => Some(addr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
|
||||
/// family.
|
||||
pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
|
||||
match self.as_socket() {
|
||||
Some(SocketAddr::V6(addr)) => Some(addr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SocketAddr> for SockAddr {
|
||||
fn from(addr: SocketAddr) -> SockAddr {
|
||||
match addr {
|
||||
SocketAddr::V4(addr) => addr.into(),
|
||||
SocketAddr::V6(addr) => addr.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SocketAddrV4> for SockAddr {
|
||||
fn from(addr: SocketAddrV4) -> SockAddr {
|
||||
let sockaddr_in = sockaddr_in {
|
||||
sin_family: AF_INET as sa_family_t,
|
||||
sin_port: addr.port().to_be(),
|
||||
sin_addr: crate::sys::to_in_addr(addr.ip()),
|
||||
sin_zero: Default::default(),
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
sin_len: 0,
|
||||
};
|
||||
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
|
||||
// Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage`
|
||||
unsafe { (storage.as_mut_ptr() as *mut sockaddr_in).write(sockaddr_in) };
|
||||
SockAddr {
|
||||
storage: unsafe { storage.assume_init() },
|
||||
len: mem::size_of::<sockaddr_in>() as socklen_t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SocketAddrV6> for SockAddr {
|
||||
fn from(addr: SocketAddrV6) -> SockAddr {
|
||||
#[cfg(windows)]
|
||||
let u = unsafe {
|
||||
let mut u = mem::zeroed::<SOCKADDR_IN6_LH_u>();
|
||||
*u.sin6_scope_id_mut() = addr.scope_id();
|
||||
u
|
||||
};
|
||||
|
||||
let sockaddr_in6 = sockaddr_in6 {
|
||||
sin6_family: AF_INET6 as sa_family_t,
|
||||
sin6_port: addr.port().to_be(),
|
||||
sin6_addr: crate::sys::to_in6_addr(addr.ip()),
|
||||
sin6_flowinfo: addr.flowinfo(),
|
||||
#[cfg(unix)]
|
||||
sin6_scope_id: addr.scope_id(),
|
||||
#[cfg(windows)]
|
||||
u,
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
sin6_len: 0,
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
__sin6_src_id: 0,
|
||||
};
|
||||
let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
|
||||
// Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage`
|
||||
unsafe { (storage.as_mut_ptr() as *mut sockaddr_in6).write(sockaddr_in6) };
|
||||
SockAddr {
|
||||
storage: unsafe { storage.assume_init() },
|
||||
len: mem::size_of::<sockaddr_in6>() as socklen_t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SockAddr {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut f = fmt.debug_struct("SockAddr");
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "hermit",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "vxworks",
|
||||
))]
|
||||
f.field("ss_len", &self.storage.ss_len);
|
||||
f.field("ss_family", &self.storage.ss_family)
|
||||
.field("len", &self.len)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ipv4() {
|
||||
use std::net::Ipv4Addr;
|
||||
let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
|
||||
let addr = SockAddr::from(std);
|
||||
assert_eq!(addr.family(), AF_INET as sa_family_t);
|
||||
assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
|
||||
assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
|
||||
assert_eq!(addr.as_socket_ipv4(), Some(std));
|
||||
assert!(addr.as_socket_ipv6().is_none());
|
||||
|
||||
let addr = SockAddr::from(SocketAddr::from(std));
|
||||
assert_eq!(addr.family(), AF_INET as sa_family_t);
|
||||
assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
|
||||
assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
|
||||
assert_eq!(addr.as_socket_ipv4(), Some(std));
|
||||
assert!(addr.as_socket_ipv6().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ipv6() {
|
||||
use std::net::Ipv6Addr;
|
||||
let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
|
||||
let addr = SockAddr::from(std);
|
||||
assert_eq!(addr.family(), AF_INET6 as sa_family_t);
|
||||
assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
|
||||
assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
|
||||
assert!(addr.as_socket_ipv4().is_none());
|
||||
assert_eq!(addr.as_socket_ipv6(), Some(std));
|
||||
|
||||
let addr = SockAddr::from(SocketAddr::from(std));
|
||||
assert_eq!(addr.family(), AF_INET6 as sa_family_t);
|
||||
assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
|
||||
assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
|
||||
assert!(addr.as_socket_ipv4().is_none());
|
||||
assert_eq!(addr.as_socket_ipv6(), Some(std));
|
||||
}
|
||||
1781
zeroidc/vendor/socket2/src/socket.rs
vendored
Normal file
1781
zeroidc/vendor/socket2/src/socket.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
147
zeroidc/vendor/socket2/src/sockref.rs
vendored
Normal file
147
zeroidc/vendor/socket2/src/sockref.rs
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::Deref;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::io::{AsRawSocket, FromRawSocket};
|
||||
|
||||
use crate::Socket;
|
||||
|
||||
/// A reference to a [`Socket`] that can be used to configure socket types other
|
||||
/// than the `Socket` type itself.
|
||||
///
|
||||
/// This allows for example a [`TcpStream`], found in the standard library, to
|
||||
/// be configured using all the additional methods found in the [`Socket`] API.
|
||||
///
|
||||
/// `SockRef` can be created from any socket type that implements [`AsRawFd`]
|
||||
/// (Unix) or [`AsRawSocket`] (Windows) using the [`From`] implementation, but
|
||||
/// the caller must ensure the file descriptor/socket is a valid.
|
||||
///
|
||||
/// [`TcpStream`]: std::net::TcpStream
|
||||
// Don't use intra-doc links because they won't build on every platform.
|
||||
/// [`AsRawFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsRawFd.html
|
||||
/// [`AsRawSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsRawSocket.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Below is an example of converting a [`TcpStream`] into a [`SockRef`].
|
||||
///
|
||||
/// ```
|
||||
/// use std::net::{TcpStream, SocketAddr};
|
||||
///
|
||||
/// use socket2::SockRef;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// // Create `TcpStream` from the standard library.
|
||||
/// let address: SocketAddr = "127.0.0.1:1234".parse()?;
|
||||
/// # let b1 = std::sync::Arc::new(std::sync::Barrier::new(2));
|
||||
/// # let b2 = b1.clone();
|
||||
/// # let handle = std::thread::spawn(move || {
|
||||
/// # let listener = std::net::TcpListener::bind(address).unwrap();
|
||||
/// # b2.wait();
|
||||
/// # let (stream, _) = listener.accept().unwrap();
|
||||
/// # std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
/// # drop(stream);
|
||||
/// # });
|
||||
/// # b1.wait();
|
||||
/// let stream = TcpStream::connect(address)?;
|
||||
///
|
||||
/// // Create a `SockRef`erence to the stream.
|
||||
/// let socket_ref = SockRef::from(&stream);
|
||||
/// // Use `Socket::set_nodelay` on the stream.
|
||||
/// socket_ref.set_nodelay(true)?;
|
||||
/// drop(socket_ref);
|
||||
///
|
||||
/// assert_eq!(stream.nodelay()?, true);
|
||||
/// # handle.join().unwrap();
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Below is an example of **incorrect usage** of `SockRef::from`, which is
|
||||
/// currently possible (but not intended and will be fixed in future versions).
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// use socket2::SockRef;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// /// THIS USAGE IS NOT VALID!
|
||||
/// let socket_ref = SockRef::from(&123);
|
||||
/// // The above line is overseen possibility when using `SockRef::from`, it
|
||||
/// // uses the `RawFd` (on Unix), which is a type alias for `c_int`/`i32`,
|
||||
/// // which implements `AsRawFd`. However it may be clear that this usage is
|
||||
/// // invalid as it doesn't guarantee that `123` is a valid file descriptor.
|
||||
///
|
||||
/// // Using `Socket::set_nodelay` now will call it on a file descriptor we
|
||||
/// // don't own! We don't even not if the file descriptor is valid or a socket.
|
||||
/// socket_ref.set_nodelay(true)?;
|
||||
/// drop(socket_ref);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// # DO_NOT_COMPILE
|
||||
/// ```
|
||||
pub struct SockRef<'s> {
|
||||
/// Because this is a reference we don't own the `Socket`, however `Socket`
|
||||
/// closes itself when dropped, so we use `ManuallyDrop` to prevent it from
|
||||
/// closing itself.
|
||||
socket: ManuallyDrop<Socket>,
|
||||
/// Because we don't own the socket we need to ensure the socket remains
|
||||
/// open while we have a "reference" to it, the lifetime `'s` ensures this.
|
||||
_lifetime: PhantomData<&'s Socket>,
|
||||
}
|
||||
|
||||
impl<'s> Deref for SockRef<'s> {
|
||||
type Target = Socket;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.socket
|
||||
}
|
||||
}
|
||||
|
||||
/// On Windows, a corresponding `From<&impl AsRawSocket>` implementation exists.
|
||||
#[cfg(unix)]
|
||||
#[cfg_attr(docsrs, doc(cfg(unix)))]
|
||||
impl<'s, S> From<&'s S> for SockRef<'s>
|
||||
where
|
||||
S: AsRawFd,
|
||||
{
|
||||
/// The caller must ensure `S` is actually a socket.
|
||||
fn from(socket: &'s S) -> Self {
|
||||
let fd = socket.as_raw_fd();
|
||||
assert!(fd >= 0);
|
||||
SockRef {
|
||||
socket: ManuallyDrop::new(unsafe { Socket::from_raw_fd(fd) }),
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// On Unix, a corresponding `From<&impl AsRawFd>` implementation exists.
|
||||
#[cfg(windows)]
|
||||
#[cfg_attr(docsrs, doc(cfg(windows)))]
|
||||
impl<'s, S> From<&'s S> for SockRef<'s>
|
||||
where
|
||||
S: AsRawSocket,
|
||||
{
|
||||
/// See the `From<&impl AsRawFd>` implementation.
|
||||
fn from(socket: &'s S) -> Self {
|
||||
let socket = socket.as_raw_socket();
|
||||
assert!(socket != winapi::um::winsock2::INVALID_SOCKET as _);
|
||||
SockRef {
|
||||
socket: ManuallyDrop::new(unsafe { Socket::from_raw_socket(socket) }),
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SockRef<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SockRef")
|
||||
.field("raw", &self.socket.as_raw())
|
||||
.field("local_addr", &self.socket.local_addr().ok())
|
||||
.field("peer_addr", &self.socket.peer_addr().ok())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
2053
zeroidc/vendor/socket2/src/sys/unix.rs
vendored
Normal file
2053
zeroidc/vendor/socket2/src/sys/unix.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
848
zeroidc/vendor/socket2/src/sys/windows.rs
vendored
Normal file
848
zeroidc/vendor/socket2/src/sys/windows.rs
vendored
Normal file
@@ -0,0 +1,848 @@
|
||||
// Copyright 2015 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cmp::min;
|
||||
use std::io::{self, IoSlice};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{self, size_of, MaybeUninit};
|
||||
use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown};
|
||||
use std::os::windows::prelude::*;
|
||||
use std::sync::Once;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{ptr, slice};
|
||||
|
||||
use winapi::ctypes::c_long;
|
||||
use winapi::shared::in6addr::*;
|
||||
use winapi::shared::inaddr::*;
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::shared::minwindef::ULONG;
|
||||
use winapi::shared::mstcpip::{tcp_keepalive, SIO_KEEPALIVE_VALS};
|
||||
use winapi::shared::ntdef::HANDLE;
|
||||
use winapi::shared::ws2def;
|
||||
use winapi::shared::ws2def::WSABUF;
|
||||
use winapi::um::handleapi::SetHandleInformation;
|
||||
use winapi::um::processthreadsapi::GetCurrentProcessId;
|
||||
use winapi::um::winbase::{self, INFINITE};
|
||||
use winapi::um::winsock2::{
|
||||
self as sock, u_long, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, SD_BOTH, SD_RECEIVE, SD_SEND,
|
||||
WSAPOLLFD,
|
||||
};
|
||||
|
||||
use crate::{RecvFlags, SockAddr, TcpKeepalive, Type};
|
||||
|
||||
pub(crate) use winapi::ctypes::c_int;
|
||||
|
||||
/// Fake MSG_TRUNC flag for the [`RecvFlags`] struct.
|
||||
///
|
||||
/// The flag is enabled when a `WSARecv[From]` call returns `WSAEMSGSIZE`. The
|
||||
/// value of the flag is defined by us.
|
||||
pub(crate) const MSG_TRUNC: c_int = 0x01;
|
||||
|
||||
// Used in `Domain`.
|
||||
pub(crate) use winapi::shared::ws2def::{AF_INET, AF_INET6};
|
||||
// Used in `Type`.
|
||||
pub(crate) use winapi::shared::ws2def::{SOCK_DGRAM, SOCK_STREAM};
|
||||
#[cfg(feature = "all")]
|
||||
pub(crate) use winapi::shared::ws2def::{SOCK_RAW, SOCK_SEQPACKET};
|
||||
// Used in `Protocol`.
|
||||
pub(crate) const IPPROTO_ICMP: c_int = winapi::shared::ws2def::IPPROTO_ICMP as c_int;
|
||||
pub(crate) const IPPROTO_ICMPV6: c_int = winapi::shared::ws2def::IPPROTO_ICMPV6 as c_int;
|
||||
pub(crate) const IPPROTO_TCP: c_int = winapi::shared::ws2def::IPPROTO_TCP as c_int;
|
||||
pub(crate) const IPPROTO_UDP: c_int = winapi::shared::ws2def::IPPROTO_UDP as c_int;
|
||||
// Used in `SockAddr`.
|
||||
pub(crate) use winapi::shared::ws2def::{
|
||||
ADDRESS_FAMILY as sa_family_t, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in,
|
||||
SOCKADDR_STORAGE as sockaddr_storage,
|
||||
};
|
||||
pub(crate) use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;
|
||||
pub(crate) use winapi::um::ws2tcpip::socklen_t;
|
||||
// Used in `Socket`.
|
||||
pub(crate) use winapi::shared::ws2def::{
|
||||
IPPROTO_IP, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE,
|
||||
SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
|
||||
};
|
||||
#[cfg(feature = "all")]
|
||||
pub(crate) use winapi::shared::ws2ipdef::IP_HDRINCL;
|
||||
pub(crate) use winapi::shared::ws2ipdef::{
|
||||
IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MREQ as Ipv6Mreq, IPV6_MULTICAST_HOPS,
|
||||
IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP,
|
||||
IP_DROP_MEMBERSHIP, IP_MREQ as IpMreq, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
|
||||
IP_TOS, IP_TTL,
|
||||
};
|
||||
pub(crate) use winapi::um::winsock2::{linger, MSG_OOB, MSG_PEEK};
|
||||
pub(crate) const IPPROTO_IPV6: c_int = winapi::shared::ws2def::IPPROTO_IPV6 as c_int;
|
||||
|
||||
/// Type used in set/getsockopt to retrieve the `TCP_NODELAY` option.
|
||||
///
|
||||
/// NOTE: <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt>
|
||||
/// documents that options such as `TCP_NODELAY` and `SO_KEEPALIVE` expect a
|
||||
/// `BOOL` (alias for `c_int`, 4 bytes), however in practice this turns out to
|
||||
/// be false (or misleading) as a `BOOLEAN` (`c_uchar`, 1 byte) is returned by
|
||||
/// `getsockopt`.
|
||||
pub(crate) type Bool = winapi::shared::ntdef::BOOLEAN;
|
||||
|
||||
/// Maximum size of a buffer passed to system call like `recv` and `send`.
|
||||
const MAX_BUF_LEN: usize = <c_int>::max_value() as usize;
|
||||
|
||||
/// Helper macro to execute a system call that returns an `io::Result`.
|
||||
macro_rules! syscall {
|
||||
($fn: ident ( $($arg: expr),* $(,)* ), $err_test: path, $err_value: expr) => {{
|
||||
#[allow(unused_unsafe)]
|
||||
let res = unsafe { sock::$fn($($arg, )*) };
|
||||
if $err_test(&res, &$err_value) {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
impl_debug!(
|
||||
crate::Domain,
|
||||
ws2def::AF_INET,
|
||||
ws2def::AF_INET6,
|
||||
ws2def::AF_UNIX,
|
||||
ws2def::AF_UNSPEC, // = 0.
|
||||
);
|
||||
|
||||
/// Windows only API.
|
||||
impl Type {
|
||||
/// Our custom flag to set `WSA_FLAG_NO_HANDLE_INHERIT` on socket creation.
|
||||
/// Trying to mimic `Type::cloexec` on windows.
|
||||
const NO_INHERIT: c_int = 1 << ((size_of::<c_int>() * 8) - 1); // Last bit.
|
||||
|
||||
/// Set `WSA_FLAG_NO_HANDLE_INHERIT` on the socket.
|
||||
#[cfg(feature = "all")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
|
||||
pub const fn no_inherit(self) -> Type {
|
||||
self._no_inherit()
|
||||
}
|
||||
|
||||
pub(crate) const fn _no_inherit(self) -> Type {
|
||||
Type(self.0 | Type::NO_INHERIT)
|
||||
}
|
||||
}
|
||||
|
||||
impl_debug!(
|
||||
crate::Type,
|
||||
ws2def::SOCK_STREAM,
|
||||
ws2def::SOCK_DGRAM,
|
||||
ws2def::SOCK_RAW,
|
||||
ws2def::SOCK_RDM,
|
||||
ws2def::SOCK_SEQPACKET,
|
||||
);
|
||||
|
||||
impl_debug!(
|
||||
crate::Protocol,
|
||||
self::IPPROTO_ICMP,
|
||||
self::IPPROTO_ICMPV6,
|
||||
self::IPPROTO_TCP,
|
||||
self::IPPROTO_UDP,
|
||||
);
|
||||
|
||||
impl std::fmt::Debug for RecvFlags {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("RecvFlags")
|
||||
.field("is_truncated", &self.is_truncated())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct MaybeUninitSlice<'a> {
|
||||
vec: WSABUF,
|
||||
_lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
|
||||
}
|
||||
|
||||
unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
|
||||
|
||||
unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
|
||||
|
||||
impl<'a> MaybeUninitSlice<'a> {
|
||||
pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
|
||||
assert!(buf.len() <= ULONG::MAX as usize);
|
||||
MaybeUninitSlice {
|
||||
vec: WSABUF {
|
||||
len: buf.len() as ULONG,
|
||||
buf: buf.as_mut_ptr().cast(),
|
||||
},
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[MaybeUninit<u8>] {
|
||||
unsafe { slice::from_raw_parts(self.vec.buf.cast(), self.vec.len as usize) }
|
||||
}
|
||||
|
||||
pub fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
|
||||
unsafe { slice::from_raw_parts_mut(self.vec.buf.cast(), self.vec.len as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
fn init() {
|
||||
static INIT: Once = Once::new();
|
||||
|
||||
INIT.call_once(|| {
|
||||
// Initialize winsock through the standard library by just creating a
|
||||
// dummy socket. Whether this is successful or not we drop the result as
|
||||
// libstd will be sure to have initialized winsock.
|
||||
let _ = net::UdpSocket::bind("127.0.0.1:34254");
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) type Socket = sock::SOCKET;
|
||||
|
||||
pub(crate) unsafe fn socket_from_raw(socket: Socket) -> crate::socket::Inner {
|
||||
crate::socket::Inner::from_raw_socket(socket as RawSocket)
|
||||
}
|
||||
|
||||
pub(crate) fn socket_as_raw(socket: &crate::socket::Inner) -> Socket {
|
||||
socket.as_raw_socket() as Socket
|
||||
}
|
||||
|
||||
pub(crate) fn socket_into_raw(socket: crate::socket::Inner) -> Socket {
|
||||
socket.into_raw_socket() as Socket
|
||||
}
|
||||
|
||||
pub(crate) fn socket(family: c_int, mut ty: c_int, protocol: c_int) -> io::Result<Socket> {
|
||||
init();
|
||||
|
||||
// Check if we set our custom flag.
|
||||
let flags = if ty & Type::NO_INHERIT != 0 {
|
||||
ty = ty & !Type::NO_INHERIT;
|
||||
sock::WSA_FLAG_NO_HANDLE_INHERIT
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
syscall!(
|
||||
WSASocketW(
|
||||
family,
|
||||
ty,
|
||||
protocol,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
sock::WSA_FLAG_OVERLAPPED | flags,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::INVALID_SOCKET
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn bind(socket: Socket, addr: &SockAddr) -> io::Result<()> {
|
||||
syscall!(bind(socket, addr.as_ptr(), addr.len()), PartialEq::ne, 0).map(|_| ())
|
||||
}
|
||||
|
||||
pub(crate) fn connect(socket: Socket, addr: &SockAddr) -> io::Result<()> {
|
||||
syscall!(connect(socket, addr.as_ptr(), addr.len()), PartialEq::ne, 0).map(|_| ())
|
||||
}
|
||||
|
||||
pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Result<()> {
|
||||
let start = Instant::now();
|
||||
|
||||
let mut fd_array = WSAPOLLFD {
|
||||
fd: socket.as_raw(),
|
||||
events: POLLRDNORM | POLLWRNORM,
|
||||
revents: 0,
|
||||
};
|
||||
|
||||
loop {
|
||||
let elapsed = start.elapsed();
|
||||
if elapsed >= timeout {
|
||||
return Err(io::ErrorKind::TimedOut.into());
|
||||
}
|
||||
|
||||
let timeout = (timeout - elapsed).as_millis();
|
||||
let timeout = clamp(timeout, 1, c_int::max_value() as u128) as c_int;
|
||||
|
||||
match syscall!(
|
||||
WSAPoll(&mut fd_array, 1, timeout),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
) {
|
||||
Ok(0) => return Err(io::ErrorKind::TimedOut.into()),
|
||||
Ok(_) => {
|
||||
// Error or hang up indicates an error (or failure to connect).
|
||||
if (fd_array.revents & POLLERR) != 0 || (fd_array.revents & POLLHUP) != 0 {
|
||||
match socket.take_error() {
|
||||
Ok(Some(err)) => return Err(err),
|
||||
Ok(None) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"no error set after POLLHUP",
|
||||
))
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
// Got interrupted, try again.
|
||||
Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use clamp from std lib, stable since 1.50.
|
||||
fn clamp<T>(value: T, min: T, max: T) -> T
|
||||
where
|
||||
T: Ord,
|
||||
{
|
||||
if value <= min {
|
||||
min
|
||||
} else if value >= max {
|
||||
max
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn listen(socket: Socket, backlog: c_int) -> io::Result<()> {
|
||||
syscall!(listen(socket, backlog), PartialEq::ne, 0).map(|_| ())
|
||||
}
|
||||
|
||||
pub(crate) fn accept(socket: Socket) -> io::Result<(Socket, SockAddr)> {
|
||||
// Safety: `accept` initialises the `SockAddr` for us.
|
||||
unsafe {
|
||||
SockAddr::init(|storage, len| {
|
||||
syscall!(
|
||||
accept(socket, storage.cast(), len),
|
||||
PartialEq::eq,
|
||||
sock::INVALID_SOCKET
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn getsockname(socket: Socket) -> io::Result<SockAddr> {
|
||||
// Safety: `getsockname` initialises the `SockAddr` for us.
|
||||
unsafe {
|
||||
SockAddr::init(|storage, len| {
|
||||
syscall!(
|
||||
getsockname(socket, storage.cast(), len),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
})
|
||||
}
|
||||
.map(|(_, addr)| addr)
|
||||
}
|
||||
|
||||
pub(crate) fn getpeername(socket: Socket) -> io::Result<SockAddr> {
|
||||
// Safety: `getpeername` initialises the `SockAddr` for us.
|
||||
unsafe {
|
||||
SockAddr::init(|storage, len| {
|
||||
syscall!(
|
||||
getpeername(socket, storage.cast(), len),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
})
|
||||
}
|
||||
.map(|(_, addr)| addr)
|
||||
}
|
||||
|
||||
pub(crate) fn try_clone(socket: Socket) -> io::Result<Socket> {
|
||||
let mut info: MaybeUninit<sock::WSAPROTOCOL_INFOW> = MaybeUninit::uninit();
|
||||
syscall!(
|
||||
WSADuplicateSocketW(socket, GetCurrentProcessId(), info.as_mut_ptr()),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)?;
|
||||
// Safety: `WSADuplicateSocketW` intialised `info` for us.
|
||||
let mut info = unsafe { info.assume_init() };
|
||||
|
||||
syscall!(
|
||||
WSASocketW(
|
||||
info.iAddressFamily,
|
||||
info.iSocketType,
|
||||
info.iProtocol,
|
||||
&mut info,
|
||||
0,
|
||||
sock::WSA_FLAG_OVERLAPPED | sock::WSA_FLAG_NO_HANDLE_INHERIT,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::INVALID_SOCKET
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn set_nonblocking(socket: Socket, nonblocking: bool) -> io::Result<()> {
|
||||
let mut nonblocking = nonblocking as u_long;
|
||||
ioctlsocket(socket, sock::FIONBIO, &mut nonblocking)
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown(socket: Socket, how: Shutdown) -> io::Result<()> {
|
||||
let how = match how {
|
||||
Shutdown::Write => SD_SEND,
|
||||
Shutdown::Read => SD_RECEIVE,
|
||||
Shutdown::Both => SD_BOTH,
|
||||
};
|
||||
syscall!(shutdown(socket, how), PartialEq::eq, sock::SOCKET_ERROR).map(|_| ())
|
||||
}
|
||||
|
||||
pub(crate) fn recv(socket: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int) -> io::Result<usize> {
|
||||
let res = syscall!(
|
||||
recv(
|
||||
socket,
|
||||
buf.as_mut_ptr().cast(),
|
||||
min(buf.len(), MAX_BUF_LEN) as c_int,
|
||||
flags,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
);
|
||||
match res {
|
||||
Ok(n) => Ok(n as usize),
|
||||
Err(ref err) if err.raw_os_error() == Some(sock::WSAESHUTDOWN as i32) => Ok(0),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn recv_vectored(
|
||||
socket: Socket,
|
||||
bufs: &mut [crate::MaybeUninitSlice<'_>],
|
||||
flags: c_int,
|
||||
) -> io::Result<(usize, RecvFlags)> {
|
||||
let mut nread = 0;
|
||||
let mut flags = flags as DWORD;
|
||||
let res = syscall!(
|
||||
WSARecv(
|
||||
socket,
|
||||
bufs.as_mut_ptr().cast(),
|
||||
min(bufs.len(), DWORD::max_value() as usize) as DWORD,
|
||||
&mut nread,
|
||||
&mut flags,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
);
|
||||
match res {
|
||||
Ok(_) => Ok((nread as usize, RecvFlags(0))),
|
||||
Err(ref err) if err.raw_os_error() == Some(sock::WSAESHUTDOWN as i32) => {
|
||||
Ok((0, RecvFlags(0)))
|
||||
}
|
||||
Err(ref err) if err.raw_os_error() == Some(sock::WSAEMSGSIZE as i32) => {
|
||||
Ok((nread as usize, RecvFlags(MSG_TRUNC)))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn recv_from(
|
||||
socket: Socket,
|
||||
buf: &mut [MaybeUninit<u8>],
|
||||
flags: c_int,
|
||||
) -> io::Result<(usize, SockAddr)> {
|
||||
// Safety: `recvfrom` initialises the `SockAddr` for us.
|
||||
unsafe {
|
||||
SockAddr::init(|storage, addrlen| {
|
||||
let res = syscall!(
|
||||
recvfrom(
|
||||
socket,
|
||||
buf.as_mut_ptr().cast(),
|
||||
min(buf.len(), MAX_BUF_LEN) as c_int,
|
||||
flags,
|
||||
storage.cast(),
|
||||
addrlen,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
);
|
||||
match res {
|
||||
Ok(n) => Ok(n as usize),
|
||||
Err(ref err) if err.raw_os_error() == Some(sock::WSAESHUTDOWN as i32) => Ok(0),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn recv_from_vectored(
|
||||
socket: Socket,
|
||||
bufs: &mut [crate::MaybeUninitSlice<'_>],
|
||||
flags: c_int,
|
||||
) -> io::Result<(usize, RecvFlags, SockAddr)> {
|
||||
// Safety: `recvfrom` initialises the `SockAddr` for us.
|
||||
unsafe {
|
||||
SockAddr::init(|storage, addrlen| {
|
||||
let mut nread = 0;
|
||||
let mut flags = flags as DWORD;
|
||||
let res = syscall!(
|
||||
WSARecvFrom(
|
||||
socket,
|
||||
bufs.as_mut_ptr().cast(),
|
||||
min(bufs.len(), DWORD::max_value() as usize) as DWORD,
|
||||
&mut nread,
|
||||
&mut flags,
|
||||
storage.cast(),
|
||||
addrlen,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
);
|
||||
match res {
|
||||
Ok(_) => Ok((nread as usize, RecvFlags(0))),
|
||||
Err(ref err) if err.raw_os_error() == Some(sock::WSAESHUTDOWN as i32) => {
|
||||
Ok((nread as usize, RecvFlags(0)))
|
||||
}
|
||||
Err(ref err) if err.raw_os_error() == Some(sock::WSAEMSGSIZE as i32) => {
|
||||
Ok((nread as usize, RecvFlags(MSG_TRUNC)))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
})
|
||||
}
|
||||
.map(|((n, recv_flags), addr)| (n, recv_flags, addr))
|
||||
}
|
||||
|
||||
pub(crate) fn send(socket: Socket, buf: &[u8], flags: c_int) -> io::Result<usize> {
|
||||
syscall!(
|
||||
send(
|
||||
socket,
|
||||
buf.as_ptr().cast(),
|
||||
min(buf.len(), MAX_BUF_LEN) as c_int,
|
||||
flags,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
.map(|n| n as usize)
|
||||
}
|
||||
|
||||
pub(crate) fn send_vectored(
|
||||
socket: Socket,
|
||||
bufs: &[IoSlice<'_>],
|
||||
flags: c_int,
|
||||
) -> io::Result<usize> {
|
||||
let mut nsent = 0;
|
||||
syscall!(
|
||||
WSASend(
|
||||
socket,
|
||||
// FIXME: From the `WSASend` docs [1]:
|
||||
// > For a Winsock application, once the WSASend function is called,
|
||||
// > the system owns these buffers and the application may not
|
||||
// > access them.
|
||||
//
|
||||
// So what we're doing is actually UB as `bufs` needs to be `&mut
|
||||
// [IoSlice<'_>]`.
|
||||
//
|
||||
// Tracking issue: https://github.com/rust-lang/socket2-rs/issues/129.
|
||||
//
|
||||
// NOTE: `send_to_vectored` has the same problem.
|
||||
//
|
||||
// [1] https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasend
|
||||
bufs.as_ptr() as *mut _,
|
||||
min(bufs.len(), DWORD::max_value() as usize) as DWORD,
|
||||
&mut nsent,
|
||||
flags as DWORD,
|
||||
std::ptr::null_mut(),
|
||||
None,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
.map(|_| nsent as usize)
|
||||
}
|
||||
|
||||
pub(crate) fn send_to(
|
||||
socket: Socket,
|
||||
buf: &[u8],
|
||||
addr: &SockAddr,
|
||||
flags: c_int,
|
||||
) -> io::Result<usize> {
|
||||
syscall!(
|
||||
sendto(
|
||||
socket,
|
||||
buf.as_ptr().cast(),
|
||||
min(buf.len(), MAX_BUF_LEN) as c_int,
|
||||
flags,
|
||||
addr.as_ptr(),
|
||||
addr.len(),
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
.map(|n| n as usize)
|
||||
}
|
||||
|
||||
pub(crate) fn send_to_vectored(
|
||||
socket: Socket,
|
||||
bufs: &[IoSlice<'_>],
|
||||
addr: &SockAddr,
|
||||
flags: c_int,
|
||||
) -> io::Result<usize> {
|
||||
let mut nsent = 0;
|
||||
syscall!(
|
||||
WSASendTo(
|
||||
socket,
|
||||
// FIXME: Same problem as in `send_vectored`.
|
||||
bufs.as_ptr() as *mut _,
|
||||
bufs.len().min(DWORD::MAX as usize) as DWORD,
|
||||
&mut nsent,
|
||||
flags as DWORD,
|
||||
addr.as_ptr(),
|
||||
addr.len(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
.map(|_| nsent as usize)
|
||||
}
|
||||
|
||||
/// Wrapper around `getsockopt` to deal with platform specific timeouts.
|
||||
pub(crate) fn timeout_opt(fd: Socket, lvl: c_int, name: c_int) -> io::Result<Option<Duration>> {
|
||||
unsafe { getsockopt(fd, lvl, name).map(from_ms) }
|
||||
}
|
||||
|
||||
fn from_ms(duration: DWORD) -> Option<Duration> {
|
||||
if duration == 0 {
|
||||
None
|
||||
} else {
|
||||
let secs = duration / 1000;
|
||||
let nsec = (duration % 1000) * 1000000;
|
||||
Some(Duration::new(secs as u64, nsec as u32))
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around `setsockopt` to deal with platform specific timeouts.
|
||||
pub(crate) fn set_timeout_opt(
|
||||
fd: Socket,
|
||||
level: c_int,
|
||||
optname: c_int,
|
||||
duration: Option<Duration>,
|
||||
) -> io::Result<()> {
|
||||
let duration = into_ms(duration);
|
||||
unsafe { setsockopt(fd, level, optname, duration) }
|
||||
}
|
||||
|
||||
fn into_ms(duration: Option<Duration>) -> DWORD {
|
||||
// Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
|
||||
// timeouts in windows APIs are typically u32 milliseconds. To translate, we
|
||||
// have two pieces to take care of:
|
||||
//
|
||||
// * Nanosecond precision is rounded up
|
||||
// * Greater than u32::MAX milliseconds (50 days) is rounded up to
|
||||
// INFINITE (never time out).
|
||||
duration
|
||||
.map(|duration| min(duration.as_millis(), INFINITE as u128) as DWORD)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub(crate) fn set_tcp_keepalive(socket: Socket, keepalive: &TcpKeepalive) -> io::Result<()> {
|
||||
let mut keepalive = tcp_keepalive {
|
||||
onoff: 1,
|
||||
keepalivetime: into_ms(keepalive.time),
|
||||
keepaliveinterval: into_ms(keepalive.interval),
|
||||
};
|
||||
let mut out = 0;
|
||||
syscall!(
|
||||
WSAIoctl(
|
||||
socket,
|
||||
SIO_KEEPALIVE_VALS,
|
||||
&mut keepalive as *mut _ as *mut _,
|
||||
size_of::<tcp_keepalive>() as _,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
&mut out,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
/// Caller must ensure `T` is the correct type for `level` and `optname`.
|
||||
pub(crate) unsafe fn getsockopt<T>(socket: Socket, level: c_int, optname: c_int) -> io::Result<T> {
|
||||
let mut optval: MaybeUninit<T> = MaybeUninit::uninit();
|
||||
let mut optlen = mem::size_of::<T>() as c_int;
|
||||
syscall!(
|
||||
getsockopt(
|
||||
socket,
|
||||
level,
|
||||
optname,
|
||||
optval.as_mut_ptr().cast(),
|
||||
&mut optlen,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
.map(|_| {
|
||||
debug_assert_eq!(optlen as usize, mem::size_of::<T>());
|
||||
// Safety: `getsockopt` initialised `optval` for us.
|
||||
optval.assume_init()
|
||||
})
|
||||
}
|
||||
|
||||
/// Caller must ensure `T` is the correct type for `level` and `optname`.
|
||||
pub(crate) unsafe fn setsockopt<T>(
|
||||
socket: Socket,
|
||||
level: c_int,
|
||||
optname: c_int,
|
||||
optval: T,
|
||||
) -> io::Result<()> {
|
||||
syscall!(
|
||||
setsockopt(
|
||||
socket,
|
||||
level,
|
||||
optname,
|
||||
(&optval as *const T).cast(),
|
||||
mem::size_of::<T>() as c_int,
|
||||
),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
fn ioctlsocket(socket: Socket, cmd: c_long, payload: &mut u_long) -> io::Result<()> {
|
||||
syscall!(
|
||||
ioctlsocket(socket, cmd, payload),
|
||||
PartialEq::eq,
|
||||
sock::SOCKET_ERROR
|
||||
)
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub(crate) fn to_in_addr(addr: &Ipv4Addr) -> IN_ADDR {
|
||||
let mut s_un: in_addr_S_un = unsafe { mem::zeroed() };
|
||||
// `S_un` is stored as BE on all machines, and the array is in BE order. So
|
||||
// the native endian conversion method is used so that it's never swapped.
|
||||
unsafe { *(s_un.S_addr_mut()) = u32::from_ne_bytes(addr.octets()) };
|
||||
IN_ADDR { S_un: s_un }
|
||||
}
|
||||
|
||||
pub(crate) fn from_in_addr(in_addr: IN_ADDR) -> Ipv4Addr {
|
||||
Ipv4Addr::from(unsafe { *in_addr.S_un.S_addr() }.to_ne_bytes())
|
||||
}
|
||||
|
||||
pub(crate) fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
|
||||
let mut ret_addr: in6_addr_u = unsafe { mem::zeroed() };
|
||||
unsafe { *(ret_addr.Byte_mut()) = addr.octets() };
|
||||
let mut ret: in6_addr = unsafe { mem::zeroed() };
|
||||
ret.u = ret_addr;
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
|
||||
Ipv6Addr::from(*unsafe { addr.u.Byte() })
|
||||
}
|
||||
|
||||
pub(crate) fn to_mreqn(
|
||||
multiaddr: &Ipv4Addr,
|
||||
interface: &crate::socket::InterfaceIndexOrAddress,
|
||||
) -> IpMreq {
|
||||
IpMreq {
|
||||
imr_multiaddr: to_in_addr(multiaddr),
|
||||
// Per https://docs.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-ip_mreq#members:
|
||||
//
|
||||
// imr_interface
|
||||
//
|
||||
// The local IPv4 address of the interface or the interface index on
|
||||
// which the multicast group should be joined or dropped. This value is
|
||||
// in network byte order. If this member specifies an IPv4 address of
|
||||
// 0.0.0.0, the default IPv4 multicast interface is used.
|
||||
//
|
||||
// To use an interface index of 1 would be the same as an IP address of
|
||||
// 0.0.0.1.
|
||||
imr_interface: match interface {
|
||||
crate::socket::InterfaceIndexOrAddress::Index(interface) => {
|
||||
to_in_addr(&(*interface).into())
|
||||
}
|
||||
crate::socket::InterfaceIndexOrAddress::Address(interface) => to_in_addr(interface),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Windows only API.
|
||||
impl crate::Socket {
|
||||
/// Sets `HANDLE_FLAG_INHERIT` using `SetHandleInformation`.
|
||||
#[cfg(feature = "all")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))]
|
||||
pub fn set_no_inherit(&self, no_inherit: bool) -> io::Result<()> {
|
||||
self._set_no_inherit(no_inherit)
|
||||
}
|
||||
|
||||
pub(crate) fn _set_no_inherit(&self, no_inherit: bool) -> io::Result<()> {
|
||||
// NOTE: can't use `syscall!` because it expects the function in the
|
||||
// `sock::` path.
|
||||
let res = unsafe {
|
||||
SetHandleInformation(
|
||||
self.as_raw() as HANDLE,
|
||||
winbase::HANDLE_FLAG_INHERIT,
|
||||
!no_inherit as _,
|
||||
)
|
||||
};
|
||||
if res == 0 {
|
||||
// Zero means error.
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawSocket for crate::Socket {
|
||||
fn as_raw_socket(&self) -> RawSocket {
|
||||
self.as_raw() as RawSocket
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawSocket for crate::Socket {
|
||||
fn into_raw_socket(self) -> RawSocket {
|
||||
self.into_raw() as RawSocket
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawSocket for crate::Socket {
|
||||
unsafe fn from_raw_socket(socket: RawSocket) -> crate::Socket {
|
||||
crate::Socket::from_raw(socket as Socket)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn in_addr_convertion() {
|
||||
let ip = Ipv4Addr::new(127, 0, 0, 1);
|
||||
let raw = to_in_addr(&ip);
|
||||
assert_eq!(unsafe { *raw.S_un.S_addr() }, 127 << 0 | 1 << 24);
|
||||
assert_eq!(from_in_addr(raw), ip);
|
||||
|
||||
let ip = Ipv4Addr::new(127, 34, 4, 12);
|
||||
let raw = to_in_addr(&ip);
|
||||
assert_eq!(
|
||||
unsafe { *raw.S_un.S_addr() },
|
||||
127 << 0 | 34 << 8 | 4 << 16 | 12 << 24
|
||||
);
|
||||
assert_eq!(from_in_addr(raw), ip);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn in6_addr_convertion() {
|
||||
let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
|
||||
let raw = to_in6_addr(&ip);
|
||||
let want = [
|
||||
0x2000u16.to_be(),
|
||||
1u16.to_be(),
|
||||
2u16.to_be(),
|
||||
3u16.to_be(),
|
||||
4u16.to_be(),
|
||||
5u16.to_be(),
|
||||
6u16.to_be(),
|
||||
7u16.to_be(),
|
||||
];
|
||||
assert_eq!(unsafe { *raw.u.Word() }, want);
|
||||
assert_eq!(from_in6_addr(raw), ip);
|
||||
}
|
||||
Reference in New Issue
Block a user