1use std::io;
5use std::net::SocketAddr;
6use std::sync::Arc;
7use std::time::Duration;
8
9use tokio::io::{AsyncReadExt, AsyncWriteExt};
10use tokio::net::{TcpListener, TcpStream};
11use tokio::sync::watch;
12use tracing::{debug, warn};
13
14use crate::stream::sni::{extract_sni, SniResult, SniRouter};
15
16const MAX_CLIENT_HELLO: usize = 8 * 1024;
18
19pub async fn spawn(
24 cfg: &crate::config::StreamListenerConfig,
25 router: Arc<SniRouter>,
26 connect_timeout: Duration,
27 mut shutdown_rx: watch::Receiver<bool>,
28) -> io::Result<SocketAddr> {
29 let ip = cfg
30 .bind
31 .parse()
32 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("invalid bind: {}", e)))?;
33 let addr = SocketAddr::new(ip, cfg.port);
34 let listener = TcpListener::bind(addr).await?;
35 let local = listener.local_addr()?;
36
37 tokio::spawn(async move {
38 loop {
39 let (mut client, peer) = tokio::select! {
40 accepted = listener.accept() => match accepted {
41 Ok(v) => v,
42 Err(e) => {
43 warn!("tcp stream accept error: {}", e);
44 continue;
45 }
46 },
47 _ = shutdown_rx.changed() => break,
48 };
49 let router = router.clone();
50 tokio::spawn(async move {
51 let (balancer, prebuffer) = if router.has_sni_routes() {
55 let (sni, buf) = peek_sni(&mut client, connect_timeout).await;
56 (router.select(sni.as_deref()).clone(), buf)
57 } else {
58 (router.select(None).clone(), Vec::new())
59 };
60
61 let idx = balancer.select(&peer.to_string());
62 let _guard = balancer.owned_acquire(idx);
65 let target = balancer.target(idx);
66 let dest = (target.host.as_str(), target.port);
67
68 match tokio::time::timeout(connect_timeout, TcpStream::connect(dest)).await {
69 Ok(Ok(mut upstream)) => {
70 if !prebuffer.is_empty() {
72 if let Err(e) = upstream.write_all(&prebuffer).await {
73 warn!(
74 "tcp stream replay to {}:{} failed: {}",
75 target.host, target.port, e
76 );
77 return;
78 }
79 }
80 if let Err(e) =
81 tokio::io::copy_bidirectional(&mut client, &mut upstream).await
82 {
83 debug!("tcp stream relay closed: {}", e);
84 }
85 }
86 Ok(Err(e)) => {
87 warn!(
88 "tcp stream connect to {}:{} failed: {}",
89 target.host, target.port, e
90 )
91 }
92 Err(_) => warn!(
93 "tcp stream connect to {}:{} timed out",
94 target.host, target.port
95 ),
96 }
97 });
98 }
99 });
100
101 Ok(local)
102}
103
104async fn peek_sni(client: &mut TcpStream, timeout: Duration) -> (Option<String>, Vec<u8>) {
109 let mut buf = Vec::with_capacity(1024);
110 let deadline = tokio::time::Instant::now() + timeout;
111 let mut tmp = [0u8; 4096];
112 loop {
113 match extract_sni(&buf) {
114 SniResult::Found(host) => return (Some(host), buf),
115 SniResult::NotPresent => return (None, buf),
116 SniResult::Incomplete => {}
117 }
118 if buf.len() >= MAX_CLIENT_HELLO {
119 return (None, buf);
120 }
121 match tokio::time::timeout_at(deadline, client.read(&mut tmp)).await {
122 Ok(Ok(0)) => return (None, buf), Ok(Ok(n)) => {
124 let take = n.min(MAX_CLIENT_HELLO - buf.len());
125 buf.extend_from_slice(&tmp[..take]);
126 }
127 Ok(Err(_)) | Err(_) => return (None, buf), }
129 }
130}