Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for UnixStream and UnixListener on Windows #1610

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7f69b97
add first pass implementation of windows uds
sullivan-sean Aug 15, 2022
bec570b
modify src/net for windows compatibility
sullivan-sean Aug 15, 2022
63e50c3
fix tests
sullivan-sean Aug 16, 2022
3591238
add docs back in
sullivan-sean Aug 16, 2022
9015ca2
cleanup
sullivan-sean Aug 16, 2022
7265833
remove log statements
sullivan-sean Aug 16, 2022
3884bb5
clean up selector
sullivan-sean Aug 16, 2022
5ca8952
clean up stream and listener sys logic
sullivan-sean Aug 18, 2022
985a145
fix re-registration
sullivan-sean Aug 18, 2022
f5ec8ce
add test for serial calls to listener.accept
sullivan-sean Aug 18, 2022
cee5c6b
fix serial calls to accept
sullivan-sean Aug 18, 2022
488254d
remove tempfile dependency and fix doc tests
sullivan-sean Aug 18, 2022
b6bae73
revert change in draining behavior
sullivan-sean Aug 20, 2022
2113b9f
re-organize stdnet files to mirror std::os::unix::net
sullivan-sean Aug 21, 2022
86c4c9a
use single syscall vectored approach from rust-lang/socket2
sullivan-sean Aug 21, 2022
9f26286
lint
sullivan-sean Aug 21, 2022
09a9b79
improve support across feature matrix
sullivan-sean Aug 21, 2022
bb914db
fix doc tests
sullivan-sean Aug 22, 2022
648855d
use bcrypt instead of rand
sullivan-sean Aug 22, 2022
3dd3c0f
add -_ to random char set to avoid rejection sampling
sullivan-sean Aug 22, 2022
2283d39
optimize rng syscall logic
sullivan-sean Aug 22, 2022
569de72
fix lint and fmt
sullivan-sean Aug 22, 2022
bdc6933
remove unused functions
sullivan-sean Aug 22, 2022
b07b4f1
fmt
sullivan-sean Aug 26, 2022
a2831ea
simplify windows mod
sullivan-sean Aug 26, 2022
73d5fae
clean up tests
sullivan-sean Aug 26, 2022
0baf112
fix indentation, imports, address other comments
sullivan-sean Aug 26, 2022
d9d4bb3
fmt
sullivan-sean Aug 26, 2022
82b17e8
remove unrelated code changes
sullivan-sean Sep 12, 2022
96e0735
fix lint
sullivan-sean Sep 12, 2022
0e1b6df
remove explicit SetHandleInformation calls
sullivan-sean Sep 13, 2022
77155cc
abstract socketaddr behind common API in net
sullivan-sean Sep 13, 2022
26a060b
fix lint
sullivan-sean Sep 13, 2022
fd8ddc1
add comment clarifying inheritance during calls to accept
sullivan-sean Oct 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,17 @@ log = "0.4.8"
[target.'cfg(unix)'.dependencies]
libc = "0.2.121"

[target.'cfg(windows)'.dependencies]
tempfile = "3"
sullivan-sean marked this conversation as resolved.
Show resolved Hide resolved

[target.'cfg(windows)'.dependencies.windows-sys]
version = "0.36"
features = [
"Win32_Storage_FileSystem", # Enables NtCreateFile
"Win32_Foundation", # Basic types eg HANDLE
"Win32_Networking_WinSock", # winsock2 types/functions
"Win32_System_IO", # IO types like OVERLAPPED etc
"Win32_System_Threading", # Process utilities
"Win32_System_WindowsProgramming", # General future used for various types/funcs
]

Expand Down
8 changes: 6 additions & 2 deletions src/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ mod udp;
#[cfg(not(target_os = "wasi"))]
pub use self::udp::UdpSocket;

#[cfg(unix)]
#[cfg(any(unix, windows))]
mod uds;
#[cfg(any(unix, windows))]
pub use self::uds::{SocketAddr, UnixListener, UnixStream};
#[cfg(unix)]
pub use self::uds::{SocketAddr, UnixDatagram, UnixListener, UnixStream};
pub use self::uds::UnixDatagram;
#[cfg(windows)]
pub use self::uds::stdnet;
30 changes: 30 additions & 0 deletions src/net/uds/listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ use crate::io_source::IoSource;
use crate::net::{SocketAddr, UnixStream};
use crate::{event, sys, Interest, Registry, Token};

#[cfg(unix)]
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg(unix)]
use std::os::unix::net;
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
#[cfg(windows)]
use crate::sys::uds::{stdnet as net};
use std::path::Path;
use std::{fmt, io};

Expand Down Expand Up @@ -79,18 +85,21 @@ impl fmt::Debug for UnixListener {
}
}

#[cfg(unix)]
sullivan-sean marked this conversation as resolved.
Show resolved Hide resolved
impl IntoRawFd for UnixListener {
fn into_raw_fd(self) -> RawFd {
self.inner.into_inner().into_raw_fd()
}
}

