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:
Adam Ierymenko
2022-06-08 07:32:16 -04:00
parent 373ca30269
commit d5ca4e5f52
12611 changed files with 2898014 additions and 284 deletions

442
zeroidc/vendor/socket2/src/lib.rs vendored Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

147
zeroidc/vendor/socket2/src/sockref.rs vendored Normal file
View 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

File diff suppressed because it is too large Load Diff

View 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);
}