// TODO: logging (dropped errors) #![allow(unused_must_use)] use std::{ net::{IpAddr, SocketAddr}, str::FromStr, }; use tokio::net::TcpStream; mod jid; pub struct Jabber { connection: Option, login: jid::JID, password: String, } impl Jabber { fn new(login: jid::JID, password: String) -> Self { Self { connection: None, login, password, } } async fn resolve_client(&self) -> Vec { let mut socket_addrs = Vec::new(); // if it's a socket/ip then just return that // socket if let Ok(socket_addr) = SocketAddr::from_str(&self.login.domainpart) { socket_addrs.push(socket_addr); return socket_addrs; } // ip if let Ok(ip) = IpAddr::from_str(&self.login.domainpart) { socket_addrs.push(SocketAddr::new(ip, 5222)); socket_addrs.push(SocketAddr::new(ip, 5223)); return socket_addrs; } // if port specified return name resolutions with specified port // otherwise resolve if let Ok(resolver) = trust_dns_resolver::AsyncResolver::tokio_from_system_conf() { if let Ok(lookup) = resolver .srv_lookup(format!("_xmpp-client._tcp.{}", self.login.domainpart)) .await { for srv in lookup { resolver .lookup_ip(srv.target().to_owned()) .await .map(|ips| { for ip in ips { socket_addrs.push(SocketAddr::new(ip, srv.port())) } }); } } if let Ok(lookup) = resolver .srv_lookup(format!("_xmpps-client._tcp.{}", self.login.domainpart)) .await { for srv in lookup { resolver .lookup_ip(srv.target().to_owned()) .await .map(|ips| { for ip in ips { socket_addrs.push(SocketAddr::new(ip, srv.port())) } }); } } // in case cannot connect through SRV records resolver.lookup_ip(&self.login.domainpart).await.map(|ips| { for ip in ips { socket_addrs.push(SocketAddr::new(ip, 5222)); socket_addrs.push(SocketAddr::new(ip, 5223)); } }); } socket_addrs } async fn connect(&mut self) { for socket_addr in self.resolve_client().await { println!("trying {}", socket_addr); if let Ok(stream) = TcpStream::connect(socket_addr).await { println!("connected to {}", socket_addr); self.connection = Some(stream); return; } } println!("could not connect") } } #[cfg(test)] mod tests { use crate::jid::JID; use super::*; #[tokio::test] async fn get_sockets() { let client = Jabber::new(JID::from_str("cel@blos.sm").unwrap(), "password".to_owned()); println!("{:?}", client.resolve_client().await) } }