1use std::collections::HashMap;
13use std::io;
14use std::net::SocketAddr;
15use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
16use std::sync::Arc;
17use std::time::{Duration, Instant};
18
19use tokio::net::UdpSocket;
20use tokio::sync::watch;
21use tokio::time::timeout;
22use tracing::{debug, warn};
23
24use crate::balancer::{Balancer, OwnedConnGuard};
25use crate::config::StreamListenerConfig;
26
27const BUF_SIZE: usize = 65_535;
29
30struct Session {
33 upstream: Arc<UdpSocket>,
34 last_seen: Arc<AtomicU64>,
35 alive: Arc<AtomicBool>,
36 _guard: OwnedConnGuard,
37}
38
39fn now_ms(epoch: Instant) -> u64 {
40 epoch.elapsed().as_millis() as u64
41}
42
43pub async fn spawn(
46 cfg: &StreamListenerConfig,
47 balancer: Arc<Balancer>,
48 idle: Duration,
49 mut shutdown_rx: watch::Receiver<bool>,
50) -> io::Result<SocketAddr> {
51 let ip = cfg
52 .bind
53 .parse()
54 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("invalid bind: {}", e)))?;
55 let addr = SocketAddr::new(ip, cfg.port);
56 let sock = Arc::new(UdpSocket::bind(addr).await?);
57 let local = sock.local_addr()?;
58
59 tokio::spawn(async move {
60 let epoch = Instant::now();
61 let mut sessions: HashMap<SocketAddr, Session> = HashMap::new();
62 let mut buf = [0u8; BUF_SIZE];
63 let mut prune = tokio::time::interval(Duration::from_secs(1));
64
65 loop {
66 tokio::select! {
67 _ = shutdown_rx.changed() => break,
68 _ = prune.tick() => {
69 sessions.retain(|_, s| s.alive.load(Ordering::Relaxed));
70 }
71 recv = sock.recv_from(&mut buf) => {
72 let (n, client) = match recv {
73 Ok(v) => v,
74 Err(e) => { warn!("udp stream recv error: {}", e); continue; }
75 };
76 let now = now_ms(epoch);
77
78 if sessions.get(&client).is_some_and(|s| !s.alive.load(Ordering::Relaxed)) {
80 sessions.remove(&client);
81 }
82 if let std::collections::hash_map::Entry::Vacant(e) = sessions.entry(client) {
83 match create_session(&balancer, &sock, client, idle, epoch).await {
84 Ok(session) => { e.insert(session); }
85 Err(e) => { warn!("udp stream session setup failed: {}", e); continue; }
86 }
87 }
88 if let Some(session) = sessions.get(&client) {
89 session.last_seen.store(now, Ordering::Relaxed);
90 if let Err(e) = session.upstream.send(&buf[..n]).await {
91 debug!("udp stream send to upstream failed: {}", e);
92 }
93 }
94 }
95 }
96 }
97 });
98
99 Ok(local)
100}
101
102async fn create_session(
105 balancer: &Arc<Balancer>,
106 listener: &Arc<UdpSocket>,
107 client: SocketAddr,
108 idle: Duration,
109 epoch: Instant,
110) -> io::Result<Session> {
111 let idx = balancer.select(&client.to_string());
112 let guard = balancer.owned_acquire(idx);
113 let target = balancer.target(idx);
114
115 let upstream = Arc::new(UdpSocket::bind(("0.0.0.0", 0)).await?);
116 upstream
117 .connect((target.host.as_str(), target.port))
118 .await?;
119
120 let last_seen = Arc::new(AtomicU64::new(now_ms(epoch)));
121 let alive = Arc::new(AtomicBool::new(true));
122
123 tokio::spawn(reader(
124 listener.clone(),
125 upstream.clone(),
126 client,
127 alive.clone(),
128 last_seen.clone(),
129 idle,
130 epoch,
131 ));
132
133 Ok(Session {
134 upstream,
135 last_seen,
136 alive,
137 _guard: guard,
138 })
139}
140
141async fn reader(
145 listener: Arc<UdpSocket>,
146 upstream: Arc<UdpSocket>,
147 client: SocketAddr,
148 alive: Arc<AtomicBool>,
149 last_seen: Arc<AtomicU64>,
150 idle: Duration,
151 epoch: Instant,
152) {
153 let mut buf = [0u8; BUF_SIZE];
154 let idle_ms = idle.as_millis() as u64;
155 loop {
156 match timeout(idle, upstream.recv(&mut buf)).await {
157 Ok(Ok(n)) => {
158 if let Err(e) = listener.send_to(&buf[..n], client).await {
159 debug!("udp stream send to client failed: {}", e);
160 break;
161 }
162 last_seen.store(now_ms(epoch), Ordering::Relaxed);
163 }
164 Ok(Err(e)) => {
165 debug!("udp stream upstream recv error: {}", e);
166 break;
167 }
168 Err(_) => {
169 if now_ms(epoch).saturating_sub(last_seen.load(Ordering::Relaxed)) >= idle_ms {
171 break;
172 }
173 }
174 }
175 }
176 alive.store(false, Ordering::Relaxed);
177}