xmpp-rs/src/happy_eyeballs.rs

194 lines
7.2 KiB
Rust
Raw Normal View History

2018-12-18 18:04:31 +00:00
use crate::{ConnecterError, Error};
use futures::{Async, Future, Poll};
use std::cell::RefCell;
2018-09-06 22:12:00 +00:00
use std::collections::BTreeMap;
2018-09-01 19:59:02 +00:00
use std::collections::VecDeque;
2018-12-18 18:04:31 +00:00
use std::io::Error as IoError;
use std::mem;
use std::net::SocketAddr;
use tokio::net::tcp::ConnectFuture;
2018-12-18 18:04:31 +00:00
use tokio::net::TcpStream;
use trust_dns_resolver::{AsyncResolver, Name, IntoName, Background, BackgroundLookup};
2018-09-01 19:59:02 +00:00
use trust_dns_resolver::lookup::SrvLookupFuture;
use trust_dns_resolver::lookup_ip::LookupIpFuture;
2017-07-13 00:56:02 +00:00
2018-09-06 22:12:00 +00:00
enum State {
ResolveSrv(AsyncResolver, BackgroundLookup<SrvLookupFuture>),
ResolveTarget(AsyncResolver, Background<LookupIpFuture>, u16),
Connecting(Option<AsyncResolver>, Vec<RefCell<ConnectFuture>>),
2018-09-06 22:12:00 +00:00
Invalid,
}
2017-07-13 00:56:02 +00:00
pub struct Connecter {
2018-09-01 19:59:02 +00:00
fallback_port: u16,
2018-09-06 22:12:00 +00:00
srv_domain: Option<Name>,
2018-09-01 19:59:02 +00:00
domain: Name,
2018-09-06 22:12:00 +00:00
state: State,
targets: VecDeque<(Name, u16)>,
error: Option<Error>,
2017-07-13 00:56:02 +00:00
}
fn resolver() -> Result<AsyncResolver, IoError> {
let (resolver, resolver_background) = AsyncResolver::from_system_conf()?;
tokio::runtime::current_thread::spawn(resolver_background);
Ok(resolver)
}
2017-07-13 00:56:02 +00:00
impl Connecter {
2018-12-18 18:04:31 +00:00
pub fn from_lookup(
domain: &str,
srv: Option<&str>,
fallback_port: u16,
) -> Result<Connecter, Error> {
2018-09-06 22:12:00 +00:00
if let Ok(ip) = domain.parse() {
// use specified IP address, not domain name, skip the whole dns part
2018-12-18 18:04:31 +00:00
let connect = RefCell::new(TcpStream::connect(&SocketAddr::new(ip, fallback_port)));
2018-09-06 22:12:00 +00:00
return Ok(Connecter {
fallback_port,
srv_domain: None,
2018-12-18 18:04:31 +00:00
domain: "nohost".into_name().map_err(ConnecterError::Dns)?,
2018-09-06 22:12:00 +00:00
state: State::Connecting(None, vec![connect]),
targets: VecDeque::new(),
error: None,
2018-09-06 22:12:00 +00:00
});
}
let srv_domain = match srv {
2018-12-18 18:04:31 +00:00
Some(srv) => Some(
format!("{}.{}.", srv, domain)
.into_name()
.map_err(ConnecterError::Dns)?,
),
None => None,
2018-09-06 22:12:00 +00:00
};
2017-07-13 00:56:02 +00:00
2019-01-17 00:29:48 +00:00
let mut self_ = Connecter {
2018-09-01 19:59:02 +00:00
fallback_port,
2018-09-06 22:12:00 +00:00
srv_domain,
2018-12-18 18:04:31 +00:00
domain: domain.into_name().map_err(ConnecterError::Dns)?,
2019-01-17 00:29:48 +00:00
state: State::Invalid,
2018-09-06 22:12:00 +00:00
targets: VecDeque::new(),
error: None,
2019-01-17 00:29:48 +00:00
};
let resolver = resolver()?;
// Initialize state
match &self_.srv_domain {
&Some(ref srv_domain) => {
let srv_lookup = resolver.lookup_srv(srv_domain);
self_.state = State::ResolveSrv(resolver, srv_lookup);
}
None => {
self_.targets = [(self_.domain.clone(), self_.fallback_port)]
.into_iter()
.cloned()
.collect();
self_.state = State::Connecting(Some(resolver), vec![]);
}
}
Ok(self_)
2017-07-13 00:56:02 +00:00
}
}
impl Future for Connecter {
type Item = TcpStream;
type Error = Error;
2017-07-13 00:56:02 +00:00
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
2018-09-06 22:12:00 +00:00
let state = mem::replace(&mut self.state, State::Invalid);
match state {
State::ResolveSrv(resolver, mut srv_lookup) => {
match srv_lookup.poll() {
Ok(Async::NotReady) => {
self.state = State::ResolveSrv(resolver, srv_lookup);
Ok(Async::NotReady)
2018-09-01 19:59:02 +00:00
}
2018-09-06 22:12:00 +00:00
Ok(Async::Ready(srv_result)) => {
2018-12-18 18:04:31 +00:00
let srv_map: BTreeMap<_, _> = srv_result
.iter()
2018-09-06 22:12:00 +00:00
.map(|srv| (srv.priority(), (srv.target().clone(), srv.port())))
.collect();
2018-12-18 18:04:31 +00:00
let targets = srv_map.into_iter().map(|(_, tp)| tp).collect();
2018-09-06 22:12:00 +00:00
self.targets = targets;
self.state = State::Connecting(Some(resolver), vec![]);
self.poll()
}
Err(_) => {
// ignore, fallback
2018-12-18 18:04:31 +00:00
self.targets = [(self.domain.clone(), self.fallback_port)]
.into_iter()
2018-09-06 22:12:00 +00:00
.cloned()
.collect();
self.state = State::Connecting(Some(resolver), vec![]);
self.poll()
2018-09-01 19:59:02 +00:00
}
}
2018-09-06 22:12:00 +00:00
}
State::Connecting(resolver, mut connects) => {
if resolver.is_some() && connects.len() == 0 && self.targets.len() > 0 {
let resolver = resolver.unwrap();
let (host, port) = self.targets.pop_front().unwrap();
let ip_lookup = resolver.lookup_ip(host);
self.state = State::ResolveTarget(resolver, ip_lookup, port);
self.poll()
2018-09-06 22:12:00 +00:00
} else if connects.len() > 0 {
let mut success = None;
2018-12-18 18:04:31 +00:00
connects.retain(|connect| match connect.borrow_mut().poll() {
Ok(Async::NotReady) => true,
Ok(Async::Ready(connection)) => {
success = Some(connection);
false
}
Err(e) => {
if self.error.is_none() {
self.error = Some(e.into());
2018-09-06 22:12:00 +00:00
}
2018-12-18 18:04:31 +00:00
false
2018-09-06 22:12:00 +00:00
}
});
match success {
2018-12-18 18:04:31 +00:00
Some(connection) => Ok(Async::Ready(connection)),
2018-09-06 22:12:00 +00:00
None => {
self.state = State::Connecting(resolver, connects);
Ok(Async::NotReady)
2018-12-18 18:04:31 +00:00
}
2018-09-01 19:59:02 +00:00
}
2018-09-06 22:12:00 +00:00
} else {
// All targets tried
match self.error.take() {
2018-12-18 18:04:31 +00:00
None => Err(ConnecterError::AllFailed.into()),
Some(e) => Err(e),
}
2018-09-01 19:59:02 +00:00
}
2017-07-13 00:56:02 +00:00
}
2018-09-06 22:12:00 +00:00
State::ResolveTarget(resolver, mut ip_lookup, port) => {
match ip_lookup.poll() {
2018-09-01 19:59:02 +00:00
Ok(Async::NotReady) => {
2018-09-06 22:12:00 +00:00
self.state = State::ResolveTarget(resolver, ip_lookup, port);
Ok(Async::NotReady)
}
Ok(Async::Ready(ip_result)) => {
2018-12-18 18:04:31 +00:00
let connects = ip_result
.iter()
2018-09-06 22:12:00 +00:00
.map(|ip| RefCell::new(TcpStream::connect(&SocketAddr::new(ip, port))))
.collect();
self.state = State::Connecting(Some(resolver), connects);
self.poll()
2018-09-01 19:59:02 +00:00
}
Err(e) => {
if self.error.is_none() {
self.error = Some(ConnecterError::Resolve(e).into());
}
2018-09-06 22:12:00 +00:00
// ignore, next…
self.state = State::Connecting(Some(resolver), vec![]);
self.poll()
}
2018-09-01 19:59:02 +00:00
}
2017-07-13 00:56:02 +00:00
}
2018-12-18 18:04:31 +00:00
_ => panic!(""),
2017-07-13 20:17:29 +00:00
}
2017-07-13 00:56:02 +00:00
}
}