This provides a clear and consistent interface for selecting TLS-related
features on both (xmpp and tokio-xmpp) crates. All feature checks have
been revamped. All working combinations have been tested (including a
connectivity test + --all-features docs build) using:
```
set -xeuo pipefail
features=(aws_lc_rs ring ktls,aws_lc_rs ktls,ring aws_lc_rs,ring aws_lc_rs,ring,ktls native-tls rustls-any-backend)
export RUSTFLAGS=" -D warnings"
cargo test --no-default-features
cargo test
for feature in ${features[@]}; do
echo ">>> BUILDING with $feature" 2>&1
# Running code or building examples cannot succeed with rustls-any-backend.
features="starttls,$feature"
if [ "$feature" != 'rustls-any-backend' ]; then
if ! cargo test --no-default-features --features="$features"; then
echo ">>> BUILD FAILED for tls feature set: $features" >&2
exit 1
fi
set +e
timeout -sINT -p -k 2 3 cargo run --no-default-features --features="$features" --example keep_connection -- test@hub.sotecware.net "$(pass xmpp/test@hub.sotecware.net)"
status="$?"
set -e
if [ $status -ne 0 ]; then
echo ">>> keep_connection did not shut down cleanly! (status: $status)" >&2
exit 1
fi
else
if ! cargo build --no-default-features --features="$feature"; then
echo ">>> BUILD FAILED for tls feature set: $features" >&2
exit 1
fi
fi
done
RUSTDOCFLAGS="--cfg docsrs" RUSTFLAGS="--cfg xmpprs_doc_build" cargo +nightly doc -Zrustdoc-map --all-features
```
106 lines
3.2 KiB
Rust
106 lines
3.2 KiB
Rust
// Copyright (c) 2024 Jonas Schäfer <jonas@zombofant.net>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
//! Keep a connection alive
|
|
//!
|
|
//! This example demonstrates that tokio_xmpp will keep a connection alive
|
|
//! as good as it can, transparently reconnecting on interruptions of the TCP
|
|
//! stream.
|
|
|
|
use core::str::FromStr;
|
|
use core::time::Duration;
|
|
use std::env::args;
|
|
use std::process::exit;
|
|
|
|
use rand::{thread_rng, Rng};
|
|
|
|
use futures::StreamExt;
|
|
|
|
#[cfg(feature = "rustls-any-backend")]
|
|
use tokio_xmpp::rustls;
|
|
use tokio_xmpp::{
|
|
connect::{DnsConfig, StartTlsServerConnector},
|
|
parsers::{
|
|
iq::Iq,
|
|
jid::{BareJid, Jid},
|
|
ping,
|
|
},
|
|
stanzastream::StanzaStream,
|
|
xmlstream::Timeouts,
|
|
};
|
|
|
|
#[cfg(all(
|
|
feature = "rustls-any-backend",
|
|
not(any(feature = "aws_lc_rs", feature = "ring"))
|
|
))]
|
|
compile_error!("using rustls (e.g. via the ktls feature) needs an enabled rustls backend feature (either aws_lc_rs or ring).");
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
env_logger::init();
|
|
|
|
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
|
|
rustls::crypto::aws_lc_rs::default_provider()
|
|
.install_default()
|
|
.expect("failed to install rustls crypto provider");
|
|
|
|
#[cfg(all(feature = "ring"))]
|
|
rustls::crypto::ring::default_provider()
|
|
.install_default()
|
|
.expect("failed to install rustls crypto provider");
|
|
|
|
let args: Vec<String> = args().collect();
|
|
if args.len() != 3 {
|
|
println!("Usage: {} <jid> <password>", args[0]);
|
|
exit(1);
|
|
}
|
|
let jid = BareJid::from_str(&args[1]).expect(&format!("Invalid JID: {}", &args[1]));
|
|
let password = &args[2];
|
|
|
|
let mut timeouts = Timeouts::tight();
|
|
timeouts.read_timeout = Duration::new(5, 0);
|
|
|
|
let mut stream = StanzaStream::new_c2s(
|
|
StartTlsServerConnector::from(DnsConfig::UseSrv {
|
|
host: jid.domain().as_str().to_owned(),
|
|
srv: "_xmpp-client._tcp".to_owned(),
|
|
fallback_port: 5222,
|
|
}),
|
|
jid.clone().into(),
|
|
password.clone(),
|
|
timeouts,
|
|
16,
|
|
);
|
|
let domain: Jid = jid.domain().to_owned().into();
|
|
let mut ping_timer = tokio::time::interval(Duration::new(5, 0));
|
|
let mut ping_ctr: u64 = thread_rng().gen();
|
|
let signal = tokio::signal::ctrl_c();
|
|
tokio::pin!(signal);
|
|
loop {
|
|
tokio::select! {
|
|
_ = &mut signal => {
|
|
log::info!("Ctrl+C pressed, shutting down cleanly.");
|
|
break;
|
|
}
|
|
_ = ping_timer.tick() => {
|
|
log::info!("sending ping for fun & profit");
|
|
ping_ctr = ping_ctr.wrapping_add(1);
|
|
let mut iq = Iq::from_get(format!("ping-{}", ping_ctr), ping::Ping);
|
|
iq.to = Some(domain.clone());
|
|
stream.send(Box::new(iq.into())).await;
|
|
}
|
|
ev = stream.next() => match ev {
|
|
Some(ev) => {
|
|
log::info!("{:?}", ev);
|
|
}
|
|
None => {
|
|
panic!("stream terminated unexpectedly!");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
stream.close().await;
|
|
}
|