aboutsummaryrefslogtreecommitdiff
path: root/src/sys/windows
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-11-16 17:42:39 -0800
committerHaibo Huang <hhb@google.com>2020-11-16 17:42:39 -0800
commitb871bf78acdb643f7b39ac9d1110ab94d886d7d1 (patch)
tree9953974f4f90698632f6dcdcb001e8f962af4dbd /src/sys/windows
parent8414138e74aa469015108049230e70b0a325c6e9 (diff)
downloadmio-b871bf78acdb643f7b39ac9d1110ab94d886d7d1.tar.gz
Upgrade rust/crates/mio to 0.7.6
Test: make Change-Id: I26de17b65a22ec1ba472a61c51b55681afdb8ffa
Diffstat (limited to 'src/sys/windows')
-rw-r--r--src/sys/windows/afd.rs9
-rw-r--r--src/sys/windows/event.rs2
-rw-r--r--src/sys/windows/io_status_block.rs3
-rw-r--r--src/sys/windows/mod.rs16
-rw-r--r--src/sys/windows/net.rs80
-rw-r--r--src/sys/windows/overlapped.rs6
-rw-r--r--src/sys/windows/selector.rs4
-rw-r--r--src/sys/windows/tcp.rs205
-rw-r--r--src/sys/windows/udp.rs2
9 files changed, 270 insertions, 57 deletions
diff --git a/src/sys/windows/afd.rs b/src/sys/windows/afd.rs
index b2e3b11..bf3704d 100644
--- a/src/sys/windows/afd.rs
+++ b/src/sys/windows/afd.rs
@@ -112,17 +112,16 @@ impl Afd {
}
cfg_io_source! {
- use miow::iocp::CompletionPort;
- use ntapi::ntioapi::FILE_OPEN;
- use ntapi::ntioapi::NtCreateFile;
use std::mem::zeroed;
use std::os::windows::io::{FromRawHandle, RawHandle};
use std::sync::atomic::{AtomicUsize, Ordering};
+
+ use miow::iocp::CompletionPort;
+ use ntapi::ntioapi::{NtCreateFile, FILE_OPEN};
use winapi::shared::ntdef::{OBJECT_ATTRIBUTES, UNICODE_STRING, USHORT, WCHAR};
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::winbase::{SetFileCompletionNotificationModes, FILE_SKIP_SET_EVENT_ON_HANDLE};
- use winapi::um::winnt::SYNCHRONIZE;
- use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE};
+ use winapi::um::winnt::{SYNCHRONIZE, FILE_SHARE_READ, FILE_SHARE_WRITE};
const AFD_HELPER_ATTRIBUTES: OBJECT_ATTRIBUTES = OBJECT_ATTRIBUTES {
Length: size_of::<OBJECT_ATTRIBUTES>() as ULONG,
diff --git a/src/sys/windows/event.rs b/src/sys/windows/event.rs
index 235074a..4d04e64 100644
--- a/src/sys/windows/event.rs
+++ b/src/sys/windows/event.rs
@@ -26,7 +26,7 @@ impl Event {
self.flags |= afd::POLL_RECEIVE
}
- #[cfg(feature = "os-util")]
+ #[cfg(feature = "os-ext")]
pub(super) fn set_writable(&mut self) {
self.flags |= afd::POLL_SEND;
}
diff --git a/src/sys/windows/io_status_block.rs b/src/sys/windows/io_status_block.rs
index 9da5e7a..3e60334 100644
--- a/src/sys/windows/io_status_block.rs
+++ b/src/sys/windows/io_status_block.rs
@@ -1,7 +1,8 @@
-use ntapi::ntioapi::IO_STATUS_BLOCK;
use std::fmt;
use std::ops::{Deref, DerefMut};
+use ntapi::ntioapi::IO_STATUS_BLOCK;
+
pub struct IoStatusBlock(IO_STATUS_BLOCK);
cfg_io_source! {
diff --git a/src/sys/windows/mod.rs b/src/sys/windows/mod.rs
index 25590c2..98b6fc6 100644
--- a/src/sys/windows/mod.rs
+++ b/src/sys/windows/mod.rs
@@ -25,26 +25,20 @@ cfg_net! {
}
}};
}
-}
-cfg_tcp! {
- pub(crate) mod tcp;
-}
+ mod net;
-cfg_udp! {
+ pub(crate) mod tcp;
pub(crate) mod udp;
}
-#[cfg(feature = "os-util")]
-pub(crate) mod named_pipe;
+cfg_os_ext! {
+ pub(crate) mod named_pipe;
+}
mod waker;
pub(crate) use waker::Waker;
-cfg_net! {
- mod net;
-}
-
cfg_io_source! {
use std::io;
use std::os::windows::io::RawSocket;
diff --git a/src/sys/windows/net.rs b/src/sys/windows/net.rs
index f825ee3..2de98fa 100644
--- a/src/sys/windows/net.rs
+++ b/src/sys/windows/net.rs
@@ -1,13 +1,14 @@
use std::io;
-use std::mem::size_of_val;
+use std::mem;
use std::net::SocketAddr;
use std::sync::Once;
use winapi::ctypes::c_int;
-use winapi::shared::ws2def::SOCKADDR;
-use winapi::um::winsock2::{
- ioctlsocket, socket, FIONBIO, INVALID_SOCKET, SOCKET,
-};
+use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR};
+use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR};
+use winapi::shared::ws2def::{AF_INET, AF_INET6, ADDRESS_FAMILY, SOCKADDR, SOCKADDR_IN};
+use winapi::shared::ws2ipdef::{SOCKADDR_IN6_LH, SOCKADDR_IN6_LH_u};
+use winapi::um::winsock2::{ioctlsocket, socket, FIONBIO, INVALID_SOCKET, SOCKET};
/// Initialise the network stack for Windows.
pub(crate) fn init() {
@@ -21,7 +22,6 @@ pub(crate) fn init() {
}
/// Create a new non-blocking socket.
-#[cfg(feature = "udp")]
pub(crate) fn new_ip_socket(addr: SocketAddr, socket_type: c_int) -> io::Result<SOCKET> {
use winapi::um::winsock2::{PF_INET, PF_INET6};
@@ -44,15 +44,65 @@ pub(crate) fn new_socket(domain: c_int, socket_type: c_int) -> io::Result<SOCKET
})
}
-pub(crate) fn socket_addr(addr: &SocketAddr) -> (*const SOCKADDR, c_int) {
+/// A type with the same memory layout as `SOCKADDR`. Used in converting Rust level
+/// SocketAddr* types into their system representation. The benefit of this specific
+/// type over using `SOCKADDR_STORAGE` is that this type is exactly as large as it
+/// needs to be and not a lot larger. And it can be initialized cleaner from Rust.
+#[repr(C)]
+pub(crate) union SocketAddrCRepr {
+ v4: SOCKADDR_IN,
+ v6: SOCKADDR_IN6_LH,
+}
+
+impl SocketAddrCRepr {
+ pub(crate) fn as_ptr(&self) -> *const SOCKADDR {
+ self as *const _ as *const SOCKADDR
+ }
+}
+
+pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) {
match addr {
- SocketAddr::V4(ref addr) => (
- addr as *const _ as *const SOCKADDR,
- size_of_val(addr) as c_int,
- ),
- SocketAddr::V6(ref addr) => (
- addr as *const _ as *const SOCKADDR,
- size_of_val(addr) as c_int,
- ),
+ SocketAddr::V4(ref addr) => {
+ // `s_addr` is stored as BE on all machine and the array is in BE order.
+ // So the native endian conversion method is used so that it's never swapped.
+ let sin_addr = unsafe {
+ let mut s_un = mem::zeroed::<in_addr_S_un>();
+ *s_un.S_addr_mut() = u32::from_ne_bytes(addr.ip().octets());
+ IN_ADDR { S_un: s_un }
+ };
+
+ let sockaddr_in = SOCKADDR_IN {
+ sin_family: AF_INET as ADDRESS_FAMILY,
+ sin_port: addr.port().to_be(),
+ sin_addr,
+ sin_zero: [0; 8],
+ };
+
+ let sockaddr = SocketAddrCRepr { v4: sockaddr_in };
+ (sockaddr, mem::size_of::<SOCKADDR_IN>() as c_int)
+ },
+ SocketAddr::V6(ref addr) => {
+ let sin6_addr = unsafe {
+ let mut u = mem::zeroed::<in6_addr_u>();
+ *u.Byte_mut() = addr.ip().octets();
+ IN6_ADDR { u }
+ };
+ 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_LH {
+ sin6_family: AF_INET6 as ADDRESS_FAMILY,
+ sin6_port: addr.port().to_be(),
+ sin6_addr,
+ sin6_flowinfo: addr.flowinfo(),
+ u,
+ };
+
+ let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 };
+ (sockaddr, mem::size_of::<SOCKADDR_IN6_LH>() as c_int)
+ }
}
}
diff --git a/src/sys/windows/overlapped.rs b/src/sys/windows/overlapped.rs
index 3708f9e..837b78b 100644
--- a/src/sys/windows/overlapped.rs
+++ b/src/sys/windows/overlapped.rs
@@ -3,9 +3,9 @@ use crate::sys::windows::Event;
use std::cell::UnsafeCell;
use std::fmt;
-use winapi::um::minwinbase::OVERLAPPED_ENTRY;
-#[cfg(feature = "os-util")]
+#[cfg(feature = "os-ext")]
use winapi::um::minwinbase::OVERLAPPED;
+use winapi::um::minwinbase::OVERLAPPED_ENTRY;
#[repr(C)]
pub(crate) struct Overlapped {
@@ -13,7 +13,7 @@ pub(crate) struct Overlapped {
pub(crate) callback: fn(&OVERLAPPED_ENTRY, Option<&mut Vec<Event>>),
}
-#[cfg(feature = "os-util")]
+#[cfg(feature = "os-ext")]
impl Overlapped {
pub(crate) fn new(cb: fn(&OVERLAPPED_ENTRY, Option<&mut Vec<Event>>)) -> Overlapped {
Overlapped {
diff --git a/src/sys/windows/selector.rs b/src/sys/windows/selector.rs
index df2c3f0..572a9a9 100644
--- a/src/sys/windows/selector.rs
+++ b/src/sys/windows/selector.rs
@@ -374,7 +374,7 @@ impl Selector {
self.inner.cp.clone()
}
- #[cfg(feature = "os-util")]
+ #[cfg(feature = "os-ext")]
pub(super) fn same_port(&self, other: &Arc<CompletionPort>) -> bool {
Arc::ptr_eq(&self.inner.cp, other)
}
@@ -749,4 +749,4 @@ cfg_net! {
flags
}
-} \ No newline at end of file
+}
diff --git a/src/sys/windows/tcp.rs b/src/sys/windows/tcp.rs
index b78d864..6757b44 100644
--- a/src/sys/windows/tcp.rs
+++ b/src/sys/windows/tcp.rs
@@ -1,21 +1,25 @@
use std::io;
+use std::convert::TryInto;
use std::mem::size_of;
-use std::net::{self, SocketAddr, SocketAddrV4, SocketAddrV6};
+use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::time::Duration;
+use std::ptr;
use std::os::windows::io::FromRawSocket;
use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib uses u32/u64.
-use winapi::ctypes::{c_char, c_int, c_ushort};
-use winapi::shared::ws2def::{SOCKADDR_STORAGE, AF_INET, SOCKADDR_IN};
+use winapi::ctypes::{c_char, c_int, c_ushort, c_ulong};
+use winapi::shared::ws2def::{SOCKADDR_STORAGE, AF_INET, AF_INET6, SOCKADDR_IN};
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH;
+use winapi::shared::mstcpip;
-use winapi::shared::minwindef::{BOOL, TRUE, FALSE};
+use winapi::shared::minwindef::{BOOL, TRUE, FALSE, DWORD, LPVOID, LPDWORD};
use winapi::um::winsock2::{
self, closesocket, linger, setsockopt, getsockopt, getsockname, PF_INET, PF_INET6, SOCKET, SOCKET_ERROR,
- SOCK_STREAM, SOL_SOCKET, SO_LINGER, SO_REUSEADDR,
+ SOCK_STREAM, SOL_SOCKET, SO_LINGER, SO_REUSEADDR, SO_RCVBUF, SO_SNDBUF, SO_KEEPALIVE, WSAIoctl, LPWSAOVERLAPPED,
};
use crate::sys::windows::net::{init, new_socket, socket_addr};
+use crate::net::TcpKeepalive;
pub(crate) type TcpSocket = SOCKET;
@@ -34,7 +38,7 @@ pub(crate) fn bind(socket: TcpSocket, addr: SocketAddr) -> io::Result<()> {
let (raw_addr, raw_addr_length) = socket_addr(&addr);
syscall!(
- bind(socket, raw_addr, raw_addr_length),
+ bind(socket, raw_addr.as_ptr(), raw_addr_length),
PartialEq::eq,
SOCKET_ERROR
)?;
@@ -47,7 +51,7 @@ pub(crate) fn connect(socket: TcpSocket, addr: SocketAddr) -> io::Result<net::Tc
let (raw_addr, raw_addr_length) = socket_addr(&addr);
let res = syscall!(
- connect(socket, raw_addr, raw_addr_length),
+ connect(socket, raw_addr.as_ptr(), raw_addr_length),
PartialEq::eq,
SOCKET_ERROR
);
@@ -107,28 +111,35 @@ pub(crate) fn get_reuseaddr(socket: TcpSocket) -> io::Result<bool> {
}
pub(crate) fn get_localaddr(socket: TcpSocket) -> io::Result<SocketAddr> {
- let mut addr: SOCKADDR_STORAGE = unsafe { std::mem::zeroed() };
- let mut length = std::mem::size_of_val(&addr) as c_int;
+ let mut storage: SOCKADDR_STORAGE = unsafe { std::mem::zeroed() };
+ let mut length = std::mem::size_of_val(&storage) as c_int;
match unsafe { getsockname(
socket,
- &mut addr as *mut _ as *mut _,
+ &mut storage as *mut _ as *mut _,
&mut length
) } {
SOCKET_ERROR => Err(io::Error::last_os_error()),
_ => {
- let storage: *const SOCKADDR_STORAGE = (&addr) as *const _;
- if addr.ss_family as c_int == AF_INET {
- let sock_addr : SocketAddrV4 = unsafe { *(storage as *const SOCKADDR_IN as *const _) };
- Ok(sock_addr.into())
+ if storage.ss_family as c_int == AF_INET {
+ // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
+ let addr: &SOCKADDR_IN = unsafe { &*(&storage as *const _ as *const SOCKADDR_IN) };
+ let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() };
+ let ip = Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4]);
+ let port = u16::from_be(addr.sin_port);
+ Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
+ } else if storage.ss_family as c_int == AF_INET6 {
+ // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
+ let addr: &SOCKADDR_IN6_LH = unsafe { &*(&storage as *const _ as *const SOCKADDR_IN6_LH) };
+ let ip = Ipv6Addr::from(*unsafe { addr.sin6_addr.u.Byte() });
+ let port = u16::from_be(addr.sin6_port);
+ let scope_id = unsafe { *addr.u.sin6_scope_id() };
+ Ok(SocketAddr::V6(SocketAddrV6::new(ip, port, addr.sin6_flowinfo, scope_id)))
} else {
- let sock_addr : SocketAddrV6 = unsafe { *(storage as *const SOCKADDR_IN6_LH as *const _) };
- Ok(sock_addr.into())
+ Err(std::io::ErrorKind::InvalidInput.into())
}
},
}
-
-
}
pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {
@@ -149,6 +160,164 @@ pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result
}
}
+pub(crate) fn get_linger(socket: TcpSocket) -> io::Result<Option<Duration>> {
+ let mut val: linger = unsafe { std::mem::zeroed() };
+ let mut len = size_of::<linger>() as c_int;
+
+ match unsafe { getsockopt(
+ socket,
+ SOL_SOCKET,
+ SO_LINGER,
+ &mut val as *mut _ as *mut _,
+ &mut len,
+ ) } {
+ SOCKET_ERROR => Err(io::Error::last_os_error()),
+ _ => {
+ if val.l_onoff == 0 {
+ Ok(None)
+ } else {
+ Ok(Some(Duration::from_secs(val.l_linger as u64)))
+ }
+ },
+ }
+}
+
+
+pub(crate) fn set_recv_buffer_size(socket: TcpSocket, size: u32) -> io::Result<()> {
+ let size = size.try_into().ok().unwrap_or_else(i32::max_value);
+ match unsafe { setsockopt(
+ socket,
+ SOL_SOCKET,
+ SO_RCVBUF,
+ &size as *const _ as *const c_char,
+ size_of::<c_int>() as c_int
+ ) } {
+ SOCKET_ERROR => Err(io::Error::last_os_error()),
+ _ => Ok(()),
+ }
+}
+
+pub(crate) fn get_recv_buffer_size(socket: TcpSocket) -> io::Result<u32> {
+ let mut optval: c_int = 0;
+ let mut optlen = size_of::<c_int>() as c_int;
+ match unsafe { getsockopt(
+ socket,
+ SOL_SOCKET,
+ SO_RCVBUF,
+ &mut optval as *mut _ as *mut _,
+ &mut optlen as *mut _,
+ ) } {
+ SOCKET_ERROR => Err(io::Error::last_os_error()),
+ _ => Ok(optval as u32),
+ }
+}
+
+pub(crate) fn set_send_buffer_size(socket: TcpSocket, size: u32) -> io::Result<()> {
+ let size = size.try_into().ok().unwrap_or_else(i32::max_value);
+ match unsafe { setsockopt(
+ socket,
+ SOL_SOCKET,
+ SO_SNDBUF,
+ &size as *const _ as *const c_char,
+ size_of::<c_int>() as c_int
+ ) } {
+ SOCKET_ERROR => Err(io::Error::last_os_error()),
+ _ => Ok(()),
+ }
+}
+
+pub(crate) fn get_send_buffer_size(socket: TcpSocket) -> io::Result<u32> {
+ let mut optval: c_int = 0;
+ let mut optlen = size_of::<c_int>() as c_int;
+ match unsafe { getsockopt(
+ socket,
+ SOL_SOCKET,
+ SO_SNDBUF,
+ &mut optval as *mut _ as *mut _,
+ &mut optlen as *mut _,
+ ) } {
+ SOCKET_ERROR => Err(io::Error::last_os_error()),
+ _ => Ok(optval as u32),
+ }
+}
+
+pub(crate) fn set_keepalive(socket: TcpSocket, keepalive: bool) -> io::Result<()> {
+ let val: BOOL = if keepalive { TRUE } else { FALSE };
+ match unsafe { setsockopt(
+ socket,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ &val as *const _ as *const c_char,
+ size_of::<BOOL>() as c_int
+ ) } {
+ SOCKET_ERROR => Err(io::Error::last_os_error()),
+ _ => Ok(()),
+ }
+}
+
+pub(crate) fn get_keepalive(socket: TcpSocket) -> io::Result<bool> {
+ let mut optval: c_char = 0;
+ let mut optlen = size_of::<BOOL>() as c_int;
+
+ match unsafe { getsockopt(
+ socket,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ &mut optval as *mut _ as *mut _,
+ &mut optlen,
+ ) } {
+ SOCKET_ERROR => Err(io::Error::last_os_error()),
+ _ => Ok(optval != FALSE as c_char),
+ }
+}
+
+pub(crate) fn set_keepalive_params(socket: TcpSocket, keepalive: TcpKeepalive) -> io::Result<()> {
+ /// Windows configures keepalive time/interval in a u32 of milliseconds.
+ fn dur_to_ulong_ms(dur: Duration) -> c_ulong {
+ dur.as_millis().try_into().ok().unwrap_or_else(u32::max_value)
+ }
+
+ // If any of the fields on the `tcp_keepalive` struct were not provided by
+ // the user, just leaving them zero will clobber any existing value.
+ // Unfortunately, we can't access the current value, so we will use the
+ // defaults if a value for the time or interval was not not provided.
+ let time = keepalive.time.unwrap_or_else(|| {
+ // The default value is two hours, as per
+ // https://docs.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals
+ let two_hours = 2 * 60 * 60;
+ Duration::from_secs(two_hours)
+ });
+
+ let interval = keepalive.interval.unwrap_or_else(|| {
+ // The default value is one second, as per
+ // https://docs.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals
+ Duration::from_secs(1)
+ });
+
+ let mut keepalive = mstcpip::tcp_keepalive {
+ // Enable keepalive
+ onoff: 1,
+ keepalivetime: dur_to_ulong_ms(time),
+ keepaliveinterval: dur_to_ulong_ms(interval),
+ };
+
+ let mut out = 0;
+ match unsafe { WSAIoctl(
+ socket,
+ mstcpip::SIO_KEEPALIVE_VALS,
+ &mut keepalive as *mut _ as LPVOID,
+ size_of::<mstcpip::tcp_keepalive>() as DWORD,
+ ptr::null_mut() as LPVOID,
+ 0 as DWORD,
+ &mut out as *mut _ as LPDWORD,
+ 0 as LPWSAOVERLAPPED,
+ None,
+ ) } {
+ 0 => Ok(()),
+ _ => Err(io::Error::last_os_error())
+ }
+}
+
pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, SocketAddr)> {
// The non-blocking state of `listener` is inherited. See
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept#remarks.
diff --git a/src/sys/windows/udp.rs b/src/sys/windows/udp.rs
index 667c775..ba2aeac 100644
--- a/src/sys/windows/udp.rs
+++ b/src/sys/windows/udp.rs
@@ -12,7 +12,7 @@ pub fn bind(addr: SocketAddr) -> io::Result<net::UdpSocket> {
new_ip_socket(addr, SOCK_DGRAM).and_then(|socket| {
let (raw_addr, raw_addr_length) = socket_addr(&addr);
syscall!(
- win_bind(socket, raw_addr, raw_addr_length,),
+ win_bind(socket, raw_addr.as_ptr(), raw_addr_length,),
PartialEq::eq,
SOCKET_ERROR
)