diff options
author | Haibo Huang <hhb@google.com> | 2020-11-16 17:42:39 -0800 |
---|---|---|
committer | Haibo Huang <hhb@google.com> | 2020-11-16 17:42:39 -0800 |
commit | b871bf78acdb643f7b39ac9d1110ab94d886d7d1 (patch) | |
tree | 9953974f4f90698632f6dcdcb001e8f962af4dbd /src/sys/windows | |
parent | 8414138e74aa469015108049230e70b0a325c6e9 (diff) | |
download | mio-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.rs | 9 | ||||
-rw-r--r-- | src/sys/windows/event.rs | 2 | ||||
-rw-r--r-- | src/sys/windows/io_status_block.rs | 3 | ||||
-rw-r--r-- | src/sys/windows/mod.rs | 16 | ||||
-rw-r--r-- | src/sys/windows/net.rs | 80 | ||||
-rw-r--r-- | src/sys/windows/overlapped.rs | 6 | ||||
-rw-r--r-- | src/sys/windows/selector.rs | 4 | ||||
-rw-r--r-- | src/sys/windows/tcp.rs | 205 | ||||
-rw-r--r-- | src/sys/windows/udp.rs | 2 |
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 ) |