aboutsummaryrefslogtreecommitdiff
path: root/src/output_protocol/udp.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-20 06:58:31 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-20 06:58:31 +0800
commitd1cda84f0d9acf2700e4c2eeafff4dbb63cc51fe (patch)
treec8c8faff8f419e4d94fae72757d179492ae58b37 /src/output_protocol/udp.rs
parent332ee84b59f33e3a3f1cb109e02a1c0c9fe108cd (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.rs81
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;
+ }
+ }
}
}