Repository: rust-lang/socket2
Pull request #222 (2021-04-25 12:48:18)

Allow for niche optimization on Unix platforms
The standard library's file descriptor types have a niche of -1, allowing `Option<T>` to have the same size as `T`. By storing a `TcpStream` internally instead of a raw file descriptor, `Socket` can also take advantage of this. Currently, this incurs a slightly cost as `{from, as, into}_raw_{fd, socket}` won't be inlined, however if [this Rust PR](https://github.com/rust-lang/rust/pull/84541) is merged it will be. Storing a `TcpStream` also allows for closing to be implemented by the standard library instead of this one, which is a nice benefit.

Thomasdezeeuw: I actually plan to use socket2 in std lib (issue #212), so this change would make it a lot harder. Do you know if there are any plans to expose the valid range of an int (i.e. what `TcpStream` is already using) as a public API?
KaiJewson: I do not know of any plans for that, no. This niche actually makes things difficult because it would probably be considered a regression for std to remove the niche. Excluding adding more things to the language, we could hide `Socket` behind a `std` feature flag, and have libstd use `SockRef` instead so it can implement its own niche optimization. I don't know if that would cause a circular dependency though - potentially if `-Zbuild-std` is enabled?
Thomasdezeeuw: FreeBSD failure seems unrelated, so I'm merging.

Patch:
diff --git a/src/socket.rs b/src/socket.rs
index 6e09f37..ef8781f 100644
--- a/src/socket.rs
+++ b/src/socket.rs
@@ -68,11 +68,26 @@ use crate::{MaybeUninitSlice, RecvFlags};
 /// # Ok(()) }
 /// ```
 pub struct Socket {
-    // The `sys` module most have access to the socket.
-    pub(crate) inner: sys::Socket,
+    inner: Inner,
 }
 
+/// Store a `TcpStream` internally to take advantage of its niche optimizations on Unix platforms.
+pub(crate) type Inner = std::net::TcpStream;
+
+// The `sys` module must have access to the below three functions.
 impl Socket {
+    pub(crate) fn from_raw(raw: sys::Socket) -> Socket {
+        Socket {
+            inner: sys::socket_from_raw(raw),
+        }
+    }
+    pub(crate) fn as_raw(&self) -> sys::Socket {
+        sys::socket_as_raw(&self.inner)
+    }
+    pub(crate) fn into_raw(self) -> sys::Socket {
+        sys::socket_into_raw(self.inner)
+    }
+
     /// Creates a new socket and sets common flags.
     ///
     /// This function corresponds to `socket(2)` on Unix and `WSASocketW` on
@@ -94,7 +109,7 @@ impl Socket {
     /// Windows and simply creates a new socket, no other configuration is done.
     pub fn new_raw(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<Socket> {
         let protocol = protocol.map(|p| p.0).unwrap_or(0);
-        sys::socket(domain.0, ty.0, protocol).map(|inner| Socket { inner })
+        sys::socket(domain.0, ty.0, protocol).map(Socket::from_raw)
     }
 
     /// Creates a pair of sockets which are connected to each other.
@@ -135,7 +150,7 @@ impl Socket {
     ) -> io::Result<(Socket, Socket)> {
         let protocol = protocol.map(|p| p.0).unwrap_or(0);
         sys::socketpair(domain.0, ty.0, protocol)
-            .map(|fds| (Socket { inner: fds[0] }, Socket { inner: fds[1] }))
+            .map(|[a, b]| (Socket::from_raw(a), Socket::from_raw(b)))
     }
 
     /// Binds this socket to the specified address.
@@ -143,7 +158,7 @@ impl Socket {
     /// This function directly corresponds to the `bind(2)` function on Windows
     /// and Unix.
     pub fn bind(&self, address: &SockAddr) -> io::Result<()> {
-        sys::bind(self.inner, address)
+        sys::bind(self.as_raw(), address)
     }
 
     /// Initiate a connection on this socket to the specified address.
@@ -161,7 +176,7 @@ impl Socket {
     /// set *while connecting*. This will cause errors on Windows. Socket
     /// options can be safely set before and after connecting the socket.
     pub fn connect(&self, address: &SockAddr) -> io::Result<()> {
-        sys::connect(self.inner, address)
+        sys::connect(self.as_raw(), address)
     }
 
     /// Initiate a connection on this socket to the specified address, only
@@ -208,7 +223,7 @@ impl Socket {
     /// An error will be returned if `listen` or `connect` has already been
     /// called on this builder.
     pub fn listen(&self, backlog: c_int) -> io::Result<()> {
-        sys::listen(self.inner, backlog)
+        sys::listen(self.as_raw(), backlog)
     }
 
     /// Accept a new incoming connection from this listener.
@@ -254,7 +269,7 @@ impl Socket {
     /// This function directly corresponds to the `accept(2)` function on
     /// Windows and Unix.
     pub fn accept_raw(&self) -> io::Result<(Socket, SockAddr)> {
-        sys::accept(self.inner).map(|(inner, addr)| (Socket { inner }, addr))
+        sys::accept(self.as_raw()).map(|(inner, addr)| (Socket::from_raw(inner), addr))
     }
 
     /// Returns the socket address of the local half of this socket.
@@ -266,7 +281,7 @@ impl Socket {
     ///
     /// [bound]: Socket::bind
     pub fn local_addr(&self) -> io::Result<SockAddr> {
-        sys::getsockname(self.inner)
+        sys::getsockname(self.as_raw())
     }
 
     /// Returns the socket address of the remote peer of this socket.
@@ -277,13 +292,13 @@ impl Socket {
     ///
     /// [`connect`ed]: Socket::connect
     pub fn peer_addr(&self) -> io::Result<SockAddr> {
-        sys::getpeername(self.inner)
+        sys::getpeername(self.as_raw())
     }
 
     /// Returns the [`Type`] of this socket by checking the `SO_TYPE` option on
     /// this socket.
     pub fn r#type(&self) -> io::Result<Type> {
-        unsafe { getsockopt::<c_int>(self.inner, sys::SOL_SOCKET, sys::SO_TYPE).map(Type) }
+        unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_TYPE).map(Type) }
     }
 
     /// Creates a new independently owned handle to the underlying socket.
@@ -300,7 +315,7 @@ impl Socket {
     /// QOS-enabled socket, see
     /// <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaduplicatesocketw>.
     pub fn try_clone(&self) -> io::Result<Socket> {
-        sys::try_clone(self.inner).map(|inner| Socket { inner })
+        sys::try_clone(self.as_raw()).map(Socket::from_raw)
     }
 
     /// Moves this TCP stream into or out of nonblocking mode.
@@ -312,7 +327,7 @@ impl Socket {
     /// On Windows this corresponds to calling `ioctlsocket` (un)setting
     /// `FIONBIO`.
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
-        sys::set_nonblocking(self.inner, nonblocking)
+        sys::set_nonblocking(self.as_raw(), nonblocking)
     }
 
     /// Shuts down the read, write, or both halves of this connection.
@@ -320,7 +335,7 @@ impl Socket {
     /// This function will cause all pending and future I/O on the specified
     /// portions to return immediately with an appropriate value.
     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
-        sys::shutdown(self.inner, how)
+        sys::shutdown(self.as_raw(), how)
     }
 
     /// Receives data on the socket from the remote address to which it is
@@ -367,7 +382,7 @@ impl Socket {
         buf: &mut [MaybeUninit<u8>],
         flags: sys::c_int,
     ) -> io::Result<usize> {
-        sys::recv(self.inner, buf, flags)
+        sys::recv(self.as_raw(), buf, flags)
     }
 
     /// Receives data on the socket from the remote address to which it is
@@ -420,7 +435,7 @@ impl Socket {
         bufs: &mut [MaybeUninitSlice<'_>],
         flags: c_int,
     ) -> io::Result<(usize, RecvFlags)> {
-        sys::recv_vectored(self.inner, bufs, flags)
+        sys::recv_vectored(self.as_raw(), bufs, flags)
     }
 
     /// Receives data on the socket from the remote adress to which it is
@@ -462,7 +477,7 @@ impl Socket {
         buf: &mut [MaybeUninit<u8>],
         flags: c_int,
     ) -> io::Result<(usize, SockAddr)> {
-        sys::recv_from(self.inner, buf, flags)
+        sys::recv_from(self.as_raw(), buf, flags)
     }
 
     /// Receives data from the socket. Returns the amount of bytes read, the
@@ -502,7 +517,7 @@ impl Socket {
         bufs: &mut [MaybeUninitSlice<'_>],
         flags: c_int,
     ) -> io::Result<(usize, RecvFlags, SockAddr)> {
-        sys::recv_from_vectored(self.inner, bufs, flags)
+        sys::recv_from_vectored(self.as_raw(), bufs, flags)
     }
 
     /// Receives data from the socket, without removing it from the queue.
@@ -538,7 +553,7 @@ impl Socket {
     ///
     /// [`send`]: #method.send
     pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
-        sys::send(self.inner, buf, flags)
+        sys::send(self.as_raw(), buf, flags)
     }
 
     /// Send data to the connected peer. Returns the amount of bytes written.
@@ -557,7 +572,7 @@ impl Socket {
         bufs: &[IoSlice<'_>],
         flags: c_int,
     ) -> io::Result<usize> {
-        sys::send_vectored(self.inner, bufs, flags)
+        sys::send_vectored(self.as_raw(), bufs, flags)
     }
 
     /// Sends out-of-band (OOB) data on the socket to connected peer
@@ -589,7 +604,7 @@ impl Socket {
         addr: &SockAddr,
         flags: c_int,
     ) -> io::Result<usize> {
-        sys::send_to(self.inner, buf, addr, flags)
+        sys::send_to(self.as_raw(), buf, addr, flags)
     }
 
     /// Send data to a peer listening on `addr`. Returns the amount of bytes
@@ -610,7 +625,7 @@ impl Socket {
         addr: &SockAddr,
         flags: c_int,
     ) -> io::Result<usize> {
-        sys::send_to_vectored(self.inner, bufs, addr, flags)
+        sys::send_to_vectored(self.as_raw(), bufs, addr, flags)
     }
 }
 
@@ -677,7 +692,7 @@ impl Socket {
     /// [`set_broadcast`]: Socket::set_broadcast
     pub fn broadcast(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::SOL_SOCKET, sys::SO_BROADCAST)
+            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_BROADCAST)
                 .map(|broadcast| broadcast != 0)
         }
     }
@@ -689,7 +704,7 @@ impl Socket {
     pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::SOL_SOCKET,
                 sys::SO_BROADCAST,
                 broadcast as c_int,
@@ -703,7 +718,7 @@ impl Socket {
     /// the field in the process. This can be useful for checking errors between
     /// calls.
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        match unsafe { getsockopt::<c_int>(self.inner, sys::SOL_SOCKET, sys::SO_ERROR) } {
+        match unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_ERROR) } {
             Ok(0) => Ok(None),
             Ok(errno) => Ok(Some(io::Error::from_raw_os_error(errno))),
             Err(err) => Err(err),
@@ -717,7 +732,7 @@ impl Socket {
     /// [`set_keepalive`]: Socket::set_keepalive
     pub fn keepalive(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<Bool>(self.inner, sys::SOL_SOCKET, sys::SO_KEEPALIVE)
+            getsockopt::<Bool>(self.as_raw(), sys::SOL_SOCKET, sys::SO_KEEPALIVE)
                 .map(|keepalive| keepalive != 0)
         }
     }
@@ -728,7 +743,7 @@ impl Socket {
     pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::SOL_SOCKET,
                 sys::SO_KEEPALIVE,
                 keepalive as c_int,
@@ -743,7 +758,8 @@ impl Socket {
     /// [`set_linger`]: Socket::set_linger
     pub fn linger(&self) -> io::Result<Option<Duration>> {
         unsafe {
-            getsockopt::<sys::linger>(self.inner, sys::SOL_SOCKET, sys::SO_LINGER).map(from_linger)
+            getsockopt::<sys::linger>(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER)
+                .map(from_linger)
         }
     }
 
@@ -763,7 +779,7 @@ impl Socket {
     /// On Apple platforms (e.g. macOS, iOS, etc) this uses `SO_LINGER_SEC`.
     pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
         let linger = into_linger(linger);
-        unsafe { setsockopt(self.inner, sys::SOL_SOCKET, sys::SO_LINGER, linger) }
+        unsafe { setsockopt(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER, linger) }
     }
 
     /// Get value for the `SO_OOBINLINE` option on this socket.
@@ -774,7 +790,7 @@ impl Socket {
     #[cfg(not(target_os = "redox"))]
     pub fn out_of_band_inline(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::SOL_SOCKET, sys::SO_OOBINLINE)
+            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_OOBINLINE)
                 .map(|oob_inline| oob_inline != 0)
         }
     }
@@ -789,7 +805,7 @@ impl Socket {
     pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::SOL_SOCKET,
                 sys::SO_OOBINLINE,
                 oob_inline as c_int,
@@ -804,7 +820,7 @@ impl Socket {
     /// [`set_recv_buffer_size`]: Socket::set_recv_buffer_size
     pub fn recv_buffer_size(&self) -> io::Result<usize> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::SOL_SOCKET, sys::SO_RCVBUF)
+            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVBUF)
                 .map(|size| size as usize)
         }
     }
@@ -814,7 +830,14 @@ impl Socket {
     /// Changes the size of the operating system's receive buffer associated
     /// with the socket.
     pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
-        unsafe { setsockopt(self.inner, sys::SOL_SOCKET, sys::SO_RCVBUF, size as c_int) }
+        unsafe {
+            setsockopt(
+                self.as_raw(),
+                sys::SOL_SOCKET,
+                sys::SO_RCVBUF,
+                size as c_int,
+            )
+        }
     }
 
     /// Get value for the `SO_RCVTIMEO` option on this socket.
@@ -822,7 +845,7 @@ impl Socket {
     /// If the returned timeout is `None`, then `read` and `recv` calls will
     /// block indefinitely.
     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        sys::timeout_opt(self.inner, sys::SOL_SOCKET, sys::SO_RCVTIMEO)
+        sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO)
     }
 
     /// Set value for the `SO_RCVTIMEO` option on this socket.
@@ -830,7 +853,7 @@ impl Socket {
     /// If `timeout` is `None`, then `read` and `recv` calls will block
     /// indefinitely.
     pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
-        sys::set_timeout_opt(self.inner, sys::SOL_SOCKET, sys::SO_RCVTIMEO, duration)
+        sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO, duration)
     }
 
     /// Get the value of the `SO_REUSEADDR` option on this socket.
@@ -840,7 +863,7 @@ impl Socket {
     /// [`set_reuse_address`]: Socket::set_reuse_address
     pub fn reuse_address(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::SOL_SOCKET, sys::SO_REUSEADDR)
+            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_REUSEADDR)
                 .map(|reuse| reuse != 0)
         }
     }
@@ -853,7 +876,7 @@ impl Socket {
     pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::SOL_SOCKET,
                 sys::SO_REUSEADDR,
                 reuse as c_int,
@@ -868,7 +891,7 @@ impl Socket {
     /// [`set_send_buffer_size`]: Socket::set_send_buffer_size
     pub fn send_buffer_size(&self) -> io::Result<usize> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::SOL_SOCKET, sys::SO_SNDBUF)
+            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDBUF)
                 .map(|size| size as usize)
         }
     }
@@ -878,7 +901,14 @@ impl Socket {
     /// Changes the size of the operating system's send buffer associated with
     /// the socket.
     pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
-        unsafe { setsockopt(self.inner, sys::SOL_SOCKET, sys::SO_SNDBUF, size as c_int) }
+        unsafe {
+            setsockopt(
+                self.as_raw(),
+                sys::SOL_SOCKET,
+                sys::SO_SNDBUF,
+                size as c_int,
+            )
+        }
     }
 
     /// Get value for the `SO_SNDTIMEO` option on this socket.
@@ -886,7 +916,7 @@ impl Socket {
     /// If the returned timeout is `None`, then `write` and `send` calls will
     /// block indefinitely.
     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        sys::timeout_opt(self.inner, sys::SOL_SOCKET, sys::SO_SNDTIMEO)
+        sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO)
     }
 
     /// Set value for the `SO_SNDTIMEO` option on this socket.
@@ -894,7 +924,7 @@ impl Socket {
     /// If `timeout` is `None`, then `write` and `send` calls will block
     /// indefinitely.
     pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
-        sys::set_timeout_opt(self.inner, sys::SOL_SOCKET, sys::SO_SNDTIMEO, duration)
+        sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO, duration)
     }
 }
 
