winapi_wsapoll/
lib.rs

1//! This crate provides a safe binding to `WSAPoll`.
2//!
3//! On non-windows, this crate is empty.
4//!
5//! # Minimum Rust version
6//!
7//! The minimum Rust version required by this crate is 1.34.
8
9#![deny(
10    rust_2018_idioms,
11    trivial_numeric_casts,
12    unreachable_pub,
13    unused_import_braces,
14    unused_must_use,
15    unused_qualifications
16)]
17
18#[cfg(windows)]
19pub use socket::wsa_poll;
20
21#[cfg(windows)]
22mod socket {
23    use std::convert::TryInto;
24    use std::io;
25
26    use winapi::shared::minwindef::INT;
27    use winapi::um::winsock2::{WSAGetLastError, WSAPoll, SOCKET_ERROR, WSAPOLLFD};
28
29    /// `wsa_poll` waits for one of a set of file descriptors to become ready to
30    /// perform I/O.
31    ///
32    /// This corresponds to calling [`WSAPoll`].
33    ///
34    /// [`WSAPoll`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll
35    pub fn wsa_poll(fd_array: &mut [WSAPOLLFD], timeout: INT) -> io::Result<usize> {
36        unsafe {
37            let length = fd_array.len().try_into().unwrap();
38            let rc = WSAPoll(fd_array.as_mut_ptr(), length, timeout);
39            if rc == SOCKET_ERROR {
40                return Err(io::Error::from_raw_os_error(WSAGetLastError()));
41            };
42            Ok(rc.try_into().unwrap())
43        }
44    }
45
46    #[cfg(test)]
47    mod test {
48        use std::io::{Result, Write};
49        use std::net::{TcpListener, TcpStream};
50        use std::os::windows::io::{AsRawSocket, RawSocket};
51
52        use winapi::um::winnt::SHORT;
53        use winapi::um::winsock2::{POLLIN, POLLOUT, POLLRDNORM, WSAPOLLFD};
54
55        use super::wsa_poll;
56
57        /// Get a pair of connected TcpStreams
58        fn get_connection_pair() -> Result<(TcpStream, TcpStream)> {
59            let listener = TcpListener::bind("127.0.0.1:0")?;
60            let stream1 = TcpStream::connect(listener.local_addr()?)?;
61            let stream2 = listener.accept()?.0;
62
63            Ok((stream1, stream2))
64        }
65
66        fn poll(socket: RawSocket, events: SHORT, revents: SHORT) -> Result<()> {
67            let mut sockets = [WSAPOLLFD {
68                fd: socket as _,
69                events,
70                revents: 0,
71            }];
72            let count = wsa_poll(&mut sockets, -1)?;
73            assert_eq!(count, 1);
74            assert_eq!(sockets[0].revents, revents);
75
76            Ok(())
77        }
78
79        #[test]
80        fn test_poll() -> Result<()> {
81            let (mut stream1, stream2) = get_connection_pair()?;
82
83            // Check that stream1 is writable
84            poll(stream1.as_raw_socket(), POLLOUT, POLLOUT)?;
85
86            // Write something to the stream
87            stream1.write_all(b"1")?;
88
89            // stream2 should now be readable and writable
90            poll(
91                stream2.as_raw_socket(),
92                POLLIN | POLLOUT,
93                POLLOUT | POLLRDNORM,
94            )?;
95
96            Ok(())
97        }
98    }
99}