radius_server/
lib.rs

1pub mod packet;
2pub mod dictionary;
3pub mod handler;
4use std::sync::Arc;
5use tokio::net::UdpSocket;
6use crate::{dictionary::Dictionary, packet::RadiusPacket, handler::build_response_with_auth};
7
8pub async fn serve_async<F, Fut>(
9    addr: &str,
10    dict: Arc<Dictionary>,
11    secret: &str,
12    handler: F,
13) -> Result<(), Box<dyn std::error::Error>>
14where
15    F: Fn(RadiusPacket) -> Fut + Send + Sync + 'static,
16    Fut: std::future::Future<Output = Result<RadiusPacket, String>> + Send,
17{
18    use tokio::net::UdpSocket;
19
20    let socket = UdpSocket::bind(addr).await?;
21    let mut buf = [0u8; 1024];
22
23    loop {
24        let (len, src) = socket.recv_from(&mut buf).await?;
25        let req = RadiusPacket::from_bytes(&buf[..len])?;
26
27        let fut = handler(req.clone());
28        let response_result = fut.await;
29
30        let response = match response_result {
31            Ok(reply_packet) => build_response_with_auth(reply_packet, req.authenticator, secret),
32            Err(err) => {
33                eprintln!("❌ Error from handler: {err}");
34                build_response_with_auth(req.reply_reject("Internal Error"), req.authenticator, secret)
35            }
36        };
37
38        socket.send_to(&response.to_bytes(), src).await?;
39    }
40}