From b60483f4f5a620240358d06b37f5f2674ab64357 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Wed, 27 Apr 2022 14:17:03 +0200 Subject: [PATCH 1/2] Replace winapi with windows-sys windows-sys is officially supported by Microsoft. --- Cargo.toml | 10 +- src/lib.rs | 2 +- src/sockaddr.rs | 18 ++- src/sockref.rs | 2 +- src/sys/unix.rs | 10 +- src/sys/windows.rs | 290 +++++++++++++++++++++++---------------------- tests/socket.rs | 8 +- 7 files changed, 171 insertions(+), 169 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f99228ef..2b0619d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,8 +35,14 @@ features = ["all"] [target."cfg(unix)".dependencies] libc = "0.2.124" -[target."cfg(windows)".dependencies] -winapi = { version = "0.3.9", features = ["handleapi", "ws2ipdef", "ws2tcpip"] } +[target.'cfg(windows)'.dependencies.windows-sys] +version = "=0.36" +features = [ + "Win32_Foundation", + "Win32_Networking_WinSock", + "Win32_System_IO", + "Win32_System_WindowsProgramming", +] [features] # Enable all API, even ones not available on all OSs. diff --git a/src/lib.rs b/src/lib.rs index d01b652c..936d01a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,7 +78,7 @@ macro_rules! impl_debug { $(#[$target: meta])* // The flag(s) to check. // Need to specific the libc crate because Windows doesn't use - // `libc` but `winapi`. + // `libc` but `windows_sys`. $libc: ident :: $flag: ident ),+ $(,)* ) => { diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 55951b63..64b70e19 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -2,12 +2,13 @@ use std::mem::{self, size_of, MaybeUninit}; use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use std::{fmt, io}; +#[cfg(windows)] +use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0; + 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. /// @@ -183,7 +184,7 @@ impl SockAddr { addr.sin6_scope_id, #[cfg(windows)] unsafe { - *addr.u.sin6_scope_id() + addr.Anonymous.sin6_scope_id }, ))) } else { @@ -249,13 +250,6 @@ impl From for SockAddr { impl From for SockAddr { fn from(addr: SocketAddrV6) -> SockAddr { - #[cfg(windows)] - let u = unsafe { - let mut u = mem::zeroed::(); - *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(), @@ -264,7 +258,9 @@ impl From for SockAddr { #[cfg(unix)] sin6_scope_id: addr.scope_id(), #[cfg(windows)] - u, + Anonymous: SOCKADDR_IN6_0 { + sin6_scope_id: addr.scope_id(), + }, #[cfg(any( target_os = "dragonfly", target_os = "freebsd", diff --git a/src/sockref.rs b/src/sockref.rs index 257323be..c00abf0c 100644 --- a/src/sockref.rs +++ b/src/sockref.rs @@ -128,7 +128,7 @@ where /// 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 _); + assert!(socket != windows_sys::Win32::Networking::WinSock::INVALID_SOCKET as _); SockRef { socket: ManuallyDrop::new(unsafe { Socket::from_raw_socket(socket) }), _lifetime: PhantomData, diff --git a/src/sys/unix.rs b/src/sys/unix.rs index d4624a6c..c847b616 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -174,7 +174,7 @@ macro_rules! syscall { /// Maximum size of a buffer passed to system call like `recv` and `send`. #[cfg(not(target_vendor = "apple"))] -const MAX_BUF_LEN: usize = ::max_value() as usize; +const MAX_BUF_LEN: usize = ssize_t::MAX as usize; // The maximum read limit on most posix-like systems is `SSIZE_MAX`, with the // man page quoting that if the count of bytes to read is greater than @@ -185,7 +185,7 @@ const MAX_BUF_LEN: usize = ::max_value() as usize; // than or equal to INT_MAX. To handle both of these the read size is capped on // both platforms. #[cfg(target_vendor = "apple")] -const MAX_BUF_LEN: usize = ::max_value() as usize - 1; +const MAX_BUF_LEN: usize = c_int::MAX as usize - 1; #[cfg(any( all( @@ -622,7 +622,7 @@ pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Res } let timeout = (timeout - elapsed).as_millis(); - let timeout = clamp(timeout, 1, c_int::max_value() as u128) as c_int; + let timeout = clamp(timeout, 1, c_int::MAX as u128) as c_int; match syscall!(poll(&mut pollfd, 1, timeout)) { Ok(0) => return Err(io::ErrorKind::TimedOut.into()), @@ -878,7 +878,7 @@ fn into_timeval(duration: Option) -> libc::timeval { // https://github.com/rust-lang/libc/issues/1848 #[cfg_attr(target_env = "musl", allow(deprecated))] Some(duration) => libc::timeval { - tv_sec: min(duration.as_secs(), libc::time_t::max_value() as u64) as libc::time_t, + tv_sec: min(duration.as_secs(), libc::time_t::MAX as u64) as libc::time_t, tv_usec: duration.subsec_micros() as libc::suseconds_t, }, None => libc::timeval { @@ -931,7 +931,7 @@ pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Res #[cfg(not(any(target_os = "haiku", target_os = "openbsd")))] fn into_secs(duration: Duration) -> c_int { - min(duration.as_secs(), c_int::max_value() as u64) as c_int + min(duration.as_secs(), c_int::MAX as u64) as c_int } /// Add `flag` to the current set flags of `F_GETFD`. diff --git a/src/sys/windows.rs b/src/sys/windows.rs index fc4ca464..fe9130fa 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -11,31 +11,24 @@ 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::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; 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 std::{process, ptr, slice}; + +use windows_sys::Win32::Foundation::{SetHandleInformation, HANDLE, HANDLE_FLAG_INHERIT}; +use windows_sys::Win32::Networking::WinSock::{ + self, tcp_keepalive, FIONBIO, IN6_ADDR, IN6_ADDR_0, INVALID_SOCKET, IN_ADDR, IN_ADDR_0, + POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, SD_BOTH, SD_RECEIVE, SD_SEND, SIO_KEEPALIVE_VALS, + SOCKET_ERROR, WSABUF, WSAEMSGSIZE, WSAESHUTDOWN, WSAPOLLFD, WSAPROTOCOL_INFOW, + WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED, }; +use windows_sys::Win32::System::WindowsProgramming::INFINITE; use crate::{RecvFlags, SockAddr, TcpKeepalive, Type}; -pub(crate) use winapi::ctypes::c_int; +#[allow(non_camel_case_types)] +pub(crate) type c_int = i32; /// Fake MSG_TRUNC flag for the [`RecvFlags`] struct. /// @@ -44,39 +37,44 @@ pub(crate) use winapi::ctypes::c_int; pub(crate) const MSG_TRUNC: c_int = 0x01; // Used in `Domain`. -pub(crate) use winapi::shared::ws2def::{AF_INET, AF_INET6}; +pub(crate) const AF_INET: c_int = windows_sys::Win32::Networking::WinSock::AF_INET as c_int; +pub(crate) const AF_INET6: c_int = windows_sys::Win32::Networking::WinSock::AF_INET6 as c_int; +const AF_UNIX: c_int = windows_sys::Win32::Networking::WinSock::AF_UNIX as c_int; +const AF_UNSPEC: c_int = windows_sys::Win32::Networking::WinSock::AF_UNSPEC as c_int; // 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}; +pub(crate) const SOCK_STREAM: c_int = windows_sys::Win32::Networking::WinSock::SOCK_STREAM as c_int; +pub(crate) const SOCK_DGRAM: c_int = windows_sys::Win32::Networking::WinSock::SOCK_DGRAM as c_int; +pub(crate) const SOCK_RAW: c_int = windows_sys::Win32::Networking::WinSock::SOCK_RAW as c_int; +const SOCK_RDM: c_int = windows_sys::Win32::Networking::WinSock::SOCK_RDM as c_int; +pub(crate) const SOCK_SEQPACKET: c_int = + windows_sys::Win32::Networking::WinSock::SOCK_SEQPACKET as c_int; // 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; +pub(crate) use windows_sys::Win32::Networking::WinSock::{ + IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP, +}; // Used in `SockAddr`. -pub(crate) use winapi::shared::ws2def::{ - ADDRESS_FAMILY as sa_family_t, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, +pub(crate) use windows_sys::Win32::Networking::WinSock::{ + SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, SOCKADDR_IN6 as sockaddr_in6, 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; +#[allow(non_camel_case_types)] +pub(crate) type sa_family_t = u16; +#[allow(non_camel_case_types)] +pub(crate) type socklen_t = i32; // 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_ADD_SOURCE_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, IP_MREQ as IpMreq, - IP_MREQ_SOURCE as IpMreqSource, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TOS, - IP_TTL, +pub(crate) use windows_sys::Win32::Networking::WinSock::IP_HDRINCL; +pub(crate) use windows_sys::Win32::Networking::WinSock::{ + linger, IPPROTO_IPV6, 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_ADD_SOURCE_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, + IP_MREQ as IpMreq, IP_MREQ_SOURCE as IpMreqSource, IP_MULTICAST_IF, IP_MULTICAST_LOOP, + IP_MULTICAST_TTL, IP_TOS, IP_TTL, MSG_OOB, MSG_PEEK, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, + SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, + TCP_NODELAY, }; -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; +pub(crate) const IPPROTO_IP: c_int = windows_sys::Win32::Networking::WinSock::IPPROTO_IP as c_int; +pub(crate) const SOL_SOCKET: c_int = windows_sys::Win32::Networking::WinSock::SOL_SOCKET as c_int; /// Type used in set/getsockopt to retrieve the `TCP_NODELAY` option. /// @@ -85,16 +83,16 @@ pub(crate) const IPPROTO_IPV6: c_int = winapi::shared::ws2def::IPPROTO_IPV6 as c /// `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; +pub(crate) type Bool = windows_sys::Win32::Foundation::BOOLEAN; /// Maximum size of a buffer passed to system call like `recv` and `send`. -const MAX_BUF_LEN: usize = ::max_value() as usize; +const MAX_BUF_LEN: usize = c_int::MAX 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, )*) }; + let res = unsafe { windows_sys::Win32::Networking::WinSock::$fn($($arg, )*) }; if $err_test(&res, &$err_value) { Err(io::Error::last_os_error()) } else { @@ -105,10 +103,10 @@ macro_rules! syscall { impl_debug!( crate::Domain, - ws2def::AF_INET, - ws2def::AF_INET6, - ws2def::AF_UNIX, - ws2def::AF_UNSPEC, // = 0. + self::AF_INET, + self::AF_INET6, + self::AF_UNIX, + self::AF_UNSPEC, // = 0. ); /// Windows only API. @@ -131,19 +129,19 @@ impl Type { impl_debug!( crate::Type, - ws2def::SOCK_STREAM, - ws2def::SOCK_DGRAM, - ws2def::SOCK_RAW, - ws2def::SOCK_RDM, - ws2def::SOCK_SEQPACKET, + self::SOCK_STREAM, + self::SOCK_DGRAM, + self::SOCK_RAW, + self::SOCK_RDM, + self::SOCK_SEQPACKET, ); impl_debug!( crate::Protocol, - self::IPPROTO_ICMP, - self::IPPROTO_ICMPV6, - self::IPPROTO_TCP, - self::IPPROTO_UDP, + WinSock::IPPROTO_ICMP, + WinSock::IPPROTO_ICMPV6, + WinSock::IPPROTO_TCP, + WinSock::IPPROTO_UDP, ); impl std::fmt::Debug for RecvFlags { @@ -166,10 +164,10 @@ unsafe impl<'a> Sync for MaybeUninitSlice<'a> {} impl<'a> MaybeUninitSlice<'a> { pub fn new(buf: &'a mut [MaybeUninit]) -> MaybeUninitSlice<'a> { - assert!(buf.len() <= ULONG::MAX as usize); + assert!(buf.len() <= u32::MAX as usize); MaybeUninitSlice { vec: WSABUF { - len: buf.len() as ULONG, + len: buf.len() as u32, buf: buf.as_mut_ptr().cast(), }, _lifetime: PhantomData, @@ -196,7 +194,7 @@ fn init() { }); } -pub(crate) type Socket = sock::SOCKET; +pub(crate) type Socket = windows_sys::Win32::Networking::WinSock::SOCKET; pub(crate) unsafe fn socket_from_raw(socket: Socket) -> crate::socket::Inner { crate::socket::Inner::from_raw_socket(socket as RawSocket) @@ -216,7 +214,7 @@ pub(crate) fn socket(family: c_int, mut ty: c_int, protocol: c_int) -> io::Resul // 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 + WSA_FLAG_NO_HANDLE_INHERIT } else { 0 }; @@ -228,10 +226,10 @@ pub(crate) fn socket(family: c_int, mut ty: c_int, protocol: c_int) -> io::Resul protocol, ptr::null_mut(), 0, - sock::WSA_FLAG_OVERLAPPED | flags, + WSA_FLAG_OVERLAPPED | flags, ), PartialEq::eq, - sock::INVALID_SOCKET + INVALID_SOCKET ) } @@ -248,7 +246,7 @@ pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Res let mut fd_array = WSAPOLLFD { fd: socket.as_raw(), - events: POLLRDNORM | POLLWRNORM, + events: (POLLRDNORM | POLLWRNORM) as i16, revents: 0, }; @@ -259,17 +257,19 @@ pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Res } let timeout = (timeout - elapsed).as_millis(); - let timeout = clamp(timeout, 1, c_int::max_value() as u128) as c_int; + let timeout = clamp(timeout, 1, c_int::MAX as u128) as c_int; match syscall!( WSAPoll(&mut fd_array, 1, timeout), PartialEq::eq, - sock::SOCKET_ERROR + 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 { + if (fd_array.revents & POLLERR as i16) != 0 + || (fd_array.revents & POLLHUP as i16) != 0 + { match socket.take_error() { Ok(Some(err)) => return Err(err), Ok(None) => { @@ -315,7 +315,7 @@ pub(crate) fn accept(socket: Socket) -> io::Result<(Socket, SockAddr)> { syscall!( accept(socket, storage.cast(), len), PartialEq::eq, - sock::INVALID_SOCKET + INVALID_SOCKET ) }) } @@ -328,7 +328,7 @@ pub(crate) fn getsockname(socket: Socket) -> io::Result { syscall!( getsockname(socket, storage.cast(), len), PartialEq::eq, - sock::SOCKET_ERROR + SOCKET_ERROR ) }) } @@ -342,7 +342,7 @@ pub(crate) fn getpeername(socket: Socket) -> io::Result { syscall!( getpeername(socket, storage.cast(), len), PartialEq::eq, - sock::SOCKET_ERROR + SOCKET_ERROR ) }) } @@ -350,11 +350,12 @@ pub(crate) fn getpeername(socket: Socket) -> io::Result { } pub(crate) fn try_clone(socket: Socket) -> io::Result { - let mut info: MaybeUninit = MaybeUninit::uninit(); + let mut info: MaybeUninit = MaybeUninit::uninit(); syscall!( - WSADuplicateSocketW(socket, GetCurrentProcessId(), info.as_mut_ptr()), + // NOTE: `process.id` is the same as `GetCurrentProcessId`. + WSADuplicateSocketW(socket, process::id(), info.as_mut_ptr()), PartialEq::eq, - sock::SOCKET_ERROR + SOCKET_ERROR )?; // Safety: `WSADuplicateSocketW` intialised `info` for us. let mut info = unsafe { info.assume_init() }; @@ -366,16 +367,16 @@ pub(crate) fn try_clone(socket: Socket) -> io::Result { info.iProtocol, &mut info, 0, - sock::WSA_FLAG_OVERLAPPED | sock::WSA_FLAG_NO_HANDLE_INHERIT, + WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT, ), PartialEq::eq, - sock::INVALID_SOCKET + 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) + let mut nonblocking = if nonblocking { 1 } else { 0 }; + ioctlsocket(socket, FIONBIO, &mut nonblocking) } pub(crate) fn shutdown(socket: Socket, how: Shutdown) -> io::Result<()> { @@ -383,8 +384,8 @@ pub(crate) fn shutdown(socket: Socket, how: Shutdown) -> io::Result<()> { Shutdown::Write => SD_SEND, Shutdown::Read => SD_RECEIVE, Shutdown::Both => SD_BOTH, - }; - syscall!(shutdown(socket, how), PartialEq::eq, sock::SOCKET_ERROR).map(|_| ()) + } as i32; + syscall!(shutdown(socket, how), PartialEq::eq, SOCKET_ERROR).map(|_| ()) } pub(crate) fn recv(socket: Socket, buf: &mut [MaybeUninit], flags: c_int) -> io::Result { @@ -396,11 +397,11 @@ pub(crate) fn recv(socket: Socket, buf: &mut [MaybeUninit], flags: c_int) -> flags, ), PartialEq::eq, - sock::SOCKET_ERROR + 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(ref err) if err.raw_os_error() == Some(WSAESHUTDOWN as i32) => Ok(0), Err(err) => Err(err), } } @@ -411,26 +412,24 @@ pub(crate) fn recv_vectored( flags: c_int, ) -> io::Result<(usize, RecvFlags)> { let mut nread = 0; - let mut flags = flags as DWORD; + let mut flags = flags as u32; let res = syscall!( WSARecv( socket, bufs.as_mut_ptr().cast(), - min(bufs.len(), DWORD::max_value() as usize) as DWORD, + min(bufs.len(), u32::MAX as usize) as u32, &mut nread, &mut flags, ptr::null_mut(), None, ), PartialEq::eq, - sock::SOCKET_ERROR + 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) => { + Err(ref err) if err.raw_os_error() == Some(WSAESHUTDOWN as i32) => Ok((0, RecvFlags(0))), + Err(ref err) if err.raw_os_error() == Some(WSAEMSGSIZE as i32) => { Ok((nread as usize, RecvFlags(MSG_TRUNC))) } Err(err) => Err(err), @@ -455,11 +454,11 @@ pub(crate) fn recv_from( addrlen, ), PartialEq::eq, - sock::SOCKET_ERROR + 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(ref err) if err.raw_os_error() == Some(WSAESHUTDOWN as i32) => Ok(0), Err(err) => Err(err), } }) @@ -475,12 +474,12 @@ pub(crate) fn recv_from_vectored( unsafe { SockAddr::init(|storage, addrlen| { let mut nread = 0; - let mut flags = flags as DWORD; + let mut flags = flags as u32; let res = syscall!( WSARecvFrom( socket, bufs.as_mut_ptr().cast(), - min(bufs.len(), DWORD::max_value() as usize) as DWORD, + min(bufs.len(), u32::MAX as usize) as u32, &mut nread, &mut flags, storage.cast(), @@ -489,14 +488,14 @@ pub(crate) fn recv_from_vectored( None, ), PartialEq::eq, - sock::SOCKET_ERROR + SOCKET_ERROR ); match res { Ok(_) => Ok((nread as usize, RecvFlags(0))), - Err(ref err) if err.raw_os_error() == Some(sock::WSAESHUTDOWN as i32) => { + Err(ref err) if err.raw_os_error() == Some(WSAESHUTDOWN as i32) => { Ok((nread as usize, RecvFlags(0))) } - Err(ref err) if err.raw_os_error() == Some(sock::WSAEMSGSIZE as i32) => { + Err(ref err) if err.raw_os_error() == Some(WSAEMSGSIZE as i32) => { Ok((nread as usize, RecvFlags(MSG_TRUNC))) } Err(err) => Err(err), @@ -515,7 +514,7 @@ pub(crate) fn send(socket: Socket, buf: &[u8], flags: c_int) -> io::Result io::Result> { +pub(crate) fn timeout_opt(fd: Socket, lvl: c_int, name: u32) -> io::Result> { unsafe { getsockopt(fd, lvl, name).map(from_ms) } } -fn from_ms(duration: DWORD) -> Option { +fn from_ms(duration: u32) -> Option { if duration == 0 { None } else { @@ -619,16 +618,16 @@ fn from_ms(duration: DWORD) -> Option { /// Wrapper around `setsockopt` to deal with platform specific timeouts. pub(crate) fn set_timeout_opt( - fd: Socket, + socket: Socket, level: c_int, - optname: c_int, + optname: u32, duration: Option, ) -> io::Result<()> { let duration = into_ms(duration); - unsafe { setsockopt(fd, level, optname, duration) } + unsafe { setsockopt(socket, level, optname, duration) } } -fn into_ms(duration: Option) -> DWORD { +fn into_ms(duration: Option) -> u32 { // 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: @@ -637,7 +636,7 @@ fn into_ms(duration: Option) -> DWORD { // * 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) + .map(|duration| min(duration.as_millis(), INFINITE as u128) as u32) .unwrap_or(0) } @@ -661,25 +660,26 @@ pub(crate) fn set_tcp_keepalive(socket: Socket, keepalive: &TcpKeepalive) -> io: None, ), PartialEq::eq, - sock::SOCKET_ERROR + SOCKET_ERROR ) .map(|_| ()) } /// Caller must ensure `T` is the correct type for `level` and `optname`. -pub(crate) unsafe fn getsockopt(socket: Socket, level: c_int, optname: c_int) -> io::Result { +// NOTE: `optname` is actually `i32`, but all constants are `u32`. +pub(crate) unsafe fn getsockopt(socket: Socket, level: c_int, optname: u32) -> io::Result { let mut optval: MaybeUninit = MaybeUninit::uninit(); let mut optlen = mem::size_of::() as c_int; syscall!( getsockopt( socket, - level, - optname, + level as i32, + optname as i32, optval.as_mut_ptr().cast(), &mut optlen, ), PartialEq::eq, - sock::SOCKET_ERROR + SOCKET_ERROR ) .map(|_| { debug_assert_eq!(optlen as usize, mem::size_of::()); @@ -689,57 +689,61 @@ pub(crate) unsafe fn getsockopt(socket: Socket, level: c_int, optname: c_int) } /// Caller must ensure `T` is the correct type for `level` and `optname`. +// NOTE: `optname` is actually `i32`, but all constants are `u32`. pub(crate) unsafe fn setsockopt( socket: Socket, level: c_int, - optname: c_int, + optname: u32, optval: T, ) -> io::Result<()> { syscall!( setsockopt( socket, - level, - optname, + level as i32, + optname as i32, (&optval as *const T).cast(), mem::size_of::() as c_int, ), PartialEq::eq, - sock::SOCKET_ERROR + SOCKET_ERROR ) .map(|_| ()) } -fn ioctlsocket(socket: Socket, cmd: c_long, payload: &mut u_long) -> io::Result<()> { +fn ioctlsocket(socket: Socket, cmd: i32, payload: &mut u32) -> io::Result<()> { syscall!( ioctlsocket(socket, cmd, payload), PartialEq::eq, - sock::SOCKET_ERROR + 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 } + IN_ADDR { + S_un: IN_ADDR_0 { + // `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. + S_addr: u32::from_ne_bytes(addr.octets()), + }, + } } pub(crate) fn from_in_addr(in_addr: IN_ADDR) -> Ipv4Addr { - Ipv4Addr::from(unsafe { *in_addr.S_un.S_addr() }.to_ne_bytes()) + 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 to_in6_addr(addr: &Ipv6Addr) -> IN6_ADDR { + IN6_ADDR { + u: IN6_ADDR_0 { + Byte: addr.octets(), + }, + } } -pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr { - Ipv6Addr::from(*unsafe { addr.u.Byte() }) +pub(crate) fn from_in6_addr(addr: IN6_ADDR) -> Ipv6Addr { + Ipv6Addr::from(unsafe { addr.u.Byte }) } pub(crate) fn to_mreqn( @@ -779,11 +783,11 @@ impl crate::Socket { 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. + // `windows_sys::Win32::Networking::WinSock::` path. let res = unsafe { SetHandleInformation( self.as_raw() as HANDLE, - winbase::HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT, !no_inherit as _, ) }; @@ -818,13 +822,13 @@ impl FromRawSocket for crate::Socket { 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!(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() }, + unsafe { raw.S_un.S_addr }, 127 << 0 | 34 << 8 | 4 << 16 | 12 << 24 ); assert_eq!(from_in_addr(raw), ip); @@ -844,6 +848,6 @@ fn in6_addr_convertion() { 6u16.to_be(), 7u16.to_be(), ]; - assert_eq!(unsafe { *raw.u.Word() }, want); + assert_eq!(unsafe { raw.u.Word }, want); assert_eq!(from_in6_addr(raw), ip); } diff --git a/tests/socket.rs b/tests/socket.rs index 6653608f..6fd22ae9 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -40,11 +40,7 @@ use std::time::Duration; use std::{env, fs}; #[cfg(windows)] -use winapi::shared::minwindef::DWORD; -#[cfg(windows)] -use winapi::um::handleapi::GetHandleInformation; -#[cfg(windows)] -use winapi::um::winbase::HANDLE_FLAG_INHERIT; +use windows_sys::Win32::Foundation::{GetHandleInformation, HANDLE_FLAG_INHERIT}; #[cfg(not(target_os = "redox"))] use socket2::MaybeUninitSlice; @@ -320,7 +316,7 @@ pub fn assert_flag_no_inherit(socket: &S, want: bool) where S: AsRawSocket, { - let mut flags: DWORD = 0; + let mut flags = 0; if unsafe { GetHandleInformation(socket.as_raw_socket() as _, &mut flags) } == 0 { let err = io::Error::last_os_error(); panic!("unexpected error: {}", err); From 25b2164f9b524bf6a80e43a8ff08677f2cd5479a Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Wed, 27 Apr 2022 14:21:24 +0200 Subject: [PATCH 2/2] Support Socket::(set_)recv_tos on Windows --- src/socket.rs | 2 -- src/sys/windows.rs | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 591a4b2d..aa3e1588 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -1400,7 +1400,6 @@ impl Socket { target_os = "netbsd", target_os = "redox", target_os = "solaris", - target_os = "windows", )))] pub fn set_recv_tos(&self, recv_tos: bool) -> io::Result<()> { let recv_tos = if recv_tos { 1 } else { 0 }; @@ -1426,7 +1425,6 @@ impl Socket { target_os = "netbsd", target_os = "redox", target_os = "solaris", - target_os = "windows", )))] pub fn recv_tos(&self) -> io::Result { unsafe { diff --git a/src/sys/windows.rs b/src/sys/windows.rs index fe9130fa..8b1d0c0f 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -69,9 +69,9 @@ pub(crate) use windows_sys::Win32::Networking::WinSock::{ IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, IP_MREQ as IpMreq, IP_MREQ_SOURCE as IpMreqSource, IP_MULTICAST_IF, IP_MULTICAST_LOOP, - IP_MULTICAST_TTL, IP_TOS, IP_TTL, MSG_OOB, MSG_PEEK, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, - SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, - TCP_NODELAY, + IP_MULTICAST_TTL, IP_RECVTOS, IP_TOS, IP_TTL, MSG_OOB, MSG_PEEK, SO_BROADCAST, SO_ERROR, + SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, + SO_SNDTIMEO, SO_TYPE, TCP_NODELAY, }; pub(crate) const IPPROTO_IP: c_int = windows_sys::Win32::Networking::WinSock::IPPROTO_IP as c_int; pub(crate) const SOL_SOCKET: c_int = windows_sys::Win32::Networking::WinSock::SOL_SOCKET as c_int;