use crate::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 = future::Ready>; cfg_net! { pub(crate) fn to_socket_addrs(arg: T) -> T::Future where T: ToSocketAddrs, { arg.to_socket_addrs(sealed::Internal) } } // ===== impl &impl ToSocketAddrs ===== impl ToSocketAddrs for &T {} impl 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; type Future = ReadyFuture; fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future { let iter = Some(*self).into_iter(); future::ok(iter) } } // ===== impl SocketAddrV4 ===== impl ToSocketAddrs for SocketAddrV4 {} impl sealed::ToSocketAddrsPriv for SocketAddrV4 { type Iter = std::option::IntoIter; type Future = ReadyFuture; 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; type Future = ReadyFuture; 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; type Future = ReadyFuture; fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future { let iter = Some(SocketAddr::from(*self)).into_iter(); future::ok(iter) } } // ===== impl (Ipv4Addr, u16) ===== impl ToSocketAddrs for (Ipv4Addr, u16) {} impl sealed::ToSocketAddrsPriv for (Ipv4Addr, u16) { type Iter = std::option::IntoIter; type Future = ReadyFuture; 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; type Future = ReadyFuture; 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; type Future = ReadyFuture; fn to_socket_addrs(&self, _: sealed::Internal) -> Self::Future { let iter = self.to_vec().into_iter(); future::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 = 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::() { let addr = SocketAddrV4::new(addr, port); let addr = SocketAddr::V4(addr); return MaybeReady(sealed::State::Ready(Some(addr))); } if let Ok(addr) = host.parse::() { 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 = ::Iter; type Future = ::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 + Send + 'static; type Future: Future> + 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), Blocking(JoinHandle>>), } #[doc(hidden)] #[derive(Debug)] pub enum OneOrMore { One(option::IntoIter), More(vec::IntoIter), } impl Future for MaybeReady { type Output = io::Result; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 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 { match self { OneOrMore::One(i) => i.next(), OneOrMore::More(i) => i.next(), } } fn size_hint(&self) -> (usize, Option) { match self { OneOrMore::One(i) => i.size_hint(), OneOrMore::More(i) => i.size_hint(), } } } } }