aboutsummaryrefslogtreecommitdiff
path: root/src/sys
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
parent8414138e74aa469015108049230e70b0a325c6e9 (diff)
downloadmio-b871bf78acdb643f7b39ac9d1110ab94d886d7d1.tar.gz
Upgrade rust/crates/mio to 0.7.6
Test: make Change-Id: I26de17b65a22ec1ba472a61c51b55681afdb8ffa
Diffstat (limited to 'src/sys')
-rw-r--r--src/sys/mod.rs30
-rw-r--r--src/sys/shell/mod.rs10
-rw-r--r--src/sys/shell/selector.rs2
-rw-r--r--src/sys/shell/tcp.rs74
-rw-r--r--src/sys/unix/mod.rs18
-rw-r--r--src/sys/unix/net.rs140
-rw-r--r--src/sys/unix/selector/kqueue.rs1
-rw-r--r--src/sys/unix/sourcefd.rs6
-rw-r--r--src/sys/unix/tcp.rs304
-rw-r--r--src/sys/unix/udp.rs2
-rw-r--r--src/sys/unix/uds/socketaddr.rs2
-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
20 files changed, 760 insertions, 156 deletions
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index 08bd271..81ae6d2 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -54,31 +54,7 @@ cfg_os_poll! {
#[cfg(unix)]
cfg_os_poll! {
mod unix;
- pub use self::unix::SourceFd;
-
- pub(crate) use self::unix::{event, Event, Events, Selector, Waker};
-
- cfg_tcp! {
- pub(crate) use self::unix::tcp;
- }
-
- cfg_udp! {
- pub(crate) use self::unix::udp;
- }
-
- cfg_uds! {
- pub use self::unix::SocketAddr;
-
- pub(crate) use self::unix::uds;
- }
-
- cfg_pipe! {
- pub(crate) use self::unix::pipe;
- }
-
- cfg_io_source! {
- pub(crate) use self::unix::IoSourceState;
- }
+ pub use self::unix::*;
}
#[cfg(windows)]
@@ -92,13 +68,13 @@ cfg_not_os_poll! {
pub(crate) use self::shell::*;
#[cfg(unix)]
- cfg_any_os_util! {
+ cfg_any_os_ext! {
mod unix;
pub use self::unix::SourceFd;
}
#[cfg(unix)]
- cfg_uds! {
+ cfg_net! {
pub use self::unix::SocketAddr;
}
}
diff --git a/src/sys/shell/mod.rs b/src/sys/shell/mod.rs
index a63760a..7e1533f 100644
--- a/src/sys/shell/mod.rs
+++ b/src/sys/shell/mod.rs
@@ -10,16 +10,10 @@ pub(crate) use self::selector::{event, Event, Events, Selector};
mod waker;
pub(crate) use self::waker::Waker;
-cfg_tcp! {
+cfg_net! {
pub(crate) mod tcp;
-}
-
-cfg_udp! {
pub(crate) mod udp;
-}
-
-#[cfg(unix)]
-cfg_uds! {
+ #[cfg(unix)]
pub(crate) mod uds;
}
diff --git a/src/sys/shell/selector.rs b/src/sys/shell/selector.rs
index 69be370..91fc0bf 100644
--- a/src/sys/shell/selector.rs
+++ b/src/sys/shell/selector.rs
@@ -26,7 +26,7 @@ impl Selector {
}
#[cfg(unix)]
-cfg_any_os_util! {
+cfg_any_os_ext! {
use crate::{Interest, Token};
impl Selector {
diff --git a/src/sys/shell/tcp.rs b/src/sys/shell/tcp.rs
index 3073d42..2017bda 100644
--- a/src/sys/shell/tcp.rs
+++ b/src/sys/shell/tcp.rs
@@ -1,6 +1,7 @@
use std::io;
use std::net::{self, SocketAddr};
use std::time::Duration;
+use crate::net::TcpKeepalive;
pub(crate) type TcpSocket = i32;
@@ -50,6 +51,79 @@ pub(crate) fn set_linger(_: TcpSocket, _: Option<Duration>) -> io::Result<()> {
os_required!();
}
+pub(crate) fn get_linger(_: TcpSocket) -> io::Result<Option<Duration>> {
+ os_required!();
+}
+
+pub(crate) fn set_recv_buffer_size(_: TcpSocket, _: u32) -> io::Result<()> {
+ os_required!();
+}
+
+pub(crate) fn get_recv_buffer_size(_: TcpSocket) -> io::Result<u32> {
+ os_required!();
+}
+
+pub(crate) fn set_send_buffer_size(_: TcpSocket, _: u32) -> io::Result<()> {
+ os_required!();
+}
+
+pub(crate) fn get_send_buffer_size(_: TcpSocket) -> io::Result<u32> {
+ os_required!();
+}
+
+pub(crate) fn set_keepalive(_: TcpSocket, _: bool) -> io::Result<()> {
+ os_required!();
+}
+
+pub(crate) fn get_keepalive(_: TcpSocket) -> io::Result<bool> {
+ os_required!();
+}
+
+#[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "windows",
+))]
+pub(crate) fn set_keepalive_params(_: TcpSocket, _: TcpKeepalive) -> io::Result<()> {
+ os_required!()
+}
+
+#[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+))]
+pub(crate) fn get_keepalive_time(_: TcpSocket) -> io::Result<Option<Duration>> {
+ os_required!()
+}
+
+#[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+))]
+pub(crate) fn get_keepalive_interval(_: TcpSocket) -> io::Result<Option<Duration>> {
+ os_required!()
+}
+
+#[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+))]
+pub(crate) fn get_keepalive_retries(_: TcpSocket) -> io::Result<Option<u32>> {
+ os_required!()
+}
+
pub fn accept(_: &net::TcpListener) -> io::Result<(net::TcpStream, SocketAddr)> {
os_required!();
}
diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs
index f045fb5..231480a 100644
--- a/src/sys/unix/mod.rs
+++ b/src/sys/unix/mod.rs
@@ -14,8 +14,6 @@ macro_rules! syscall {
}
cfg_os_poll! {
- mod net;
-
mod selector;
pub(crate) use self::selector::{event, Event, Events, Selector};
@@ -25,15 +23,11 @@ cfg_os_poll! {
mod waker;
pub(crate) use self::waker::Waker;
- cfg_tcp! {
- pub(crate) mod tcp;
- }
+ cfg_net! {
+ mod net;
- cfg_udp! {
+ pub(crate) mod tcp;
pub(crate) mod udp;
- }
-
- cfg_uds! {
pub(crate) mod uds;
pub use self::uds::SocketAddr;
}
@@ -60,18 +54,18 @@ cfg_os_poll! {
}
}
- cfg_pipe! {
+ cfg_os_ext! {
pub(crate) mod pipe;
}
}
cfg_not_os_poll! {
- cfg_uds! {
+ cfg_net! {
mod uds;
pub use self::uds::SocketAddr;
}
- cfg_any_os_util! {
+ cfg_any_os_ext! {
mod sourcefd;
pub use self::sourcefd::SourceFd;
}
diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs
index 2671b42..2f8d618 100644
--- a/src/sys/unix/net.rs
+++ b/src/sys/unix/net.rs
@@ -1,11 +1,8 @@
-#[cfg(all(feature = "os-poll", any(feature = "tcp", feature = "udp")))]
-use std::net::SocketAddr;
+use std::io;
+use std::mem::size_of;
+use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
-#[cfg(all(feature = "os-poll", any(feature = "udp")))]
-pub(crate) fn new_ip_socket(
- addr: SocketAddr,
- socket_type: libc::c_int,
-) -> std::io::Result<libc::c_int> {
+pub(crate) fn new_ip_socket(addr: SocketAddr, socket_type: libc::c_int) -> io::Result<libc::c_int> {
let domain = match addr {
SocketAddr::V4(..) => libc::AF_INET,
SocketAddr::V6(..) => libc::AF_INET6,
@@ -15,14 +12,7 @@ pub(crate) fn new_ip_socket(
}
/// Create a new non-blocking socket.
-#[cfg(all(
- feature = "os-poll",
- any(feature = "tcp", feature = "udp", feature = "uds")
-))]
-pub(crate) fn new_socket(
- domain: libc::c_int,
- socket_type: libc::c_int,
-) -> std::io::Result<libc::c_int> {
+pub(crate) fn new_socket(domain: libc::c_int, socket_type: libc::c_int) -> io::Result<libc::c_int> {
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
@@ -46,7 +36,7 @@ pub(crate) fn new_socket(
libc::SOL_SOCKET,
libc::SO_NOSIGPIPE,
&1 as *const libc::c_int as *const libc::c_void,
- std::mem::size_of::<libc::c_int>() as libc::socklen_t
+ size_of::<libc::c_int>() as libc::socklen_t
))
.map(|_| socket)
});
@@ -70,34 +60,110 @@ pub(crate) fn new_socket(
socket
}
-#[cfg(all(feature = "os-poll", any(feature = "tcp", feature = "udp")))]
-pub(crate) fn socket_addr(addr: &SocketAddr) -> (*const libc::sockaddr, libc::socklen_t) {
- use std::mem::size_of_val;
+/// A type with the same memory layout as `libc::sockaddr`. Used in converting Rust level
+/// SocketAddr* types into their system representation. The benefit of this specific
+/// type over using `libc::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: libc::sockaddr_in,
+ v6: libc::sockaddr_in6,
+}
+
+impl SocketAddrCRepr {
+ pub(crate) fn as_ptr(&self) -> *const libc::sockaddr {
+ self as *const _ as *const libc::sockaddr
+ }
+}
+/// Converts a Rust `SocketAddr` into the system representation.
+pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_t) {
match addr {
- SocketAddr::V4(ref addr) => (
- addr as *const _ as *const libc::sockaddr,
- size_of_val(addr) as libc::socklen_t,
- ),
- SocketAddr::V6(ref addr) => (
- addr as *const _ as *const libc::sockaddr,
- size_of_val(addr) as libc::socklen_t,
- ),
+ 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 = libc::in_addr {
+ s_addr: u32::from_ne_bytes(addr.ip().octets()),
+ };
+
+ let sockaddr_in = libc::sockaddr_in {
+ sin_family: libc::AF_INET as libc::sa_family_t,
+ sin_port: addr.port().to_be(),
+ sin_addr,
+ sin_zero: [0; 8],
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ sin_len: 0,
+ };
+
+ let sockaddr = SocketAddrCRepr { v4: sockaddr_in };
+ let socklen = size_of::<libc::sockaddr_in>() as libc::socklen_t;
+ (sockaddr, socklen)
+ }
+ SocketAddr::V6(ref addr) => {
+ let sockaddr_in6 = libc::sockaddr_in6 {
+ sin6_family: libc::AF_INET6 as libc::sa_family_t,
+ sin6_port: addr.port().to_be(),
+ sin6_addr: libc::in6_addr {
+ s6_addr: addr.ip().octets(),
+ },
+ sin6_flowinfo: addr.flowinfo(),
+ sin6_scope_id: addr.scope_id(),
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ sin6_len: 0,
+ #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+ __sin6_src_id: 0,
+ };
+
+ let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 };
+ let socklen = size_of::<libc::sockaddr_in6>() as libc::socklen_t;
+ (sockaddr, socklen)
+ }
}
}
-/// `storage` must be initialised to `sockaddr_in` or `sockaddr_in6`.
-#[cfg(all(feature = "os-poll", feature = "tcp"))]
+/// Converts a `libc::sockaddr` compatible struct into a native Rust `SocketAddr`.
+///
+/// # Safety
+///
+/// `storage` must have the `ss_family` field correctly initialized.
+/// `storage` must be initialised to a `sockaddr_in` or `sockaddr_in6`.
pub(crate) unsafe fn to_socket_addr(
storage: *const libc::sockaddr_storage,
-) -> std::io::Result<SocketAddr> {
+) -> io::Result<SocketAddr> {
match (*storage).ss_family as libc::c_int {
- libc::AF_INET => Ok(SocketAddr::V4(
- *(storage as *const libc::sockaddr_in as *const _),
- )),
- libc::AF_INET6 => Ok(SocketAddr::V6(
- *(storage as *const libc::sockaddr_in6 as *const _),
- )),
- _ => Err(std::io::ErrorKind::InvalidInput.into()),
+ libc::AF_INET => {
+ // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
+ let addr: &libc::sockaddr_in = &*(storage as *const libc::sockaddr_in);
+ let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes());
+ let port = u16::from_be(addr.sin_port);
+ Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
+ }
+ libc::AF_INET6 => {
+ // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
+ let addr: &libc::sockaddr_in6 = &*(storage as *const libc::sockaddr_in6);
+ let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr);
+ let port = u16::from_be(addr.sin6_port);
+ Ok(SocketAddr::V6(SocketAddrV6::new(
+ ip,
+ port,
+ addr.sin6_flowinfo,
+ addr.sin6_scope_id,
+ )))
+ }
+ _ => Err(io::ErrorKind::InvalidInput.into()),
}
}
diff --git a/src/sys/unix/selector/kqueue.rs b/src/sys/unix/selector/kqueue.rs
index 454f47d..f509f92 100644
--- a/src/sys/unix/selector/kqueue.rs
+++ b/src/sys/unix/selector/kqueue.rs
@@ -671,6 +671,7 @@ pub mod event {
}
#[test]
+#[cfg(feature = "os-ext")]
fn does_not_register_rw() {
use crate::unix::SourceFd;
use crate::{Poll, Token};
diff --git a/src/sys/unix/sourcefd.rs b/src/sys/unix/sourcefd.rs
index 68511d7..ba52b38 100644
--- a/src/sys/unix/sourcefd.rs
+++ b/src/sys/unix/sourcefd.rs
@@ -25,7 +25,8 @@ use std::os::unix::io::RawFd;
///
/// Basic usage.
///
-/// ```
+#[cfg_attr(all(feature = "os-poll", features = "net"), doc = "```")]
+#[cfg_attr(not(all(feature = "os-poll", features = "net")), doc = "```ignore")]
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Interest, Poll, Token};
@@ -50,7 +51,8 @@ use std::os::unix::io::RawFd;
///
/// Implementing [`event::Source`] for a custom type backed by a [`RawFd`].
///
-/// ```
+#[cfg_attr(all(feature = "os-poll", features = "os-ext"), doc = "```")]
+#[cfg_attr(not(all(feature = "os-poll", features = "os-ext")), doc = "```ignore")]
/// use mio::{event, Interest, Registry, Token};
/// use mio::unix::SourceFd;
///
diff --git a/src/sys/unix/tcp.rs b/src/sys/unix/tcp.rs
index 65b7400..9e1d700 100644
--- a/src/sys/unix/tcp.rs
+++ b/src/sys/unix/tcp.rs
@@ -1,12 +1,26 @@
+use std::convert::TryInto;
use std::io;
use std::mem;
use std::mem::{size_of, MaybeUninit};
use std::net::{self, SocketAddr};
-use std::time::Duration;
use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::time::Duration;
use crate::sys::unix::net::{new_socket, socket_addr, to_socket_addr};
+use crate::net::TcpKeepalive;
+#[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "haiku"))]
+use libc::SO_KEEPALIVE as KEEPALIVE_TIME;
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+use libc::TCP_KEEPALIVE as KEEPALIVE_TIME;
+#[cfg(not(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "haiku"
+)))]
+use libc::TCP_KEEPIDLE as KEEPALIVE_TIME;
pub type TcpSocket = libc::c_int;
pub(crate) fn new_v4_socket() -> io::Result<TcpSocket> {
@@ -19,14 +33,14 @@ pub(crate) fn new_v6_socket() -> io::Result<TcpSocket> {
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))?;
+ syscall!(bind(socket, raw_addr.as_ptr(), raw_addr_length))?;
Ok(())
}
pub(crate) fn connect(socket: TcpSocket, addr: SocketAddr) -> io::Result<net::TcpStream> {
let (raw_addr, raw_addr_length) = socket_addr(&addr);
- match syscall!(connect(socket, raw_addr, raw_addr_length)) {
+ match syscall!(connect(socket, raw_addr.as_ptr(), raw_addr_length)) {
Err(err) if err.raw_os_error() != Some(libc::EINPROGRESS) => {
Err(err)
}
@@ -37,8 +51,6 @@ pub(crate) fn connect(socket: TcpSocket, addr: SocketAddr) -> io::Result<net::Tc
}
pub(crate) fn listen(socket: TcpSocket, backlog: u32) -> io::Result<net::TcpListener> {
- use std::convert::TryInto;
-
let backlog = backlog.try_into().unwrap_or(i32::max_value());
syscall!(listen(socket, backlog))?;
Ok(unsafe { net::TcpListener::from_raw_fd(socket) })
@@ -56,7 +68,8 @@ pub(crate) fn set_reuseaddr(socket: TcpSocket, reuseaddr: bool) -> io::Result<()
libc::SO_REUSEADDR,
&val as *const libc::c_int as *const libc::c_void,
size_of::<libc::c_int>() as libc::socklen_t,
- )).map(|_| ())
+ ))
+ .map(|_| ())
}
pub(crate) fn get_reuseaddr(socket: TcpSocket) -> io::Result<bool> {
@@ -84,7 +97,8 @@ pub(crate) fn set_reuseport(socket: TcpSocket, reuseport: bool) -> io::Result<()
libc::SO_REUSEPORT,
&val as *const libc::c_int as *const libc::c_void,
size_of::<libc::c_int>() as libc::socklen_t,
- )).map(|_| ())
+ ))
+ .map(|_| ())
}
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
@@ -119,7 +133,9 @@ pub(crate) fn get_localaddr(socket: TcpSocket) -> io::Result<SocketAddr> {
pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {
let val: libc::linger = libc::linger {
l_onoff: if dur.is_some() { 1 } else { 0 },
- l_linger: dur.map(|dur| dur.as_secs() as libc::c_int).unwrap_or_default(),
+ l_linger: dur
+ .map(|dur| dur.as_secs() as libc::c_int)
+ .unwrap_or_default(),
};
syscall!(setsockopt(
socket,
@@ -127,7 +143,277 @@ pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result
libc::SO_LINGER,
&val as *const libc::linger as *const libc::c_void,
size_of::<libc::linger>() as libc::socklen_t,
- )).map(|_| ())
+ ))
+ .map(|_| ())
+}
+
+pub(crate) fn get_linger(socket: TcpSocket) -> io::Result<Option<Duration>> {
+ let mut val: libc::linger = unsafe { std::mem::zeroed() };
+ let mut len = mem::size_of::<libc::linger>() as libc::socklen_t;
+
+ syscall!(getsockopt(
+ socket,
+ libc::SOL_SOCKET,
+ libc::SO_LINGER,
+ &mut val as *mut _ as *mut _,
+ &mut len,
+ ))?;
+
+ 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);
+ syscall!(setsockopt(
+ socket,
+ libc::SOL_SOCKET,
+ libc::SO_RCVBUF,
+ &size as *const _ as *const libc::c_void,
+ size_of::<libc::c_int>() as libc::socklen_t
+ ))
+ .map(|_| ())
+}
+
+pub(crate) fn get_recv_buffer_size(socket: TcpSocket) -> io::Result<u32> {
+ let mut optval: libc::c_int = 0;
+ let mut optlen = size_of::<libc::c_int>() as libc::socklen_t;
+ syscall!(getsockopt(
+ socket,
+ libc::SOL_SOCKET,
+ libc::SO_RCVBUF,
+ &mut optval as *mut _ as *mut _,
+ &mut optlen,
+ ))?;
+
+ 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);
+ syscall!(setsockopt(
+ socket,
+ libc::SOL_SOCKET,
+ libc::SO_SNDBUF,
+ &size as *const _ as *const libc::c_void,
+ size_of::<libc::c_int>() as libc::socklen_t
+ ))
+ .map(|_| ())
+}
+
+pub(crate) fn get_send_buffer_size(socket: TcpSocket) -> io::Result<u32> {
+ let mut optval: libc::c_int = 0;
+ let mut optlen = size_of::<libc::c_int>() as libc::socklen_t;
+
+ syscall!(getsockopt(
+ socket,
+ libc::SOL_SOCKET,
+ libc::SO_SNDBUF,
+ &mut optval as *mut _ as *mut _,
+ &mut optlen,
+ ))?;
+
+ Ok(optval as u32)
+}
+
+pub(crate) fn set_keepalive(socket: TcpSocket, keepalive: bool) -> io::Result<()> {
+ let val: libc::c_int = if keepalive { 1 } else { 0 };
+ syscall!(setsockopt(
+ socket,
+ libc::SOL_SOCKET,
+ libc::SO_KEEPALIVE,
+ &val as *const _ as *const libc::c_void,
+ size_of::<libc::c_int>() as libc::socklen_t
+ ))
+ .map(|_| ())
+}
+
+pub(crate) fn get_keepalive(socket: TcpSocket) -> io::Result<bool> {
+ let mut optval: libc::c_int = 0;
+ let mut optlen = mem::size_of::<libc::c_int>() as libc::socklen_t;
+
+ syscall!(getsockopt(
+ socket,
+ libc::SOL_SOCKET,
+ libc::SO_KEEPALIVE,
+ &mut optval as *mut _ as *mut _,
+ &mut optlen,
+ ))?;
+
+ Ok(optval != 0)
+}
+
+pub(crate) fn set_keepalive_params(socket: TcpSocket, keepalive: TcpKeepalive) -> io::Result<()> {
+ if let Some(dur) = keepalive.time {
+ set_keepalive_time(socket, dur)?;
+ }
+
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ ))]
+ {
+ if let Some(dur) = keepalive.interval {
+ set_keepalive_interval(socket, dur)?;
+ }
+
+ if let Some(retries) = keepalive.retries {
+ set_keepalive_retries(socket, retries)?;
+ }
+ }
+
+
+ Ok(())
+}
+
+fn set_keepalive_time(socket: TcpSocket, time: Duration) -> io::Result<()> {
+ let time_secs = time
+ .as_secs()
+ .try_into()
+ .ok()
+ .unwrap_or_else(i32::max_value);
+ syscall!(setsockopt(
+ socket,
+ libc::IPPROTO_TCP,
+ KEEPALIVE_TIME,
+ &(time_secs as libc::c_int) as *const _ as *const libc::c_void,
+ size_of::<libc::c_int>() as libc::socklen_t
+ ))
+ .map(|_| ())
+}
+
+pub(crate) fn get_keepalive_time(socket: TcpSocket) -> io::Result<Option<Duration>> {
+ if !get_keepalive(socket)? {
+ return Ok(None);
+ }
+
+ let mut optval: libc::c_int = 0;
+ let mut optlen = mem::size_of::<libc::c_int>() as libc::socklen_t;
+ syscall!(getsockopt(
+ socket,
+ libc::IPPROTO_TCP,
+ KEEPALIVE_TIME,
+ &mut optval as *mut _ as *mut _,
+ &mut optlen,
+ ))?;
+
+ Ok(Some(Duration::from_secs(optval as u64)))
+}
+
+/// Linux, FreeBSD, and NetBSD support setting the keepalive interval via
+/// `TCP_KEEPINTVL`.
+/// See:
+/// - https://man7.org/linux/man-pages/man7/tcp.7.html
+/// - https://www.freebsd.org/cgi/man.cgi?query=tcp#end
+/// - http://man.netbsd.org/tcp.4#DESCRIPTION
+///
+/// OpenBSD does not:
+/// https://man.openbsd.org/tcp
+#[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+))]
+fn set_keepalive_interval(socket: TcpSocket, interval: Duration) -> io::Result<()> {
+ let interval_secs = interval
+ .as_secs()
+ .try_into()
+ .ok()
+ .unwrap_or_else(i32::max_value);
+ syscall!(setsockopt(
+ socket,
+ libc::IPPROTO_TCP,
+ libc::TCP_KEEPINTVL,
+ &(interval_secs as libc::c_int) as *const _ as *const libc::c_void,
+ size_of::<libc::c_int>() as libc::socklen_t
+ ))
+ .map(|_| ())
+}
+
+#[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+))]
+pub(crate) fn get_keepalive_interval(socket: TcpSocket) -> io::Result<Option<Duration>> {
+ if !get_keepalive(socket)? {
+ return Ok(None);
+ }
+
+ let mut optval: libc::c_int = 0;
+ let mut optlen = mem::size_of::<libc::c_int>() as libc::socklen_t;
+ syscall!(getsockopt(
+ socket,
+ libc::IPPROTO_TCP,
+ libc::TCP_KEEPINTVL,
+ &mut optval as *mut _ as *mut _,
+ &mut optlen,
+ ))?;
+
+ Ok(Some(Duration::from_secs(optval as u64)))
+}
+
+/// Linux, macOS/iOS, FreeBSD, and NetBSD support setting the number of TCP
+/// keepalive retries via `TCP_KEEPCNT`.
+/// See:
+/// - https://man7.org/linux/man-pages/man7/tcp.7.html
+/// - https://www.freebsd.org/cgi/man.cgi?query=tcp#end
+/// - http://man.netbsd.org/tcp.4#DESCRIPTION
+///
+/// OpenBSD does not:
+/// https://man.openbsd.org/tcp
+#[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+))]
+fn set_keepalive_retries(socket: TcpSocket, retries: u32) -> io::Result<()> {
+ let retries = retries.try_into().ok().unwrap_or_else(i32::max_value);
+ syscall!(setsockopt(
+ socket,
+ libc::IPPROTO_TCP,
+ libc::TCP_KEEPCNT,
+ &(retries as libc::c_int) as *const _ as *const libc::c_void,
+ size_of::<libc::c_int>() as libc::socklen_t
+ ))
+ .map(|_| ())
+}
+
+#[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+))]
+pub(crate) fn get_keepalive_retries(socket: TcpSocket) -> io::Result<Option<u32>> {
+ if !get_keepalive(socket)? {
+ return Ok(None);
+ }
+
+ let mut optval: libc::c_int = 0;
+ let mut optlen = mem::size_of::<libc::c_int>() as libc::socklen_t;
+ syscall!(getsockopt(
+ socket,
+ libc::IPPROTO_TCP,
+ libc::TCP_KEEPCNT,
+ &mut optval as *mut _ as *mut _,
+ &mut optlen,
+ ))?;
+
+ Ok(Some(optval as u32))
}
pub fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, SocketAddr)> {
diff --git a/src/sys/unix/udp.rs b/src/sys/unix/udp.rs
index 947a60a..e9c4d4c 100644
--- a/src/sys/unix/udp.rs
+++ b/src/sys/unix/udp.rs
@@ -11,7 +11,7 @@ pub fn bind(addr: SocketAddr) -> io::Result<net::UdpSocket> {
socket.and_then(|socket| {
let (raw_addr, raw_addr_length) = socket_addr(&addr);
- syscall!(bind(socket, raw_addr, raw_addr_length))
+ syscall!(bind(socket, raw_addr.as_ptr(), raw_addr_length))
.map_err(|err| {
// Close the socket if we hit an error, ignoring the error
// from closing since we can't pass back two errors.
diff --git a/src/sys/unix/uds/socketaddr.rs b/src/sys/unix/uds/socketaddr.rs
index ddfa2f0..31f8a51 100644
--- a/src/sys/unix/uds/socketaddr.rs
+++ b/src/sys/unix/uds/socketaddr.rs
@@ -109,8 +109,6 @@ impl fmt::Debug for SocketAddr {
}
}
-// ===== impl AsciiEscaped =====
-
impl<'a> fmt::Display for AsciiEscaped<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "\"")?;
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
)