The command line package is now `tsunagi` and builds the `tsng` executable, which the packages, the unit, the installers and the workflows install and run. The core library package becomes `tsunagi-core`, keeping the library name `tsunagi`, so no code changes `use tsunagi::...`. Directories follow (crates/tsunagi-core, crates/tsunagi). Every command shown to a person is now `tsng ...`. Co-Authored-By: Claude <noreply@anthropic.com>
69 lines
2.7 KiB
Rust
69 lines
2.7 KiB
Rust
//! The real Mainline UDP receive loop must be quiet while idle on Windows too.
|
|
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
|
|
|
|
use std::net::Ipv4Addr;
|
|
use std::sync::Arc;
|
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
use std::time::Duration;
|
|
|
|
use tracing_subscriber::layer::SubscriberExt;
|
|
|
|
struct SocketWarnings(Arc<AtomicUsize>);
|
|
|
|
impl<S: tracing::Subscriber> tracing_subscriber::Layer<S> for SocketWarnings {
|
|
fn on_event(&self, event: &tracing::Event<'_>, _: tracing_subscriber::layer::Context<'_, S>) {
|
|
if event.metadata().target() == "mainline::rpc::socket"
|
|
&& *event.metadata().level() <= tracing::Level::WARN
|
|
{
|
|
self.0.fetch_add(1, Ordering::Relaxed);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn an_idle_dht_socket_stays_quiet_and_still_answers_packets() {
|
|
// Mainline owns an OS thread, so a thread-local subscriber cannot see its
|
|
// events. This integration-test binary has just this test and installs
|
|
// its own subscriber; it cannot affect the application or other binaries.
|
|
let warnings = Arc::new(AtomicUsize::new(0));
|
|
tracing::subscriber::set_global_default(
|
|
tracing_subscriber::registry().with(SocketWarnings(Arc::clone(&warnings))),
|
|
)
|
|
.unwrap();
|
|
|
|
tokio::time::timeout(Duration::from_secs(5), async {
|
|
let dht = mainline::Dht::builder()
|
|
.no_bootstrap()
|
|
.server_mode()
|
|
.bind_address(Ipv4Addr::LOCALHOST)
|
|
.port(0)
|
|
.build()
|
|
.unwrap()
|
|
.as_async();
|
|
|
|
let address = dht.info().await.local_addr();
|
|
// Each info response comes from the actor after another receive-loop
|
|
// iteration. With no peers or packets, these exercise real socket
|
|
// read timeouts, without an arbitrary sleep or public bootstrap.
|
|
for _ in 0..8 {
|
|
assert_eq!(dht.info().await.local_addr(), address);
|
|
}
|
|
assert_eq!(warnings.load(Ordering::Relaxed), 0, "idle receive warnings");
|
|
|
|
let client = tokio::net::UdpSocket::bind((Ipv4Addr::LOCALHOST, 0))
|
|
.await
|
|
.unwrap();
|
|
let ping = b"d1:ad2:id20:abcdefghijklmnopqrste1:q4:ping1:t4:ping1:y1:qe";
|
|
client.send_to(ping, address).await.unwrap();
|
|
let mut response = [0u8; 2048];
|
|
let (len, from) = client.recv_from(&mut response).await.unwrap();
|
|
assert_eq!(from, std::net::SocketAddr::V4(address));
|
|
let response = &response[..len];
|
|
assert!(response.windows(9).any(|field| field == b"1:t4:ping"));
|
|
assert!(response.windows(6).any(|field| field == b"1:y1:r"));
|
|
assert_eq!(warnings.load(Ordering::Relaxed), 0);
|
|
})
|
|
.await
|
|
.expect("the DHT receive loop keeps making progress");
|
|
}
|