1use std::{
2 collections::VecDeque,
3 fmt::Debug,
4 future::{Future, poll_fn},
5 io,
6 mem::ManuallyDrop,
7 net::{SocketAddr, SocketAddrV6},
8 ops::Deref,
9 pin::pin,
10 ptr,
11 sync::Arc,
12 task::{Context, Poll, Waker},
13 time::Instant,
14};
15
16use compio_buf::{BufResult, bytes::Bytes};
17use compio_log::{Instrument, error};
18#[cfg(rustls)]
19use compio_net::ToSocketAddrsAsync;
20use compio_net::UdpSocket;
21use compio_runtime::{JoinHandle, SpawnMeta};
22use flume::{Receiver, Sender, unbounded};
23use futures_util::{FutureExt, StreamExt, future, select, task::AtomicWaker};
24use quinn_proto::{
25 ClientConfig, ConnectError, ConnectionError, ConnectionHandle, DatagramEvent, EndpointConfig,
26 EndpointEvent, ServerConfig, Transmit, VarInt,
27};
28use rustc_hash::FxHashMap as HashMap;
29
30use crate::{
31 Connecting, ConnectionEvent, Incoming, RecvMeta, Socket,
32 sync::{mutex_blocking::Mutex, shared::Shared},
33};
34
35#[derive(Debug)]
36struct EndpointState {
37 endpoint: quinn_proto::Endpoint,
38 worker: Option<JoinHandle<()>>,
39 connections: HashMap<ConnectionHandle, Sender<ConnectionEvent>>,
40 close: Option<(VarInt, Bytes)>,
41 exit_on_idle: bool,
42 incoming: VecDeque<quinn_proto::Incoming>,
43 incoming_wakers: VecDeque<Waker>,
44 stats: EndpointStats,
45}
46
47#[non_exhaustive]
49#[derive(Debug, Default, Copy, Clone)]
50pub struct EndpointStats {
51 pub accepted_handshakes: u64,
53 pub outgoing_handshakes: u64,
55 pub refused_handshakes: u64,
57 pub ignored_handshakes: u64,
59}
60
61impl EndpointState {
62 fn handle_data(&mut self, meta: RecvMeta, buf: &[u8], respond_fn: impl Fn(Vec<u8>, Transmit)) {
63 let now = Instant::now();
64 for data in buf[..meta.len]
65 .chunks(meta.stride.min(meta.len))
66 .map(Into::into)
67 {
68 let mut resp_buf = Vec::new();
69 match self.endpoint.handle(
70 now,
71 meta.remote,
72 meta.local_ip,
73 meta.ecn,
74 data,
75 &mut resp_buf,
76 ) {
77 Some(DatagramEvent::NewConnection(incoming)) => {
78 if self.close.is_none() {
79 self.incoming.push_back(incoming);
80 } else {
81 let transmit = self.endpoint.refuse(incoming, &mut resp_buf);
82 respond_fn(resp_buf, transmit);
83 }
84 }
85 Some(DatagramEvent::ConnectionEvent(ch, event)) => {
86 let _ = self
87 .connections
88 .get(&ch)
89 .unwrap()
90 .send(ConnectionEvent::Proto(event));
91 }
92 Some(DatagramEvent::Response(transmit)) => respond_fn(resp_buf, transmit),
93 None => {}
94 }
95 }
96 }
97
98 fn handle_event(&mut self, ch: ConnectionHandle, event: EndpointEvent) {
99 if event.is_drained() {
100 self.connections.remove(&ch);
101 }
102 if let Some(event) = self.endpoint.handle_event(ch, event) {
103 let _ = self
104 .connections
105 .get(&ch)
106 .unwrap()
107 .send(ConnectionEvent::Proto(event));
108 }
109 }
110
111 fn is_idle(&self) -> bool {
112 self.connections.is_empty()
113 }
114
115 fn poll_incoming(&mut self, cx: &mut Context) -> Poll<Option<quinn_proto::Incoming>> {
116 if self.close.is_none() {
117 if let Some(incoming) = self.incoming.pop_front() {
118 Poll::Ready(Some(incoming))
119 } else {
120 self.incoming_wakers.push_back(cx.waker().clone());
121 Poll::Pending
122 }
123 } else {
124 Poll::Ready(None)
125 }
126 }
127
128 #[track_caller]
129 fn new_connection(
130 &mut self,
131 handle: ConnectionHandle,
132 conn: quinn_proto::Connection,
133 socket: Socket,
134 events_tx: Sender<(ConnectionHandle, EndpointEvent)>,
135 ) -> Connecting {
136 let (tx, rx) = unbounded();
137 if let Some((error_code, reason)) = &self.close {
138 tx.send(ConnectionEvent::Close(*error_code, reason.clone()))
139 .unwrap();
140 }
141 self.connections.insert(handle, tx);
142 Connecting::new(handle, conn, socket, events_tx, rx)
143 }
144}
145
146impl Drop for EndpointState {
147 fn drop(&mut self) {
148 for incoming in self.incoming.drain(..) {
149 self.endpoint.ignore(incoming);
150 }
151 }
152}
153
154type ChannelPair<T> = (Sender<T>, Receiver<T>);
155
156#[derive(Debug)]
157pub(crate) struct EndpointInner {
158 state: Mutex<EndpointState>,
159 socket: Socket,
160 ipv6: bool,
161 events: ChannelPair<(ConnectionHandle, EndpointEvent)>,
162 done: AtomicWaker,
163}
164
165impl EndpointInner {
166 fn new(
167 socket: UdpSocket,
168 config: EndpointConfig,
169 server_config: Option<ServerConfig>,
170 ) -> io::Result<Self> {
171 let socket = Socket::new(socket)?;
172 let ipv6 = socket.local_addr()?.is_ipv6();
173 let allow_mtud = !socket.may_fragment();
174
175 Ok(Self {
176 state: Mutex::new(EndpointState {
177 endpoint: quinn_proto::Endpoint::new(
178 Arc::new(config),
179 server_config.map(Arc::new),
180 allow_mtud,
181 None,
182 ),
183 worker: None,
184 connections: HashMap::default(),
185 close: None,
186 exit_on_idle: false,
187 incoming: VecDeque::new(),
188 incoming_wakers: VecDeque::new(),
189 stats: EndpointStats::default(),
190 }),
191 socket,
192 ipv6,
193 events: unbounded(),
194 done: AtomicWaker::new(),
195 })
196 }
197
198 #[track_caller]
199 fn connect(
200 &self,
201 remote: SocketAddr,
202 server_name: &str,
203 config: ClientConfig,
204 ) -> Result<Connecting, ConnectError> {
205 let mut state = self.state.lock();
206
207 if state.worker.is_none() {
208 return Err(ConnectError::EndpointStopping);
209 }
210 if remote.is_ipv6() && !self.ipv6 {
211 return Err(ConnectError::InvalidRemoteAddress(remote));
212 }
213 let remote = if self.ipv6 {
214 SocketAddr::V6(match remote {
215 SocketAddr::V4(addr) => {
216 SocketAddrV6::new(addr.ip().to_ipv6_mapped(), addr.port(), 0, 0)
217 }
218 SocketAddr::V6(addr) => addr,
219 })
220 } else {
221 remote
222 };
223
224 let (handle, conn) = state
225 .endpoint
226 .connect(Instant::now(), config, remote, server_name)?;
227 state.stats.outgoing_handshakes += 1;
228
229 Ok(state.new_connection(handle, conn, self.socket.clone(), self.events.0.clone()))
230 }
231
232 fn respond(&self, buf: Vec<u8>, transmit: Transmit) {
233 let socket = self.socket.clone();
234 let meta = SpawnMeta::capture().named("quic::respond");
237 compio_runtime::spawn_at(
238 async move {
239 socket.send(buf, &transmit).await;
240 },
241 meta,
242 )
243 .detach();
244 }
245
246 #[track_caller]
247 pub(crate) fn accept(
248 &self,
249 incoming: quinn_proto::Incoming,
250 server_config: Option<ServerConfig>,
251 ) -> Result<Connecting, ConnectionError> {
252 let mut state = self.state.lock();
253 let mut resp_buf = Vec::new();
254 let now = Instant::now();
255 match state
256 .endpoint
257 .accept(incoming, now, &mut resp_buf, server_config.map(Arc::new))
258 {
259 Ok((handle, conn)) => {
260 state.stats.accepted_handshakes += 1;
261 Ok(state.new_connection(handle, conn, self.socket.clone(), self.events.0.clone()))
262 }
263 Err(err) => {
264 if let Some(transmit) = err.response {
265 self.respond(resp_buf, transmit);
266 }
267 Err(err.cause)
268 }
269 }
270 }
271
272 pub(crate) fn refuse(&self, incoming: quinn_proto::Incoming) {
273 let mut state = self.state.lock();
274 state.stats.refused_handshakes += 1;
275 let mut resp_buf = Vec::new();
276 let transmit = state.endpoint.refuse(incoming, &mut resp_buf);
277 self.respond(resp_buf, transmit);
278 }
279
280 #[allow(clippy::result_large_err)]
281 pub(crate) fn retry(
282 &self,
283 incoming: quinn_proto::Incoming,
284 ) -> Result<(), quinn_proto::RetryError> {
285 let mut state = self.state.lock();
286 let mut resp_buf = Vec::new();
287 let transmit = state.endpoint.retry(incoming, &mut resp_buf)?;
288 self.respond(resp_buf, transmit);
289 Ok(())
290 }
291
292 pub(crate) fn ignore(&self, incoming: quinn_proto::Incoming) {
293 let mut state = self.state.lock();
294 state.stats.ignored_handshakes += 1;
295 state.endpoint.ignore(incoming);
296 }
297
298 async fn run(&self) -> io::Result<()> {
299 let respond_fn = |buf: Vec<u8>, transmit: Transmit| self.respond(buf, transmit);
300
301 let mut recv_fut = pin!(
302 self.socket
303 .recv(Vec::with_capacity(
304 self.state
305 .lock()
306 .endpoint
307 .config()
308 .get_max_udp_payload_size()
309 .min(64 * 1024) as usize
310 * self.socket.max_gro_segments(),
311 ))
312 .fuse()
313 );
314
315 let mut event_stream = self.events.1.stream().ready_chunks(100);
316
317 loop {
318 let mut state = select! {
319 BufResult(res, recv_buf) = recv_fut => {
320 let mut state = self.state.lock();
321 match res {
322 Ok(meta) => state.handle_data(meta, &recv_buf, respond_fn),
323 Err(e) if e.kind() == io::ErrorKind::ConnectionReset => {}
324 #[cfg(windows)]
325 Err(e) if e.raw_os_error() == Some(windows_sys::Win32::Foundation::ERROR_PORT_UNREACHABLE as _) => {}
326 Err(e) => break Err(e),
327 }
328 recv_fut.set(self.socket.recv(recv_buf).fuse());
329 state
330 },
331 events = event_stream.select_next_some() => {
332 let mut state = self.state.lock();
333 for (ch, event) in events {
334 state.handle_event(ch, event);
335 }
336 state
337 },
338 };
339
340 if state.exit_on_idle && state.is_idle() {
341 break Ok(());
342 }
343 if !state.incoming.is_empty() {
344 let n = state.incoming.len().min(state.incoming_wakers.len());
345 state.incoming_wakers.drain(..n).for_each(Waker::wake);
346 }
347 }
348 }
349}
350
351#[derive(Debug, Clone)]
352pub(crate) struct EndpointRef(Shared<EndpointInner>);
353
354impl EndpointRef {
355 fn into_inner(self) -> Shared<EndpointInner> {
356 let this = ManuallyDrop::new(self);
357 unsafe { ptr::read(&this.0) }
359 }
360
361 async fn shutdown(self) -> io::Result<()> {
362 let (worker, idle) = {
363 let mut state = self.0.state.lock();
364 let idle = state.is_idle();
365 if !idle {
366 state.exit_on_idle = true;
367 }
368 (state.worker.take(), idle)
369 };
370 if let Some(worker) = worker {
371 if idle {
372 worker.cancel().await;
373 } else {
374 _ = worker.await;
375 }
376 }
377
378 let mut this = Some(self.into_inner());
379 let inner = poll_fn(move |cx| {
380 let s = match Shared::try_unwrap(this.take().unwrap()) {
381 Ok(inner) => return Poll::Ready(inner),
382 Err(s) => s,
383 };
384
385 s.done.register(cx.waker());
386
387 match Shared::try_unwrap(s) {
388 Ok(inner) => Poll::Ready(inner),
389 Err(s) => {
390 this.replace(s);
391 Poll::Pending
392 }
393 }
394 })
395 .await;
396
397 inner.socket.close().await
398 }
399}
400
401impl Drop for EndpointRef {
402 fn drop(&mut self) {
403 if Shared::strong_count(&self.0) == 2 {
404 self.0.done.wake();
407 self.0.state.lock().exit_on_idle = true;
409 }
410 }
411}
412
413impl Deref for EndpointRef {
414 type Target = EndpointInner;
415
416 fn deref(&self) -> &Self::Target {
417 &self.0
418 }
419}
420
421#[track_caller]
428pub(crate) fn worker_meta() -> SpawnMeta {
429 SpawnMeta::capture().named("quic::endpoint")
430}
431
432#[derive(Debug, Clone)]
434pub struct Endpoint {
435 inner: EndpointRef,
436 pub default_client_config: Option<ClientConfig>,
438}
439
440impl Endpoint {
441 #[track_caller]
443 pub fn new(
444 socket: UdpSocket,
445 config: EndpointConfig,
446 server_config: Option<ServerConfig>,
447 default_client_config: Option<ClientConfig>,
448 ) -> io::Result<Self> {
449 Self::new_at(
450 socket,
451 config,
452 server_config,
453 default_client_config,
454 worker_meta(),
455 )
456 }
457
458 pub(crate) fn new_at(
459 socket: UdpSocket,
460 config: EndpointConfig,
461 server_config: Option<ServerConfig>,
462 default_client_config: Option<ClientConfig>,
463 meta: SpawnMeta,
464 ) -> io::Result<Self> {
465 let inner = EndpointRef(Shared::new(EndpointInner::new(
466 socket,
467 config,
468 server_config,
469 )?));
470 let worker = compio_runtime::spawn_at(
475 {
476 let inner = inner.clone();
477 async move {
478 if let Err(e) = inner.run().await {
479 error!("I/O error: {:?}", e);
480 }
481 }
482 .in_current_span()
483 },
484 meta,
485 );
486 inner.state.lock().worker = Some(worker);
487 Ok(Self {
488 inner,
489 default_client_config,
490 })
491 }
492
493 #[cfg(rustls)]
508 #[track_caller]
509 pub fn client(addr: impl ToSocketAddrsAsync) -> impl Future<Output = io::Result<Endpoint>> {
510 Self::client_at(addr, worker_meta())
511 }
512
513 #[cfg(rustls)]
514 pub(crate) async fn client_at(
515 addr: impl ToSocketAddrsAsync,
516 meta: SpawnMeta,
517 ) -> io::Result<Endpoint> {
518 let socket = UdpSocket::bind(addr).await?;
520 Self::new_at(socket, EndpointConfig::default(), None, None, meta)
521 }
522
523 #[cfg(rustls)]
532 #[track_caller]
533 pub fn server(
534 addr: impl ToSocketAddrsAsync,
535 config: ServerConfig,
536 ) -> impl Future<Output = io::Result<Self>> {
537 Self::server_at(addr, config, worker_meta())
538 }
539
540 #[cfg(rustls)]
541 pub(crate) async fn server_at(
542 addr: impl ToSocketAddrsAsync,
543 config: ServerConfig,
544 meta: SpawnMeta,
545 ) -> io::Result<Self> {
546 let socket = UdpSocket::bind(addr).await?;
547 Self::new_at(socket, EndpointConfig::default(), Some(config), None, meta)
548 }
549
550 pub fn stats(&self) -> EndpointStats {
552 self.inner.state.lock().stats
553 }
554
555 #[track_caller]
557 pub fn connect(
558 &self,
559 remote: SocketAddr,
560 server_name: &str,
561 config: Option<ClientConfig>,
562 ) -> Result<Connecting, ConnectError> {
563 let config = config
564 .or_else(|| self.default_client_config.clone())
565 .ok_or(ConnectError::NoDefaultClientConfig)?;
566
567 self.inner.connect(remote, server_name, config)
568 }
569
570 pub async fn wait_incoming(&self) -> Option<Incoming> {
579 future::poll_fn(|cx| self.inner.state.lock().poll_incoming(cx))
580 .await
581 .map(|incoming| Incoming::new(incoming, self.inner.clone()))
582 }
583
584 pub fn set_server_config(&self, server_config: Option<ServerConfig>) {
590 self.inner
591 .state
592 .lock()
593 .endpoint
594 .set_server_config(server_config.map(Arc::new))
595 }
596
597 pub fn local_addr(&self) -> io::Result<SocketAddr> {
599 self.inner.socket.local_addr()
600 }
601
602 pub fn open_connections(&self) -> usize {
604 self.inner.state.lock().endpoint.open_connections()
605 }
606
607 pub fn close(&self, error_code: VarInt, reason: &[u8]) {
614 let reason = Bytes::copy_from_slice(reason);
615 let mut state = self.inner.state.lock();
616 if state.close.is_some() {
617 return;
618 }
619 state.close = Some((error_code, reason.clone()));
620 for conn in state.connections.values() {
621 let _ = conn.send(ConnectionEvent::Close(error_code, reason.clone()));
622 }
623 state.incoming_wakers.drain(..).for_each(Waker::wake);
624 }
625
626 pub async fn shutdown(self) -> io::Result<()> {
643 self.inner.shutdown().await
644 }
645}