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<F>(
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) -> Result<RadiusPacket, String> + Send + Sync + 'static,
16{
17 let socket = UdpSocket::bind(addr).await?;
18 let mut buf = [0u8; 1024];
19
20 loop {
21 let (len, src) = socket.recv_from(&mut buf).await?;
22 let req = RadiusPacket::from_bytes(&buf[..len])?;
23
24 let response = match handler(req.clone()) {
25 Ok(reply_packet) => build_response_with_auth(reply_packet, req.authenticator, secret),
26 Err(err) => {
27 eprintln!("❌ Error from handler: {err}");
28 build_response_with_auth(req.reply_reject("Internal Error"), req.authenticator, secret)
29 }
30 };
31
32 socket.send_to(&response.to_bytes(), src).await?;
33 }
34}