aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-12-02 16:15:35 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-12-02 16:15:35 +0000
commit016a64f4f53e8078f41e9f22a242151b58e9ed79 (patch)
tree9953974f4f90698632f6dcdcb001e8f962af4dbd
parent58b16263e2f66995cbabe8c2e957039e9bcd086c (diff)
parentb871bf78acdb643f7b39ac9d1110ab94d886d7d1 (diff)
downloadmio-016a64f4f53e8078f41e9f22a242151b58e9ed79.tar.gz
Upgrade rust/crates/mio to 0.7.6 am: b871bf78ac
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/mio/+/1500656 Change-Id: I24b05baf23c9a063169a3b50a78af3c421ef7ef2
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp4
-rw-r--r--CHANGELOG.md58
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml24
-rw-r--r--Cargo.toml.orig34
-rw-r--r--METADATA6
-rw-r--r--README.md3
-rw-r--r--src/event/events.rs12
-rw-r--r--src/event/source.rs3
-rw-r--r--src/lib.rs106
-rw-r--r--src/macros.rs70
-rw-r--r--src/macros/mod.rs131
-rw-r--r--src/net/mod.rs21
-rw-r--r--src/net/tcp/listener.rs3
-rw-r--r--src/net/tcp/mod.rs2
-rw-r--r--src/net/tcp/socket.rs336
-rw-r--r--src/net/tcp/stream.rs5
-rw-r--r--src/net/udp.rs25
-rw-r--r--src/poll.rs18
-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
-rw-r--r--src/token.rs3
-rw-r--r--src/waker.rs3
42 files changed, 1335 insertions, 460 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 3096345..7fefbd3 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "27fbd5f04bb5f52a4d1c358cf0c04c6074a3d46b"
+ "sha1": "e6e403fe2a4fc14dfbc74dbb3ae3a14e3044eb6f"
}
}
diff --git a/Android.bp b/Android.bp
index 1223c02..81d1675 100644
--- a/Android.bp
+++ b/Android.bp
@@ -7,6 +7,8 @@ rust_library {
srcs: ["src/lib.rs"],
edition: "2018",
features: [
+ "net",
+ "os-ext",
"os-poll",
"os-util",
"tcp",
@@ -21,5 +23,5 @@ rust_library {
// dependent_library ["feature_list"]
// cfg-if-0.1.10
-// libc-0.2.80 "default,std"
+// libc-0.2.80 "align,default,std"
// log-0.4.11 "std"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1ca5125..f024bfb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,43 +1,79 @@
+# 0.7.6
+
+## Added
+
+* `net` feature, replaces `tcp`, `udp` and `uds` features
+ (https://github.com/tokio-rs/mio/commit/a301ba520a8479b459c4acdcefa4a7c5eea818c7).
+* `os-ext` feature, replaces `os-util` and `pipe` features
+ (https://github.com/tokio-rs/mio/commit/f5017fae8a3d3bb4b4cada25b01a2d76a406badc).
+* Added keepalive support to `TcpSocket`
+ (https://github.com/tokio-rs/mio/commit/290c43a96662d54ab7c4b8814e5a9f9a9e523fda).
+* `TcpSocket::set_{send, recv}_buffer_size`
+ (https://github.com/tokio-rs/mio/commit/40c4af79bf5b32b8fbdbf6f2e5c16290e1d3d406).
+* `TcpSocket::get_linger`
+ (https://github.com/tokio-rs/mio/commit/13e82ced655bbb6e2729226e485a7de9f2c2ccd9).
+* Implement `IntoRawFd` for `TcpSocket`
+ (https://github.com/tokio-rs/mio/commit/50548ed45d0b2c98f1f2e003e210d14195284ef4).
+
+## Deprecated
+
+* The `tcp`, `udp` and `uds` features, replaced by a new `net` feature.
+ (https://github.com/tokio-rs/mio/commit/a301ba520a8479b459c4acdcefa4a7c5eea818c7).
+* The `extra-docs` feature, now enabled by default.
+ (https://github.com/tokio-rs/mio/commit/25731e8688a2d91c5c700674a2c2d3841240ece1).
+* The `os-util` and `pipe` features, replaced by a new `os-ext` feature.
+ (https://github.com/tokio-rs/mio/commit/f5017fae8a3d3bb4b4cada25b01a2d76a406badc).
+
+## Fixes
+
+* Incorrect assumption of the layout of `std::net::SocketAddr`. Previously Mio
+ would assume that `SocketAddrV{4,6}` had the same layout as
+ `libc::sockaddr_in(6)`, however this is not guaranteed by the standard
+ library.
+ (https://github.com/tokio-rs/mio/commit/152e0751f0be1c9b0cbd6778645b76bcb0eba93c).
+* Also bumped the miow dependency to version 0.3.6 to solve the same problem as
+ above.
+
# 0.7.5
## Added
* `TcpSocket::get_localaddr()` retrieves local address
- (https://github.com/tokio-rs/mio/commit/b41a022b2242eef1969c70c8ba93e04c528dba47)
-* `TcpSocket::set_reuseport()` & `TcpSocket::get_reuseport()` configures and reads SO_REUSEPORT
- (https://github.com/tokio-rs/mio/commit/183bbe409ab69cbf9db41d0263b41ec86202d9a0)
+ (https://github.com/tokio-rs/mio/commit/b41a022b2242eef1969c70c8ba93e04c528dba47).
+* `TcpSocket::set_reuseport()` & `TcpSocket::get_reuseport()` configures and reads `SO_REUSEPORT`
+ (https://github.com/tokio-rs/mio/commit/183bbe409ab69cbf9db41d0263b41ec86202d9a0).
* `unix:pipe()` a wrapper around pipe(2) sys call
- (https://github.com/tokio-rs/mio/commit/2b7c0967a7362303946deb3d4ca2ae507af6c72d)
+ (https://github.com/tokio-rs/mio/commit/2b7c0967a7362303946deb3d4ca2ae507af6c72d).
* Add a check that a single Waker is active per Poll instance (only in debug mode)
- (https://github.com/tokio-rs/mio/commit/f4874f28b32efcf4841691884c65a89734d96a56)
+ (https://github.com/tokio-rs/mio/commit/f4874f28b32efcf4841691884c65a89734d96a56).
* Added `Interest:remove()`
- (https://github.com/tokio-rs/mio/commit/b8639c3d9ac07bb7e2e27685680c8a6510fa1357)
+ (https://github.com/tokio-rs/mio/commit/b8639c3d9ac07bb7e2e27685680c8a6510fa1357).
# 0.7.4
## Fixes
* lost "socket closed" events on windows
- (https://github.com/tokio-rs/mio/commit/50c299aca56c4a26e5ed20c283007239fbe6a7a7)
+ (https://github.com/tokio-rs/mio/commit/50c299aca56c4a26e5ed20c283007239fbe6a7a7).
## Added
* `TcpSocket::set_linger()` configures SO_LINGER
- (https://github.com/tokio-rs/mio/commit/3b4096565c1a879f651b8f8282ecdcbdbd5c92d3)
+ (https://github.com/tokio-rs/mio/commit/3b4096565c1a879f651b8f8282ecdcbdbd5c92d3).
# 0.7.3
## Added
-* `TcpSocket` for configuring a TCP socket before connecting or listening.
- (https://github.com/tokio-rs/mio/commit/5b09e60d0f64419b989bda88c86a3147334a03b3)
+* `TcpSocket` for configuring a TCP socket before connecting or listening
+ (https://github.com/tokio-rs/mio/commit/5b09e60d0f64419b989bda88c86a3147334a03b3).
# 0.7.2
## Added
* Windows named pipe support.
- (https://github.com/tokio-rs/mio/commit/52e8c2220e87696d20f13561402bcaabba4136ed)
+ (https://github.com/tokio-rs/mio/commit/52e8c2220e87696d20f13561402bcaabba4136ed).
# 0.7.1
diff --git a/Cargo.lock b/Cargo.lock
index 2a0e767..25ad6d6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -38,7 +38,7 @@ dependencies = [
[[package]]
name = "mio"
-version = "0.7.5"
+version = "0.7.6"
dependencies = [
"env_logger",
"libc",
@@ -51,9 +51,9 @@ dependencies = [
[[package]]
name = "miow"
-version = "0.3.5"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
+checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
dependencies = [
"socket2",
"winapi",
@@ -113,9 +113,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "socket2"
-version = "0.3.15"
+version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44"
+checksum = "7fd8b795c389288baa5f355489c65e71fd48a02104600d15c4cfbc561e9e429d"
dependencies = [
"cfg-if",
"libc",
diff --git a/Cargo.toml b/Cargo.toml
index a490943..7f0d023 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,12 +13,12 @@
[package]
edition = "2018"
name = "mio"
-version = "0.7.5"
+version = "0.7.6"
authors = ["Carl Lerche <me@carllerche.com>"]
include = ["Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md", "src/**/*.rs", "examples/**/*.rs"]
description = "Lightweight non-blocking IO"
homepage = "https://github.com/tokio-rs/mio"
-documentation = "https://docs.rs/mio/0.7.5"
+documentation = "https://docs.rs/mio/0.7.6"
readme = "README.md"
keywords = ["io", "async", "non-blocking"]
categories = ["asynchronous"]
@@ -29,15 +29,15 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.playground]
-features = ["os-poll", "os-util", "tcp", "udp", "uds"]
+features = ["os-poll", "os-ext", "net"]
[[example]]
name = "tcp_server"
-required-features = ["os-poll", "tcp"]
+required-features = ["os-poll", "net"]
[[example]]
name = "udp_server"
-required-features = ["os-poll", "udp"]
+required-features = ["os-poll", "net"]
[dependencies.log]
version = "0.4.8"
[dev-dependencies.env_logger]
@@ -50,16 +50,18 @@ version = "0.4"
[features]
default = []
extra-docs = []
+net = []
+os-ext = ["os-poll"]
os-poll = []
-os-util = []
-pipe = ["os-poll"]
-tcp = []
-udp = []
-uds = []
+os-util = ["os-ext"]
+pipe = ["os-ext"]
+tcp = ["net"]
+udp = ["net"]
+uds = ["net"]
[target."cfg(unix)".dependencies.libc]
version = "0.2.69"
[target."cfg(windows)".dependencies.miow]
-version = "0.3.3"
+version = "0.3.6"
[target."cfg(windows)".dependencies.ntapi]
version = "0.3"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index e01d453..e0937ed 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -6,11 +6,11 @@ name = "mio"
# - Update CHANGELOG.md.
# - Update doc URL.
# - Create git tag
-version = "0.7.5"
+version = "0.7.6"
license = "MIT"
authors = ["Carl Lerche <me@carllerche.com>"]
description = "Lightweight non-blocking IO"
-documentation = "https://docs.rs/mio/0.7.5"
+documentation = "https://docs.rs/mio/0.7.6"
homepage = "https://github.com/tokio-rs/mio"
repository = "https://github.com/tokio-rs/mio"
readme = "README.md"
@@ -25,15 +25,25 @@ include = [
"examples/**/*.rs",
]
+# For documentation of features see the `mio::features` module.
[features]
+# By default Mio only provides a shell implementation.
default = []
+
+# Enables the `Poll` and `Registry` types.
os-poll = []
-os-util = []
-pipe = ["os-poll"]
-tcp = []
-udp = []
-uds = []
-extra-docs = []
+# Enables additional OS specific extensions, e.g. Unix `pipe(2)`.
+os-ext = ["os-poll"]
+# Enables `mio::net` module containing networking primitives.
+net = []
+
+# Deprecated features, will be removed in a future version.
+extra-docs = [] # Docs are now always present.
+tcp = ["net"] # Replaced with "net" feature.
+udp = ["net"] # Replaced with "net" feature.
+uds = ["net"] # Replaced with "net" feature.
+pipe = ["os-ext"] # Replaced with "os-ext" feature.
+os-util = ["os-ext"]# Replaced with "os-ext" feature.
[dependencies]
log = "0.4.8"
@@ -42,7 +52,7 @@ log = "0.4.8"
libc = "0.2.69"
[target.'cfg(windows)'.dependencies]
-miow = "0.3.3"
+miow = "0.3.6"
winapi = { version = "0.3", features = ["winsock2", "mswsock"] }
ntapi = "0.3"
@@ -55,12 +65,12 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.playground]
-features = ["os-poll", "os-util", "tcp", "udp", "uds"]
+features = ["os-poll", "os-ext", "net"]
[[example]]
name = "tcp_server"
-required-features = ["os-poll", "tcp"]
+required-features = ["os-poll", "net"]
[[example]]
name = "udp_server"
-required-features = ["os-poll", "udp"]
+required-features = ["os-poll", "net"]
diff --git a/METADATA b/METADATA
index a63bcc3..54e4612 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/mio/mio-0.7.5.crate"
+ value: "https://static.crates.io/crates/mio/mio-0.7.6.crate"
}
- version: "0.7.5"
+ version: "0.7.6"
license_type: NOTICE
last_upgrade_date {
year: 2020
month: 11
- day: 2
+ day: 16
}
}
diff --git a/README.md b/README.md
index 62ebc47..c8653f8 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,8 @@ mio = "0.7"
```
Next we can start using Mio. The following is quick introduction using
-`TcpListener` and `TcpStream`. Note that `features = ["os-poll", "tcp"]` must be specified for this example.
+`TcpListener` and `TcpStream`. Note that `features = ["os-poll", "net"]` must be
+specified for this example.
```rust
use std::error::Error;
diff --git a/src/event/events.rs b/src/event/events.rs
index 8fbdc10..f3c5a2f 100644
--- a/src/event/events.rs
+++ b/src/event/events.rs
@@ -17,7 +17,8 @@ use std::fmt;
///
/// # Examples
///
-/// ```
+#[cfg_attr(feature = "os-poll", doc = "```")]
+#[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Events, Poll};
@@ -51,7 +52,8 @@ pub struct Events {
///
/// # Examples
///
-/// ```
+#[cfg_attr(feature = "os-poll", doc = "```")]
+#[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Events, Poll};
@@ -123,7 +125,8 @@ impl Events {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(feature = "os-poll", doc = "```")]
+ #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Events, Poll};
@@ -158,7 +161,8 @@ impl Events {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(feature = "os-poll", doc = "```")]
+ #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Events, Poll};
diff --git a/src/event/source.rs b/src/event/source.rs
index 1db6596..f38268a 100644
--- a/src/event/source.rs
+++ b/src/event/source.rs
@@ -38,7 +38,8 @@ use std::io;
///
/// Implementing `Source` on a struct containing a socket:
///
-/// ```
+#[cfg_attr(all(feature = "os-poll", features = "net"), doc = "```")]
+#[cfg_attr(not(all(feature = "os-poll", features = "net")), doc = "```ignore")]
/// use mio::{Interest, Registry, Token};
/// use mio::event::Source;
/// use mio::net::TcpStream;
diff --git a/src/lib.rs b/src/lib.rs
index 332ee24..1491a62 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,4 @@
-#![doc(html_root_url = "https://docs.rs/mio/0.7.5")]
+#![doc(html_root_url = "https://docs.rs/mio/0.7.6")]
#![deny(
missing_docs,
missing_debug_implementations,
@@ -35,27 +35,11 @@
//!
//! ## Guide
//!
-//! A getting started guide is available in the
-#![cfg_attr(
- feature = "extra-docs",
- doc = "[`guide`](../mio/guide/index.html) module."
-)]
-#![cfg_attr(
- not(feature = "extra-docs"),
- doc = "`guide` (only available when the `extra-docs` feature is enabled)."
-)]
+//! A getting started guide is available in the [`guide`] module.
//!
//! ## Available features
//!
-//! The available features are described in the
-#![cfg_attr(
- feature = "extra-docs",
- doc = "[`features`](../mio/features/index.html) module."
-)]
-#![cfg_attr(
- not(feature = "extra-docs"),
- doc = "`features` (only available when the `extra-docs` feature is enabled)."
-)]
+//! The available features are described in the [`features`] module.
// macros used internally
#[macro_use]
@@ -84,41 +68,30 @@ pub use poll::{Poll, Registry};
pub use token::Token;
pub use waker::Waker;
-#[cfg(all(unix, any(feature = "os-util", feature = "pipe")))]
-#[cfg_attr(
- docsrs,
- doc(cfg(all(unix, any(feature = "os-util", feature = "pipe"))))
-)]
+#[cfg(all(unix, feature = "os-ext"))]
+#[cfg_attr(docsrs, doc(cfg(all(unix, feature = "os-ext"))))]
pub mod unix {
//! Unix only extensions.
- #[cfg(feature = "os-util")]
- #[cfg_attr(docsrs, doc(cfg(all(unix, feature = "os-util"))))]
- pub use crate::sys::SourceFd;
-
- cfg_pipe! {
- pub mod pipe {
- //! Unix pipe.
- //!
- //! See the [`new`] function for documentation.
+ pub mod pipe {
+ //! Unix pipe.
+ //!
+ //! See the [`new`] function for documentation.
- pub use crate::sys::pipe::{new, Receiver, Sender};
- }
+ pub use crate::sys::pipe::{new, Receiver, Sender};
}
+
+ pub use crate::sys::SourceFd;
}
-#[cfg(all(windows, feature = "os-util"))]
-#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "os-util"))))]
+#[cfg(all(windows, feature = "os-ext"))]
+#[cfg_attr(docsrs, doc(cfg(all(windows, feature = "os-ext"))))]
pub mod windows {
//! Windows only extensions.
- cfg_os_poll! {
- pub use crate::sys::named_pipe::NamedPipe;
- }
+ pub use crate::sys::named_pipe::NamedPipe;
}
-// Enable with `cargo doc --features extra-docs`.
-#[cfg(feature = "extra-docs")]
pub mod features {
//! # Mio's optional features.
//!
@@ -133,44 +106,18 @@ pub mod features {
//!
//! This makes `Poll`, `Registry` and `Waker` functional.
//!
- #![cfg_attr(feature = "os-util", doc = "## `os-util` (enabled)")]
- #![cfg_attr(not(feature = "os-util"), doc = "## `os-util` (disabled)")]
+ #![cfg_attr(feature = "os-ext", doc = "## `os-ext` (enabled)")]
+ #![cfg_attr(not(feature = "os-ext"), doc = "## `os-ext` (disabled)")]
//!
- //! `os-util` enables additional OS specific facilities. Currently this
- //! means the `unix` module (with `SourceFd`) becomes available.
+ //! `os-ext` enables additional OS specific facilities. These facilities can
+ //! be found in the `unix` and `windows` module.
//!
- #![cfg_attr(feature = "pipe", doc = "## `pipe` (enabled)")]
- #![cfg_attr(not(feature = "pipe"), doc = "## `pipe` (disabled)")]
+ #![cfg_attr(feature = "net", doc = "## Network types (enabled)")]
+ #![cfg_attr(not(feature = "net"), doc = "## Network types (disabled)")]
//!
- //! The `pipe` feature adds `unix::pipe`, and related types, a non-blocking
- //! wrapper around the `pipe(2)` system call.
- //!
- //! ## Network types
- //!
- //! Mio provide three features to enable network types:
- //!
- #![cfg_attr(feature = "tcp", doc = "* `tcp` (enabled)")]
- #![cfg_attr(not(feature = "tcp"), doc = "* `tcp` (disabled)")]
- //! : includes `TcpStream` and `TcpListener`,
- #![cfg_attr(feature = "udp", doc = "* `udp` (enabled)")]
- #![cfg_attr(not(feature = "udp"), doc = "* `udp` (disabled)")]
- //! : includes `UdpSocket`, and
- #![cfg_attr(feature = "uds", doc = "* `uds` (enabled)")]
- #![cfg_attr(not(feature = "uds"), doc = "* `uds` (disabled)")]
- //! : includes `UnixDatagram`, `UnixListener`, `UnixStream` and `SocketAddr`.
- //!
- //! All types can be found in the `net` module.
- //!
- #![cfg_attr(feature = "extra-docs", doc = "## `extra-docs` (enabled)")]
- #![cfg_attr(not(feature = "extra-docs"), doc = "## `extra-docs` (disabled)")]
- //!
- //! This feature includes additional documentation such as this document and
- //! the getting started guide. It adds nothing in terms of types (only
- //! documentation).
+ //! The `net` feature enables networking primitives in the `net` module.
}
-// Enable with `cargo doc --features extra-docs`.
-#[cfg(feature = "extra-docs")]
pub mod guide {
//! # Getting started guide.
//!
@@ -192,7 +139,8 @@ pub mod guide {
//! [`Poll`]: ../struct.Poll.html
//! [`Events`]: ../event/struct.Events.html
//!
- //! ```
+ #![cfg_attr(feature = "os-poll", doc = "```")]
+ #![cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
//! # use mio::{Poll, Events};
//! # fn main() -> std::io::Result<()> {
//! // `Poll` allows for polling of readiness events.
@@ -226,7 +174,8 @@ pub mod guide {
//!
//! [event source]: ../event/trait.Source.html
//!
- //! ```
+ #![cfg_attr(all(feature = "os-poll", features = "net"), doc = "```")]
+ #![cfg_attr(not(all(feature = "os-poll", features = "net")), doc = "```ignore")]
//! # use mio::net::TcpListener;
//! # use mio::{Poll, Token, Interest};
//! # fn main() -> std::io::Result<()> {
@@ -264,7 +213,8 @@ pub mod guide {
//! [poll]: ../struct.Poll.html#method.poll
//! [event sources]: ../event/trait.Source.html
//!
- //! ```
+ #![cfg_attr(all(feature = "os-poll", features = "net"), doc = "```")]
+ #![cfg_attr(not(all(feature = "os-poll", features = "net")), doc = "```ignore")]
//! # use std::io;
//! # use std::time::Duration;
//! # use mio::net::TcpListener;
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..db93dfd
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,70 @@
+//! Macros to ease conditional code based on enabled features.
+
+// Depending on the features not all macros are used.
+#![allow(unused_macros)]
+
+/// The `os-poll` feature is enabled.
+macro_rules! cfg_os_poll {
+ ($($item:item)*) => {
+ $(
+ #[cfg(feature = "os-poll")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "os-poll")))]
+ $item
+ )*
+ }
+}
+
+/// The `os-poll` feature is disabled.
+macro_rules! cfg_not_os_poll {
+ ($($item:item)*) => {
+ $(
+ #[cfg(not(feature = "os-poll"))]
+ $item
+ )*
+ }
+}
+
+/// The `os-ext` feature is enabled.
+macro_rules! cfg_os_ext {
+ ($($item:item)*) => {
+ $(
+ #[cfg(feature = "os-ext")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "os-ext")))]
+ $item
+ )*
+ }
+}
+
+/// The `net` feature is enabled.
+macro_rules! cfg_net {
+ ($($item:item)*) => {
+ $(
+ #[cfg(feature = "net")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
+ $item
+ )*
+ }
+}
+
+/// One of the features enabled that needs `IoSource`. That is `net` or `os-ext`
+/// on Unix (for `pipe`).
+macro_rules! cfg_io_source {
+ ($($item:item)*) => {
+ $(
+ #[cfg(any(feature = "net", all(unix, feature = "os-ext")))]
+ #[cfg_attr(docsrs, doc(any(feature = "net", all(unix, feature = "os-ext"))))]
+ $item
+ )*
+ }
+}
+
+/// The `os-ext` feature is enabled, or one of the features that need `os-ext`.
+macro_rules! cfg_any_os_ext {
+ ($($item:item)*) => {
+ $(
+ #[cfg(any(feature = "os-ext", feature = "net"))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "os-ext", feature = "net"))))]
+ $item
+ )*
+ }
+}
diff --git a/src/macros/mod.rs b/src/macros/mod.rs
deleted file mode 100644
index 2275ed9..0000000
--- a/src/macros/mod.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-//! Macros to ease conditional code based on enabled features.
-
-// Depending on the features not all macros are used.
-#![allow(unused_macros)]
-
-/// Feature `os-poll` enabled.
-macro_rules! cfg_os_poll {
- ($($item:item)*) => {
- $(
- #[cfg(feature = "os-poll")]
- #[cfg_attr(docsrs, doc(cfg(feature = "os-poll")))]
- $item
- )*
- }
-}
-
-/// Feature `os-poll` disabled.
-macro_rules! cfg_not_os_poll {
- ($($item:item)*) => {
- $(
- #[cfg(not(feature = "os-poll"))]
- $item
- )*
- }
-}
-
-/// One of the `tcp`, `udp`, `uds` features enabled.
-#[cfg(unix)]
-macro_rules! cfg_net {
- ($($item:item)*) => {
- $(
- #[cfg(any(feature = "tcp", feature = "udp", feature = "uds"))]
- #[cfg_attr(docsrs, doc(cfg(any(feature = "tcp", feature = "udp", feature = "uds"))))]
- $item
- )*
- }
-}
-
-/// One of the features enabled that needs `IoSource`. That is `tcp`, or `udp`,
-/// or on Unix `uds` or `pipe`.
-macro_rules! cfg_io_source {
- ($($item:item)*) => {
- $(
- #[cfg(any(feature = "tcp", feature = "udp", all(unix, any(feature = "uds", feature = "pipe"))))]
- #[cfg_attr(docsrs, doc(any(feature = "tcp", feature = "udp", all(unix, any(feature = "uds", feature = "pipe")))))]
- $item
- )*
- }
-}
-
-/// One of the `tcp`, `udp` features enabled.
-#[cfg(windows)]
-macro_rules! cfg_net {
- ($($item:item)*) => {
- $(
- #[cfg(any(feature = "tcp", feature = "udp"))]
- #[cfg_attr(docsrs, doc(cfg(any(feature = "tcp", feature = "udp"))))]
- $item
- )*
- }
-}
-
-/// Feature `tcp` enabled.
-macro_rules! cfg_tcp {
- ($($item:item)*) => {
- $(
- #[cfg(feature = "tcp")]
- #[cfg_attr(docsrs, doc(cfg(feature = "tcp")))]
- $item
- )*
- }
-}
-
-/// Feature `udp` enabled.
-macro_rules! cfg_udp {
- ($($item:item)*) => {
- $(
- #[cfg(feature = "udp")]
- #[cfg_attr(docsrs, doc(cfg(feature = "udp")))]
- $item
- )*
- }
-}
-
-/// Feature `uds` enabled.
-#[cfg(unix)]
-macro_rules! cfg_uds {
- ($($item:item)*) => {
- $(
- #[cfg(feature = "uds")]
- #[cfg_attr(docsrs, doc(cfg(feature = "uds")))]
- $item
- )*
- }
-}
-
-/// Feature `pipe` enabled.
-#[cfg(unix)]
-macro_rules! cfg_pipe {
- ($($item:item)*) => {
- $(
- #[cfg(feature = "pipe")]
- #[cfg_attr(docsrs, doc(cfg(feature = "pipe")))]
- $item
- )*
- }
-}
-
-/// Feature `os-util` enabled, or one of the features that need `os-util`.
-#[cfg(unix)]
-macro_rules! cfg_any_os_util {
- ($($item:item)*) => {
- $(
- #[cfg(any(feature = "os-util", feature = "tcp", feature = "udp", feature = "uds", feature = "pipe"))]
- #[cfg_attr(docsrs, doc(cfg(any(feature = "os-util", feature = "tcp", feature = "udp", feature = "uds", feature = "pipe"))))]
- $item
- )*
- }
-}
-
-/// Feature `os-util` enabled, or one of the features that need `os-util`.
-#[cfg(windows)]
-macro_rules! cfg_any_os_util {
- ($($item:item)*) => {
- $(
- #[cfg(any(feature = "os-util", feature = "tcp", feature = "udp", feature = "pipe"))]
- #[cfg_attr(docsrs, doc(cfg(any(feature = "os-util", feature = "tcp", feature = "udp", feature = "pipe"))))]
- $item
- )*
- }
-}
diff --git a/src/net/mod.rs b/src/net/mod.rs
index 91804ec..4df701d 100644
--- a/src/net/mod.rs
+++ b/src/net/mod.rs
@@ -1,4 +1,4 @@
-//! Networking primitives
+//! Networking primitives.
//!
//! The types provided in this module are non-blocking by default and are
//! designed to be portable across all supported Mio platforms. As long as the
@@ -7,18 +7,13 @@
//!
//! [portability guidelines]: ../struct.Poll.html#portability
-cfg_tcp! {
- mod tcp;
- pub use self::tcp::{TcpListener, TcpSocket, TcpStream};
-}
+mod tcp;
+pub use self::tcp::{TcpListener, TcpSocket, TcpStream, TcpKeepalive};
-cfg_udp! {
- mod udp;
- pub use self::udp::UdpSocket;
-}
+mod udp;
+pub use self::udp::UdpSocket;
#[cfg(unix)]
-cfg_uds! {
- mod uds;
- pub use self::uds::{SocketAddr, UnixDatagram, UnixListener, UnixStream};
-}
+mod uds;
+#[cfg(unix)]
+pub use self::uds::{SocketAddr, UnixDatagram, UnixListener, UnixStream};
diff --git a/src/net/tcp/listener.rs b/src/net/tcp/listener.rs
index b6f5736..da276f3 100644
--- a/src/net/tcp/listener.rs
+++ b/src/net/tcp/listener.rs
@@ -13,7 +13,8 @@ use crate::{event, sys, Interest, Registry, Token};
///
/// # Examples
///
-/// ```
+#[cfg_attr(feature = "os-poll", doc = "```")]
+#[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Events, Interest, Poll, Token};
diff --git a/src/net/tcp/mod.rs b/src/net/tcp/mod.rs
index b39b909..4e47aee 100644
--- a/src/net/tcp/mod.rs
+++ b/src/net/tcp/mod.rs
@@ -2,7 +2,7 @@ mod listener;
pub use self::listener::TcpListener;
mod socket;
-pub use self::socket::TcpSocket;
+pub use self::socket::{TcpSocket, TcpKeepalive};
mod stream;
pub use self::stream::TcpStream;
diff --git a/src/net/tcp/socket.rs b/src/net/tcp/socket.rs
index f3e27c3..35a589c 100644
--- a/src/net/tcp/socket.rs
+++ b/src/net/tcp/socket.rs
@@ -1,14 +1,14 @@
-use crate::net::{TcpStream, TcpListener};
-use crate::sys;
-
use std::io;
use std::mem;
use std::net::SocketAddr;
-use std::time::Duration;
#[cfg(unix)]
-use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
+use std::time::Duration;
+
+use crate::net::{TcpListener, TcpStream};
+use crate::sys;
/// A non-blocking TCP socket used to configure a stream or listener.
///
@@ -22,23 +22,42 @@ pub struct TcpSocket {
sys: sys::tcp::TcpSocket,
}
+/// Configures a socket's TCP keepalive parameters.
+#[derive(Debug, Default, Clone)]
+pub struct TcpKeepalive {
+ pub(crate) time: Option<Duration>,
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "windows",
+ ))]
+ pub(crate) interval: Option<Duration>,
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ ))]
+ pub(crate) retries: Option<u32>,
+}
+
impl TcpSocket {
/// Create a new IPv4 TCP socket.
///
/// This calls `socket(2)`.
pub fn new_v4() -> io::Result<TcpSocket> {
- sys::tcp::new_v4_socket().map(|sys| TcpSocket {
- sys
- })
+ sys::tcp::new_v4_socket().map(|sys| TcpSocket { sys })
}
/// Create a new IPv6 TCP socket.
///
/// This calls `socket(2)`.
pub fn new_v6() -> io::Result<TcpSocket> {
- sys::tcp::new_v6_socket().map(|sys| TcpSocket {
- sys
- })
+ sys::tcp::new_v6_socket().map(|sys| TcpSocket { sys })
}
pub(crate) fn new_for_addr(addr: SocketAddr) -> io::Result<TcpSocket> {
@@ -106,6 +125,201 @@ impl TcpSocket {
sys::tcp::set_linger(self.sys, dur)
}
+ /// Gets the value of `SO_LINGER` on this socket
+ pub fn get_linger(&self) -> io::Result<Option<Duration>> {
+ sys::tcp::get_linger(self.sys)
+ }
+
+ /// Sets the value of `SO_RCVBUF` on this socket.
+ pub fn set_recv_buffer_size(&self, size: u32) -> io::Result<()> {
+ sys::tcp::set_recv_buffer_size(self.sys, size)
+ }
+
+ /// Get the value of `SO_RCVBUF` set on this socket.
+ ///
+ /// Note that if [`set_recv_buffer_size`] has been called on this socket
+ /// previously, the value returned by this function may not be the same as
+ /// the argument provided to `set_recv_buffer_size`. This is for the
+ /// following reasons:
+ ///
+ /// * Most operating systems have minimum and maximum allowed sizes for the
+ /// receive buffer, and will clamp the provided value if it is below the
+ /// minimum or above the maximum. The minimum and maximum buffer sizes are
+ /// OS-dependent.
+ /// * Linux will double the buffer size to account for internal bookkeeping
+ /// data, and returns the doubled value from `getsockopt(2)`. As per `man
+ /// 7 socket`:
+ /// > Sets or gets the maximum socket receive buffer in bytes. The
+ /// > kernel doubles this value (to allow space for bookkeeping
+ /// > overhead) when it is set using `setsockopt(2)`, and this doubled
+ /// > value is returned by `getsockopt(2)`.
+ ///
+ /// [`set_recv_buffer_size`]: #method.set_recv_buffer_size
+ pub fn get_recv_buffer_size(&self) -> io::Result<u32> {
+ sys::tcp::get_recv_buffer_size(self.sys)
+ }
+
+ /// Sets the value of `SO_SNDBUF` on this socket.
+ pub fn set_send_buffer_size(&self, size: u32) -> io::Result<()> {
+ sys::tcp::set_send_buffer_size(self.sys, size)
+ }
+
+ /// Get the value of `SO_SNDBUF` set on this socket.
+ ///
+ /// Note that if [`set_send_buffer_size`] has been called on this socket
+ /// previously, the value returned by this function may not be the same as
+ /// the argument provided to `set_send_buffer_size`. This is for the
+ /// following reasons:
+ ///
+ /// * Most operating systems have minimum and maximum allowed sizes for the
+ /// receive buffer, and will clamp the provided value if it is below the
+ /// minimum or above the maximum. The minimum and maximum buffer sizes are
+ /// OS-dependent.
+ /// * Linux will double the buffer size to account for internal bookkeeping
+ /// data, and returns the doubled value from `getsockopt(2)`. As per `man
+ /// 7 socket`:
+ /// > Sets or gets the maximum socket send buffer in bytes. The
+ /// > kernel doubles this value (to allow space for bookkeeping
+ /// > overhead) when it is set using `setsockopt(2)`, and this doubled
+ /// > value is returned by `getsockopt(2)`.
+ ///
+ /// [`set_send_buffer_size`]: #method.set_send_buffer_size
+ pub fn get_send_buffer_size(&self) -> io::Result<u32> {
+ sys::tcp::get_send_buffer_size(self.sys)
+ }
+
+ /// Sets whether keepalive messages are enabled to be sent on this socket.
+ ///
+ /// This will set the `SO_KEEPALIVE` option on this socket.
+ pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
+ sys::tcp::set_keepalive(self.sys, keepalive)
+ }
+
+ /// Returns whether or not TCP keepalive probes will be sent by this socket.
+ pub fn get_keepalive(&self) -> io::Result<bool> {
+ sys::tcp::get_keepalive(self.sys)
+ }
+
+ /// Sets parameters configuring TCP keepalive probes for this socket.
+ ///
+ /// The supported parameters depend on the operating system, and are
+ /// configured using the [`TcpKeepalive`] struct. At a minimum, all systems
+ /// support configuring the [keepalive time]: the time after which the OS
+ /// will start sending keepalive messages on an idle connection.
+ ///
+ /// # Notes
+ ///
+ /// * This will enable TCP keepalive on this socket, if it is not already
+ /// enabled.
+ /// * On some platforms, such as Windows, any keepalive parameters *not*
+ /// configured by the `TcpKeepalive` struct passed to this function may be
+ /// overwritten with their default values. Therefore, this function should
+ /// either only be called once per socket, or the same parameters should
+ /// be passed every time it is called.
+ ///
+ /// # Examples
+ /// ```
+ /// use mio::net::{TcpSocket, TcpKeepalive};
+ /// use std::time::Duration;
+ ///
+ /// # fn main() -> Result<(), std::io::Error> {
+ /// let socket = TcpSocket::new_v6()?;
+ /// let keepalive = TcpKeepalive::default()
+ /// .with_time(Duration::from_secs(4));
+ /// // Depending on the target operating system, we may also be able to
+ /// // configure the keepalive probe interval and/or the number of retries
+ /// // here as well.
+ ///
+ /// socket.set_keepalive_params(keepalive)?;
+ /// # Ok(()) }
+ /// ```
+ ///
+ /// [`TcpKeepalive`]: ../struct.TcpKeepalive.html
+ /// [keepalive time]: ../struct.TcpKeepalive.html#method.with_time
+ pub fn set_keepalive_params(&self, keepalive: TcpKeepalive) -> io::Result<()> {
+ self.set_keepalive(true)?;
+ sys::tcp::set_keepalive_params(self.sys, keepalive)
+ }
+
+ /// Returns the amount of time after which TCP keepalive probes will be sent
+ /// on idle connections.
+ ///
+ /// If `None`, then keepalive messages are disabled.
+ ///
+ /// This returns the value of `SO_KEEPALIVE` + `IPPROTO_TCP` on OpenBSD,
+ /// NetBSD, and Haiku, `TCP_KEEPALIVE` on macOS and iOS, and `TCP_KEEPIDLE`
+ /// on all other Unix operating systems. On Windows, it is not possible to
+ /// access the value of TCP keepalive parameters after they have been set.
+ ///
+ /// Some platforms specify this value in seconds, so sub-second
+ /// specifications may be omitted.
+ #[cfg_attr(docsrs, doc(cfg(not(target_os = "windows"))))]
+ #[cfg(not(target_os = "windows"))]
+ pub fn get_keepalive_time(&self) -> io::Result<Option<Duration>> {
+ sys::tcp::get_keepalive_time(self.sys)
+ }
+
+ /// Returns the time interval between TCP keepalive probes, if TCP keepalive is
+ /// enabled on this socket.
+ ///
+ /// If `None`, then keepalive messages are disabled.
+ ///
+ /// This returns the value of `TCP_KEEPINTVL` on supported Unix operating
+ /// systems. On Windows, it is not possible to access the value of TCP
+ /// keepalive parameters after they have been set..
+ ///
+ /// Some platforms specify this value in seconds, so sub-second
+ /// specifications may be omitted.
+ #[cfg_attr(
+ docsrs,
+ doc(cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ )))
+ )]
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ ))]
+ pub fn get_keepalive_interval(&self) -> io::Result<Option<Duration>> {
+ sys::tcp::get_keepalive_interval(self.sys)
+ }
+
+ /// Returns the maximum number of TCP keepalive probes that will be sent before
+ /// dropping a connection, if TCP keepalive is enabled on this socket.
+ ///
+ /// If `None`, then keepalive messages are disabled.
+ ///
+ /// This returns the value of `TCP_KEEPCNT` on Unix operating systems that
+ /// support this option. On Windows, it is not possible to access the value
+ /// of TCP keepalive parameters after they have been set.
+ #[cfg_attr(
+ docsrs,
+ doc(cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ )))
+ )]
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ ))]
+ pub fn get_keepalive_retries(&self) -> io::Result<Option<u32>> {
+ sys::tcp::get_keepalive_retries(self.sys)
+ }
+
/// Returns the local address of this socket
///
/// Will return `Err` result in windows if called before calling `bind`
@@ -121,6 +335,16 @@ impl Drop for TcpSocket {
}
#[cfg(unix)]
+impl IntoRawFd for TcpSocket {
+ fn into_raw_fd(self) -> RawFd {
+ let ret = self.sys;
+ // Avoid closing the socket
+ mem::forget(self);
+ ret
+ }
+}
+
+#[cfg(unix)]
impl AsRawFd for TcpSocket {
fn as_raw_fd(&self) -> RawFd {
self.sys
@@ -172,6 +396,94 @@ impl FromRawSocket for TcpSocket {
/// The caller is responsible for ensuring that the socket is in
/// non-blocking mode.
unsafe fn from_raw_socket(socket: RawSocket) -> TcpSocket {
- TcpSocket { sys: socket as sys::tcp::TcpSocket }
+ TcpSocket {
+ sys: socket as sys::tcp::TcpSocket,
+ }
+ }
+}
+
+impl TcpKeepalive {
+ // Sets the amount of time after which TCP keepalive probes will be sent
+ /// on idle connections.
+ ///
+ /// This will set the value of `SO_KEEPALIVE` + `IPPROTO_TCP` on OpenBSD,
+ /// NetBSD, and Haiku, `TCP_KEEPALIVE` on macOS and iOS, and `TCP_KEEPIDLE`
+ /// on all other Unix operating systems. On Windows, this sets the value of
+ /// the `tcp_keepalive` struct's `keepalivetime` field.
+ ///
+ /// Some platforms specify this value in seconds, so sub-second
+ /// specifications may be omitted.
+ pub fn with_time(self, time: Duration) -> Self {
+ Self {
+ time: Some(time),
+ ..self
+ }
+ }
+
+ /// Sets the time interval between TCP keepalive probes.
+ /// This sets the value of `TCP_KEEPINTVL` on supported Unix operating
+ /// systems. On Windows, this sets the value of the `tcp_keepalive` struct's
+ /// `keepaliveinterval` field.
+ ///
+ /// Some platforms specify this value in seconds, so sub-second
+ /// specifications may be omitted.
+ #[cfg_attr(
+ docsrs,
+ doc(cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "windows"
+ )))
+ )]
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "windows"
+ ))]
+ pub fn with_interval(self, interval: Duration) -> Self {
+ Self {
+ interval: Some(interval),
+ ..self
+ }
+ }
+
+ /// Sets the maximum number of TCP keepalive probes that will be sent before
+ /// dropping a connection, if TCP keepalive is enabled on this socket.
+ ///
+ /// This will set the value of `TCP_KEEPCNT` on Unix operating systems that
+ /// support this option.
+ #[cfg_attr(
+ docsrs,
+ doc(cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ )))
+ )]
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ ))]
+ pub fn with_retries(self, retries: u32) -> Self {
+ Self {
+ retries: Some(retries),
+ ..self
+ }
+ }
+
+ /// Returns a new, empty set of TCP keepalive parameters.
+ pub fn new() -> Self {
+ Self::default()
}
}
diff --git a/src/net/tcp/stream.rs b/src/net/tcp/stream.rs
index 86f674c..cdbd46a 100644
--- a/src/net/tcp/stream.rs
+++ b/src/net/tcp/stream.rs
@@ -7,8 +7,8 @@ use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
use crate::io_source::IoSource;
-use crate::{event, Interest, Registry, Token};
use crate::net::TcpSocket;
+use crate::{event, Interest, Registry, Token};
/// A non-blocking TCP stream between a local socket and a remote socket.
///
@@ -16,7 +16,8 @@ use crate::net::TcpSocket;
///
/// # Examples
///
-/// ```
+#[cfg_attr(feature = "os-poll", doc = "```")]
+#[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::net::{TcpListener, SocketAddr};
/// # use std::error::Error;
/// #
diff --git a/src/net/udp.rs b/src/net/udp.rs
index 164315a..436b4cc 100644
--- a/src/net/udp.rs
+++ b/src/net/udp.rs
@@ -27,7 +27,8 @@ use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}
///
/// # Examples
///
-/// ```
+#[cfg_attr(feature = "os-poll", doc = "```")]
+#[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -96,7 +97,8 @@ impl UdpSocket {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(feature = "os-poll", doc = "```")]
+ #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -139,8 +141,11 @@ impl UdpSocket {
// This assertion is almost, but not quite, universal. It fails on
// shared-IP FreeBSD jails. It's hard for mio to know whether we're jailed,
// so simply disable the test on FreeBSD.
- #[cfg_attr(not(target_os = "freebsd"), doc = " ```")]
- #[cfg_attr(target_os = "freebsd", doc = " ```no_run")]
+ #[cfg_attr(all(feature = "os-poll", not(target_os = "freebsd")), doc = "```")]
+ #[cfg_attr(
+ any(not(feature = "os-poll"), target_os = "freebsd"),
+ doc = "```ignore"
+ )]
/// # use std::error::Error;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -303,7 +308,8 @@ impl UdpSocket {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(feature = "os-poll", doc = "```")]
+ #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -332,7 +338,8 @@ impl UdpSocket {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(feature = "os-poll", doc = "```")]
+ #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -412,7 +419,8 @@ impl UdpSocket {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(feature = "os-poll", doc = "```")]
+ #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -440,7 +448,8 @@ impl UdpSocket {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(feature = "os-poll", doc = "```")]
+ #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # use std::error::Error;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
diff --git a/src/poll.rs b/src/poll.rs
index 7ff2038..b06f138 100644
--- a/src/poll.rs
+++ b/src/poll.rs
@@ -30,7 +30,8 @@ use std::{fmt, io};
///
/// A basic example -- establishing a `TcpStream` connection.
///
-/// ```
+#[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::{Events, Poll, Interest, Token};
@@ -126,7 +127,8 @@ use std::{fmt, io};
///
/// For example:
///
-/// ```
+#[cfg_attr(all(feature = "os-poll", features = "net"), doc = "```")]
+#[cfg_attr(not(all(feature = "os-poll", features = "net")), doc = "```ignore")]
/// # use std::error::Error;
/// # use std::net;
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -258,7 +260,8 @@ impl Poll {
///
/// A basic example -- establishing a `TcpStream` connection.
///
- /// ```
+ #[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::{Events, Poll, Interest, Token};
@@ -422,7 +425,8 @@ impl Registry {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(all(feature = "os-poll", features = "net"), doc = "```")]
+ #[cfg_attr(not(all(feature = "os-poll", features = "net")), doc = "```ignore")]
/// # use std::error::Error;
/// # use std::net;
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -499,7 +503,8 @@ impl Registry {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(all(feature = "os-poll", features = "net"), doc = "```")]
+ #[cfg_attr(not(all(feature = "os-poll", features = "net")), doc = "```ignore")]
/// # use std::error::Error;
/// # use std::net;
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -565,7 +570,8 @@ impl Registry {
///
/// # Examples
///
- /// ```
+ #[cfg_attr(all(feature = "os-poll", features = "net"), doc = "```")]
+ #[cfg_attr(not(all(feature = "os-poll", features = "net")), doc = "```ignore")]
/// # use std::error::Error;
/// # use std::net;
/// # fn main() -> Result<(), Box<dyn Error>> {
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
)
diff --git a/src/token.rs b/src/token.rs
index 3773949..d8a1fd1 100644
--- a/src/token.rs
+++ b/src/token.rs
@@ -17,7 +17,8 @@
///
/// [`slab`]: https://crates.io/crates/slab
///
-/// ```
+#[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::{Events, Interest, Poll, Token};
diff --git a/src/waker.rs b/src/waker.rs
index b8e4496..bc73029 100644
--- a/src/waker.rs
+++ b/src/waker.rs
@@ -34,7 +34,8 @@ use std::io;
///
/// Wake a [`Poll`] instance from another thread.
///
-/// ```
+#[cfg_attr(feature = "os-poll", doc = "```")]
+#[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use std::thread;
/// use std::time::Duration;