@@ -937,7 +967,7 @@ impl Socket {
             imr_multiaddr: sys::to_in_addr(multiaddr),
             imr_interface: sys::to_in_addr(interface),
         };
-        unsafe { setsockopt(self.inner, sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
+        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
     }
 
     /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
@@ -950,7 +980,14 @@ impl Socket {
             imr_multiaddr: sys::to_in_addr(multiaddr),
             imr_interface: sys::to_in_addr(interface),
         };
-        unsafe { setsockopt(self.inner, sys::IPPROTO_IP, sys::IP_DROP_MEMBERSHIP, mreq) }
+        unsafe {
+            setsockopt(
+                self.as_raw(),
+                sys::IPPROTO_IP,
+                sys::IP_DROP_MEMBERSHIP,
+                mreq,
+            )
+        }
     }
 
     /// Get the value of the `IP_MULTICAST_IF` option for this socket.
@@ -960,7 +997,7 @@ impl Socket {
     /// [`set_multicast_if_v4`]: Socket::set_multicast_if_v4
     pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
         unsafe {
-            getsockopt(self.inner, sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
+            getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
         }
     }
 
@@ -969,7 +1006,14 @@ impl Socket {
     /// Specifies the interface to use for routing multicast packets.
     pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
         let interface = sys::to_in_addr(interface);
-        unsafe { setsockopt(self.inner, sys::IPPROTO_IP, sys::IP_MULTICAST_IF, interface) }
+        unsafe {
+            setsockopt(
+                self.as_raw(),
+                sys::IPPROTO_IP,
+                sys::IP_MULTICAST_IF,
+                interface,
+            )
+        }
     }
 
     /// Get the value of the `IP_MULTICAST_LOOP` option for this socket.
@@ -979,7 +1023,7 @@ impl Socket {
     /// [`set_multicast_loop_v4`]: Socket::set_multicast_loop_v4
     pub fn multicast_loop_v4(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
                 .map(|loop_v4| loop_v4 != 0)
         }
     }
@@ -991,7 +1035,7 @@ impl Socket {
     pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_IP,
                 sys::IP_MULTICAST_LOOP,
                 loop_v4 as c_int,
@@ -1006,7 +1050,7 @@ impl Socket {
     /// [`set_multicast_ttl_v4`]: Socket::set_multicast_ttl_v4
     pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
                 .map(|ttl| ttl as u32)
         }
     }
@@ -1021,7 +1065,7 @@ impl Socket {
     pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_IP,
                 sys::IP_MULTICAST_TTL,
                 ttl as c_int,
@@ -1036,7 +1080,7 @@ impl Socket {
     /// [`set_ttl`]: Socket::set_ttl
     pub fn ttl(&self) -> io::Result<u32> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
         }
     }
 
@@ -1045,7 +1089,7 @@ impl Socket {
     /// This value sets the time-to-live field that is used in every packet sent
     /// from this socket.
     pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
-        unsafe { setsockopt(self.inner, sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
+        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
     }
 }
 
@@ -1070,7 +1114,7 @@ impl Socket {
         };
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_IPV6,
                 sys::IPV6_ADD_MEMBERSHIP,
                 mreq,
@@ -1093,7 +1137,7 @@ impl Socket {
         };
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_IPV6,
                 sys::IPV6_DROP_MEMBERSHIP,
                 mreq,
@@ -1108,7 +1152,7 @@ impl Socket {
     /// [`set_multicast_hops_v6`]: Socket::set_multicast_hops_v6
     pub fn multicast_hops_v6(&self) -> io::Result<u32> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
                 .map(|hops| hops as u32)
         }
     }
@@ -1121,7 +1165,7 @@ impl Socket {
     pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_IPV6,
                 sys::IPV6_MULTICAST_HOPS,
                 hops as c_int,
@@ -1136,7 +1180,7 @@ impl Socket {
     /// [`set_multicast_if_v6`]: Socket::set_multicast_if_v6
     pub fn multicast_if_v6(&self) -> io::Result<u32> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
                 .map(|interface| interface as u32)
         }
     }
@@ -1149,7 +1193,7 @@ impl Socket {
     pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_IPV6,
                 sys::IPV6_MULTICAST_IF,
                 interface as c_int,
@@ -1164,7 +1208,7 @@ impl Socket {
     /// [`set_multicast_loop_v6`]: Socket::set_multicast_loop_v6
     pub fn multicast_loop_v6(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
                 .map(|loop_v6| loop_v6 != 0)
         }
     }
@@ -1176,7 +1220,7 @@ impl Socket {
     pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_IPV6,
                 sys::IPV6_MULTICAST_LOOP,
                 loop_v6 as c_int,
@@ -1189,7 +1233,7 @@ impl Socket {
     /// Specifies the hop limit for ipv6 unicast packets
     pub fn unicast_hops_v6(&self) -> io::Result<u32> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
                 .map(|hops| hops as u32)
         }
     }
@@ -1200,7 +1244,7 @@ impl Socket {
     pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_IPV6,
                 sys::IPV6_UNICAST_HOPS,
                 hops as c_int,
@@ -1215,7 +1259,7 @@ impl Socket {
     /// [`set_only_v6`]: Socket::set_only_v6
     pub fn only_v6(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
                 .map(|only_v6| only_v6 != 0)
         }
     }
@@ -1231,7 +1275,7 @@ impl Socket {
     pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_IPV6,
                 sys::IPV6_V6ONLY,
                 only_v6 as c_int,
@@ -1253,7 +1297,7 @@ impl Socket {
     /// operating systems.
     #[cfg(all(feature = "all", not(windows)))]
     pub fn keepalive_time(&self) -> io::Result<Duration> {
-        sys::keepalive_time(self.inner)
+        sys::keepalive_time(self.as_raw())
     }
 
     /// Get the value of the `TCP_KEEPINTVL` option on this socket.
@@ -1276,7 +1320,7 @@ impl Socket {
     ))]
     pub fn keepalive_interval(&self) -> io::Result<Duration> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
                 .map(|secs| Duration::from_secs(secs as u64))
         }
     }
@@ -1301,7 +1345,7 @@ impl Socket {
     ))]
     pub fn keepalive_retries(&self) -> io::Result<u32> {
         unsafe {
-            getsockopt::<c_int>(self.inner, sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
+            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
                 .map(|retries| retries as u32)
         }
     }
@@ -1346,7 +1390,7 @@ impl Socket {
     ///
     pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<()> {
         self.set_keepalive(true)?;
-        sys::set_tcp_keepalive(self.inner, params)
+        sys::set_tcp_keepalive(self.as_raw(), params)
     }
 
     /// Get the value of the `TCP_NODELAY` option on this socket.
@@ -1356,7 +1400,7 @@ impl Socket {
     /// [`set_nodelay`]: Socket::set_nodelay
     pub fn nodelay(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<Bool>(self.inner, sys::IPPROTO_TCP, sys::TCP_NODELAY)
+            getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_NODELAY)
                 .map(|nodelay| nodelay != 0)
         }
     }
@@ -1371,7 +1415,7 @@ impl Socket {
     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 sys::IPPROTO_TCP,
                 sys::TCP_NODELAY,
                 nodelay as c_int,
@@ -1447,7 +1491,7 @@ impl<'a> Write for &'a Socket {
 impl fmt::Debug for Socket {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Socket")
-            .field("raw", &self.inner)
+            .field("raw", &self.as_raw())
             .field("local_addr", &self.local_addr().ok())
             .field("peer_addr", &self.peer_addr().ok())
             .finish()
@@ -1460,9 +1504,3 @@ from!(net::UdpSocket, Socket);
 from!(Socket, net::TcpStream);
 from!(Socket, net::TcpListener);
 from!(Socket, net::UdpSocket);
-
-impl Drop for Socket {
-    fn drop(&mut self) {
-        sys::close(self.inner);
-    }
-}
diff --git a/src/sockref.rs b/src/sockref.rs
index 8415718..279e687 100644
--- a/src/sockref.rs
+++ b/src/sockref.rs
@@ -105,7 +105,7 @@ where
 impl fmt::Debug for SockRef<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("SockRef")
-            .field("raw", &self.socket.inner)
+            .field("raw", &self.socket.as_raw())
             .field("local_addr", &self.socket.local_addr().ok())
             .field("peer_addr", &self.socket.peer_addr().ok())
             .finish()
diff --git a/src/sys/unix.rs b/src/sys/unix.rs
index bde007b..49a63e9 100644
--- a/src/sys/unix.rs
+++ b/src/sys/unix.rs
@@ -482,6 +482,18 @@ impl SockAddr {
 
 pub(crate) type Socket = c_int;
 
+pub(crate) fn socket_from_raw(socket: Socket) -> crate::socket::Inner {
+    unsafe { crate::socket::Inner::from_raw_fd(socket) }
+}
+
+pub(crate) fn socket_as_raw(socket: &crate::socket::Inner) -> Socket {
+    socket.as_raw_fd()
+}
+
+pub(crate) fn socket_into_raw(socket: crate::socket::Inner) -> Socket {
+    socket.into_raw_fd()
+}
+
 pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> {
     syscall!(socket(family, ty, protocol))
 }
@@ -504,7 +516,7 @@ pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Res
     let start = Instant::now();
 
     let mut pollfd = libc::pollfd {
-        fd: socket.inner,
+        fd: socket.as_raw(),
         events: libc::POLLIN | libc::POLLOUT,
         revents: 0,
     };
@@ -884,12 +896,6 @@ pub(crate) unsafe fn setsockopt<T>(
     .map(|_| ())
 }
 
-pub(crate) fn close(fd: Socket) {
-    unsafe {
-        let _ = libc::close(fd);
-    }
-}
-
 pub(crate) fn to_in_addr(addr: &Ipv4Addr) -> in_addr {
     // `s_addr` is stored as BE on all machines, and the array is in BE order.
     // So the native endian conversion method is used so that it's never
@@ -953,8 +959,8 @@ impl crate::Socket {
         // Safety: `accept4` initialises the `SockAddr` for us.
         unsafe {
             SockAddr::init(|storage, len| {
-                syscall!(accept4(self.inner, storage.cast(), len, flags))
-                    .map(|inner| crate::Socket { inner })
+                syscall!(accept4(self.as_raw(), storage.cast(), len, flags))
+                    .map(crate::Socket::from_raw)
             })
         }
     }
@@ -971,9 +977,19 @@ impl crate::Socket {
 
     pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> {
         if close_on_exec {
-            fcntl_add(self.inner, libc::F_GETFD, libc::F_SETFD, libc::FD_CLOEXEC)
+            fcntl_add(
+                self.as_raw(),
+                libc::F_GETFD,
+                libc::F_SETFD,
+                libc::FD_CLOEXEC,
+            )
         } else {
-            fcntl_remove(self.inner, libc::F_GETFD, libc::F_SETFD, libc::FD_CLOEXEC)
+            fcntl_remove(
+                self.as_raw(),
+                libc::F_GETFD,
+                libc::F_SETFD,
+                libc::FD_CLOEXEC,
+            )
         }
     }
 
@@ -991,7 +1007,7 @@ impl crate::Socket {
     pub(crate) fn _set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 libc::SOL_SOCKET,
                 libc::SO_NOSIGPIPE,
                 nosigpipe as c_int,
@@ -1007,7 +1023,7 @@ impl crate::Socket {
     #[cfg(all(feature = "all", not(target_os = "redox")))]
     pub fn mss(&self) -> io::Result<u32> {
         unsafe {
-            getsockopt::<c_int>(self.inner, libc::IPPROTO_TCP, libc::TCP_MAXSEG)
+            getsockopt::<c_int>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG)
                 .map(|mss| mss as u32)
         }
     }
@@ -1020,7 +1036,7 @@ impl crate::Socket {
     pub fn set_mss(&self, mss: u32) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 libc::IPPROTO_TCP,
                 libc::TCP_MAXSEG,
                 mss as c_int,
@@ -1041,7 +1057,8 @@ impl crate::Socket {
     ))]
     pub fn is_listener(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<c_int>(self.inner, libc::SOL_SOCKET, libc::SO_ACCEPTCONN).map(|v| v != 0)
+            getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN)
+                .map(|v| v != 0)
         }
     }
 
@@ -1058,7 +1075,7 @@ impl crate::Socket {
         )
     ))]
     pub fn domain(&self) -> io::Result<Domain> {
-        unsafe { getsockopt::<c_int>(self.inner, libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
+        unsafe { getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) }
     }
 
     /// Returns the [`Protocol`] of this socket by checking the `SO_PROTOCOL`
@@ -1074,7 +1091,8 @@ impl crate::Socket {
     ))]
     pub fn protocol(&self) -> io::Result<Option<Protocol>> {
         unsafe {
-            getsockopt::<c_int>(self.inner, libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v {
+            getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v
+            {
                 0 => None,
                 p => Some(Protocol(p)),
             })
@@ -1094,7 +1112,8 @@ impl crate::Socket {
     ))]
     pub fn mark(&self) -> io::Result<u32> {
         unsafe {
-            getsockopt::<c_int>(self.inner, libc::SOL_SOCKET, libc::SO_MARK).map(|mark| mark as u32)
+            getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK)
+                .map(|mark| mark as u32)
         }
     }
 
@@ -1111,7 +1130,14 @@ impl crate::Socket {
         any(target_os = "android", target_os = "fuchsia", target_os = "linux")
     ))]
     pub fn set_mark(&self, mark: u32) -> io::Result<()> {
-        unsafe { setsockopt::<c_int>(self.inner, libc::SOL_SOCKET, libc::SO_MARK, mark as c_int) }
+        unsafe {
+            setsockopt::<c_int>(
+                self.as_raw(),
+                libc::SOL_SOCKET,
+                libc::SO_MARK,
+                mark as c_int,
+            )
+        }
     }
 
     /// Gets the value for the `SO_BINDTODEVICE` option on this socket.
