seyd_transport/
endpoint.rs1use crate::cert::Cert;
4use crate::prober::Prober;
5use crate::session::Session;
6use crate::webtransport;
7use std::sync::atomic::{AtomicU64, Ordering};
8use std::sync::Arc;
9use std::time::Duration;
10use tokio::sync::mpsc;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum Congestion {
14 Bbr,
16 Cubic,
18}
19
20#[derive(Debug, Clone)]
21pub struct TransportConfig {
22 pub congestion: Congestion,
23 pub datagram_send_buffer: usize,
35 pub datagram_receive_buffer: usize,
36 pub max_idle: Duration,
37 pub keep_alive: Duration,
38 pub initial_mtu: u16,
40}
41
42impl Default for TransportConfig {
43 fn default() -> Self {
44 Self {
45 congestion: Congestion::Bbr,
46 datagram_send_buffer: 256 * 1024,
47 datagram_receive_buffer: 2 * 1024 * 1024,
48 max_idle: Duration::from_secs(10),
49 keep_alive: Duration::from_secs(2),
50 initial_mtu: 1200,
51 }
52 }
53}
54
55pub struct Endpoint {
57 endpoints: Vec<quinn::Endpoint>,
58 probers: Vec<Prober>,
59 sessions: tokio::sync::Mutex<mpsc::Receiver<Session>>,
60 local_addrs: Vec<std::net::SocketAddr>,
61 cfg: TransportConfig,
62}
63
64fn install_crypto_provider() {
65 let _ = rustls::crypto::ring::default_provider().install_default();
67}
68
69fn make_server_config(cert: &Cert, cfg: &TransportConfig) -> anyhow::Result<quinn::ServerConfig> {
72 let cert_chain = vec![rustls::pki_types::CertificateDer::from(
73 cert.cert_der.clone(),
74 )];
75 let key = rustls::pki_types::PrivateKeyDer::Pkcs8(rustls::pki_types::PrivatePkcs8KeyDer::from(
76 cert.key_der.clone(),
77 ));
78 let mut tls = rustls::ServerConfig::builder_with_provider(Arc::new(
79 rustls::crypto::ring::default_provider(),
80 ))
81 .with_protocol_versions(&[&rustls::version::TLS13])?
82 .with_no_client_auth()
83 .with_single_cert(cert_chain, key)?;
84 tls.alpn_protocols = vec![b"h3".to_vec()];
85 tls.max_early_data_size = 0;
86
87 let mut transport = quinn::TransportConfig::default();
88 transport
89 .max_idle_timeout(Some(cfg.max_idle.try_into()?))
90 .keep_alive_interval(Some(cfg.keep_alive))
91 .datagram_send_buffer_size(cfg.datagram_send_buffer)
92 .datagram_receive_buffer_size(Some(cfg.datagram_receive_buffer))
93 .initial_mtu(cfg.initial_mtu)
94 .mtu_discovery_config(Some(quinn::MtuDiscoveryConfig::default()))
95 .max_concurrent_bidi_streams(16u32.into())
98 .max_concurrent_uni_streams(16u32.into());
99 match cfg.congestion {
100 Congestion::Bbr => {
101 transport
102 .congestion_controller_factory(Arc::new(quinn::congestion::BbrConfig::default()));
103 }
104 Congestion::Cubic => {
105 transport
106 .congestion_controller_factory(Arc::new(quinn::congestion::CubicConfig::default()));
107 }
108 }
109
110 let quic_server = quinn::crypto::rustls::QuicServerConfig::try_from(tls)?;
111 let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(quic_server));
112 server_config.transport_config(Arc::new(transport));
113 Ok(server_config)
114}
115
116impl Endpoint {
117 pub fn bind(
120 socks: Vec<std::net::UdpSocket>,
121 cert: &Cert,
122 cfg: TransportConfig,
123 ) -> anyhow::Result<Endpoint> {
124 install_crypto_provider();
125 anyhow::ensure!(!socks.is_empty(), "at least one socket is required");
126 let server_config = make_server_config(cert, &cfg)?;
127 let (tx, rx) = mpsc::channel(16);
128 let next_id = Arc::new(AtomicU64::new(1));
129 let mut endpoints = Vec::new();
130 let mut probers = Vec::new();
131 let mut local_addrs = Vec::new();
132 for sock in socks {
133 sock.set_nonblocking(true)?;
134 let probe_sock = sock.try_clone()?;
135 local_addrs.push(sock.local_addr()?);
136 let ep = quinn::Endpoint::new(
137 quinn::EndpointConfig::default(),
138 Some(server_config.clone()),
139 sock,
140 Arc::new(quinn::TokioRuntime),
141 )?;
142 probers.push(Prober::new(probe_sock));
143 let accept_ep = ep.clone();
144 let tx = tx.clone();
145 let next_id = next_id.clone();
146 let send_buffer = cfg.datagram_send_buffer;
147 tokio::spawn(async move {
148 while let Some(incoming) = accept_ep.accept().await {
149 let tx = tx.clone();
150 let id = next_id.fetch_add(1, Ordering::Relaxed);
151 tokio::spawn(async move {
152 let conn = match incoming.await {
153 Ok(c) => c,
154 Err(e) => {
155 tracing::debug!("handshake failed: {e}");
156 return;
157 }
158 };
159 tracing::info!(session = id, peer = %conn.remote_address(), "quic connection");
160 if let Err(e) = webtransport::serve(conn, id, tx, send_buffer).await {
161 tracing::debug!(session = id, "h3 connection ended: {e:#}");
162 }
163 });
164 }
165 });
166 endpoints.push(ep);
167 }
168 Ok(Endpoint {
169 endpoints,
170 probers,
171 sessions: tokio::sync::Mutex::new(rx),
172 local_addrs,
173 cfg,
174 })
175 }
176
177 pub async fn accept(&self) -> Option<Session> {
179 self.sessions.lock().await.recv().await
180 }
181
182 pub fn rotate(&self, cert: &Cert) -> anyhow::Result<()> {
186 let sc = make_server_config(cert, &self.cfg)?;
187 for ep in &self.endpoints {
188 ep.set_server_config(Some(sc.clone()));
189 }
190 Ok(())
191 }
192
193 pub fn local_addrs(&self) -> &[std::net::SocketAddr] {
194 &self.local_addrs
195 }
196
197 pub fn prober(&self, index: usize) -> Option<&Prober> {
199 self.probers.get(index)
200 }
201
202 pub fn socket_index_for(&self, ip: std::net::IpAddr) -> Option<usize> {
204 self.local_addrs
205 .iter()
206 .position(|a| a.is_ipv6() == ip.is_ipv6())
207 }
208
209 pub fn close(&self) {
210 for ep in &self.endpoints {
211 ep.close(0u32.into(), b"shutdown");
212 }
213 }
214}