diff --git a/tokio-xmpp/Cargo.toml b/tokio-xmpp/Cargo.toml index 1d70da62..dcec9761 100644 --- a/tokio-xmpp/Cargo.toml +++ b/tokio-xmpp/Cargo.toml @@ -36,6 +36,8 @@ tokio-rustls = { version = "0.24", optional = true } [dev-dependencies] env_logger = { version = "0.10", default-features = false, features = ["auto-color", "humantime"] } +# this is needed for echo-component example +tokio-xmpp = { path = ".", features = ["insecure-tcp"]} [features] default = ["starttls-rust"] @@ -44,4 +46,5 @@ tls-rust = ["tokio-rustls", "webpki-roots"] tls-native = ["tokio-native-tls", "native-tls"] starttls-native = ["starttls", "tls-native"] starttls-rust = ["starttls", "tls-rust"] +insecure-tcp = [] syntax-highlighting = ["syntect"] diff --git a/tokio-xmpp/examples/echo_component.rs b/tokio-xmpp/examples/echo_component.rs index 9f3425e3..98417dce 100644 --- a/tokio-xmpp/examples/echo_component.rs +++ b/tokio-xmpp/examples/echo_component.rs @@ -2,7 +2,7 @@ use futures::stream::StreamExt; use std::env::args; use std::process::exit; use std::str::FromStr; -use tokio_xmpp::Component; +use tokio_xmpp::tcp::TcpComponent as Component; use xmpp_parsers::message::{Body, Message, MessageType}; use xmpp_parsers::presence::{Presence, Show as PresenceShow, Type as PresenceType}; use xmpp_parsers::{Element, Jid}; @@ -12,22 +12,21 @@ async fn main() { env_logger::init(); let args: Vec = args().collect(); - if args.len() < 3 || args.len() > 5 { - println!("Usage: {} [server] [port]", args[0]); + if args.len() < 3 || args.len() > 4 { + println!("Usage: {} [server:port]", args[0]); exit(1); } let jid = &args[1]; let password = &args[2]; - let server = &args + let server = args .get(3) .unwrap() .parse() - .unwrap_or("127.0.0.1".to_owned()); - let port: u16 = args.get(4).unwrap().parse().unwrap_or(5347u16); + .unwrap_or("127.0.0.1:5347".to_owned()); // Component instance - println!("{} {} {} {}", jid, password, server, port); - let mut component = Component::new(jid, password, server, port).await.unwrap(); + println!("{} {} {}", jid, password, server); + let mut component = Component::new(jid, password, server).await.unwrap(); // Make the two interfaces for sending and receiving independent // of each other so we can move one into a closure. diff --git a/tokio-xmpp/src/component/mod.rs b/tokio-xmpp/src/component/mod.rs index d2b4bfa5..5dc6860d 100644 --- a/tokio-xmpp/src/component/mod.rs +++ b/tokio-xmpp/src/component/mod.rs @@ -31,7 +31,11 @@ pub struct Component { impl Component { /// Start a new XMPP component - pub async fn new(jid: &str, password: &str, connector: C) -> Result { + pub async fn new_with_connector( + jid: &str, + password: &str, + connector: C, + ) -> Result { let jid = Jid::from_str(jid)?; let password = password.to_owned(); let stream = component_login(connector, jid.clone(), password).await?; diff --git a/tokio-xmpp/src/lib.rs b/tokio-xmpp/src/lib.rs index 1b95b04c..7d7503b6 100644 --- a/tokio-xmpp/src/lib.rs +++ b/tokio-xmpp/src/lib.rs @@ -17,6 +17,8 @@ compile_error!( #[cfg(feature = "starttls")] pub mod starttls; mod stream_start; +#[cfg(feature = "insecure-tcp")] +pub mod tcp; mod xmpp_codec; pub use crate::xmpp_codec::Packet; mod event; diff --git a/tokio-xmpp/src/starttls/error.rs b/tokio-xmpp/src/starttls/error.rs index f2db656e..85ec19db 100644 --- a/tokio-xmpp/src/starttls/error.rs +++ b/tokio-xmpp/src/starttls/error.rs @@ -1,3 +1,5 @@ +//! StartTLS ServerConnector Error + use hickory_resolver::{error::ResolveError, proto::error::ProtoError}; #[cfg(feature = "tls-native")] use native_tls::Error as TlsError; @@ -9,7 +11,7 @@ use tokio_rustls::rustls::client::InvalidDnsNameError; #[cfg(all(feature = "tls-rust", not(feature = "tls-native")))] use tokio_rustls::rustls::Error as TlsError; -/// Top-level error type +/// StartTLS ServerConnector Error #[derive(Debug)] pub enum Error { /// Error resolving DNS and establishing a connection diff --git a/tokio-xmpp/src/starttls/mod.rs b/tokio-xmpp/src/starttls/mod.rs index 67ecb25b..224d0b34 100644 --- a/tokio-xmpp/src/starttls/mod.rs +++ b/tokio-xmpp/src/starttls/mod.rs @@ -26,16 +26,21 @@ use tokio::{ }; use xmpp_parsers::{ns, Element, Jid}; -use crate::{connect::ServerConnector, xmpp_codec::Packet}; +use crate::{connect::ServerConnector, xmpp_codec::Packet, AsyncClient, SimpleClient}; use crate::{connect::ServerConnectorError, xmpp_stream::XMPPStream}; use self::error::Error; use self::happy_eyeballs::{connect_to_host, connect_with_srv}; mod client; -mod error; +pub mod error; mod happy_eyeballs; +/// AsyncClient that connects over StartTls +pub type StartTlsAsyncClient = AsyncClient; +/// SimpleClient that connects over StartTls +pub type StartTlsSimpleClient = SimpleClient; + /// StartTLS XMPP server connection configuration #[derive(Clone, Debug)] pub enum ServerConfig { diff --git a/tokio-xmpp/src/tcp/component.rs b/tokio-xmpp/src/tcp/component.rs new file mode 100644 index 00000000..29a9e621 --- /dev/null +++ b/tokio-xmpp/src/tcp/component.rs @@ -0,0 +1,10 @@ +use crate::{Component, Error}; + +use super::TcpServerConnector; + +impl Component { + /// Start a new XMPP component + pub async fn new(jid: &str, password: &str, server: String) -> Result { + Self::new_with_connector(jid, password, TcpServerConnector::new(server)).await + } +} diff --git a/tokio-xmpp/src/tcp/error.rs b/tokio-xmpp/src/tcp/error.rs new file mode 100644 index 00000000..f384e588 --- /dev/null +++ b/tokio-xmpp/src/tcp/error.rs @@ -0,0 +1,26 @@ +//! TCP ServerConnector Error + +use core::fmt; + +/// TCP ServerConnector Error +#[derive(Debug)] +pub enum Error { + /// tokio-xmpp error + TokioXMPP(crate::error::Error), +} + +impl std::error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::TokioXMPP(e) => write!(fmt, "TokioXMPP error: {}", e), + } + } +} + +impl From for Error { + fn from(e: crate::error::Error) -> Self { + Error::TokioXMPP(e) + } +} diff --git a/tokio-xmpp/src/tcp/mod.rs b/tokio-xmpp/src/tcp/mod.rs new file mode 100644 index 00000000..db246008 --- /dev/null +++ b/tokio-xmpp/src/tcp/mod.rs @@ -0,0 +1,49 @@ +//! `starttls::ServerConfig` provides a `ServerConnector` for starttls connections + +use std::sync::Arc; + +use tokio::net::TcpStream; + +use crate::{ + connect::{ServerConnector, ServerConnectorError}, + xmpp_stream::XMPPStream, + Component, +}; + +use self::error::Error; + +mod component; +pub mod error; + +/// Component that connects over TCP +pub type TcpComponent = Component; + +/// Connect via insecure plaintext TCP to an XMPP server +/// This should only be used over localhost or otherwise when you know what you are doing +/// Probably mostly useful for Components +#[derive(Debug, Clone)] +pub struct TcpServerConnector(Arc); + +impl TcpServerConnector { + /// Create a new connector with the given address + pub fn new(addr: String) -> Self { + Self(addr.into()) + } +} + +impl ServerConnectorError for Error {} + +impl ServerConnector for TcpServerConnector { + type Stream = TcpStream; + type Error = Error; + async fn connect( + &self, + jid: &xmpp_parsers::Jid, + ns: &str, + ) -> Result, Self::Error> { + let stream = TcpStream::connect(&*self.0) + .await + .map_err(|e| crate::Error::Io(e))?; + Ok(XMPPStream::start(stream, jid.clone(), ns.to_owned()).await?) + } +}