@@ -1130,7 +1156,7 @@ impl crate::Socket {
         let mut len = buf.len() as libc::socklen_t;
         unsafe {
             syscall!(getsockopt(
-                self.inner,
+                self.as_raw(),
                 libc::SOL_SOCKET,
                 libc::SO_BINDTODEVICE,
                 buf.as_mut_ptr().cast(),
@@ -1166,7 +1192,7 @@ impl crate::Socket {
             (ptr::null(), 0)
         };
         syscall!(setsockopt(
-            self.inner,
+            self.as_raw(),
             libc::SOL_SOCKET,
             libc::SO_BINDTODEVICE,
             value.cast(),
@@ -1185,7 +1211,7 @@ impl crate::Socket {
     #[cfg(all(feature = "all", any(target_os = "linux")))]
     pub fn cpu_affinity(&self) -> io::Result<usize> {
         unsafe {
-            getsockopt::<c_int>(self.inner, libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
+            getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU)
                 .map(|cpu| cpu as usize)
         }
     }
@@ -1199,7 +1225,7 @@ impl crate::Socket {
     pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 libc::SOL_SOCKET,
                 libc::SO_INCOMING_CPU,
                 cpu as c_int,
@@ -1220,7 +1246,7 @@ impl crate::Socket {
     ))]
     pub fn reuse_port(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<c_int>(self.inner, libc::SOL_SOCKET, libc::SO_REUSEPORT)
+            getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT)
                 .map(|reuse| reuse != 0)
         }
     }
@@ -1239,7 +1265,7 @@ impl crate::Socket {
     pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 libc::SOL_SOCKET,
                 libc::SO_REUSEPORT,
                 reuse as c_int,
@@ -1260,7 +1286,7 @@ impl crate::Socket {
     ))]
     pub fn freebind(&self) -> io::Result<bool> {
         unsafe {
-            getsockopt::<c_int>(self.inner, libc::SOL_SOCKET, libc::IP_FREEBIND)
+            getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::IP_FREEBIND)
                 .map(|reuse| reuse != 0)
         }
     }
@@ -1281,7 +1307,7 @@ impl crate::Socket {
     pub fn set_freebind(&self, reuse: bool) -> io::Result<()> {
         unsafe {
             setsockopt(
-                self.inner,
+                self.as_raw(),
                 libc::SOL_SOCKET,
                 libc::IP_FREEBIND,
                 reuse as c_int,
@@ -1344,7 +1370,7 @@ impl crate::Socket {
         };
         syscall!(sendfile(
             file,
-            self.inner,
+            self.as_raw(),
             offset,
             &mut length,
             ptr::null_mut(),
@@ -1366,7 +1392,7 @@ impl crate::Socket {
             None => 0x7ffff000, // 2,147,479,552 bytes.
         };
         let mut offset = offset;
-        syscall!(sendfile(self.inner, file, &mut offset, count)).map(|n| n as usize)
+        syscall!(sendfile(self.as_raw(), file, &mut offset, count)).map(|n| n as usize)
     }
 
     #[cfg(all(feature = "all", target_os = "freebsd"))]
@@ -1384,7 +1410,7 @@ impl crate::Socket {
         let mut sbytes: libc::off_t = 0;
         syscall!(sendfile(
             file,
-            self.inner,
+            self.as_raw(),
             offset,
             nbytes,
             ptr::null_mut(),
@@ -1397,21 +1423,19 @@ impl crate::Socket {
 
 impl AsRawFd for crate::Socket {
     fn as_raw_fd(&self) -> c_int {
-        self.inner
+        self.as_raw()
     }
 }
 
 impl IntoRawFd for crate::Socket {
     fn into_raw_fd(self) -> c_int {
-        let fd = self.inner;
-        mem::forget(self);
-        fd
+        self.into_raw()
     }
 }
 
 impl FromRawFd for crate::Socket {
     unsafe fn from_raw_fd(fd: c_int) -> crate::Socket {
-        crate::Socket { inner: fd }
+        crate::Socket::from_raw(fd)
     }
 }
 
diff --git a/src/sys/windows.rs b/src/sys/windows.rs
index ad5cc72..6eeb021 100644
--- a/src/sys/windows.rs
+++ b/src/sys/windows.rs
@@ -190,6 +190,18 @@ fn init() {
 
 pub(crate) type Socket = sock::SOCKET;
 
+pub(crate) fn socket_from_raw(socket: Socket) -> crate::socket::Inner {
+    unsafe { crate::socket::Inner::from_raw_socket(socket as RawSocket) }
+}
+
+pub(crate) fn socket_as_raw(socket: &crate::socket::Inner) -> Socket {
+    socket.as_raw_socket() as Socket
+}
+
+pub(crate) fn socket_into_raw(socket: crate::socket::Inner) -> Socket {
+    socket.into_raw_socket() as Socket
+}
+
 pub(crate) fn socket(family: c_int, mut ty: c_int, protocol: c_int) -> io::Result<Socket> {
     init();
 
@@ -227,7 +239,7 @@ pub(crate) fn poll_connect(socket: &crate::Socket, timeout: Duration) -> io::Res
     let start = Instant::now();
 
     let mut fd_array = WSAPOLLFD {
-        fd: socket.inner,
+        fd: socket.as_raw(),
         events: POLLRDNORM | POLLWRNORM,
         revents: 0,
     };
@@ -698,12 +710,6 @@ fn ioctlsocket(socket: Socket, cmd: c_long, payload: &mut u_long) -> io::Result<
     .map(|_| ())
 }
 
-pub(crate) fn close(socket: Socket) {
-    unsafe {
-        let _ = sock::closesocket(socket);
-    }
-}
-
 pub(crate) fn to_in_addr(addr: &Ipv4Addr) -> IN_ADDR {
     let mut s_un: in_addr_S_un = unsafe { mem::zeroed() };
     // `S_un` is stored as BE on all machines, and the array is in BE order. So
@@ -741,7 +747,7 @@ impl crate::Socket {
         // `sock::` path.
         let res = unsafe {
             SetHandleInformation(
-                self.inner as HANDLE,
+                self.as_raw() as HANDLE,
                 winbase::HANDLE_FLAG_INHERIT,
                 !no_inherit as _,
             )
@@ -757,23 +763,19 @@ impl crate::Socket {
 
 impl AsRawSocket for crate::Socket {
     fn as_raw_socket(&self) -> RawSocket {
-        self.inner as RawSocket
+        self.as_raw() as RawSocket
     }
 }
 
 impl IntoRawSocket for crate::Socket {
     fn into_raw_socket(self) -> RawSocket {
-        let socket = self.inner;
-        mem::forget(self);
-        socket as RawSocket
+        self.into_raw() as RawSocket
     }
 }
 
 impl FromRawSocket for crate::Socket {
     unsafe fn from_raw_socket(socket: RawSocket) -> crate::Socket {
-        crate::Socket {
-            inner: socket as Socket,
-        }
+        crate::Socket::from_raw(socket as Socket)
     }
 }
 


Test patch:
diff --git a/tests/socket.rs b/tests/socket.rs
index 32efe8e..5f39bd8 100644
--- a/tests/socket.rs
+++ b/tests/socket.rs
@@ -14,8 +14,8 @@ use std::io::IoSlice;
 #[cfg(all(unix, feature = "all"))]
 use std::io::Read;
 use std::io::Write;
-use std::mem::MaybeUninit;
-use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
+use std::mem::{self, MaybeUninit};
+use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream};
 #[cfg(not(target_os = "redox"))]
 use std::net::{Ipv6Addr, SocketAddrV6};
 #[cfg(all(
@@ -953,6 +953,13 @@ fn cpu_affinity() {
     assert_eq!(socket.cpu_affinity().unwrap(), want);
 }
 
+#[test]
+fn niche() {
+    if mem::size_of::<Option<TcpStream>>() == mem::size_of::<TcpStream>() {
+        assert_eq!(mem::size_of::<Option<Socket>>(), mem::size_of::<Socket>());
+    }
+}
+
 fn any_ipv4() -> SockAddr {
     SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0).into()
 }