Skip to content

Commit 15185a6

Browse files
committed
Poll support for Winsock2.
Winsock2 has a POSIX-like `poll` function named `WSAPoll`, along with associated `POLL*` flags, so add rustix support for using it. To support this, fold the `AsSocketAsFd` trait into `AsFd` so that users can simply use `AsFd` on Windows when working with the Winsock2 APIs.
1 parent b567f1c commit 15185a6

File tree

14 files changed

+183
-32
lines changed

14 files changed

+183
-32
lines changed

src/imp/libc/c.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ pub(crate) use winapi::ctypes::*;
2626
pub(crate) use winapi::shared::basetsd::SSIZE_T as ssize_t;
2727

2828
pub(crate) use winapi::um::winsock2::{
29-
closesocket as close, ioctlsocket as ioctl, linger, SOL_SOCKET, SO_BROADCAST, SO_LINGER,
30-
SO_RCVTIMEO, SO_REUSEADDR, SO_SNDTIMEO, SO_TYPE, WSAEACCES as EACCES,
29+
closesocket as close, ioctlsocket as ioctl, linger, WSAPoll as poll, SOL_SOCKET, SO_BROADCAST,
30+
SO_LINGER, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDTIMEO, SO_TYPE, WSAEACCES as EACCES,
3131
WSAEADDRINUSE as EADDRINUSE, WSAEADDRNOTAVAIL as EADDRNOTAVAIL,
3232
WSAEAFNOSUPPORT as EAFNOSUPPORT, WSAEALREADY as EALREADY, WSAEBADF as EBADF,
3333
WSAECANCELLED as ECANCELED, WSAECONNABORTED as ECONNABORTED, WSAECONNREFUSED as ECONNREFUSED,
@@ -45,7 +45,7 @@ pub(crate) use winapi::um::winsock2::{
4545
WSAEPROVIDERFAILEDINIT as EPROVIDERFAILEDINIT, WSAEREFUSED as EREFUSED, WSAEREMOTE as EREMOTE,
4646
WSAESHUTDOWN as ESHUTDOWN, WSAESOCKTNOSUPPORT as ESOCKTNOSUPPORT, WSAESTALE as ESTALE,
4747
WSAETIMEDOUT as ETIMEDOUT, WSAETOOMANYREFS as ETOOMANYREFS, WSAEUSERS as EUSERS,
48-
WSAEWOULDBLOCK as EWOULDBLOCK, WSAEWOULDBLOCK as EAGAIN, *,
48+
WSAEWOULDBLOCK as EWOULDBLOCK, WSAEWOULDBLOCK as EAGAIN, WSAPOLLFD as pollfd, *,
4949
};
5050

5151
// [Documented] values for the `how` argument to `shutdown`.

src/imp/libc/io/mod.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ mod error;
22
#[cfg(not(windows))]
33
#[cfg(not(feature = "std"))]
44
mod io_slice;
5-
#[cfg(not(windows))]
65
mod poll_fd;
76
#[cfg(not(windows))]
87
mod types;
@@ -12,11 +11,13 @@ pub(crate) mod syscalls;
1211

1312
#[cfg(windows)]
1413
pub(crate) mod syscalls {
15-
use super::super::conv::{borrowed_fd, ret};
14+
use super::super::conv::{borrowed_fd, ret, ret_c_int};
1615
use super::super::fd::LibcFd;
1716
use super::c;
1817
use crate::fd::{BorrowedFd, RawFd};
1918
use crate::io;
19+
use crate::io::PollFd;
20+
use core::convert::TryInto;
2021

2122
pub(crate) unsafe fn close(raw_fd: RawFd) {
2223
let _ = c::close(raw_fd as LibcFd);
@@ -28,6 +29,16 @@ pub(crate) mod syscalls {
2829
ret(c::ioctl(borrowed_fd(fd), c::FIONBIO, &mut data))
2930
}
3031
}
32+
33+
pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> {
34+
let nfds = fds
35+
.len()
36+
.try_into()
37+
.map_err(|_convert_err| io::Error::INVAL)?;
38+
39+
ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) })
40+
.map(|nready| nready as usize)
41+
}
3142
}
3243

