From bcacf42decf91cbdda6a24a3164717fda46f34cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?cel=20=F0=9F=8C=B8?= Date: Fri, 16 Jun 2023 14:49:20 +0100 Subject: [PATCH] implement client socket resolution --- Cargo.toml | 3 ++ src/lib.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8cef70b..ccec909 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +tokio = { version = "1.28", features = ["full"] } +trust-dns-resolver = "0.22.0" +xml-rs = "0.8.14" diff --git a/src/lib.rs b/src/lib.rs index b2ce0b2..42eb7de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,114 @@ +// TODO: logging (dropped errors) +#![allow(unused_must_use)] +use std::{ + net::{IpAddr, SocketAddr}, + str::FromStr, +}; + +use tokio::net::TcpStream; + mod jid; -pub fn add(left: usize, right: usize) -> usize { - left + right +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::*; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + #[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) } }