net: perform DNS lookup on connect / bind. (#1499)

A sealed `net::ToSocketAddrs` trait is added. This trait is not intended
to be used by users. Instead, it is an argument to `connect` and `bind`
functions.

The operating system's DNS lookup functionality is used. Blocking
operations are performed on a thread pool in order to avoid blocking the
runtime.
This commit is contained in:
Carl Lerche
2019-08-28 13:25:50 -07:00
committed by GitHub
parent de9f05d4d3
commit fc1640891e
33 changed files with 632 additions and 218 deletions
+96 -42
View File
@@ -3,6 +3,7 @@ use super::incoming::Incoming;
use super::TcpStream;
use crate::driver::Handle;
use crate::util::PollEvented;
use crate::ToSocketAddrs;
use futures_core::ready;
use futures_util::future::poll_fn;
@@ -22,13 +23,13 @@ use std::task::{Context, Poll};
///
/// ```no_run
/// use tokio::net::TcpListener;
/// use std::error::Error;
///
/// use std::io;
/// # async fn process_socket<T>(socket: T) {}
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let mut listener = TcpListener::bind(&addr)?;
/// async fn main() -> io::Result<()> {
/// let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
///
/// loop {
/// let (socket, _) = listener.accept().await?;
@@ -41,24 +42,60 @@ pub struct TcpListener {
}
impl TcpListener {
/// Create a new TCP listener associated with this event loop.
/// Creates a new TcpListener which will be bound to the specified address.
///
/// The TCP listener will bind to the provided `addr` address, if available.
/// If the result is `Ok`, the socket has successfully bound.
/// The returned listener is ready for accepting connections.
///
/// Binding with a port number of 0 will request that the OS assigns a port
/// to this listener. The port allocated can be queried via the `local_addr`
/// method.
///
/// The address type can be any implementor of `ToSocketAddrs` trait.
///
/// If `addr` yields multiple addresses, bind will be attempted with each of
/// the addresses until one succeeds and returns the listener. If none of
/// the addresses succeed in creating a listener, the error returned from
/// the last attempt (the last address) is returned.
///
/// # Examples
///
/// ```
/// use std::net::SocketAddr;
/// ```no_run
/// use tokio::net::TcpListener;
///
/// let addr = "127.0.0.1:0".parse::<SocketAddr>()?;
/// let listener = TcpListener::bind(&addr)?;
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// use std::io;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let listener = TcpListener::bind("127.0.0.1:0").await?;
///
/// // use the listener
///
/// Ok(())
/// }
/// ```
pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
let l = mio::net::TcpListener::bind(addr)?;
Ok(TcpListener::new(l))
pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
let addrs = addr.to_socket_addrs().await?;
let mut last_err = None;
for addr in addrs {
match TcpListener::bind_addr(addr) {
Ok(listener) => return Ok(listener),
Err(e) => last_err = Some(e),
}
}
Err(last_err.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any addresses",
)
}))
}
fn bind_addr(addr: SocketAddr) -> io::Result<TcpListener> {
let listener = mio::net::TcpListener::bind(&addr)?;
Ok(TcpListener::new(listener))
}
/// Accept a new incoming connection from this listener.
@@ -71,18 +108,22 @@ impl TcpListener {
///
/// # Examples
///
/// ```
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// ```no_run
/// use tokio::net::TcpListener;
///
/// let addr = "127.0.0.1:8080".parse()?;
/// let mut listener = TcpListener::bind(&addr)?;
/// match listener.accept().await {
/// Ok((_socket, addr)) => println!("new client: {:?}", addr),
/// Err(e) => println!("couldn't get client: {:?}", e),
/// use std::io;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
///
/// match listener.accept().await {
/// Ok((_socket, addr)) => println!("new client: {:?}", addr),
/// Err(e) => println!("couldn't get client: {:?}", e),
/// }
///
/// Ok(())
/// }
/// # Ok(())
/// # }
/// ```
pub async fn accept(&mut self) -> io::Result<(TcpStream, SocketAddr)> {
poll_fn(|cx| self.poll_accept(cx)).await
@@ -178,13 +219,19 @@ impl TcpListener {
///
/// ```
/// use tokio::net::TcpListener;
///
/// use std::io;
/// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
///
/// let addr = "127.0.0.1:8080".parse::<SocketAddr>()?;
/// let listener = TcpListener::bind(&addr)?;
/// assert_eq!(listener.local_addr()?,
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)));
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let listener = TcpListener::bind("127.0.0.1:8080").await?;
///
/// assert_eq!(listener.local_addr()?,
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)));
///
/// Ok(())
/// }
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io.get_ref().local_addr()
@@ -215,17 +262,20 @@ impl TcpListener {
///
/// # Examples
///
/// ```
/// ```no_run
/// use tokio::net::TcpListener;
/// use std::net::SocketAddr;
///
/// let addr = "127.0.0.1:0".parse::<SocketAddr>()?;
/// let listener = TcpListener::bind(&addr)?;
/// use std::io;
///
/// listener.set_ttl(100).expect("could not set TTL");
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let listener = TcpListener::bind("127.0.0.1:0").await?;
///
/// assert_eq!(listener.ttl()?, 100);
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// listener.set_ttl(100).expect("could not set TTL");
/// assert_eq!(listener.ttl()?, 100);
///
/// Ok(())
/// }
/// ```
pub fn ttl(&self) -> io::Result<u32> {
self.io.get_ref().ttl()
@@ -238,15 +288,19 @@ impl TcpListener {
///
/// # Examples
///
/// ```
/// ```no_run
/// use tokio::net::TcpListener;
/// use std::net::SocketAddr;
///
/// let addr = "127.0.0.1:0".parse::<SocketAddr>()?;
/// let listener = TcpListener::bind(&addr)?;
/// use std::io;
///
/// listener.set_ttl(100).expect("could not set TTL");
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let listener = TcpListener::bind("127.0.0.1:0").await?;
///
/// listener.set_ttl(100).expect("could not set TTL");
///
/// Ok(())
/// }
/// ```
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.io.get_ref().set_ttl(ttl)
+50 -61
View File
@@ -4,6 +4,7 @@ use super::split::{
};
use crate::driver::Handle;
use crate::util::PollEvented;
use crate::ToSocketAddrs;
use tokio_io::{AsyncRead, AsyncWrite};
@@ -38,10 +39,8 @@ use std::time::Duration;
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
///
/// // Connect to a peer
/// let mut stream = TcpStream::connect(&addr).await?;
/// let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// // Write some data.
/// stream.write_all(b"hello world!").await?;
@@ -54,12 +53,15 @@ pub struct TcpStream {
}
impl TcpStream {
/// Create a new TCP stream connected to the specified address.
/// Opens a TCP connection to a remote host.
///
/// This function will create a new TCP socket and attempt to connect it to
/// the `addr` provided. The returned future will be resolved once the
/// stream has successfully connected, or it will return an error if one
/// occurs.
/// `addr` is an address of the remote host. Anything which implements
/// `ToSocketAddrs` trait can be supplied for the address.
///
/// If `addr` yields multiple addresses, connect will be attempted with each
/// of the addresses until a connection is successful. If none of the
/// addresses result in a successful connection, the error returned from the
/// last connection attempt (the last address) is returned.
///
/// # Examples
///
@@ -70,10 +72,8 @@ impl TcpStream {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
///
/// // Connect to a peer
/// let mut stream = TcpStream::connect(&addr).await?;
/// let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// // Write some data.
/// stream.write_all(b"hello world!").await?;
@@ -81,8 +81,29 @@ impl TcpStream {
/// Ok(())
/// }
/// ```
pub async fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
let sys = mio::net::TcpStream::connect(addr)?;
pub async fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
let addrs = addr.to_socket_addrs().await?;
let mut last_err = None;
for addr in addrs {
match TcpStream::connect_addr(addr).await {
Ok(stream) => return Ok(stream),
Err(e) => last_err = Some(e),
}
}
Err(last_err.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any addresses",
)
}))
}
/// Establish a connection to the specified `addr`.
async fn connect_addr(addr: SocketAddr) -> io::Result<TcpStream> {
let sys = mio::net::TcpStream::connect(&addr)?;
let stream = TcpStream::new(sys);
// Once we've connected, wait for the stream to be writable as
@@ -136,11 +157,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// println!("{:?}", stream.local_addr()?);
/// # Ok(())
@@ -155,11 +174,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// println!("{:?}", stream.peer_addr()?);
/// # Ok(())
@@ -198,10 +215,8 @@ impl TcpStream {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
///
/// // Connect to a peer
/// let mut stream = TcpStream::connect(&addr).await?;
/// let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// let mut b1 = [0; 10];
/// let mut b2 = [0; 10];
@@ -236,10 +251,8 @@ impl TcpStream {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
///
/// // Connect to a peer
/// let mut stream = TcpStream::connect(&addr).await?;
/// let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// // Shutdown the stream
/// stream.shutdown(Shutdown::Write)?;
@@ -261,11 +274,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// println!("{:?}", stream.nodelay()?);
/// # Ok(())
@@ -287,11 +298,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_nodelay(true)?;
/// # Ok(())
@@ -311,11 +320,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// println!("{:?}", stream.recv_buffer_size()?);
/// # Ok(())
@@ -334,11 +341,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_recv_buffer_size(100)?;
/// # Ok(())
@@ -367,11 +372,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// println!("{:?}", stream.send_buffer_size()?);
/// # Ok(())
@@ -390,11 +393,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_send_buffer_size(100)?;
/// # Ok(())
@@ -415,11 +416,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// println!("{:?}", stream.keepalive()?);
/// # Ok(())
@@ -446,11 +445,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_keepalive(None)?;
/// # Ok(())
@@ -470,11 +467,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// println!("{:?}", stream.ttl()?);
/// # Ok(())
@@ -493,11 +488,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_ttl(123)?;
/// # Ok(())
@@ -518,11 +511,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// println!("{:?}", stream.linger()?);
/// # Ok(())
@@ -548,11 +539,9 @@ impl TcpStream {
///
/// ```no_run
/// use tokio::net::TcpStream;
/// use std::net::SocketAddr;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse()?;
/// let stream = TcpStream::connect(&addr).await?;
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_linger(None)?;
/// # Ok(())