diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-20 06:58:31 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-20 06:58:31 +0800 |
| commit | d1cda84f0d9acf2700e4c2eeafff4dbb63cc51fe (patch) | |
| tree | c8c8faff8f419e4d94fae72757d179492ae58b37 /src/output_protocol/udp.rs | |
| parent | 332ee84b59f33e3a3f1cb109e02a1c0c9fe108cd (diff) | |
feat: implement core capture engine with CLI and output protocols
Diffstat (limited to 'src/output_protocol/udp.rs')
| -rw-r--r-- | src/output_protocol/udp.rs | 81 |
1 files changed, 75 insertions, 6 deletions
diff --git a/src/output_protocol/udp.rs b/src/output_protocol/udp.rs index f1e5876..8c6c9b9 100644 --- a/src/output_protocol/udp.rs +++ b/src/output_protocol/udp.rs @@ -1,14 +1,83 @@ +use crate::debug_log; use crate::OutputProtocol; +use std::net::SocketAddr; +use std::sync::Arc; +use tokio::net::UdpSocket; +use tokio::sync::Mutex; -#[derive(Debug, Default)] -pub struct UDPOutputProtocol {} +/// UDP output protocol. +/// +/// Binds to `0.0.0.0:{port}`. The first incoming datagram determines the +/// target address; all subsequent `send` calls deliver messages to that peer. +#[derive(Debug)] +pub struct UDPOutputProtocol { + inner: Arc<UDPInner>, +} + +#[derive(Debug)] +struct UDPInner { + socket: Mutex<Option<Arc<UdpSocket>>>, + target: Mutex<Option<SocketAddr>>, + target_learned: tokio::sync::watch::Sender<bool>, +} + +impl UDPOutputProtocol { + pub fn new(port: u16) -> Self { + let (tx, _rx) = tokio::sync::watch::channel(false); + let inner = Arc::new(UDPInner { + socket: Mutex::new(None), + target: Mutex::new(None), + target_learned: tx, + }); + + let inner_clone = inner.clone(); + tokio::spawn(async move { + let addr = format!("0.0.0.0:{}", port); + let socket = match UdpSocket::bind(&addr).await { + Ok(s) => { + debug_log!("[UDP] Listening on {}", addr); + Arc::new(s) + } + Err(e) => { + debug_log!("[UDP] Failed to bind: {}", e); + return; + } + }; + + // Store the socket + *inner_clone.socket.lock().await = Some(socket.clone()); + + // Learn target from first incoming packet + let mut buf = [0u8; 4096]; + let (len, src) = match socket.recv_from(&mut buf).await { + Ok(r) => r, + Err(e) => { + debug_log!("[UDP] Recv error: {}", e); + return; + } + }; + debug_log!("[UDP] Learned target address: {} (got {} bytes)", src, len); + *inner_clone.target.lock().await = Some(src); + let _ = inner_clone.target_learned.send(true); + }); + + Self { inner } + } +} impl OutputProtocol for UDPOutputProtocol { - async fn init(self) { - todo!() + async fn init(&self) { + // Everything is set up in new() — nothing more to do. } - async fn send(self: std::sync::Arc<Self>, _str: &str) { - todo!() + async fn send(self: Arc<Self>, message: &str) { + let socket_opt = self.inner.socket.lock().await; + if let Some(ref socket) = *socket_opt { + let target_opt = self.inner.target.lock().await; + if let Some(target) = *target_opt { + let bytes = format!("{}\n", message); + let _ = socket.send_to(bytes.as_bytes(), target).await; + } + } } } |
