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
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 @@
     srcs: ["src/lib.rs"],
     edition: "2018",
     features: [
+        "net",
+        "os-ext",
         "os-poll",
         "os-util",
         "tcp",
@@ -21,5 +23,5 @@
 
 // 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 @@
 
 [[package]]
 name = "mio"
-version = "0.7.5"
+version = "0.7.6"
 dependencies = [
  "env_logger",
  "libc",
@@ -51,9 +51,9 @@
 
 [[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 @@
 
 [[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 @@
 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 @@
 [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 @@
 # - 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 @@
   "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 @@
 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 @@
 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 @@
   }
   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 @@
 ```
 
 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 @@
 ///
 /// # 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 @@
 ///
 /// # 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 @@
     ///
     /// # 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 @@
     ///
     /// # 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 @@
 ///
 /// 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 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;
+    pub mod pipe {
+        //! Unix pipe.
+        //!
+        //! See the [`new`] function for documentation.
 
-    cfg_pipe! {
-        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 @@
     //!
     //! 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 @@
     //! [`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 @@
     //!
     //! [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 @@
     //! [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 @@
 ///
 /// # 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 @@
 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 @@
     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 @@
         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 @@
 }
 
 #[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 @@
     /// 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::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 @@
 ///
 /// # 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 @@
 ///
 /// # 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 @@
     ///
     /// # 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 @@
     // 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 @@
     ///
     /// # 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 @@
     ///
     /// # 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 @@
     ///
     /// # 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 @@
     ///
     /// # 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 @@
 ///
 /// 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 @@
 ///
 /// 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 @@
     ///
     /// 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 @@
     ///
     /// # 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 @@
     ///
     /// # 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 @@
     ///
     /// # 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(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 @@
     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 @@
 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 @@
 }
 
 #[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 @@
     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 @@
 }
 
 cfg_os_poll! {
-    mod net;
-
     mod selector;
     pub(crate) use self::selector::{event, Event, Events, Selector};
 
@@ -25,15 +23,11 @@
     mod waker;
     pub(crate) use self::waker::Waker;
 
-    cfg_tcp! {
+    cfg_net! {
+        mod net;
+
         pub(crate) mod tcp;
-    }
-
-    cfg_udp! {
         pub(crate) mod udp;
-    }
-
-    cfg_uds! {
         pub(crate) mod uds;
         pub use self::uds::SocketAddr;
     }
@@ -60,18 +54,18 @@
         }
     }
 
-    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 @@
 }
 
 /// 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 @@
             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 @@
     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,
+}
 
-    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,
-        ),
+impl SocketAddrCRepr {
+    pub(crate) fn as_ptr(&self) -> *const libc::sockaddr {
+        self as *const _ as *const libc::sockaddr
     }
 }
 
-/// `storage` must be initialised to `sockaddr_in` or `sockaddr_in6`.
-#[cfg(all(feature = "os-poll", feature = "tcp"))]
+/// 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) => {
+            // `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)
+        }
+    }
+}
+
+/// 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 @@
 }
 
 #[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 @@
 ///
 /// 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 @@
 ///
 /// 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 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 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 @@
         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 @@
         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 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 @@
         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 @@
 
     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 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 @@
 }
 
 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 @@
         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_tcp! {
+    mod net;
+
     pub(crate) mod tcp;
-}
-
-cfg_udp! {
     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 @@
 }
 
 /// 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 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 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) 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 @@
         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 @@
 
         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 @@
 
     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 @@
     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_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 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 @@
     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 @@
 ///
 /// 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;