mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-03 00:00:05 +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:
@@ -0,0 +1,214 @@
|
||||
use tokio_executor::blocking;
|
||||
|
||||
use futures_util::future;
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
|
||||
/// Convert or resolve without blocking to one or more `SocketAddr` values.
|
||||
///
|
||||
/// Currently, this trait is only used as an argument to Tokio functions that
|
||||
/// need to reference a target socket address.
|
||||
///
|
||||
/// This trait is sealed and is intended to be opaque. Users of Tokio should
|
||||
/// only use `ToSocketAddrs` in trait bounds and __must not__ attempt to call
|
||||
/// the functions directly or reference associated types. Changing these is not
|
||||
/// considered a breaking change.
|
||||
pub trait ToSocketAddrs: sealed::ToSocketAddrsPriv {}
|
||||
|
||||
type ReadyFuture<T> = future::Ready<io::Result<T>>;
|
||||
|
||||
// ===== impl SocketAddr =====
|
||||
|
||||
impl ToSocketAddrs for SocketAddr {}
|
||||
|
||||
impl sealed::ToSocketAddrsPriv for SocketAddr {
|
||||
type Iter = std::option::IntoIter<SocketAddr>;
|
||||
type Future = ReadyFuture<Self::Iter>;
|
||||
|
||||
fn to_socket_addrs(&self) -> Self::Future {
|
||||
let iter = Some(*self).into_iter();
|
||||
future::ready(Ok(iter))
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl str =====
|
||||
|
||||
impl ToSocketAddrs for str {}
|
||||
|
||||
impl sealed::ToSocketAddrsPriv for str {
|
||||
type Iter = sealed::OneOrMore;
|
||||
type Future = sealed::MaybeReady;
|
||||
|
||||
fn to_socket_addrs(&self) -> Self::Future {
|
||||
use sealed::MaybeReady;
|
||||
|
||||
// First check if the input parses as a socket address
|
||||
let res: Result<SocketAddr, _> = self.parse();
|
||||
|
||||
if let Ok(addr) = res {
|
||||
return MaybeReady::Ready(Some(addr));
|
||||
}
|
||||
|
||||
// Run DNS lookup on the blocking pool
|
||||
let s = self.to_owned();
|
||||
|
||||
MaybeReady::Blocking(blocking::run(move || {
|
||||
std::net::ToSocketAddrs::to_socket_addrs(&s)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl (&str, u16) =====
|
||||
|
||||
impl ToSocketAddrs for (&'_ str, u16) {}
|
||||
|
||||
impl sealed::ToSocketAddrsPriv for (&'_ str, u16) {
|
||||
type Iter = sealed::OneOrMore;
|
||||
type Future = sealed::MaybeReady;
|
||||
|
||||
fn to_socket_addrs(&self) -> Self::Future {
|
||||
use sealed::MaybeReady;
|
||||
use std::net::{SocketAddrV4, SocketAddrV6};
|
||||
|
||||
let (host, port) = *self;
|
||||
|
||||
// try to parse the host as a regular IP address first
|
||||
if let Ok(addr) = host.parse::<Ipv4Addr>() {
|
||||
let addr = SocketAddrV4::new(addr, port);
|
||||
let addr = SocketAddr::V4(addr);
|
||||
|
||||
return MaybeReady::Ready(Some(addr));
|
||||
}
|
||||
|
||||
if let Ok(addr) = host.parse::<Ipv6Addr>() {
|
||||
let addr = SocketAddrV6::new(addr, port, 0, 0);
|
||||
let addr = SocketAddr::V6(addr);
|
||||
|
||||
return MaybeReady::Ready(Some(addr));
|
||||
}
|
||||
|
||||
let host = host.to_owned();
|
||||
|
||||
MaybeReady::Blocking(blocking::run(move || {
|
||||
std::net::ToSocketAddrs::to_socket_addrs(&(&host[..], port))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl (IpAddr, u16) =====
|
||||
|
||||
impl ToSocketAddrs for (IpAddr, u16) {}
|
||||
|
||||
impl sealed::ToSocketAddrsPriv for (IpAddr, u16) {
|
||||
type Iter = std::option::IntoIter<SocketAddr>;
|
||||
type Future = ReadyFuture<Self::Iter>;
|
||||
|
||||
fn to_socket_addrs(&self) -> Self::Future {
|
||||
let iter = Some(SocketAddr::from(*self)).into_iter();
|
||||
future::ready(Ok(iter))
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl String =====
|
||||
|
||||
impl ToSocketAddrs for String {}
|
||||
|
||||
impl sealed::ToSocketAddrsPriv for String {
|
||||
type Iter = <str as sealed::ToSocketAddrsPriv>::Iter;
|
||||
type Future = <str as sealed::ToSocketAddrsPriv>::Future;
|
||||
|
||||
fn to_socket_addrs(&self) -> Self::Future {
|
||||
(&self[..]).to_socket_addrs()
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl &'_ impl ToSocketAddrs =====
|
||||
|
||||
impl<T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'_ T {}
|
||||
|
||||
impl<T> sealed::ToSocketAddrsPriv for &'_ T
|
||||
where
|
||||
T: sealed::ToSocketAddrsPriv + ?Sized,
|
||||
{
|
||||
type Iter = T::Iter;
|
||||
type Future = T::Future;
|
||||
|
||||
fn to_socket_addrs(&self) -> Self::Future {
|
||||
(**self).to_socket_addrs()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
//! The contents of this trait are intended to remain private and __not__
|
||||
//! part of the `ToSocketAddrs` public API. The details will change over
|
||||
//! time.
|
||||
|
||||
use tokio_executor::blocking::Blocking;
|
||||
|
||||
use futures_core::ready;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::option;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::vec;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait ToSocketAddrsPriv {
|
||||
type Iter: Iterator<Item = SocketAddr> + Send + 'static;
|
||||
type Future: Future<Output = io::Result<Self::Iter>> + Send + 'static;
|
||||
|
||||
fn to_socket_addrs(&self) -> Self::Future;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug)]
|
||||
pub enum MaybeReady {
|
||||
Ready(Option<SocketAddr>),
|
||||
Blocking(Blocking<io::Result<vec::IntoIter<SocketAddr>>>),
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug)]
|
||||
pub enum OneOrMore {
|
||||
One(option::IntoIter<SocketAddr>),
|
||||
More(vec::IntoIter<SocketAddr>),
|
||||
}
|
||||
|
||||
impl Future for MaybeReady {
|
||||
type Output = io::Result<OneOrMore>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
match *self {
|
||||
MaybeReady::Ready(ref mut i) => {
|
||||
let iter = OneOrMore::One(i.take().into_iter());
|
||||
Poll::Ready(Ok(iter))
|
||||
}
|
||||
MaybeReady::Blocking(ref mut rx) => {
|
||||
let res = ready!(Pin::new(rx).poll(cx)).map(OneOrMore::More);
|
||||
|
||||
Poll::Ready(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for OneOrMore {
|
||||
type Item = SocketAddr;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
OneOrMore::One(i) => i.next(),
|
||||
OneOrMore::More(i) => i.next(),
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match self {
|
||||
OneOrMore::One(i) => i.size_hint(),
|
||||
OneOrMore::More(i) => i.size_hint(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,7 @@
|
||||
//!
|
||||
//! # async fn process<T>(t: T) {}
|
||||
//! # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! let addr = "93.184.216.34:9243".parse()?;
|
||||
//!
|
||||
//! let stream = TcpStream::connect(&addr).await?;
|
||||
//! let stream = TcpStream::connect("93.184.216.34:9243").await?;
|
||||
//!
|
||||
//! println!("successfully connected");
|
||||
//!
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
#[macro_use]
|
||||
mod tracing;
|
||||
|
||||
mod addr;
|
||||
pub use addr::ToSocketAddrs;
|
||||
|
||||
pub mod driver;
|
||||
pub mod util;
|
||||
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::split::{split, UdpSocketRecvHalf, UdpSocketSendHalf};
|
||||
use crate::driver::Handle;
|
||||
use crate::util::PollEvented;
|
||||
use crate::ToSocketAddrs;
|
||||
|
||||
use futures_core::ready;
|
||||
use futures_util::future::poll_fn;
|
||||
@@ -19,8 +20,27 @@ pub struct UdpSocket {
|
||||
impl UdpSocket {
|
||||
/// This function will create a new UDP socket and attempt to bind it to
|
||||
/// the `addr` provided.
|
||||
pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
|
||||
mio::net::UdpSocket::bind(addr).map(UdpSocket::new)
|
||||
pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
|
||||
let addrs = addr.to_socket_addrs().await?;
|
||||
let mut last_err = None;
|
||||
|
||||
for addr in addrs {
|
||||
match UdpSocket::bind_addr(addr) {
|
||||
Ok(socket) => return Ok(socket),
|
||||
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<UdpSocket> {
|
||||
mio::net::UdpSocket::bind(&addr).map(UdpSocket::new)
|
||||
}
|
||||
|
||||
fn new(socket: mio::net::UdpSocket) -> UdpSocket {
|
||||
@@ -63,8 +83,23 @@ impl UdpSocket {
|
||||
/// Connects the UDP socket setting the default destination for send() and
|
||||
/// limiting packets that are read via recv from the address specified in
|
||||
/// `addr`.
|
||||
pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
|
||||
self.io.get_ref().connect(*addr)
|
||||
pub async fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
|
||||
let addrs = addr.to_socket_addrs().await?;
|
||||
let mut last_err = None;
|
||||
|
||||
for addr in addrs {
|
||||
match self.io.get_ref().connect(addr) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(e) => last_err = Some(e),
|
||||
}
|
||||
}
|
||||
|
||||
Err(last_err.unwrap_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"could not resolve to any addresses",
|
||||
)
|
||||
}))
|
||||
}
|
||||
|
||||
/// Returns a future that sends data on the socket to the remote address to which it is connected.
|
||||
@@ -141,8 +176,16 @@ impl UdpSocket {
|
||||
///
|
||||
/// The future will resolve to an error if the IP version of the socket does
|
||||
/// not match that of `target`.
|
||||
pub async fn send_to(&mut self, buf: &[u8], target: &SocketAddr) -> io::Result<usize> {
|
||||
poll_fn(|cx| self.poll_send_to_priv(cx, buf, target)).await
|
||||
pub async fn send_to<A: ToSocketAddrs>(&mut self, buf: &[u8], target: A) -> io::Result<usize> {
|
||||
let mut addrs = target.to_socket_addrs().await?;
|
||||
|
||||
match addrs.next() {
|
||||
Some(target) => poll_fn(|cx| self.poll_send_to_priv(cx, buf, &target)).await,
|
||||
None => Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"no addresses to send data to",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn poll_send_to_priv(
|
||||
|
||||
Reference in New Issue
Block a user