3344
#[cfg(not(windows))]
@@ -36,7 +47,6 @@ pub use io_slice::{IoSlice, IoSliceMut};
3647
#[cfg(any(target_os = "android", target_os = "linux"))]
3748
pub mod epoll;
3849
pub use error::Error;
39-
#[cfg(not(windows))]
4050
pub use poll_fd::{PollFd, PollFlags};
4151
#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))]
4252
pub use types::Advice;

src/imp/libc/io/poll_fd.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
use super::super::c;
22
use super::super::conv::borrowed_fd;
3-
use crate::fd::{AsFd, AsRawFd, BorrowedFd};
3+
#[cfg(windows)]
4+
use super::super::fd::RawFd;
5+
use super::super::fd::{AsFd, AsRawFd, BorrowedFd, LibcFd};
46
use bitflags::bitflags;
57
use core::marker::PhantomData;
8+
#[cfg(windows)]
9+
use std::fmt;
610

711
bitflags! {
812
/// `POLL*` flags for use with [`poll`].
@@ -47,13 +51,25 @@ bitflags! {
4751
///
4852
/// [`poll`]: rustix::io::poll
4953
#[doc(alias = "pollfd")]
50-
#[derive(Clone, Debug)]
54+
#[derive(Clone)]
55+
#[cfg_attr(not(windows), derive(Debug))]
5156
#[repr(transparent)]
5257
pub struct PollFd<'fd> {
5358
pollfd: c::pollfd,
5459
_phantom: PhantomData<BorrowedFd<'fd>>,
5560
}
5661

62+
#[cfg(windows)]
63+
impl<'fd> fmt::Debug for PollFd<'fd> {
64+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
65+
fmt.debug_struct("pollfd")
66+
.field("fd", &self.pollfd.fd)
67+
.field("events", &self.pollfd.events)
68+
.field("revents", &self.pollfd.revents)
69+
.finish()
70+
}
71+
}
72+
5773
impl<'fd> PollFd<'fd> {
5874
/// Constructs a new `PollFd` holding `fd` and `events`.
5975
#[inline]
@@ -64,7 +80,7 @@ impl<'fd> PollFd<'fd> {
6480
/// Sets the contained file descriptor to `fd`.
6581
#[inline]
6682
pub fn set_fd<Fd: AsFd>(&mut self, fd: &'fd Fd) {
67-
self.pollfd.fd = fd.as_fd().as_raw_fd();
83+
self.pollfd.fd = fd.as_fd().as_raw_fd() as LibcFd;
6884
}
6985

7086
/// Constructs a new `PollFd` holding `fd` and `events`.
@@ -93,6 +109,7 @@ impl<'fd> PollFd<'fd> {
93109
}
94110
}
95111

112+
#[cfg(not(windows))]
96113
impl<'fd> AsFd for PollFd<'fd> {
97114
#[inline]
98115
fn as_fd(&self) -> BorrowedFd<'_> {
@@ -103,3 +120,15 @@ impl<'fd> AsFd for PollFd<'fd> {
103120
unsafe { BorrowedFd::borrow_raw_fd(self.pollfd.fd) }
104121
}
105122
}
123+
124+
#[cfg(windows)]
125+
impl<'fd> io_lifetimes::AsSocket for PollFd<'fd> {
126+
#[inline]
127+
fn as_socket(&self) -> BorrowedFd<'_> {
128+
// Safety:
129+
//
130+
// Our constructors and `set_fd` require `pollfd.fd` to be valid
131+
// for the `fd lifetime.
132+
unsafe { BorrowedFd::borrow_raw_socket(self.pollfd.fd as RawFd) }
133+
}
134+
}

