Skip to content

Commit

Permalink
Remove net2 dependency (#1029)
Browse files Browse the repository at this point in the history
Removing the need for the net2 crate.

On Unix platforms (expect for iOS, macOS and Solaris) this reduces the
number of system calls from four to two, on iOS, macOS and Solaris this
reduces it to three system calls.

# Windows net initialization

The standard library calls WSAStartup for us, ensuring (with an assert)
that the return value is ok. This means that we can't initialise it
ourselves and need to let the standard library do it for us. To work
around this we create and drop a UdpSocket (from std::net).
  • Loading branch information
Thomasdezeeuw authored and carllerche committed Aug 13, 2019
1 parent 2f688de commit f30debe
Show file tree
Hide file tree
Showing 18 changed files with 435 additions and 399 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ publish = false
[features]

[dependencies]
log = "0.4.6"
net2 = "0.2.33"
log = "0.4.6"

[target.'cfg(unix)'.dependencies]
libc = "0.2.58"
Expand All @@ -43,3 +42,4 @@ bytes = "0.4.12"
env_logger = { version = "0.6.1", default-features = false }
slab = "0.4.2"
tempdir = "0.3.7"
net2 = "0.2.33"
234 changes: 20 additions & 214 deletions src/net/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@
//!
//! [portability guidelines]: ../struct.Poll.html#portability

use std::fmt;
use std::io::{self, IoSlice, IoSliceMut, Read, Write};
use std::net::SocketAddr;

#[cfg(debug_assertions)]
use crate::poll::SelectorId;
use crate::{event, sys, Interests, Registry, Token};

use net2::TcpBuilder;
use std::fmt;
use std::io::{self, IoSlice, IoSliceMut, Read, Write};
use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::time::Duration;

/*
*
* ===== TcpStream =====
Expand Down Expand Up @@ -62,74 +60,12 @@ pub struct TcpStream {

use std::net::Shutdown;

fn set_nonblocking(stream: &net::TcpStream) -> io::Result<()> {
stream.set_nonblocking(true)
}

impl TcpStream {
/// Create a new TCP stream and issue a non-blocking connect to the
/// specified address.
///
/// This convenience method is available and uses the system's default
/// options when creating a socket which is then connected. If fine-grained
/// control over the creation of the socket is desired, you can use
/// `net2::TcpBuilder` to configure a socket and then pass its socket to
/// `TcpStream::connect_stream` to transfer ownership into mio and schedule
/// the connect operation.
pub fn connect(addr: SocketAddr) -> io::Result<TcpStream> {
let sock = match addr {
SocketAddr::V4(..) => TcpBuilder::new_v4(),
SocketAddr::V6(..) => TcpBuilder::new_v6(),
}?;
// Required on Windows for a future `connect_overlapped` operation to be
// executed successfully.
if cfg!(windows) {
sock.bind(inaddr_any(addr))?;
}
TcpStream::connect_stream(sock.to_tcp_stream()?, addr)
}

/// Creates a new `TcpStream` from the pending socket inside the given
/// `std::net::TcpBuilder`, connecting it to the address specified.
///
/// This constructor allows configuring the socket before it's actually
/// connected, and this function will transfer ownership to the returned
/// `TcpStream` if successful. An unconnected `TcpStream` can be created
/// with the `net2::TcpBuilder` type (and also configured via that route).
///
/// The platform specific behavior of this function looks like:
///
/// * On Unix, the socket is placed into nonblocking mode and then a
/// `connect` call is issued.
///
/// * On Windows, the address is stored internally and the connect operation
/// is issued when the returned `TcpStream` is registered with an event
/// loop. Note that on Windows you must `bind` a socket before it can be
/// connected, so if a custom `TcpBuilder` is used it should be bound
/// (perhaps to `INADDR_ANY`) before this method is called.
pub fn connect_stream(stream: net::TcpStream, addr: SocketAddr) -> io::Result<TcpStream> {
Ok(TcpStream {
sys: sys::TcpStream::connect(stream, addr)?,
#[cfg(debug_assertions)]
selector_id: SelectorId::new(),
})
}

/// Creates a new `TcpStream` from a standard `net::TcpStream`.
///
/// This function is intended to be used to wrap a TCP stream from the
/// standard library in the mio equivalent. The conversion here will
/// automatically set `stream` to nonblocking and the returned object should
/// be ready to get associated with an event loop.
///
/// Note that the TCP stream here will not have `connect` called on it, so
/// it should already be connected via some other means (be it manually, the
/// net2 crate, or the standard library).
pub fn from_stream(stream: net::TcpStream) -> io::Result<TcpStream> {
set_nonblocking(&stream)?;

Ok(TcpStream {
sys: sys::TcpStream::from_stream(stream),
sys::TcpStream::connect(addr).map(|sys| TcpStream {
sys,
#[cfg(debug_assertions)]
selector_id: SelectorId::new(),
})
Expand Down Expand Up @@ -188,68 +124,6 @@ impl TcpStream {
self.sys.nodelay()
}

/// Sets the value of the `SO_RCVBUF` option on this 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<()> {
self.sys.set_recv_buffer_size(size)
}

/// Gets the value of the `SO_RCVBUF` option on this socket.
///
/// For more information about this option, see
/// [`set_recv_buffer_size`][link].
///
/// [link]: #method.set_recv_buffer_size
pub fn recv_buffer_size(&self) -> io::Result<usize> {
self.sys.recv_buffer_size()
}

/// Sets the value of the `SO_SNDBUF` option on this 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<()> {
self.sys.set_send_buffer_size(size)
}

/// Gets the value of the `SO_SNDBUF` option on this socket.
///
/// For more information about this option, see
/// [`set_send_buffer_size`][link].
///
/// [link]: #method.set_send_buffer_size
pub fn send_buffer_size(&self) -> io::Result<usize> {
self.sys.send_buffer_size()
}

/// Sets whether keepalive messages are enabled to be sent on this socket.
///
/// On Unix, this option will set the `SO_KEEPALIVE` as well as the
/// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform).
/// On Windows, this will set the `SIO_KEEPALIVE_VALS` option.
///
/// If `None` is specified then keepalive messages are disabled, otherwise
/// the duration specified will be the time to remain idle before sending a
/// TCP keepalive probe.
///
/// Some platforms specify this value in seconds, so sub-second
/// specifications may be omitted.
pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
self.sys.set_keepalive(keepalive)
}

/// Returns whether keepalive messages are enabled on this socket, and if so
/// the duration of time between them.
///
/// For more information about this option, see [`set_keepalive`][link].
///
/// [link]: #method.set_keepalive
pub fn keepalive(&self) -> io::Result<Option<Duration>> {
self.sys.keepalive()
}

/// Sets the value for the `IP_TTL` option on this socket.
///
/// This value sets the time-to-live field that is used in every packet sent
Expand All @@ -267,20 +141,6 @@ impl TcpStream {
self.sys.ttl()
}

/// Sets the value for the `SO_LINGER` option on this socket.
pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
self.sys.set_linger(dur)
}

/// Gets the value of the `SO_LINGER` option on this socket.
///
/// For more information about this option, see [`set_linger`][link].
///
/// [link]: #method.set_linger
pub fn linger(&self) -> io::Result<Option<Duration>> {
self.sys.linger()
}

/// Get the value of the `SO_ERROR` option on this socket.
///
/// This will retrieve the stored error in the underlying socket, clearing
Expand All @@ -301,21 +161,6 @@ impl TcpStream {
}
}

fn inaddr_any(other: SocketAddr) -> SocketAddr {
match other {
SocketAddr::V4(..) => {
let any = Ipv4Addr::new(0, 0, 0, 0);
let addr = SocketAddrV4::new(any, 0);
SocketAddr::V4(addr)
}
SocketAddr::V6(..) => {
let any = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
let addr = SocketAddrV6::new(any, 0, 0, 0);
SocketAddr::V6(addr)
}
}
}

impl Read for TcpStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(&self.sys).read(buf)
Expand Down Expand Up @@ -436,50 +281,12 @@ impl TcpListener {
/// This function will take the following steps:
///
/// 1. Create a new TCP socket.
/// 2. Set the `SO_REUSEADDR` option on the socket.
/// 2. Set the `SO_REUSEADDR` option on the socket on Unix.
/// 3. Bind the socket to the specified address.
/// 4. Call `listen` on the socket to prepare it to receive new connections.
///
/// If fine-grained control over the binding and listening process for a
/// socket is desired then the `net2::TcpBuilder` methods can be used in
/// combination with the `TcpListener::from_listener` method to transfer
/// ownership into mio.
/// 4. Calls `listen` on the socket to prepare it to receive new connections.
pub fn bind(addr: SocketAddr) -> io::Result<TcpListener> {
// Create the socket
let sock = match addr {
SocketAddr::V4(..) => TcpBuilder::new_v4(),
SocketAddr::V6(..) => TcpBuilder::new_v6(),
}?;

// Set SO_REUSEADDR, but only on Unix (mirrors what libstd does)
if cfg!(unix) {
sock.reuse_address(true)?;
}

// Bind the socket
sock.bind(addr)?;

// listen
let listener = sock.listen(1024)?;
Ok(TcpListener {
sys: sys::TcpListener::new(listener)?,
#[cfg(debug_assertions)]
selector_id: SelectorId::new(),
})
}

/// Creates a new `TcpListener` from an instance of a
/// `std::net::TcpListener` type.
///
/// This function will set the `listener` provided into nonblocking mode on
/// Unix, and otherwise the stream will just be wrapped up in an mio stream
/// ready to accept new connections and become associated with an event
/// loop.
///
/// The address provided must be the address that the listener is bound to.
pub fn from_std(listener: net::TcpListener) -> io::Result<TcpListener> {
sys::TcpListener::new(listener).map(|s| TcpListener {
sys: s,
sys::TcpListener::bind(addr).map(|sys| TcpListener {
sys,
#[cfg(debug_assertions)]
selector_id: SelectorId::new(),
})
Expand All @@ -494,17 +301,16 @@ impl TcpListener {
/// If an accepted stream is returned, the remote address of the peer is
/// returned along with it.
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (s, a) = self.accept_std()?;
Ok((TcpStream::from_stream(s)?, a))
}

/// Accepts a new `std::net::TcpStream`.
///
/// This method is the same as `accept`, except that it returns a TCP socket
/// *in blocking mode* which isn't bound to `mio`. This can be later then
/// converted to a `mio` type, if necessary.
pub fn accept_std(&self) -> io::Result<(net::TcpStream, SocketAddr)> {
self.sys.accept()
self.sys.accept().map(|(sys, addr)| {
(
TcpStream {
sys,
#[cfg(debug_assertions)]
selector_id: SelectorId::new(),
},
addr,
)
})
}

/// Returns the local socket address of this listener.
Expand Down
21 changes: 3 additions & 18 deletions src/net/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{event, sys, Interests, Registry, Token};

use std::fmt;
use std::io;
use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};

/// A User Datagram Protocol socket.
///
Expand Down Expand Up @@ -116,23 +116,8 @@ impl UdpSocket {
/// # }
/// ```
pub fn bind(addr: SocketAddr) -> io::Result<UdpSocket> {
let socket = net::UdpSocket::bind(addr)?;
UdpSocket::from_socket(socket)
}

/// Creates a new mio-wrapped socket from an underlying and bound std
/// socket.
///
/// This function requires that `socket` has previously been bound to an
/// address to work correctly, and returns an I/O object which can be used
/// with mio to send/receive UDP messages.
///
/// This can be used in conjunction with net2's `UdpBuilder` interface to
/// configure a socket before it's handed off to mio, such as setting
/// options like `reuse_address` or binding to multiple addresses.
pub fn from_socket(socket: net::UdpSocket) -> io::Result<UdpSocket> {
Ok(UdpSocket {
sys: sys::UdpSocket::new(socket)?,
sys::UdpSocket::bind(addr).map(|sys| UdpSocket {
sys,
#[cfg(debug_assertions)]
selector_id: SelectorId::new(),
})
Expand Down
6 changes: 0 additions & 6 deletions src/sys/unix/io.rs

This file was deleted.

0 comments on commit f30debe

Please sign in to comment.