#[cfg(unix)]
impl AsRawFd for UnixListener {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}

#[cfg(unix)]
impl FromRawFd for UnixListener {
/// Converts a `RawFd` to a `UnixListener`.
///
Expand All @@ -102,3 +111,24 @@ impl FromRawFd for UnixListener {
UnixListener::from_std(FromRawFd::from_raw_fd(fd))
}
}

#[cfg(windows)]
impl IntoRawSocket for UnixListener {
fn into_raw_socket(self) -> RawSocket {
self.inner.into_inner().into_raw_socket()
}
}

#[cfg(windows)]
impl AsRawSocket for UnixListener {
fn as_raw_socket(&self) -> RawSocket {
self.inner.as_raw_socket()
}
}

#[cfg(windows)]
impl FromRawSocket for UnixListener {
unsafe fn from_raw_socket(sock: RawSocket) -> Self {
UnixListener::from_std(FromRawSocket::from_raw_socket(sock))
}
}
5 changes: 5 additions & 0 deletions src/net/uds/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#[cfg(unix)]
mod datagram;
#[cfg(unix)]
sullivan-sean marked this conversation as resolved.
Show resolved Hide resolved
pub use self::datagram::UnixDatagram;

mod listener;
Expand All @@ -8,3 +10,6 @@ mod stream;
pub use self::stream::UnixStream;

pub use crate::sys::SocketAddr;

#[cfg(windows)]
pub use crate::sys::uds::stdnet;
30 changes: 30 additions & 0 deletions src/net/uds/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ use crate::{event, sys, Interest, Registry, Token};
use std::fmt;
use std::io::{self, IoSlice, IoSliceMut, Read, Write};
use std::net::Shutdown;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg(unix)]
use std::os::unix::net;
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
#[cfg(windows)]
use crate::sys::uds::{stdnet as net};
use std::path::Path;

/// A non-blocking Unix stream socket.
Expand Down Expand Up @@ -220,18 +226,21 @@ impl fmt::Debug for UnixStream {
}
}

#[cfg(unix)]
sullivan-sean marked this conversation as resolved.
Show resolved Hide resolved
impl IntoRawFd for UnixStream {
fn into_raw_fd(self) -> RawFd {
self.inner.into_inner().into_raw_fd()
}
}

#[cfg(unix)]
impl AsRawFd for UnixStream {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}

#[cfg(unix)]
impl FromRawFd for UnixStream {
/// Converts a `RawFd` to a `UnixStream`.
///
Expand All @@ -243,3 +252,24 @@ impl FromRawFd for UnixStream {
UnixStream::from_std(FromRawFd::from_raw_fd(fd))
}
}

#[cfg(windows)]
impl IntoRawSocket for UnixStream {
fn into_raw_socket(self) -> RawSocket {
self.inner.into_inner().into_raw_socket()
}
}

#[cfg(windows)]
impl AsRawSocket for UnixStream {
fn as_raw_socket(&self) -> RawSocket {
self.inner.as_raw_socket()
}
}

#[cfg(windows)]
impl FromRawSocket for UnixStream {
unsafe fn from_raw_socket(sock: RawSocket) -> Self {
UnixStream::from_std(FromRawSocket::from_raw_socket(sock))
}
}
7 changes: 6 additions & 1 deletion src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ cfg_os_poll! {

#[cfg(windows)]
cfg_os_poll! {
mod windows;
pub mod windows;
pub use self::windows::*;
}

Expand All @@ -83,4 +83,9 @@ cfg_not_os_poll! {
cfg_net! {
pub use self::unix::SocketAddr;
}

#[cfg(windows)]
cfg_net! {
pub use self::windows::SocketAddr;
}
}
18 changes: 18 additions & 0 deletions src/sys/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,28 @@ cfg_net! {
}};
}

macro_rules! wsa_syscall {
($fn: ident ( $($arg: expr),* $(,)* ), $err_test: path, $err_value: expr) => {{
let res = unsafe { $fn($($arg, )*) };
if $err_test(&res, &$err_value) {
use windows_sys::Win32::Networking::WinSock::WSAGetLastError;
Err(io::Error::from_raw_os_error(unsafe {
WSAGetLastError()
}))
} else {
Ok(res)
}
}};
}

mod net;

pub(crate) mod tcp;
pub(crate) mod udp;
pub mod uds;
pub use self::uds::SocketAddr;
#[cfg(all(windows, test))]
pub use self::uds::stdnet;
}

