xmpp-rs/src/happy_eyeballs.rs

109 lines
3.3 KiB
Rust
Raw Normal View History

2017-07-13 00:56:02 +00:00
use std::str::FromStr;
2017-07-13 20:17:29 +00:00
use std::collections::HashMap;
use std::net::SocketAddr;
2017-07-18 20:54:10 +00:00
use futures::{Future, Poll, Async, Stream};
2017-07-13 00:56:02 +00:00
use tokio_core::reactor::Handle;
use tokio_core::net::{TcpStream, TcpStreamNew};
use domain::resolv::Resolver;
2017-07-18 20:54:10 +00:00
use domain::resolv::lookup::srv::{lookup_srv, LookupSrv, LookupSrvStream};
2018-09-06 15:46:06 +00:00
use domain::bits::name::{DNameBuf, FromStrError};
use ConnecterError;
2017-07-13 00:56:02 +00:00
pub struct Connecter {
handle: Handle,
resolver: Resolver,
lookup: Option<LookupSrv>,
srvs: Option<LookupSrvStream>,
2017-07-13 20:17:29 +00:00
connects: HashMap<SocketAddr, TcpStreamNew>,
2017-07-13 00:56:02 +00:00
}
impl Connecter {
2018-09-06 15:46:06 +00:00
pub fn from_lookup(handle: Handle, domain: &str, srv: &str, fallback_port: u16) -> Result<Connecter, FromStrError> {
let domain = DNameBuf::from_str(domain)?;
let srv = DNameBuf::from_str(srv)?;
2017-07-13 00:56:02 +00:00
let resolver = Resolver::new(&handle);
let lookup = lookup_srv(resolver.clone(), srv, domain, fallback_port);
Ok(Connecter {
handle,
resolver,
lookup: Some(lookup),
srvs: None,
2017-07-13 20:17:29 +00:00
connects: HashMap::new(),
2017-07-13 00:56:02 +00:00
})
}
}
impl Future for Connecter {
type Item = TcpStream;
2018-09-06 15:46:06 +00:00
type Error = ConnecterError;
2017-07-13 00:56:02 +00:00
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
2018-02-22 18:56:56 +00:00
match self.lookup.as_mut().map(|lookup| lookup.poll()) {
2017-07-20 22:19:08 +00:00
None | Some(Ok(Async::NotReady)) => (),
2017-07-13 00:56:02 +00:00
Some(Ok(Async::Ready(found_srvs))) => {
self.lookup = None;
match found_srvs {
Some(srvs) =>
self.srvs = Some(srvs.to_stream(self.resolver.clone())),
None =>
2018-09-06 15:46:06 +00:00
return Err(ConnecterError::NoSrv),
2017-07-13 00:56:02 +00:00
}
},
Some(Err(e)) =>
2018-09-06 15:46:06 +00:00
return Err(e.into()),
2017-07-13 00:56:02 +00:00
}
2018-02-22 18:56:56 +00:00
match self.srvs.as_mut().map(|srv| srv.poll()) {
2017-07-20 22:19:08 +00:00
None | Some(Ok(Async::NotReady)) => (),
2017-07-13 00:56:02 +00:00
Some(Ok(Async::Ready(None))) =>
self.srvs = None,
Some(Ok(Async::Ready(Some(srv_item)))) => {
2017-07-13 20:17:29 +00:00
let handle = &self.handle;
2017-07-13 00:56:02 +00:00
for addr in srv_item.to_socket_addrs() {
2017-07-13 20:17:29 +00:00
self.connects.entry(addr)
.or_insert_with(|| {
2018-08-02 23:14:21 +00:00
// println!("Connect to {}", addr);
2017-07-13 20:17:29 +00:00
TcpStream::connect(&addr, handle)
});
2017-07-13 00:56:02 +00:00
}
},
Some(Err(e)) =>
2018-09-06 15:46:06 +00:00
return Err(e.into()),
2017-07-13 00:56:02 +00:00
}
let mut connected_stream = None;
self.connects.retain(|_, connect| {
if connected_stream.is_some() {
return false;
}
2017-07-13 00:56:02 +00:00
match connect.poll() {
Ok(Async::NotReady) => true,
Ok(Async::Ready(tcp_stream)) => {
2017-07-13 00:56:02 +00:00
// Success!
connected_stream = Some(tcp_stream);
false
},
2018-08-02 23:14:21 +00:00
Err(_e) => {
// println!("{}", _e);
false
},
2017-07-13 00:56:02 +00:00
}
});
2017-07-20 22:19:08 +00:00
if let Some(tcp_stream) = connected_stream {
return Ok(Async::Ready(tcp_stream));
2017-07-13 00:56:02 +00:00
}
2017-07-13 20:17:29 +00:00
if self.lookup.is_none() &&
self.srvs.is_none() &&
self.connects.is_empty()
{
2018-09-06 15:46:06 +00:00
return Err(ConnecterError::AllFailed);
2017-07-13 20:17:29 +00:00
}
2017-07-13 00:56:02 +00:00
Ok(Async::NotReady)
}
}