Revision control
Copy as Markdown
Other Tools
use std::future;
use std::io;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
/// Converts or resolves without blocking to one or more `SocketAddr` values.
///
/// # DNS
///
/// Implementations of `ToSocketAddrs` for string types require a DNS lookup.
///
/// # Calling
///
/// Currently, this trait is only used as an argument to Tokio functions that
/// need to reference a target socket address. To perform a `SocketAddr`
/// conversion directly, use [`lookup_host()`](super::lookup_host()).
///
/// This trait is sealed and is intended to be opaque. The details of the trait
/// will change. Stabilization is pending enhancements to the Rust language.
pub trait ToSocketAddrs: sealed::ToSocketAddrsPriv {}
type ReadyFuture<T> = future::Ready<io::Result<T>>;
cfg_net! {
pub(crate) fn to_socket_addrs<T>(arg: T) -> T::Future
where
T: ToSocketAddrs,
{
arg.to_socket_addrs(sealed::Internal)
}
}
// ===== 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, _: sealed::Internal) -> Self::Future {
(**self).to_socket_addrs(sealed::Internal)
}
}
// ===== 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, _: sealed::Internal) -> Self::Future {
let iter = Some(*self).into_iter();
future::ready(Ok(iter))
}
}
// ===== impl SocketAddrV4 =====
impl ToSocketAddrs for SocketAddrV4 {}
impl sealed::ToSocketAddrsPriv for SocketAddrV4 {
type Iter = std::option::IntoIter<SocketAddr>;
type Future = ReadyFuture<Self::Iter>;
fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future {
SocketAddr::V4(*self).to_socket_addrs(sealed::Internal)
}
}
// ===== impl SocketAddrV6 =====
impl ToSocketAddrs for SocketAddrV6 {}
impl sealed::ToSocketAddrsPriv for SocketAddrV6 {
type Iter = std::option::IntoIter<SocketAddr>;
type Future = ReadyFuture<Self::Iter>;
fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future {
SocketAddr::V6(*self).to_socket_addrs(sealed::Internal)
}
}
// ===== 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, _: sealed::Internal) -> Self::Future {
let iter = Some(SocketAddr::from(*self)).into_iter();
future::ready(Ok(iter))
}
}
// ===== impl (Ipv4Addr, u16) =====
impl ToSocketAddrs for (Ipv4Addr, u16) {}
impl sealed::ToSocketAddrsPriv for (Ipv4Addr, u16) {
type Iter = std::option::IntoIter<SocketAddr>;
type Future = ReadyFuture<Self::Iter>;
fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future {
let (ip, port) = *self;
SocketAddrV4::new(ip, port).to_socket_addrs(sealed::Internal)
}
}
// ===== impl (Ipv6Addr, u16) =====
impl ToSocketAddrs for (Ipv6Addr, u16) {}
impl sealed::ToSocketAddrsPriv for (Ipv6Addr, u16) {
type Iter = std::option::IntoIter<SocketAddr>;
type Future = ReadyFuture<Self::Iter>;
fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future {
let (ip, port) = *self;
SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs(sealed::Internal)
}
}
// ===== impl &[SocketAddr] =====
impl ToSocketAddrs for &[SocketAddr] {}
impl sealed::ToSocketAddrsPriv for &[SocketAddr] {
type Iter = std::vec::IntoIter<SocketAddr>;
type Future = ReadyFuture<Self::Iter>;
fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future {
#[inline]
fn slice_to_vec(addrs: &[SocketAddr]) -> Vec<SocketAddr> {
addrs.to_vec()
}
// This uses a helper method because clippy doesn't like the `to_vec()`
// call here (it will allocate, whereas `self.iter().copied()` would
// not), but it's actually necessary in order to ensure that the
// returned iterator is valid for the `'static` lifetime, which the
// borrowed `slice::Iter` iterator would not be.
//
// Note that we can't actually add an `allow` attribute for
// `clippy::unnecessary_to_owned` here, as Tokio's CI runs clippy lints
// on Rust 1.52 to avoid breaking LTS releases of Tokio. Users of newer
// Rust versions who see this lint should just ignore it.
let iter = slice_to_vec(self).into_iter();
future::ready(Ok(iter))
}
}
cfg_net! {
// ===== impl str =====
impl ToSocketAddrs for str {}
impl sealed::ToSocketAddrsPriv for str {
type Iter = sealed::OneOrMore;
type Future = sealed::MaybeReady;
fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future {
use crate::blocking::spawn_blocking;
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(sealed::State::Ready(Some(addr)));
}
// Run DNS lookup on the blocking pool
let s = self.to_owned();
MaybeReady(sealed::State::Blocking(spawn_blocking(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, _: sealed::Internal) -> Self::Future {
use crate::blocking::spawn_blocking;
use sealed::MaybeReady;
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(sealed::State::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(sealed::State::Ready(Some(addr)));
}
let host = host.to_owned();
MaybeReady(sealed::State::Blocking(spawn_blocking(move || {
std::net::ToSocketAddrs::to_socket_addrs(&(&host[..], port))
})))
}
}
// ===== impl (String, u16) =====
impl ToSocketAddrs for (String, u16) {}
impl sealed::ToSocketAddrsPriv for (String, u16) {
type Iter = sealed::OneOrMore;
type Future = sealed::MaybeReady;
fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future {
(self.0.as_str(), self.1).to_socket_addrs(sealed::Internal)
}
}
// ===== 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, _: sealed::Internal) -> Self::Future {
self[..].to_socket_addrs(sealed::Internal)
}
}
}
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 std::future::Future;
use std::io;
use std::net::SocketAddr;
#[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, internal: Internal) -> Self::Future;
}
#[allow(missing_debug_implementations)]
pub struct Internal;
cfg_net! {
use crate::blocking::JoinHandle;
use std::option;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::vec;
#[doc(hidden)]
#[derive(Debug)]
pub struct MaybeReady(pub(super) State);
#[derive(Debug)]
pub(super) enum State {
Ready(Option<SocketAddr>),
Blocking(JoinHandle<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.0 {
State::Ready(ref mut i) => {
let iter = OneOrMore::One(i.take().into_iter());
Poll::Ready(Ok(iter))
}
State::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(),
}
}
}
}
}