cfg_os_ext! {
Expand Down
7 changes: 5 additions & 2 deletions src/sys/windows/selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,12 @@ impl SockState {
cfg_io_source! {
impl SockState {
fn new(raw_socket: RawSocket, afd: Arc<Afd>) -> io::Result<SockState> {
let base = get_base_socket(raw_socket)?;
Ok(SockState {
iosb: IoStatusBlock::zeroed(),
poll_info: AfdPollInfo::zeroed(),
afd,
base_socket: get_base_socket(raw_socket)?,
base_socket: base,
user_evts: 0,
pending_evts: 0,
user_data: 0,
Expand Down Expand Up @@ -658,6 +659,7 @@ cfg_io_source! {
}
}

#[allow(dead_code)]
fn get_base_socket(raw_socket: RawSocket) -> io::Result<RawSocket> {
let res = try_get_base_socket(raw_socket, SIO_BASE_HANDLE);
if let Ok(base_socket) = res {
Expand All @@ -674,7 +676,8 @@ cfg_io_source! {
SIO_BSP_HANDLE_POLL,
SIO_BSP_HANDLE,
] {
if let Ok(base_socket) = try_get_base_socket(raw_socket, ioctl) {
let r = try_get_base_socket(raw_socket, ioctl);
if let Ok(base_socket) = r {
// Since we know now that we're dealing with an LSP (otherwise
// SIO_BASE_HANDLE would't have failed), only return any result
// when it is different from the original `raw_socket`.
Expand Down
70 changes: 70 additions & 0 deletions src/sys/windows/uds/listener.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::{io, mem};
use std::convert::TryInto;
use std::os::windows::io::{AsRawSocket, FromRawSocket};
use std::path::Path;
use std::os::raw::c_int;
use windows_sys::Win32::Networking::WinSock::{
self,
SOCKET_ERROR,
INVALID_SOCKET,
bind as sys_bind,
listen,
accept as sys_accept
};

use super::stdnet::{self as net, socket_addr};
use crate::net::{SocketAddr, UnixStream};
use crate::sys::windows::net::{init, new_socket};

pub(crate) fn bind(path: &Path) -> io::Result<net::UnixListener> {
init();
let socket = new_socket(WinSock::AF_UNIX.into(), WinSock::SOCK_STREAM)?;
let (sockaddr, socklen) = socket_addr(path)?;
let sockaddr = &sockaddr as *const WinSock::sockaddr_un as *const WinSock::SOCKADDR;

wsa_syscall!(sys_bind(socket, sockaddr, socklen as _), PartialEq::eq, SOCKET_ERROR)
.and_then(|_| wsa_syscall!(listen(socket, 128), PartialEq::eq, SOCKET_ERROR))
.map_err(|err| {
// Close the socket if we hit an error, ignoring the error from
// closing since we can't pass back two errors.
let _ = unsafe { WinSock::closesocket(socket) };
err
})
.map(|_| unsafe { net::UnixListener::from_raw_socket(socket.try_into().unwrap()) })
}

pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> {
let sockaddr = mem::MaybeUninit::<WinSock::sockaddr_un>::zeroed();

// This is safe to assume because a `WinSock::sockaddr_un` filled with `0`
// bytes is properly initialized.
//
// `0` is a valid value for `sockaddr_un::sun_family`; it is
// `WinSock::AF_UNSPEC`.
//
// `[0; 108]` is a valid value for `sockaddr_un::sun_path`; it begins an
// abstract path.
let mut sockaddr = unsafe { sockaddr.assume_init() };

sockaddr.sun_family = WinSock::AF_UNIX;
let mut socklen = mem::size_of_val(&sockaddr) as c_int;

let socket = wsa_syscall!(
sys_accept(
listener.as_raw_socket().try_into().unwrap(),
&mut sockaddr as *mut WinSock::sockaddr_un as *mut WinSock::SOCKADDR,
&mut socklen as _
),
PartialEq::eq,
INVALID_SOCKET
);

socket
.map(|socket| unsafe { net::UnixStream::from_raw_socket(socket.try_into().unwrap()) })
.map(UnixStream::from_std)
.map(|stream| (stream, SocketAddr::from_parts(sockaddr, socklen)))
}

pub(crate) fn local_addr(listener: &net::UnixListener) -> io::Result<SocketAddr> {
super::local_addr(listener.as_raw_socket())
}
36 changes: 36 additions & 0 deletions src/sys/windows/uds/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
pub mod stdnet;
pub use self::stdnet::SocketAddr;

cfg_os_poll! {
use std::convert::TryInto;
use windows_sys::Win32::Networking::WinSock::{
getsockname,
getpeername,
SOCKET_ERROR
};
use std::os::windows::io::RawSocket;
use std::io;

pub(crate) mod listener;
pub(crate) mod stream;

pub(crate) fn local_addr(socket: RawSocket) -> io::Result<SocketAddr> {
SocketAddr::new(|sockaddr, socklen| {
wsa_syscall!(
getsockname(socket.try_into().unwrap(), sockaddr, socklen),
PartialEq::eq,
SOCKET_ERROR
)
})
}

pub(crate) fn peer_addr(socket: RawSocket) -> io::Result<SocketAddr> {
SocketAddr::new(|sockaddr, socklen| {
wsa_syscall!(
getpeername(socket.try_into().unwrap(), sockaddr, socklen),
PartialEq::eq,
SOCKET_ERROR
)
})
}
}
Loading