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;
|
2018-10-01 10:34:33 +00:00
|
|
|
use tokio::net::tcp::ConnectFuture;
|
2018-12-18 18:04:31 +00:00
|
|
|
use tokio::net::TcpStream;
|
|
|
|
use trust_dns_resolver::config::LookupIpStrategy;
|
2018-09-01 19:59:02 +00:00
|
|
|
use trust_dns_resolver::lookup::SrvLookupFuture;
|
|
|
|
use trust_dns_resolver::lookup_ip::LookupIpFuture;
|
2018-09-08 00:12:49 +00:00
|
|
|
use trust_dns_resolver::system_conf;
|
2018-12-18 18:04:31 +00:00
|
|
|
use trust_dns_resolver::{error::ResolveError, IntoName, Name, ResolverFuture};
|
2017-07-13 00:56:02 +00:00
|
|
|
|
2018-09-06 22:12:00 +00:00
|
|
|
enum State {
|
|
|
|
AwaitResolver(Box<Future<Item = ResolverFuture, Error = ResolveError> + Send>),
|
|
|
|
ResolveSrv(ResolverFuture, SrvLookupFuture),
|
|
|
|
ResolveTarget(ResolverFuture, LookupIpFuture, u16),
|
|
|
|
Connecting(Option<ResolverFuture>, Vec<RefCell<ConnectFuture>>),
|
|
|
|
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)>,
|
2018-09-07 23:35:26 +00:00
|
|
|
error: Option<Error>,
|
2017-07-13 00:56:02 +00:00
|
|
|
}
|
|
|
|
|
2018-12-18 18:04:31 +00:00
|
|
|
fn resolver_future(
|
|
|
|
) -> Result<Box<Future<Item = ResolverFuture, Error = ResolveError> + Send>, IoError> {
|
2018-09-08 00:12:49 +00:00
|
|
|
let (conf, mut opts) = system_conf::read_system_conf()?;
|
|
|
|
opts.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
|
|
|
Ok(ResolverFuture::new(conf, opts))
|
|
|
|
}
|
|
|
|
|
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(),
|
2018-09-07 23:35:26 +00:00
|
|
|
error: None,
|
2018-09-06 22:12:00 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-09-08 00:12:49 +00:00
|
|
|
let state = State::AwaitResolver(resolver_future()?);
|
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
|
|
|
|
|
|
|
Ok(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)?,
|
2018-09-06 22:12:00 +00:00
|
|
|
state,
|
|
|
|
targets: VecDeque::new(),
|
2018-09-07 23:35:26 +00:00
|
|
|
error: None,
|
2017-07-13 00:56:02 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Future for Connecter {
|
|
|
|
type Item = TcpStream;
|
2018-09-07 23:35:26 +00:00
|
|
|
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::AwaitResolver(mut resolver_future) => {
|
2018-09-07 23:35:26 +00:00
|
|
|
match resolver_future.poll().map_err(ConnecterError::Resolve)? {
|
2018-09-06 22:12:00 +00:00
|
|
|
Async::NotReady => {
|
|
|
|
self.state = State::AwaitResolver(resolver_future);
|
|
|
|
Ok(Async::NotReady)
|
|
|
|
}
|
|
|
|
Async::Ready(resolver) => {
|
|
|
|
match &self.srv_domain {
|
|
|
|
&Some(ref srv_domain) => {
|
|
|
|
let srv_lookup = resolver.lookup_srv(srv_domain);
|
|
|
|
self.state = State::ResolveSrv(resolver, srv_lookup);
|
|
|
|
}
|
|
|
|
None => {
|
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![]);
|
2018-09-01 19:59:02 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-06 22:12:00 +00:00
|
|
|
self.poll()
|
2018-09-01 19:59:02 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-18 23:32:53 +00:00
|
|
|
}
|
2018-09-06 22:12:00 +00:00
|
|
|
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) => {
|
2018-09-07 23:35:26 +00:00
|
|
|
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 {
|
2018-09-07 23:35:26 +00:00
|
|
|
// 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-07 23:35:26 +00:00
|
|
|
}
|
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
|
|
|
}
|
2018-09-07 23:35:26 +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
|
|
|
}
|
|
|
|
}
|