mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-08 00:00:13 +02:00
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:
@@ -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
@@ -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(())
|
||||
|
||||
Reference in New Issue
Block a user