Detailed changes
@@ -7,6 +7,10 @@ XXXX-YY-ZZ RELEASER <admin@example.com>
which was not used and has been completely removed (!418)
- `ProtocolError` and `AuthError` are no longer exported in crate root;
access them from `error` module (!423)
+ - `connect::ServerConnector` no longer has `Error` associated type, the methods return tokio_xmpp::Error directly,
+ where Connection variant contains any error type that implements connect::ServerConnectorError (!421)
+ - `starttls::Error` no longer has `TokioXMPP` variant ; only tokio_xmpp::Error can contain starttls::Error,
+ not the other way around (!421)
Version 4.0.0:
2024-07-26 Maxime “pep” Buquet <pep@bouah.net>
@@ -5,6 +5,7 @@ use tokio::io::{AsyncRead, AsyncWrite};
use xmpp_parsers::jid::Jid;
use crate::xmpp_stream::XMPPStream;
+use crate::Error;
/// trait returned wrapped in XMPPStream by ServerConnector
pub trait AsyncReadAndWrite: AsyncRead + AsyncWrite + Unpin + Send {}
@@ -17,19 +18,17 @@ pub trait ServerConnectorError: std::error::Error + Sync + Send {}
pub trait ServerConnector: Clone + core::fmt::Debug + Send + Unpin + 'static {
/// The type of Stream this ServerConnector produces
type Stream: AsyncReadAndWrite;
- /// Error type to return
- type Error: ServerConnectorError;
/// This must return the connection ready to login, ie if starttls is involved, after TLS has been started, and then after the <stream headers are exchanged
fn connect(
&self,
jid: &Jid,
ns: &str,
- ) -> impl std::future::Future<Output = Result<XMPPStream<Self::Stream>, Self::Error>> + Send;
+ ) -> impl std::future::Future<Output = Result<XMPPStream<Self::Stream>, Error>> + Send;
/// Return channel binding data if available
/// do not fail if channel binding is simply unavailable, just return Ok(None)
/// this should only be called after the TLS handshake is finished
- fn channel_binding(_stream: &Self::Stream) -> Result<ChannelBinding, Self::Error> {
+ fn channel_binding(_stream: &Self::Stream) -> Result<ChannelBinding, Error> {
Ok(ChannelBinding::None)
}
}
@@ -10,6 +10,8 @@ use tokio_rustls::rustls::pki_types::InvalidDnsNameError;
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
use tokio_rustls::rustls::Error as TlsError;
+use super::ServerConnectorError;
+
/// StartTLS ServerConnector Error
#[derive(Debug)]
pub enum Error {
@@ -25,41 +27,34 @@ pub enum Error {
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
/// DNS name parsing error
DnsNameError(InvalidDnsNameError),
- /// tokio-xmpp error
- TokioXMPP(crate::error::Error),
}
+impl ServerConnectorError for Error {}
+
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
- Error::Dns(e) => write!(fmt, "{:?}", e),
- Error::Resolve(e) => write!(fmt, "{:?}", e),
- Error::Idna => write!(fmt, "IDNA error"),
- Error::Tls(e) => write!(fmt, "TLS error: {}", e),
+ Self::Dns(e) => write!(fmt, "{:?}", e),
+ Self::Resolve(e) => write!(fmt, "{:?}", e),
+ Self::Idna => write!(fmt, "IDNA error"),
+ Self::Tls(e) => write!(fmt, "TLS error: {}", e),
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
- Error::DnsNameError(e) => write!(fmt, "DNS name error: {}", e),
- Error::TokioXMPP(e) => write!(fmt, "TokioXMPP error: {}", e),
+ Self::DnsNameError(e) => write!(fmt, "DNS name error: {}", e),
}
}
}
impl StdError for Error {}
-impl From<crate::error::Error> for Error {
- fn from(e: crate::error::Error) -> Self {
- Error::TokioXMPP(e)
- }
-}
-
impl From<TlsError> for Error {
fn from(e: TlsError) -> Self {
- Error::Tls(e)
+ Self::Tls(e)
}
}
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
impl From<InvalidDnsNameError> for Error {
fn from(e: InvalidDnsNameError) -> Self {
- Error::DnsNameError(e)
+ Self::DnsNameError(e)
}
}
@@ -1,4 +1,5 @@
-use super::error::Error;
+use super::error::Error as StartTlsError;
+use crate::Error;
use futures::{future::select_ok, FutureExt};
use hickory_resolver::{
config::LookupIpStrategy, name_server::TokioConnectionProvider, IntoName, TokioAsyncResolver,
@@ -8,23 +9,21 @@ use std::net::SocketAddr;
use tokio::net::TcpStream;
pub async fn connect_to_host(domain: &str, port: u16) -> Result<TcpStream, Error> {
- let ascii_domain = idna::domain_to_ascii(&domain).map_err(|_| Error::Idna)?;
+ let ascii_domain = idna::domain_to_ascii(&domain).map_err(|_| StartTlsError::Idna)?;
if let Ok(ip) = ascii_domain.parse() {
- return Ok(TcpStream::connect(&SocketAddr::new(ip, port))
- .await
- .map_err(|e| Error::from(crate::Error::Io(e)))?);
+ return Ok(TcpStream::connect(&SocketAddr::new(ip, port)).await?);
}
let (config, mut options) =
- hickory_resolver::system_conf::read_system_conf().map_err(Error::Resolve)?;
+ hickory_resolver::system_conf::read_system_conf().map_err(StartTlsError::Resolve)?;
options.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
let resolver = TokioAsyncResolver::new(config, options, TokioConnectionProvider::default());
let ips = resolver
.lookup_ip(ascii_domain)
.await
- .map_err(Error::Resolve)?;
+ .map_err(StartTlsError::Resolve)?;
// Happy Eyeballs: connect to all records in parallel, return the
// first to succeed
select_ok(
@@ -33,7 +32,7 @@ pub async fn connect_to_host(domain: &str, port: u16) -> Result<TcpStream, Error
)
.await
.map(|(result, _)| result)
- .map_err(|_| crate::Error::Disconnected.into())
+ .map_err(|_| crate::Error::Disconnected)
}
pub async fn connect_with_srv(
@@ -41,20 +40,18 @@ pub async fn connect_with_srv(
srv: &str,
fallback_port: u16,
) -> Result<TcpStream, Error> {
- let ascii_domain = idna::domain_to_ascii(&domain).map_err(|_| Error::Idna)?;
+ let ascii_domain = idna::domain_to_ascii(&domain).map_err(|_| StartTlsError::Idna)?;
if let Ok(ip) = ascii_domain.parse() {
debug!("Attempting connection to {ip}:{fallback_port}");
- return Ok(TcpStream::connect(&SocketAddr::new(ip, fallback_port))
- .await
- .map_err(|e| Error::from(crate::Error::Io(e)))?);
+ return Ok(TcpStream::connect(&SocketAddr::new(ip, fallback_port)).await?);
}
- let resolver = TokioAsyncResolver::tokio_from_system_conf().map_err(Error::Resolve)?;
+ let resolver = TokioAsyncResolver::tokio_from_system_conf().map_err(StartTlsError::Resolve)?;
let srv_domain = format!("{}.{}.", srv, ascii_domain)
.into_name()
- .map_err(Error::Dns)?;
+ .map_err(StartTlsError::Dns)?;
let srv_records = resolver.srv_lookup(srv_domain.clone()).await.ok();
match srv_records {
@@ -28,10 +28,11 @@ use tokio::{
use xmpp_parsers::{jid::Jid, ns};
use crate::error::ProtocolError;
+use crate::Error;
use crate::{connect::ServerConnector, xmpp_codec::Packet, AsyncClient, SimpleClient};
use crate::{connect::ServerConnectorError, xmpp_stream::XMPPStream};
-use self::error::Error;
+use self::error::Error as StartTlsError;
use self::happy_eyeballs::{connect_to_host, connect_with_srv};
mod client;
@@ -58,11 +59,8 @@ pub enum ServerConfig {
},
}
-impl ServerConnectorError for Error {}
-
impl ServerConnector for ServerConfig {
type Stream = TlsStream<TcpStream>;
- type Error = Error;
async fn connect(&self, jid: &Jid, ns: &str) -> Result<XMPPStream<Self::Stream>, Error> {
// TCP connection
let tcp_stream = match self {
@@ -100,11 +98,9 @@ impl ServerConnector for ServerConfig {
// TODO: Add support for TLS 1.2 and earlier.
Some(tokio_rustls::rustls::ProtocolVersion::TLSv1_3) => {
let data = vec![0u8; 32];
- let data = connection.export_keying_material(
- data,
- b"EXPORTER-Channel-Binding",
- None,
- )?;
+ let data = connection
+ .export_keying_material(data, b"EXPORTER-Channel-Binding", None)
+ .map_err(|e| StartTlsError::Tls(e))?;
ChannelBinding::TlsExporter(data)
}
_ => ChannelBinding::None,
@@ -121,7 +117,8 @@ async fn get_tls_stream<S: AsyncRead + AsyncWrite + Unpin>(
let stream = xmpp_stream.into_inner();
let tls_stream = TlsConnector::from(NativeTlsConnector::builder().build().unwrap())
.connect(&domain, stream)
- .await?;
+ .await
+ .map_err(|e| StartTlsError::Tls(e))?;
Ok(tls_stream)
}
@@ -130,7 +127,7 @@ async fn get_tls_stream<S: AsyncRead + AsyncWrite + Unpin>(
xmpp_stream: XMPPStream<S>,
) -> Result<TlsStream<S>, Error> {
let domain = xmpp_stream.jid.domain().to_string();
- let domain = ServerName::try_from(domain)?;
+ let domain = ServerName::try_from(domain).map_err(|e| StartTlsError::DnsNameError(e))?;
let stream = xmpp_stream.into_inner();
let root_store = RootCertStore {
roots: webpki_roots::TLS_SERVER_ROOTS.into(),
@@ -4,13 +4,9 @@ use std::sync::Arc;
use tokio::net::TcpStream;
-use crate::{
- connect::{ServerConnector, ServerConnectorError},
- xmpp_stream::XMPPStream,
- Component,
-};
+use crate::{connect::ServerConnector, xmpp_stream::XMPPStream, Component};
-use self::error::Error;
+use crate::Error;
mod component;
pub mod error;
@@ -31,16 +27,13 @@ impl TcpServerConnector {
}
}
-impl ServerConnectorError for Error {}
-
impl ServerConnector for TcpServerConnector {
type Stream = TcpStream;
- type Error = Error;
async fn connect(
&self,
jid: &xmpp_parsers::jid::Jid,
ns: &str,
- ) -> Result<XMPPStream<Self::Stream>, Self::Error> {
+ ) -> Result<XMPPStream<Self::Stream>, Error> {
let stream = TcpStream::connect(&*self.0)
.await
.map_err(|e| crate::Error::Io(e))?;