niom-turn/src/main.rs

100 lines
3.4 KiB
Rust

//! Binary entry point that wires configuration, UDP listener, optional TLS listener, and allocation handling.
//! Backlog: graceful shutdown signals, structured metrics, and coordinated lifecycle management across listeners.
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::net::UdpSocket;
use tracing::{error, info};
// Use the library crate's public modules instead of local `mod` declarations.
use niom_turn::alloc::AllocationManager;
use niom_turn::auth::{AuthManager, InMemoryStore};
use niom_turn::config::{AuthOptions, Config};
use niom_turn::server::udp_reader_loop;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
niom_turn::logging::init_tracing();
info!("niom-turn starting");
// Bootstrap configuration: prefer appsettings.json, otherwise rely on baked-in demo defaults.
let cfg = match Config::load_default() {
Ok(c) => {
info!("loaded config from appsettings.json");
c
}
Err(e) => {
info!(
"no appsettings.json found or failed to load: {} — using defaults",
e
);
// defaults
Config {
server: niom_turn::config::ServerOptions {
bind: "0.0.0.0:3478".to_string(),
tls_cert: None,
tls_key: None,
},
credentials: vec![niom_turn::config::CredentialEntry {
username: "testuser".into(),
password: "secretpassword".into(),
}],
auth: AuthOptions::default(),
}
}
};
let bind_addr: SocketAddr = cfg.server.bind.parse()?;
// Materialise the credential backend before starting network endpoints.
let creds = InMemoryStore::new();
for c in cfg.credentials.iter() {
creds.insert(&c.username, &c.password);
}
let auth = AuthManager::new(creds.clone(), &cfg.auth);
// Bind the UDP socket that receives STUN/TURN traffic from WebRTC clients.
let udp = UdpSocket::bind(bind_addr).await?;
let udp = Arc::new(udp);
// Allocation manager shared by UDP + TLS frontends.
let alloc_mgr = AllocationManager::new();
// Spawn the asynchronous packet loop that handles all UDP requests.
let udp_clone = udp.clone();
let auth_clone = auth.clone();
let alloc_clone = alloc_mgr.clone();
tokio::spawn(async move {
if let Err(e) = udp_reader_loop(udp_clone, auth_clone, alloc_clone).await {
error!("udp loop error: {:?}", e);
}
});
// Optionally start the TLS listener so `turns:` clients can connect via TCP/TLS.
if let (Some(cert), Some(key)) = (cfg.server.tls_cert.clone(), cfg.server.tls_key.clone()) {
let udp_for_tls = udp.clone();
let auth_for_tls = auth.clone();
let alloc_for_tls = alloc_mgr.clone();
tokio::spawn(async move {
if let Err(e) = niom_turn::tls::serve_tls(
"0.0.0.0:5349",
&cert,
&key,
udp_for_tls,
auth_for_tls,
alloc_for_tls,
)
.await
{
error!("tls serve failed: {:?}", e);
}
});
}
// Keep the runtime alive while background tasks process packets.
loop {
tokio::time::sleep(std::time::Duration::from_secs(60)).await;
}
}