src/imp/libc/io_lifetimes.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,11 @@ impl<T: std::os::windows::io::FromRawSocket> FromRawFd for T {
6262
/// A version of [`AsFd`] for use with Winsock2 API.
6363
///
6464
/// [`AsFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsFd.html
65-
pub use io_lifetimes::AsSocket as AsFd;
66-
67-
/// We define `AsFd` as an alias for `AsSocket`, but that doesn't provide
68-
/// an `as_fd` function. This trait adapts an `AsSocket` implementation to
69-
/// provide `as_fd` using a blanket implementation.
70-
pub(crate) trait AsSocketAsFd {
65+
pub trait AsFd {
66+
/// An `as_fd` function for Winsock2, where a `Fd` is a `Socket`.
7167
fn as_fd(&self) -> BorrowedFd;
7268
}
73-
impl<T: io_lifetimes::AsSocket> AsSocketAsFd for T {
69+
impl<T: io_lifetimes::AsSocket> AsFd for T {
7470
#[inline]
7571
fn as_fd(&self) -> BorrowedFd {
7672
self.as_socket()

src/io/ioctl.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
use crate::io::{Termios, Winsize};
88
use crate::{imp, io};
99
use imp::fd::AsFd;
10-
#[cfg(windows)]
11-
use imp::fd::AsSocketAsFd;
1210

1311
/// `ioctl(fd, TCGETS)`—Get terminal attributes.
1412
///

src/io/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ mod msync;
2626
mod owned_fd;
2727
#[cfg(not(any(windows, target_os = "wasi")))]
2828
mod pipe;
29-
#[cfg(not(windows))]
3029
mod poll;
3130
#[cfg(all(feature = "procfs", any(target_os = "android", target_os = "linux")))]
3231
mod procfs;
@@ -82,7 +81,6 @@ pub use owned_fd::OwnedFd;
8281
pub use pipe::pipe;
8382
#[cfg(not(any(windows, target_os = "ios", target_os = "macos", target_os = "wasi")))]
8483
pub use pipe::{pipe_with, PipeFlags};
85-
#[cfg(not(windows))]
8684
pub use poll::{poll, PollFd, PollFlags};
8785
#[cfg(all(feature = "procfs", any(target_os = "android", target_os = "linux")))]
8886
pub use procfs::{proc_self_fd, proc_self_fdinfo_fd, proc_self_maps, proc_self_pagemap};

src/io/owned_fd.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
//! file descriptor and close it ourselves.
1212
#![allow(unsafe_code)]
1313

14-
#[cfg(windows)]
15-
use crate::imp::fd::AsSocketAsFd;
1614
use crate::imp::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
1715
#[cfg(all(not(io_lifetimes_use_std), feature = "std"))]
1816
use crate::imp::fd::{FromFd, IntoFd};
@@ -29,14 +27,16 @@ pub struct OwnedFd {
2927
inner: ManuallyDrop<crate::imp::fd::OwnedFd>,
3028
}
3129

30+
#[cfg(not(windows))]
3231
impl AsFd for OwnedFd {
33-
#[cfg(not(windows))]
3432
#[inline]
3533
fn as_fd(&self) -> BorrowedFd<'_> {
3634
self.inner.as_fd()
3735
}
36+
}
3837

39-
#[cfg(windows)]
38+
#[cfg(windows)]
39+
impl io_lifetimes::AsSocket for OwnedFd {
4040
#[inline]
4141
fn as_socket(&self) -> BorrowedFd<'_> {
4242
self.inner.as_socket()

src/net/send_recv.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ use crate::net::SocketAddrUnix;
55
use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6};
66
use crate::{imp, io};
77
use imp::fd::AsFd;
8-
#[cfg(windows)]
9-
use imp::fd::AsSocketAsFd;
108

119
pub use imp::net::{RecvFlags, SendFlags};
1210

src/net/socket.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ use crate::io::{self, OwnedFd};
44
use crate::net::SocketAddrUnix;
55
use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6};
66
use imp::fd::AsFd;
7-
#[cfg(windows)]
8-
use imp::fd::AsSocketAsFd;
97

108
pub use imp::net::{AcceptFlags, AddressFamily, Protocol, Shutdown, SocketFlags, SocketType};
119

src/net/sockopt.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ use crate::net::{Ipv4Addr, Ipv6Addr, SocketType};
1010
use crate::{imp, io};
1111
use core::time::Duration;
1212
use imp::fd::AsFd;
13-
#[cfg(windows)]
14-
use imp::fd::AsSocketAsFd;
1513

1614
pub use imp::net::Timeout;
1715

0 commit comments

Comments
 (0)