noq/
connection.rs

1use std::{
2    any::Any,
3    fmt,
4    future::Future,
5    io,
6    net::{IpAddr, SocketAddr},
7    num::NonZeroUsize,
8    pin::Pin,
9    sync::{
10        Arc, Weak,
11        atomic::{AtomicUsize, Ordering},
12    },
13    task::{Context, Poll, Waker, ready},
14};
15
16use bytes::Bytes;
17use pin_project_lite::pin_project;
18use rustc_hash::FxHashMap;
19use thiserror::Error;
20use tokio::sync::{Notify, futures::Notified, mpsc, oneshot, watch};
21use tracing::{Instrument, Span, debug_span};
22
23use crate::{
24    ConnectionEvent, Duration, Instant, Path, VarInt,
25    endpoint::ensure_ipv6,
26    mutex::{Mutex, MutexGuard},
27    path::{OpenPath, PathRef, PathRefOwner},
28    recv_stream::RecvStream,
29    runtime::{AsyncTimer, Runtime, UdpSender},
30    send_stream::SendStream,
31    udp_transmit,
32};
33use proto::{
34    ConnectionError, ConnectionHandle, ConnectionStats, Dir, EndpointEvent, FourTuple, PathError,
35    PathEvent, PathId, PathStats, PathStatus, Side, StreamEvent, StreamId, TransportError,
36    TransportErrorCode, congestion::Controller, n0_nat_traversal,
37};
38
39/// In-progress connection attempt future
40#[derive(Debug)]
41pub struct Connecting {
42    conn: Option<ConnectionRef>,
43    connected: oneshot::Receiver<bool>,
44    handshake_data_ready: Option<oneshot::Receiver<()>>,
45}
46
47impl Connecting {
48    pub(crate) fn new(
49        handle: ConnectionHandle,
50        conn: proto::Connection,
51        endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>,
52        conn_events: mpsc::UnboundedReceiver<ConnectionEvent>,
53        sender: Pin<Box<dyn UdpSender>>,
54        runtime: Arc<dyn Runtime>,
55    ) -> Self {
56        let (on_handshake_data_send, on_handshake_data_recv) = oneshot::channel();
57        let (on_connected_send, on_connected_recv) = oneshot::channel();
58
59        let conn = ConnectionRef(Arc::new(Arc::new(ConnectionInner {
60            state: Mutex::new(State::new(
61                conn,
62                handle,
63                endpoint_events,
64                conn_events,
65                on_handshake_data_send,
66                on_connected_send,
67                sender,
68                runtime.clone(),
69            )),
70            shared: Shared::default(),
71        })));
72
73        let driver = ConnectionDriver(conn.clone());
74        runtime.spawn(Box::pin(
75            async {
76                if let Err(e) = driver.await {
77                    tracing::error!("I/O error: {e}");
78                }
79            }
80            .instrument(Span::current()),
81        ));
82
83        Self {
84            conn: Some(conn),
85            connected: on_connected_recv,
86            handshake_data_ready: Some(on_handshake_data_recv),
87        }
88    }
89
90    /// Convert into a 0-RTT or 0.5-RTT connection at the cost of weakened security
91    ///
92    /// Returns `Ok` immediately if the local endpoint is able to attempt sending 0/0.5-RTT data.
93    /// If so, the returned [`Connection`] can be used to send application data without waiting for
94    /// the rest of the handshake to complete, at the cost of weakened cryptographic security
95    /// guarantees. The returned [`ZeroRttAccepted`] future resolves when the handshake does
96    /// complete, at which point subsequently opened streams and written data will have full
97    /// cryptographic protection.
98    ///
99    /// ## Outgoing
100    ///
101    /// For outgoing connections, the initial attempt to convert to a [`Connection`] which sends
102    /// 0-RTT data will proceed if the [`crypto::ClientConfig`][crate::crypto::ClientConfig]
103    /// attempts to resume a previous TLS session. However, **the remote endpoint may not actually
104    /// _accept_ the 0-RTT data**--yet still accept the connection attempt in general. This
105    /// possibility is conveyed through the [`ZeroRttAccepted`] future--when the handshake
106    /// completes, it resolves to true if the 0-RTT data was accepted and false if it was rejected.
107    /// If it was rejected, the existence of streams opened and other application data sent prior
108    /// to the handshake completing will not be conveyed to the remote application, and local
109    /// operations on them will return `ZeroRttRejected` errors.
110    ///
111    /// A server may reject 0-RTT data at its discretion, but accepting 0-RTT data requires the
112    /// relevant resumption state to be stored in the server, which servers may limit or lose for
113    /// various reasons including not persisting resumption state across server restarts.
114    ///
115    /// If manually providing a [`crypto::ClientConfig`][crate::crypto::ClientConfig], check your
116    /// implementation's docs for 0-RTT pitfalls.
117    ///
118    /// ## Incoming
119    ///
120    /// For incoming connections, conversion to 0.5-RTT will always fully succeed. `into_0rtt` will
121    /// always return `Ok` and the [`ZeroRttAccepted`] will always resolve to true.
122    ///
123    /// If manually providing a [`crypto::ServerConfig`][crate::crypto::ServerConfig], check your
124    /// implementation's docs for 0-RTT pitfalls.
125    ///
126    /// ## Security
127    ///
128    /// On outgoing connections, this enables transmission of 0-RTT data, which is vulnerable to
129    /// replay attacks, and should therefore never invoke non-idempotent operations.
130    ///
131    /// On incoming connections, this enables transmission of 0.5-RTT data, which may be sent
132    /// before TLS client authentication has occurred, and should therefore not be used to send
133    /// data for which client authentication is being used.
134    pub fn into_0rtt(mut self) -> Result<(Connection, ZeroRttAccepted), Self> {
135        // This lock borrows `self` and would normally be dropped at the end of this scope, so we'll
136        // have to release it explicitly before returning `self` by value.
137        let conn = (self.conn.as_mut().unwrap()).lock_without_waking("into_0rtt");
138
139        let is_ok = conn.inner.has_0rtt() || conn.inner.side().is_server();
140        drop(conn);
141
142        if is_ok {
143            let conn = self.conn.take().unwrap();
144            Ok((Connection(conn), ZeroRttAccepted(self.connected)))
145        } else {
146            Err(self)
147        }
148    }
149
150    /// Parameters negotiated during the handshake
151    ///
152    /// The dynamic type returned is determined by the configured
153    /// [`Session`](proto::crypto::Session). For the default `rustls` session, the return value can
154    /// be [`downcast`](Box::downcast) to a
155    /// [`crypto::rustls::HandshakeData`](crate::crypto::rustls::HandshakeData).
156    pub async fn handshake_data(&mut self) -> Result<Box<dyn Any>, ConnectionError> {
157        // Taking &mut self allows us to use a single oneshot channel rather than dealing with
158        // potentially many tasks waiting on the same event. It's a bit of a hack, but keeps things
159        // simple.
160        if let Some(x) = self.handshake_data_ready.take() {
161            let _ = x.await;
162        }
163        let conn = self.conn.as_ref().unwrap();
164        let inner = conn.lock_without_waking("handshake");
165        inner
166            .inner
167            .crypto_session()
168            .handshake_data()
169            .ok_or_else(|| {
170                inner
171                    .error
172                    .clone()
173                    .expect("spurious handshake data ready notification")
174            })
175    }
176
177    /// The local IP address which was used when the peer established
178    /// the connection
179    ///
180    /// This can be different from the address the endpoint is bound to, in case
181    /// the endpoint is bound to a wildcard address like `0.0.0.0` or `::`.
182    ///
183    /// This will return `None` for clients, or when the platform does not expose this
184    /// information. See [`noq_udp::RecvMeta::dst_ip`](udp::RecvMeta::dst_ip) for a list of
185    /// supported platforms when using [`noq_udp`](udp) for I/O, which is the default.
186    ///
187    /// Will panic if called after `poll` has returned `Ready`.
188    pub fn local_ip(&self) -> Option<IpAddr> {
189        let conn = self.conn.as_ref().expect("used after yielding Ready");
190        let inner = conn.lock_without_waking("local_ip");
191
192        inner
193            .inner
194            .network_path(PathId::ZERO)
195            .expect("PathId::ZERO is the only path during the handshake")
196            .local_ip()
197    }
198
199    /// The peer's UDP addresses
200    ///
201    /// Will panic if called after `poll` has returned `Ready`.
202    pub fn remote_address(&self) -> SocketAddr {
203        let conn_ref: &ConnectionRef = self.conn.as_ref().expect("used after yielding Ready");
204        conn_ref
205            .lock_without_waking("remote_address")
206            .inner
207            .network_path(PathId::ZERO)
208            .expect("PathId::ZERO is the only path during the handshake")
209            .remote()
210    }
211}
212
213impl Future for Connecting {
214    type Output = Result<Connection, ConnectionError>;
215    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
216        Pin::new(&mut self.connected).poll(cx).map(|_| {
217            let conn = self.conn.take().unwrap();
218            let inner = conn.lock_without_waking("connecting");
219            if inner.connected {
220                drop(inner);
221                Ok(Connection(conn))
222            } else {
223                Err(inner
224                    .error
225                    .clone()
226                    .expect("connected signaled without connection success or error"))
227            }
228        })
229    }
230}
231
232/// Future that completes when a connection is fully established
233///
234/// For clients, the resulting value indicates if 0-RTT was accepted. For servers, the resulting
235/// value is meaningless.
236pub struct ZeroRttAccepted(oneshot::Receiver<bool>);
237
238impl Future for ZeroRttAccepted {
239    type Output = bool;
240    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
241        Pin::new(&mut self.0).poll(cx).map(|x| x.unwrap_or(false))
242    }
243}
244
245/// A future that drives protocol logic for a connection
246///
247/// This future handles the protocol logic for a single connection, routing events from the
248/// `Connection` API object to the `Endpoint` task and the related stream-related interfaces.
249/// It also keeps track of outstanding timeouts for the `Connection`.
250///
251/// If the connection encounters an error condition, this future will yield an error. It will
252/// terminate (yielding `Ok(())`) if the connection was closed without error. Unlike other
253/// connection-related futures, this waits for the draining period to complete to ensure that
254/// packets still in flight from the peer are handled gracefully.
255#[must_use = "connection drivers must be spawned for their connections to function"]
256#[derive(Debug)]
257struct ConnectionDriver(ConnectionRef);
258
259impl Future for ConnectionDriver {
260    type Output = Result<(), io::Error>;
261
262    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
263        let conn = &mut *self.0.lock_without_waking("poll");
264
265        let span = debug_span!("drive", id = conn.handle.0);
266        let _guard = span.enter();
267
268        if let Err(e) = conn.process_conn_events(&self.0.shared, cx) {
269            conn.terminate(e, &self.0.shared);
270            return Poll::Ready(Ok(()));
271        }
272        let mut keep_going = conn.drive_transmit(cx)?;
273        // If a timer expires, there might be more to transmit. When we transmit something, we
274        // might need to reset a timer. Hence, we must loop until neither happens.
275        keep_going |= conn.drive_timer(cx);
276        conn.forward_endpoint_events();
277        conn.forward_app_events(&self.0.shared);
278
279        if !conn.inner.is_drained() {
280            if keep_going {
281                // If the connection hasn't processed all tasks, schedule it again
282                cx.waker().wake_by_ref();
283            } else {
284                conn.driver = Some(cx.waker().clone());
285            }
286            return Poll::Pending;
287        }
288        if conn.error.is_none() {
289            unreachable!("drained connections always have an error");
290        }
291        Poll::Ready(Ok(()))
292    }
293}
294
295/// A QUIC connection.
296///
297/// If all references to a connection (including every clone of the `Connection` handle, streams of
298/// incoming streams, and the various stream types) have been dropped, then the connection will be
299/// automatically closed with an `error_code` of 0 and an empty `reason`. You can also close the
300/// connection explicitly by calling [`Connection::close()`].
301///
302/// Closing the connection immediately abandons efforts to deliver data to the peer.  Upon
303/// receiving CONNECTION_CLOSE the peer *may* drop any stream data not yet delivered to the
304/// application. [`Connection::close()`] describes in more detail how to gracefully close a
305/// connection without losing application data.
306///
307/// May be cloned to obtain another handle to the same connection.
308///
309/// [`Connection::close()`]: Connection::close
310#[derive(Debug, Clone)]
311pub struct Connection(ConnectionRef);
312
313impl Connection {
314    /// Returns a weak reference to the inner connection struct.
315    pub fn weak_handle(&self) -> WeakConnectionHandle {
316        self.0.weak_handle()
317    }
318
319    /// Initiate a new outgoing unidirectional stream.
320    ///
321    /// Streams are cheap and instantaneous to open unless blocked by flow control. As a
322    /// consequence, the peer won't be notified that a stream has been opened until the stream is
323    /// actually used.
324    pub fn open_uni(&self) -> OpenUni<'_> {
325        OpenUni {
326            conn: &self.0,
327            notify: self.0.shared.stream_budget_available[Dir::Uni as usize].notified(),
328        }
329    }
330
331    /// Initiate a new outgoing bidirectional stream.
332    ///
333    /// Streams are cheap and instantaneous to open unless blocked by flow control. As a
334    /// consequence, the peer won't be notified that a stream has been opened until the stream is
335    /// actually used. Calling [`open_bi()`] then waiting on the [`RecvStream`] without writing
336    /// anything to [`SendStream`] will never succeed.
337    ///
338    /// [`open_bi()`]: crate::Connection::open_bi
339    /// [`SendStream`]: crate::SendStream
340    /// [`RecvStream`]: crate::RecvStream
341    pub fn open_bi(&self) -> OpenBi<'_> {
342        OpenBi {
343            conn: &self.0,
344            notify: self.0.shared.stream_budget_available[Dir::Bi as usize].notified(),
345        }
346    }
347
348    /// Accept the next incoming uni-directional stream
349    pub fn accept_uni(&self) -> AcceptUni<'_> {
350        AcceptUni {
351            conn: &self.0,
352            notify: self.0.shared.stream_incoming[Dir::Uni as usize].notified(),
353        }
354    }
355
356    /// Accept the next incoming bidirectional stream
357    ///
358    /// **Important Note**: The `Connection` that calls [`open_bi()`] must write to its [`SendStream`]
359    /// before the other `Connection` is able to `accept_bi()`. Calling [`open_bi()`] then
360    /// waiting on the [`RecvStream`] without writing anything to [`SendStream`] will never succeed.
361    ///
362    /// [`accept_bi()`]: crate::Connection::accept_bi
363    /// [`open_bi()`]: crate::Connection::open_bi
364    /// [`SendStream`]: crate::SendStream
365    /// [`RecvStream`]: crate::RecvStream
366    pub fn accept_bi(&self) -> AcceptBi<'_> {
367        AcceptBi {
368            conn: &self.0,
369            notify: self.0.shared.stream_incoming[Dir::Bi as usize].notified(),
370        }
371    }
372
373    /// Receive an application datagram
374    pub fn read_datagram(&self) -> ReadDatagram<'_> {
375        ReadDatagram {
376            conn: &self.0,
377            notify: self.0.shared.datagram_received.notified(),
378        }
379    }
380
381    /// Opens a new path if no path exists yet for `network_path`.
382    ///
383    /// If `network_path` has no local IP set, then this will open a new path
384    /// if no path exists for this remote address, independent of the existing
385    /// path's local IP. If a local IP is set, it will match against the full
386    /// four-tuple of existing paths.
387    ///
388    /// Otherwise behaves exactly as [`open_path`].
389    ///
390    /// [`open_path`]: Self::open_path
391    pub fn open_path_ensure(
392        &self,
393        network_path: impl Into<FourTuple>,
394        initial_status: PathStatus,
395    ) -> OpenPath {
396        let network_path = network_path.into();
397        let mut state = self.0.lock_and_wake("open_path");
398
399        let network_path = match normalize_network_path(network_path, &state.inner) {
400            Ok(network_path) => network_path,
401            Err(err) => return OpenPath::rejected(err),
402        };
403
404        let now = state.runtime.now();
405        let open_res = state
406            .inner
407            .open_path_ensure(network_path, initial_status, now);
408        match open_res {
409            Ok((path_id, existed)) if existed => {
410                let recv = state.open_path.get(&path_id).map(|tx| tx.subscribe());
411                drop(state);
412                match recv {
413                    Some(recv) => OpenPath::new(path_id, recv, self.0.clone()),
414                    None => OpenPath::ready(path_id, self.0.clone()),
415                }
416            }
417            Ok((path_id, _)) => {
418                let (tx, rx) = watch::channel(Ok(()));
419                state.open_path.insert(path_id, tx);
420                drop(state);
421                OpenPath::new(path_id, rx, self.0.clone())
422            }
423            Err(err) => OpenPath::rejected(err),
424        }
425    }
426
427    /// Opens an additional path if the multipath extension is negotiated.
428    ///
429    /// This function takes a [`FourTuple`], which contains the remote address and an optional
430    /// local IP. If the local IP is set, the path will be opened with this source address,
431    /// and the endpoint must support sending from that IP address. You can also pass a
432    /// [`SocketAddr`] to only set the remote address and leave the local IP interface unspecified.
433    ///
434    /// The returned future completes once the path is either fully opened and ready to
435    /// carry application data, or if there was an error.
436    ///
437    /// Dropping the returned future does not cancel the opening of the path, the
438    /// [`PathEvent::Established`] event will still be emitted from [`Self::path_events`] if
439    /// the path opens.  The [`PathId`] for the events can be extracted from
440    /// [`OpenPath::path_id`].
441    ///
442    /// Failure to open a path can either occur immediately, before polling the returned
443    /// future, or at a later time.  If the failure is immediate [`OpenPath::path_id`] will
444    /// return `None` and the future will be ready immediately.  If the failure happens
445    /// later, a [`PathEvent`] will be emitted.
446    pub fn open_path(
447        &self,
448        network_path: impl Into<FourTuple>,
449        initial_status: PathStatus,
450    ) -> OpenPath {
451        let network_path = network_path.into();
452        let mut state = self.0.lock_and_wake("open_path");
453
454        let network_path = match normalize_network_path(network_path, &state.inner) {
455            Ok(network_path) => network_path,
456            Err(err) => return OpenPath::rejected(err),
457        };
458
459        let (on_open_path_send, on_open_path_recv) = watch::channel(Ok(()));
460        let now = state.runtime.now();
461        let open_res = state.inner.open_path(network_path, initial_status, now);
462        match open_res {
463            Ok(path_id) => {
464                state.open_path.insert(path_id, on_open_path_send);
465                drop(state);
466                OpenPath::new(path_id, on_open_path_recv, self.0.clone())
467            }
468            Err(err) => OpenPath::rejected(err),
469        }
470    }
471
472    /// Returns the [`Path`] structure of an open path
473    pub fn path(&self, id: PathId) -> Option<Path> {
474        Path::new(&self.0, id)
475    }
476
477    /// A stream of [`PathEvent`]s for all paths in this connection.
478    ///
479    /// The stream will yield a [`PathEvent`] whenever there is a change in the state of any path in this connection.
480    /// The events need to be processed immediately, since there isn't an unbounded buffer for them.
481    ///
482    /// If processing of events lags behind too much, you will get an error of type [`crate::Lagged`] indicating
483    /// how many events were lost. The stream continues after a lag, delivering the oldest retained message next.
484    pub fn path_events(&self) -> crate::PathEvents {
485        crate::PathEvents::new(
486            self.0
487                .lock_without_waking("path_events")
488                .path_events
489                .subscribe(),
490        )
491    }
492
493    /// A stream of NAT traversal updates for this connection.
494    ///
495    /// The events need to be processed immediately, since there isn't an unbounded buffer for them.
496    ///
497    /// If processing of events lags behind too much, you will get an error of type [`crate::Lagged`] indicating
498    /// how many events were lost. The stream continues after a lag, delivering the oldest retained message next.
499    pub fn nat_traversal_updates(&self) -> crate::NatTraversalUpdates {
500        crate::NatTraversalUpdates::new(
501            self.0
502                .lock_without_waking("nat_traversal_updates")
503                .nat_traversal_updates
504                .subscribe(),
505        )
506    }
507
508    /// Wait for the connection to be closed for any reason
509    ///
510    /// Despite the return type's name, closed connections are often not an error condition at the
511    /// application layer. Cases that might be routine include [`ConnectionError::LocallyClosed`]
512    /// and [`ConnectionError::ApplicationClosed`].
513    pub async fn closed(&self) -> ConnectionError {
514        {
515            let conn = self.0.lock_without_waking("closed");
516            if let Some(error) = conn.error.as_ref() {
517                return error.clone();
518            }
519            // Construct the future while the lock is held to ensure we can't miss a wakeup if
520            // the `Notify` is signaled immediately after we release the lock. `await` it after
521            // the lock guard is out of scope.
522            self.0.shared.closed.notified()
523        }
524        .await;
525        self.0
526            .lock_without_waking("closed")
527            .error
528            .as_ref()
529            .expect("closed without an error")
530            .clone()
531    }
532
533    /// Wait for the connection to be closed without keeping a strong reference to the connection
534    ///
535    /// Returns a future that resolves, once the connection is closed, to a [`Closed`] struct
536    /// describing the close reason and final connection and per-path statistics.
537    ///
538    /// Calling [`Self::closed`] keeps the connection alive until it is either closed locally via [`Connection::close`]
539    /// or closed by the remote peer. This function instead does not keep the connection itself alive,
540    /// so if all *other* clones of the connection are dropped, the connection will be closed implicitly even
541    /// if there are futures returned from this function still being awaited.
542    pub fn on_closed(&self) -> OnClosed {
543        let (tx, rx) = oneshot::channel();
544        let mut state = self.0.lock_without_waking("on_closed");
545        if let Some(reason) = state.error.clone() {
546            // Connection already closed, send immediately
547            let _ = tx.send(Closed::new(&mut state, reason));
548        } else {
549            state.on_closed.push(tx);
550        }
551        drop(state);
552        OnClosed {
553            conn: self.weak_handle(),
554            rx,
555        }
556    }
557
558    /// Whether the connection is closed, and why.
559    ///
560    /// The close_reason is always set to `Some(ConnectionError)` when a socket is
561    /// closed; whether it was closed manually by calling [`Connection::close()`] or due to
562    /// an internal error (such as an idle timeout or the peer closing the
563    /// connection).
564    ///
565    /// Note: when the connection is closed, `connection.close_reason().is_some()` will always be true.
566    pub fn close_reason(&self) -> Option<ConnectionError> {
567        self.0.lock_without_waking("close_reason").error.clone()
568    }
569
570    /// Close the connection immediately.
571    ///
572    /// Pending operations will fail immediately with [`ConnectionError::LocallyClosed`]. No
573    /// more data is sent to the peer and the peer may drop buffered data upon receiving
574    /// the CONNECTION_CLOSE frame.
575    ///
576    /// `error_code` and `reason` are not interpreted, and are provided directly to the peer.
577    ///
578    /// `reason` will be truncated to fit in a single packet with overhead; to improve odds that it
579    /// is preserved in full, it should be kept under 1KiB.
580    ///
581    /// # Gracefully closing a connection
582    ///
583    /// Only the peer last receiving application data can be certain that all data is
584    /// delivered. The only reliable action it can then take is to close the connection,
585    /// potentially with a custom error code. The delivery of the final CONNECTION_CLOSE
586    /// frame is very likely if both endpoints stay online long enough, and
587    /// [`Endpoint::wait_idle()`] can be used to provide sufficient time. Otherwise, the
588    /// remote peer will time out the connection, provided that the idle timeout is not
589    /// disabled.
590    ///
591    /// The sending side can not guarantee all stream data is delivered to the remote
592    /// application. It only knows the data is delivered to the QUIC stack of the remote
593    /// endpoint. Once the local side sends a CONNECTION_CLOSE frame in response to calling
594    /// [`close()`] the remote endpoint may drop any data it received but is as yet
595    /// undelivered to the application, including data that was acknowledged as received to
596    /// the local endpoint.
597    ///
598    /// [`ConnectionError::LocallyClosed`]: crate::ConnectionError::LocallyClosed
599    /// [`Endpoint::wait_idle()`]: crate::Endpoint::wait_idle
600    /// [`close()`]: Connection::close
601    pub fn close(&self, error_code: VarInt, reason: &[u8]) {
602        let conn = &mut *self.0.lock_without_waking("close"); // conn.close self-wakes
603        conn.close(error_code, Bytes::copy_from_slice(reason), &self.0.shared);
604    }
605
606    /// Wait for the handshake to be confirmed.
607    ///
608    /// As a server, who must be authenticated by clients,
609    /// this happens when the handshake completes
610    /// upon receiving a TLS Finished message from the client.
611    /// In return, the server send a HANDSHAKE_DONE frame.
612    ///
613    /// As a client, this happens when receiving a HANDSHAKE_DONE frame.
614    /// At this point, the server has either accepted our authentication,
615    /// or, if client authentication is not required, accepted our lack of authentication.
616    pub async fn handshake_confirmed(&self) -> Result<(), ConnectionError> {
617        {
618            let conn = self.0.lock_without_waking("handshake_confirmed");
619            if let Some(error) = conn.error.as_ref() {
620                return Err(error.clone());
621            }
622            if conn.handshake_confirmed {
623                return Ok(());
624            }
625            // Construct the future while the lock is held to ensure we can't miss a wakeup if
626            // the `Notify` is signaled immediately after we release the lock. `await` it after
627            // the lock guard is out of scope.
628            self.0.shared.handshake_confirmed.notified()
629        }
630        .await;
631        if let Some(error) = self
632            .0
633            .lock_without_waking("handshake_confirmed")
634            .error
635            .as_ref()
636        {
637            Err(error.clone())
638        } else {
639            Ok(())
640        }
641    }
642
643    /// Transmit `data` as an unreliable, unordered application datagram
644    ///
645    /// Application datagrams are a low-level primitive. They may be lost or delivered out of order,
646    /// and `data` must both fit inside a single QUIC packet and be smaller than the maximum
647    /// dictated by the peer.
648    ///
649    /// Previously queued datagrams which are still unsent may be discarded to make space for this
650    /// datagram, in order of oldest to newest.
651    pub fn send_datagram(&self, data: Bytes) -> Result<(), SendDatagramError> {
652        let conn = &mut *self.0.lock_and_wake("send_datagram");
653        if let Some(ref x) = conn.error {
654            return Err(SendDatagramError::ConnectionLost(x.clone()));
655        }
656        use proto::SendDatagramError::*;
657        match conn.inner.datagrams().send(data, true) {
658            Ok(()) => Ok(()),
659            Err(e) => Err(match e {
660                Blocked(..) => unreachable!(),
661                UnsupportedByPeer => SendDatagramError::UnsupportedByPeer,
662                Disabled => SendDatagramError::Disabled,
663                TooLarge => SendDatagramError::TooLarge,
664            }),
665        }
666    }
667
668    /// Transmit `data` as an unreliable, unordered application datagram
669    ///
670    /// Unlike [`send_datagram()`], this method will wait for buffer space during congestion
671    /// conditions, which effectively prioritizes old datagrams over new datagrams.
672    ///
673    /// See [`send_datagram()`] for details.
674    ///
675    /// [`send_datagram()`]: Connection::send_datagram
676    pub fn send_datagram_wait(&self, data: Bytes) -> SendDatagram<'_> {
677        SendDatagram {
678            conn: &self.0,
679            data: Some(data),
680            notify: self.0.shared.datagrams_unblocked.notified(),
681        }
682    }
683
684    /// Compute the maximum size of datagrams that may be passed to [`send_datagram()`].
685    ///
686    /// Returns `None` if datagrams are unsupported by the peer or disabled locally.
687    ///
688    /// This may change over the lifetime of a connection according to variation in the path MTU
689    /// estimate. The peer can also enforce an arbitrarily small fixed limit, but if the peer's
690    /// limit is large this is guaranteed to be a little over a kilobyte at minimum.
691    ///
692    /// Not necessarily the maximum size of received datagrams.
693    ///
694    /// [`send_datagram()`]: Connection::send_datagram
695    pub fn max_datagram_size(&self) -> Option<usize> {
696        self.0
697            .lock_without_waking("max_datagram_size")
698            .inner
699            .datagrams()
700            .max_size()
701    }
702
703    /// Bytes available in the outgoing datagram buffer
704    ///
705    /// When greater than zero, calling [`send_datagram()`](Self::send_datagram) with a datagram of
706    /// at most this size is guaranteed not to cause older datagrams to be dropped.
707    pub fn datagram_send_buffer_space(&self) -> usize {
708        self.0
709            .lock_without_waking("datagram_send_buffer_space")
710            .inner
711            .datagrams()
712            .send_buffer_space()
713    }
714
715    /// The side of the connection (client or server)
716    pub fn side(&self) -> Side {
717        self.0.lock_without_waking("side").inner.side()
718    }
719
720    /// Current best estimate of this connection's latency (round-trip-time)
721    pub fn rtt(&self, path_id: PathId) -> Option<Duration> {
722        self.0.lock_without_waking("rtt").inner.rtt(path_id)
723    }
724
725    /// Returns connection statistics
726    pub fn stats(&self) -> ConnectionStats {
727        self.0.lock_without_waking("stats").inner.stats()
728    }
729
730    /// Returns path statistics
731    pub fn path_stats(&self, path_id: PathId) -> Option<PathStats> {
732        self.0.lock_without_waking("path_stats").path_stats(path_id)
733    }
734
735    /// Current state of the congestion control algorithm, for debugging purposes
736    pub fn congestion_state(&self, path_id: PathId) -> Option<Box<dyn Controller>> {
737        self.0
738            .lock_without_waking("congestion_state")
739            .inner
740            .congestion_state(path_id)
741            .map(|c| c.clone_box())
742    }
743
744    /// Succeeds when an incoming connection is proven not to be a replay attack.
745    ///
746    /// Only interesting for `Connection`s obtained from [`Connecting::into_0rtt`]. On 1-RTT
747    /// connections, always completes immediately. Contrast
748    /// [`handshake_confirmed`](Self::handshake_confirmed), which waits longer on clients e.g. to
749    /// confirm client authentication.
750    ///
751    /// For incoming connections, reads from [`RecvStream`]s are guaranteed not to arise from replay
752    /// attacks after this succeeds, even for streams accepted or read during 0-RTT. For outgoing
753    /// connections, streams opened after this succeeds will never be discarded by the server due to
754    /// 0-RTT rejection.
755    pub async fn authenticated(&self) -> Result<(), ConnectionError> {
756        let notified = {
757            let conn = self.0.state.lock("connected");
758            if let Some(e) = &conn.error {
759                return Err(e.clone());
760            }
761            if conn.connected {
762                return Ok(());
763            }
764            self.0.shared.connected.notified()
765        };
766        notified.await;
767        let conn = self.0.state.lock("connected");
768        conn.error.clone().map_or(Ok(()), Err)
769    }
770
771    /// Parameters negotiated during the handshake
772    ///
773    /// Guaranteed to return `Some` on fully established connections or after
774    /// [`Connecting::handshake_data()`] succeeds. See that method's documentations for details on
775    /// the returned value.
776    ///
777    /// [`Connection::handshake_data()`]: crate::Connecting::handshake_data
778    pub fn handshake_data(&self) -> Option<Box<dyn Any>> {
779        self.0
780            .lock_without_waking("handshake_data")
781            .inner
782            .crypto_session()
783            .handshake_data()
784    }
785
786    /// Cryptographic identity of the peer
787    ///
788    /// The dynamic type returned is determined by the configured
789    /// [`Session`](proto::crypto::Session). For the default `rustls` session, the return value can
790    /// be [`downcast`](Box::downcast) to a <code>Vec<[rustls::pki_types::CertificateDer]></code>
791    pub fn peer_identity(&self) -> Option<Box<dyn Any>> {
792        self.0
793            .lock_without_waking("peer_identity")
794            .inner
795            .crypto_session()
796            .peer_identity()
797    }
798
799    /// A stable identifier for this connection
800    ///
801    /// Peer addresses and connection IDs can change, but this value will remain
802    /// fixed for the lifetime of the connection.
803    pub fn stable_id(&self) -> usize {
804        self.0.stable_id()
805    }
806
807    /// Update traffic keys spontaneously
808    ///
809    /// This primarily exists for testing purposes.
810    pub fn force_key_update(&self) {
811        self.0
812            .lock_and_wake("force_key_update")
813            .inner
814            .force_key_update()
815    }
816
817    /// Derive keying material from this connection's TLS session secrets.
818    ///
819    /// When both peers call this method with the same `label` and `context`
820    /// arguments and `output` buffers of equal length, they will get the
821    /// same sequence of bytes in `output`. These bytes are cryptographically
822    /// strong and pseudorandom, and are suitable for use as keying material.
823    ///
824    /// See [RFC5705](https://tools.ietf.org/html/rfc5705) for more information.
825    pub fn export_keying_material(
826        &self,
827        output: &mut [u8],
828        label: &[u8],
829        context: &[u8],
830    ) -> Result<(), proto::crypto::ExportKeyingMaterialError> {
831        self.0
832            .lock_without_waking("export_keying_material")
833            .inner
834            .crypto_session()
835            .export_keying_material(output, label, context)
836    }
837
838    /// Modify the number of remotely initiated unidirectional streams that may be concurrently open
839    ///
840    /// No streams may be opened by the peer unless fewer than `count` are already open. Large
841    /// `count`s increase both minimum and worst-case memory consumption.
842    pub fn set_max_concurrent_uni_streams(&self, count: VarInt) {
843        let mut conn = self.0.lock_and_wake("set_max_concurrent_uni_streams");
844        conn.inner.set_max_concurrent_streams(Dir::Uni, count);
845    }
846
847    /// See [`proto::TransportConfig::send_window()`]
848    pub fn set_send_window(&self, send_window: u64) {
849        let mut conn = self.0.lock_and_wake("set_send_window");
850        conn.inner.set_send_window(send_window);
851    }
852
853    /// See [`proto::TransportConfig::receive_window()`]
854    pub fn set_receive_window(&self, receive_window: VarInt) {
855        let mut conn = self.0.lock_and_wake("set_receive_window");
856        conn.inner.set_receive_window(receive_window);
857    }
858
859    /// Modify the number of remotely initiated bidirectional streams that may be concurrently open
860    ///
861    /// No streams may be opened by the peer unless fewer than `count` are already open. Large
862    /// `count`s increase both minimum and worst-case memory consumption.
863    pub fn set_max_concurrent_bi_streams(&self, count: VarInt) {
864        let mut conn = self.0.lock_and_wake("set_max_concurrent_bi_streams");
865        conn.inner.set_max_concurrent_streams(Dir::Bi, count);
866    }
867
868    /// Track changes on our external address as reported by the peer.
869    pub fn observed_external_addr(&self) -> crate::ObservedExternalAddr {
870        let conn = self.0.lock_without_waking("external_addr");
871        crate::ObservedExternalAddr::new(conn.observed_external_addr.subscribe())
872    }
873
874    /// Is multipath enabled?
875    // TODO(flub): not a useful API, once we do real things with multipath we can remove
876    // this again.
877    pub fn is_multipath_enabled(&self) -> bool {
878        let conn = self.0.lock_without_waking("is_multipath_enabled");
879        conn.inner.is_multipath_negotiated()
880    }
881
882    /// Registers one address at which this endpoint might be reachable
883    ///
884    /// When the NAT traversal extension is negotiated, servers send these addresses to clients in
885    /// `ADD_ADDRESS` frames. This allows clients to obtain server address candidates to initiate
886    /// NAT traversal attempts. Clients provide their own reachable addresses in `REACH_OUT` frames
887    /// when [`Self::initiate_nat_traversal_round`] is called.
888    pub fn add_nat_traversal_address(
889        &self,
890        address: SocketAddr,
891    ) -> Result<(), n0_nat_traversal::Error> {
892        let mut conn = self.0.lock_and_wake("add_nat_traversal_addresses");
893        conn.inner.add_nat_traversal_address(address)
894    }
895
896    /// Removes one or more addresses from the set of addresses at which this endpoint is reachable
897    ///
898    /// When the NAT traversal extension is negotiated, servers send address removals to
899    /// clients in `REMOVE_ADDRESS` frames. This allows clients to stop using outdated
900    /// server address candidates that are no longer valid for NAT traversal.
901    ///
902    /// For clients, removed addresses will no longer be advertised in `REACH_OUT` frames.
903    ///
904    /// Addresses not present in the set will be silently ignored.
905    pub fn remove_nat_traversal_address(
906        &self,
907        address: SocketAddr,
908    ) -> Result<(), n0_nat_traversal::Error> {
909        let mut conn = self.0.lock_and_wake("remove_nat_traversal_addresses");
910        conn.inner.remove_nat_traversal_address(address)
911    }
912
913    /// Get the current local nat traversal addresses
914    pub fn get_local_nat_traversal_addresses(
915        &self,
916    ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
917        let conn = self
918            .0
919            .lock_without_waking("get_local_nat_traversal_addresses");
920        conn.inner.get_local_nat_traversal_addresses()
921    }
922
923    /// Get the currently advertised nat traversal addresses by the server
924    pub fn get_remote_nat_traversal_addresses(
925        &self,
926    ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
927        let conn = self
928            .0
929            .lock_without_waking("get_remote_nat_traversal_addresses");
930        conn.inner.get_remote_nat_traversal_addresses()
931    }
932
933    /// Initiates a new nat traversal round
934    ///
935    /// A nat traversal round involves advertising the client's local addresses in `REACH_OUT`
936    /// frames, and initiating probing of the known remote addresses. When a new round is
937    /// initiated, the previous one is cancelled, and paths that have not been opened are closed.
938    ///
939    /// Returns the server addresses that are now being probed.
940    pub fn initiate_nat_traversal_round(&self) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
941        let mut conn = self.0.lock_and_wake("initiate_nat_traversal_round");
942        let now = conn.runtime.now();
943        conn.inner.initiate_nat_traversal_round(now)
944    }
945}
946
947/// Normalizes a [`FourTuple`] against the connection's address family.
948///
949/// If the connection already uses IPv6 paths, the remote is canonicalised via
950/// [`ensure_ipv6`]. If it uses IPv4 and the requested remote is IPv6, this returns
951/// [`PathError::InvalidRemoteAddress`].
952fn normalize_network_path(
953    network_path: FourTuple,
954    conn: &proto::Connection,
955) -> Result<FourTuple, PathError> {
956    // If endpoint::State::ipv6 is true we want to keep all our IP addresses as IPv6.
957    // If not, we do not support IPv6.  We can not access endpoint::State from here
958    // however, but either all our paths use an IPv6 address, or all our paths use an
959    // IPv4 address.  So we can use that information.
960    let ipv6 = conn
961        .paths()
962        .iter()
963        .filter_map(|id| {
964            conn.network_path(*id)
965                .map(|addrs| addrs.remote().is_ipv6())
966                .ok()
967        })
968        .next()
969        .unwrap_or_default();
970    let remote = network_path.remote();
971    if remote.is_ipv6() && !ipv6 {
972        Err(PathError::InvalidRemoteAddress(remote))
973    } else if ipv6 {
974        let remote = SocketAddr::V6(ensure_ipv6(remote));
975        Ok(FourTuple::new(remote, network_path.local_ip()))
976    } else {
977        Ok(network_path)
978    }
979}
980
981pin_project! {
982    /// Future produced by [`Connection::open_uni`]
983    pub struct OpenUni<'a> {
984        conn: &'a ConnectionRef,
985        #[pin]
986        notify: Notified<'a>,
987    }
988}
989
990impl Future for OpenUni<'_> {
991    type Output = Result<SendStream, ConnectionError>;
992    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
993        let this = self.project();
994        let (conn, id, is_0rtt) = ready!(poll_open(ctx, this.conn, this.notify, Dir::Uni))?;
995        Poll::Ready(Ok(SendStream::new(conn, id, is_0rtt)))
996    }
997}
998
999pin_project! {
1000    /// Future produced by [`Connection::open_bi`]
1001    pub struct OpenBi<'a> {
1002        conn: &'a ConnectionRef,
1003        #[pin]
1004        notify: Notified<'a>,
1005    }
1006}
1007
1008impl Future for OpenBi<'_> {
1009    type Output = Result<(SendStream, RecvStream), ConnectionError>;
1010    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
1011        let this = self.project();
1012        let (conn, id, is_0rtt) = ready!(poll_open(ctx, this.conn, this.notify, Dir::Bi))?;
1013
1014        Poll::Ready(Ok((
1015            SendStream::new(conn.clone(), id, is_0rtt),
1016            RecvStream::new(conn, id, is_0rtt),
1017        )))
1018    }
1019}
1020
1021fn poll_open<'a>(
1022    ctx: &mut Context<'_>,
1023    conn: &'a ConnectionRef,
1024    mut notify: Pin<&mut Notified<'a>>,
1025    dir: Dir,
1026) -> Poll<Result<(ConnectionRef, StreamId, bool), ConnectionError>> {
1027    let mut state = conn.lock_without_waking("poll_open");
1028    if let Some(ref e) = state.error {
1029        return Poll::Ready(Err(e.clone()));
1030    } else if let Some(id) = state.inner.streams().open(dir) {
1031        let is_0rtt = state.inner.side().is_client() && state.inner.is_handshaking();
1032        drop(state); // Release the lock so clone can take it
1033        return Poll::Ready(Ok((conn.clone(), id, is_0rtt)));
1034    }
1035    loop {
1036        match notify.as_mut().poll(ctx) {
1037            // `state` lock ensures we didn't race with readiness
1038            Poll::Pending => return Poll::Pending,
1039            // Spurious wakeup, get a new future
1040            Poll::Ready(()) => {
1041                notify.set(conn.shared.stream_budget_available[dir as usize].notified())
1042            }
1043        }
1044    }
1045}
1046
1047pin_project! {
1048    /// Future produced by [`Connection::accept_uni`]
1049    pub struct AcceptUni<'a> {
1050        conn: &'a ConnectionRef,
1051        #[pin]
1052        notify: Notified<'a>,
1053    }
1054}
1055
1056impl Future for AcceptUni<'_> {
1057    type Output = Result<RecvStream, ConnectionError>;
1058
1059    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
1060        let this = self.project();
1061        let (conn, id, is_0rtt) = ready!(poll_accept(ctx, this.conn, this.notify, Dir::Uni))?;
1062        Poll::Ready(Ok(RecvStream::new(conn, id, is_0rtt)))
1063    }
1064}
1065
1066pin_project! {
1067    /// Future produced by [`Connection::accept_bi`]
1068    pub struct AcceptBi<'a> {
1069        conn: &'a ConnectionRef,
1070        #[pin]
1071        notify: Notified<'a>,
1072    }
1073}
1074
1075impl Future for AcceptBi<'_> {
1076    type Output = Result<(SendStream, RecvStream), ConnectionError>;
1077
1078    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
1079        let this = self.project();
1080        let (conn, id, is_0rtt) = ready!(poll_accept(ctx, this.conn, this.notify, Dir::Bi))?;
1081        Poll::Ready(Ok((
1082            SendStream::new(conn.clone(), id, is_0rtt),
1083            RecvStream::new(conn, id, is_0rtt),
1084        )))
1085    }
1086}
1087
1088fn poll_accept<'a>(
1089    ctx: &mut Context<'_>,
1090    conn: &'a ConnectionRef,
1091    mut notify: Pin<&mut Notified<'a>>,
1092    dir: Dir,
1093) -> Poll<Result<(ConnectionRef, StreamId, bool), ConnectionError>> {
1094    let mut state = conn.lock_and_wake("poll_accept");
1095    // Check for incoming streams before checking `state.error` so that already-received streams,
1096    // which are necessarily finite, can be drained from a closed connection.
1097    if let Some(id) = state.inner.streams().accept(dir) {
1098        let is_0rtt = state.inner.is_handshaking();
1099        drop(state); // Release the lock (wake on drop) so clone can take it
1100        return Poll::Ready(Ok((conn.clone(), id, is_0rtt)));
1101    } else if let Some(ref e) = state.error {
1102        return Poll::Ready(Err(e.clone()));
1103    }
1104    loop {
1105        match notify.as_mut().poll(ctx) {
1106            // `state` lock ensures we didn't race with readiness
1107            Poll::Pending => return Poll::Pending,
1108            // Spurious wakeup, get a new future
1109            Poll::Ready(()) => notify.set(conn.shared.stream_incoming[dir as usize].notified()),
1110        }
1111    }
1112}
1113
1114pin_project! {
1115    /// Future produced by [`Connection::read_datagram`]
1116    pub struct ReadDatagram<'a> {
1117        conn: &'a ConnectionRef,
1118        #[pin]
1119        notify: Notified<'a>,
1120    }
1121}
1122
1123impl Future for ReadDatagram<'_> {
1124    type Output = Result<Bytes, ConnectionError>;
1125    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
1126        let mut this = self.project();
1127        let mut state = this.conn.lock_without_waking("ReadDatagram::poll");
1128        // Check for buffered datagrams before checking `state.error` so that already-received
1129        // datagrams, which are necessarily finite, can be drained from a closed connection.
1130        if let Some(x) = state.inner.datagrams().recv() {
1131            return Poll::Ready(Ok(x));
1132        } else if let Some(ref e) = state.error {
1133            return Poll::Ready(Err(e.clone()));
1134        }
1135        loop {
1136            match this.notify.as_mut().poll(ctx) {
1137                // `state` lock ensures we didn't race with readiness
1138                Poll::Pending => return Poll::Pending,
1139                // Spurious wakeup, get a new future
1140                Poll::Ready(()) => this
1141                    .notify
1142                    .set(this.conn.shared.datagram_received.notified()),
1143            }
1144        }
1145    }
1146}
1147
1148pin_project! {
1149    /// Future produced by [`Connection::send_datagram_wait`]
1150    pub struct SendDatagram<'a> {
1151        conn: &'a ConnectionRef,
1152        data: Option<Bytes>,
1153        #[pin]
1154        notify: Notified<'a>,
1155    }
1156}
1157
1158impl Future for SendDatagram<'_> {
1159    type Output = Result<(), SendDatagramError>;
1160    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
1161        let mut this = self.project();
1162        let mut state = this.conn.lock_and_wake("SendDatagram::poll");
1163        if let Some(ref e) = state.error {
1164            return Poll::Ready(Err(SendDatagramError::ConnectionLost(e.clone())));
1165        }
1166        use proto::SendDatagramError::*;
1167        match state
1168            .inner
1169            .datagrams()
1170            .send(this.data.take().unwrap(), false)
1171        {
1172            Ok(()) => Poll::Ready(Ok(())),
1173            Err(e) => Poll::Ready(Err(match e {
1174                Blocked(data) => {
1175                    this.data.replace(data);
1176                    loop {
1177                        match this.notify.as_mut().poll(ctx) {
1178                            Poll::Pending => return Poll::Pending,
1179                            // Spurious wakeup, get a new future
1180                            Poll::Ready(()) => this
1181                                .notify
1182                                .set(this.conn.shared.datagrams_unblocked.notified()),
1183                        }
1184                    }
1185                }
1186                UnsupportedByPeer => SendDatagramError::UnsupportedByPeer,
1187                Disabled => SendDatagramError::Disabled,
1188                TooLarge => SendDatagramError::TooLarge,
1189            })),
1190        }
1191    }
1192}
1193
1194/// State of a [`Connection`] at the moment it was closed.
1195///
1196/// Returned by the [`OnClosed`] future from [`Connection::on_closed`].
1197#[derive(Debug, Clone)]
1198#[non_exhaustive]
1199pub struct Closed {
1200    /// The reason the connection was closed.
1201    pub reason: ConnectionError,
1202    /// Aggregate connection statistics at the moment of close.
1203    pub stats: ConnectionStats,
1204    /// Per-path statistics for every path the connection knew about at close time.
1205    ///
1206    /// This includes paths that haven't been discarded at close time, plus any
1207    /// already-discarded paths whose final stats had been retained because a [`Path`]
1208    /// or [`WeakPathHandle`] handle was kept alive.
1209    ///
1210    /// [`WeakPathHandle`]: crate::WeakPathHandle
1211    pub path_stats: Vec<(PathId, PathStats)>,
1212}
1213
1214impl Closed {
1215    /// Snapshot the current connection state into a [`Closed`] value.
1216    ///
1217    /// Must only be called once `state.error` has been set.
1218    pub(crate) fn new(state: &mut State, reason: ConnectionError) -> Self {
1219        let stats = state.inner.stats();
1220
1221        let non_discarded_paths = state.inner.paths();
1222        let mut path_stats =
1223            Vec::with_capacity(non_discarded_paths.len() + state.final_path_stats.len());
1224
1225        // Non-discarded paths are tracked by proto::Connection.
1226        path_stats.extend(
1227            non_discarded_paths
1228                .into_iter()
1229                .filter_map(|id| state.inner.path_stats(id).map(|stats| (id, stats))),
1230        );
1231        // Already-discarded paths whose final stats we kept around.
1232        path_stats.extend(
1233            state
1234                .final_path_stats
1235                .iter()
1236                .map(|(id, stats)| (*id, *stats)),
1237        );
1238        Self {
1239            reason,
1240            stats,
1241            path_stats,
1242        }
1243    }
1244}
1245
1246/// Future returned by [`Connection::on_closed`]
1247///
1248/// Resolves to [`Closed`].
1249pub struct OnClosed {
1250    rx: oneshot::Receiver<Closed>,
1251    conn: WeakConnectionHandle,
1252}
1253
1254impl Drop for OnClosed {
1255    fn drop(&mut self) {
1256        if self.rx.is_terminated() {
1257            return;
1258        };
1259        if let Some(conn) = self.conn.upgrade() {
1260            self.rx.close();
1261            conn.0
1262                .lock_without_waking("OnClosed::drop")
1263                .on_closed
1264                .retain(|tx| !tx.is_closed());
1265        }
1266    }
1267}
1268
1269impl Future for OnClosed {
1270    type Output = Closed;
1271
1272    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1273        let this = self.get_mut();
1274        // The `expect` is safe because `State::drop` ensures that all senders are triggered
1275        // before being dropped.
1276        Pin::new(&mut this.rx)
1277            .poll(cx)
1278            .map(|x| x.expect("on_close sender is never dropped before sending"))
1279    }
1280}
1281
1282#[derive(Debug)]
1283#[allow(clippy::redundant_allocation)]
1284pub(crate) struct ConnectionRef(Arc<Arc<ConnectionInner>>);
1285
1286impl ConnectionRef {
1287    #[allow(clippy::redundant_allocation)]
1288    fn from_arc(inner: Arc<Arc<ConnectionInner>>) -> Self {
1289        inner.shared.ref_count.fetch_add(1, Ordering::Relaxed);
1290        Self(inner)
1291    }
1292
1293    pub(crate) fn stable_id(&self) -> usize {
1294        &*self.0 as *const _ as usize
1295    }
1296
1297    pub(crate) fn weak_handle(&self) -> WeakConnectionHandle {
1298        WeakConnectionHandle(Arc::downgrade(&self.0))
1299    }
1300}
1301
1302impl Clone for ConnectionRef {
1303    fn clone(&self) -> Self {
1304        Self::from_arc(Arc::clone(&self.0))
1305    }
1306}
1307
1308impl Drop for ConnectionRef {
1309    fn drop(&mut self) {
1310        if self.shared.ref_count.fetch_sub(1, Ordering::Relaxed) > 1 {
1311            return;
1312        }
1313
1314        let conn = &mut *self.lock_without_waking("drop");
1315
1316        if !conn.inner.is_closed() {
1317            // If the driver is alive, it's just it and us, so we'd better shut it down. If it's
1318            // not, we can't do any harm. If there were any streams being opened, then either
1319            // the connection will be closed for an unrelated reason or a fresh reference will
1320            // be constructed for the newly opened stream.
1321            conn.implicit_close(&self.shared);
1322        }
1323    }
1324}
1325
1326impl std::ops::Deref for ConnectionRef {
1327    type Target = ConnectionInner;
1328    fn deref(&self) -> &Self::Target {
1329        &self.0
1330    }
1331}
1332
1333#[derive(Debug)]
1334pub(crate) struct ConnectionInner {
1335    /// Kept private intentionally, use [`Self::lock_and_wake`].
1336    state: Mutex<State>,
1337    pub(crate) shared: Shared,
1338}
1339
1340impl ConnectionInner {
1341    /// Lock the state and return a guard that wakes the connection driver on drop.
1342    ///
1343    /// Use this for operations that may queue frames. The wake ensures the driver sends queued frames.
1344    /// If that's not needed, use [`Self::lock_without_waking`].
1345    pub(crate) fn lock_and_wake(&self, purpose: &'static str) -> WakeGuard<'_> {
1346        WakeGuard {
1347            guard: self.state.lock(purpose),
1348            wake: true,
1349        }
1350    }
1351
1352    /// Lock the state and return a guard that unlocks once dropped.
1353    ///
1354    /// Use this for operations that don't require any action from the connection driver.
1355    /// Otherwise, use [`Self::lock_and_wake`] instead.
1356    pub(crate) fn lock_without_waking(&self, purpose: &'static str) -> WakeGuard<'_> {
1357        WakeGuard {
1358            guard: self.state.lock(purpose),
1359            wake: false,
1360        }
1361    }
1362}
1363
1364/// [`MutexGuard`] wrapper that calls [`State::wake`] on drop.
1365#[derive(derive_more::Deref, derive_more::DerefMut)]
1366pub(crate) struct WakeGuard<'a> {
1367    #[deref]
1368    #[deref_mut]
1369    guard: MutexGuard<'a, State>,
1370    wake: bool,
1371}
1372
1373impl WakeGuard<'_> {
1374    pub(crate) fn skip_waking(&mut self) {
1375        self.wake = false;
1376    }
1377}
1378
1379impl Drop for WakeGuard<'_> {
1380    fn drop(&mut self) {
1381        if self.wake {
1382            self.guard.wake();
1383        }
1384    }
1385}
1386
1387/// A handle to some connection internals, use with care.
1388///
1389/// This contains a weak reference to the connection so will not itself keep the connection
1390/// alive.
1391#[derive(Debug, Clone)]
1392pub struct WeakConnectionHandle(Weak<Arc<ConnectionInner>>);
1393
1394impl WeakConnectionHandle {
1395    /// Returns `true` if the [`Connection`] associated with this handle is still alive.
1396    pub fn is_alive(&self) -> bool {
1397        self.0.upgrade().is_some()
1398    }
1399
1400    /// Upgrade the handle to a full `Connection`
1401    pub fn upgrade(&self) -> Option<Connection> {
1402        self.upgrade_to_ref().map(Connection)
1403    }
1404
1405    pub(crate) fn upgrade_to_ref(&self) -> Option<ConnectionRef> {
1406        self.0.upgrade().map(ConnectionRef::from_arc)
1407    }
1408
1409    /// Returns `true` if the two [`WeakConnectionHandle`] point at the same connection.
1410    pub fn is_same_connection(&self, other: &Self) -> bool {
1411        self.0.ptr_eq(&other.0)
1412    }
1413}
1414
1415#[derive(Debug, Default)]
1416pub(crate) struct Shared {
1417    handshake_confirmed: Notify,
1418    /// Notified when new streams may be locally initiated due to an increase in stream ID flow
1419    /// control budget
1420    stream_budget_available: [Notify; 2],
1421    /// Notified when the peer has initiated a new stream
1422    stream_incoming: [Notify; 2],
1423    datagram_received: Notify,
1424    datagrams_unblocked: Notify,
1425    closed: Notify,
1426    connected: Notify,
1427    /// Number of live handles that can be used to initiate or handle I/O; excludes the driver
1428    ref_count: AtomicUsize,
1429}
1430
1431pub(crate) struct State {
1432    pub(crate) inner: proto::Connection,
1433    driver: Option<Waker>,
1434    handle: ConnectionHandle,
1435    on_handshake_data: Option<oneshot::Sender<()>>,
1436    on_connected: Option<oneshot::Sender<bool>>,
1437    connected: bool,
1438    handshake_confirmed: bool,
1439    timer: Option<Pin<Box<dyn AsyncTimer>>>,
1440    timer_deadline: Option<Instant>,
1441    conn_events: mpsc::UnboundedReceiver<ConnectionEvent>,
1442    endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>,
1443    pub(crate) blocked_writers: FxHashMap<StreamId, Waker>,
1444    pub(crate) blocked_readers: FxHashMap<StreamId, Waker>,
1445    pub(crate) stopped: FxHashMap<StreamId, Arc<Notify>>,
1446    /// Always set to Some before the connection becomes drained
1447    pub(crate) error: Option<ConnectionError>,
1448    /// Tracks paths being opened
1449    open_path: FxHashMap<PathId, watch::Sender<Result<(), PathError>>>,
1450    /// Tracks reference counts for paths.
1451    ///
1452    /// I.e. how many [`Path`] and [`WeakPathHandle`] structs are alive for a path.
1453    /// Each entry's [`PathRefOwner`] holds an [`AtomicUsize`] so that cloning or
1454    /// dropping a [`PathRef`] (held by [`Path`] or [`WeakPathHandle`]) does not need
1455    /// to lock this state.
1456    ///
1457    /// [`WeakPathHandle`]: crate::path::WeakPathHandle
1458    pub(crate) path_refs: FxHashMap<PathId, PathRefOwner>,
1459    /// Final path stats for discarded paths.
1460    ///
1461    /// We only insert entries if the discarded path has a non-zero reference count in [`Self::path_refs`].
1462    /// When the last reference to a path is dropped its entry is removed from both maps.
1463    pub(crate) final_path_stats: FxHashMap<PathId, PathStats>,
1464    pub(crate) path_events: tokio::sync::broadcast::Sender<PathEvent>,
1465    sender: Pin<Box<dyn UdpSender>>,
1466    pub(crate) runtime: Arc<dyn Runtime>,
1467    send_buffer: Vec<u8>,
1468    /// We buffer a transmit when the underlying I/O would block
1469    buffered_transmit: Option<proto::Transmit>,
1470    /// Our last external address reported by the peer. When multipath is enabled, this will be the
1471    /// last report across all paths.
1472    pub(crate) observed_external_addr: watch::Sender<Option<SocketAddr>>,
1473    pub(crate) nat_traversal_updates: tokio::sync::broadcast::Sender<n0_nat_traversal::Event>,
1474    on_closed: Vec<oneshot::Sender<Closed>>,
1475}
1476
1477impl State {
1478    #[allow(clippy::too_many_arguments)]
1479    fn new(
1480        inner: proto::Connection,
1481        handle: ConnectionHandle,
1482        endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>,
1483        conn_events: mpsc::UnboundedReceiver<ConnectionEvent>,
1484        on_handshake_data: oneshot::Sender<()>,
1485        on_connected: oneshot::Sender<bool>,
1486        sender: Pin<Box<dyn UdpSender>>,
1487        runtime: Arc<dyn Runtime>,
1488    ) -> Self {
1489        Self {
1490            inner,
1491            driver: None,
1492            handle,
1493            on_handshake_data: Some(on_handshake_data),
1494            on_connected: Some(on_connected),
1495            connected: false,
1496            handshake_confirmed: false,
1497            timer: None,
1498            timer_deadline: None,
1499            conn_events,
1500            endpoint_events,
1501            blocked_writers: FxHashMap::default(),
1502            blocked_readers: FxHashMap::default(),
1503            stopped: FxHashMap::default(),
1504            open_path: FxHashMap::default(),
1505            error: None,
1506            sender,
1507            runtime,
1508            send_buffer: Vec::new(),
1509            buffered_transmit: None,
1510            path_events: tokio::sync::broadcast::channel(32).0,
1511            observed_external_addr: watch::Sender::new(None),
1512            nat_traversal_updates: tokio::sync::broadcast::channel(32).0,
1513            on_closed: Vec::new(),
1514            final_path_stats: Default::default(),
1515            path_refs: Default::default(),
1516        }
1517    }
1518
1519    fn drive_transmit(&mut self, cx: &mut Context<'_>) -> io::Result<bool> {
1520        let now = self.runtime.now();
1521        let mut transmits = 0;
1522
1523        let max_datagrams = self
1524            .sender
1525            .max_transmit_segments()
1526            .min(MAX_TRANSMIT_SEGMENTS);
1527
1528        loop {
1529            // Retry the last transmit, or get a new one.
1530            let t = match self.buffered_transmit.take() {
1531                Some(t) => t,
1532                None => {
1533                    self.send_buffer.clear();
1534                    match self
1535                        .inner
1536                        .poll_transmit(now, max_datagrams, &mut self.send_buffer)
1537                    {
1538                        Some(t) => {
1539                            transmits += match t.segment_size {
1540                                None => 1,
1541                                Some(s) => t.size.div_ceil(s), // round up
1542                            };
1543                            t
1544                        }
1545                        None => break,
1546                    }
1547                }
1548            };
1549
1550            let len = t.size;
1551            match self
1552                .sender
1553                .as_mut()
1554                .poll_send(&udp_transmit(&t, &self.send_buffer[..len]), cx)
1555            {
1556                Poll::Pending => {
1557                    self.buffered_transmit = Some(t);
1558                    return Ok(false);
1559                }
1560                Poll::Ready(Err(e)) => return Err(e),
1561                Poll::Ready(Ok(())) => {}
1562            }
1563
1564            if transmits >= MAX_TRANSMIT_DATAGRAMS {
1565                // TODO: What isn't ideal here yet is that if we don't poll all
1566                // datagrams that could be sent we don't go into the `app_limited`
1567                // state and CWND continues to grow until we get here the next time.
1568                // See https://github.com/quinn-rs/quinn/issues/1126
1569                return Ok(true);
1570            }
1571        }
1572
1573        Ok(false)
1574    }
1575
1576    fn forward_endpoint_events(&mut self) {
1577        while let Some(event) = self.inner.poll_endpoint_events() {
1578            // If the endpoint driver is gone, noop.
1579            let _ = self.endpoint_events.send((self.handle, event));
1580        }
1581    }
1582
1583    /// If this returns `Err`, the endpoint is dead, so the driver should exit immediately.
1584    fn process_conn_events(
1585        &mut self,
1586        shared: &Shared,
1587        cx: &mut Context<'_>,
1588    ) -> Result<(), ConnectionError> {
1589        loop {
1590            match self.conn_events.poll_recv(cx) {
1591                Poll::Ready(Some(ConnectionEvent::Rebind(sender))) => {
1592                    self.sender = sender;
1593                    self.inner.handle_network_change(None, self.runtime.now());
1594                }
1595                Poll::Ready(Some(ConnectionEvent::LocalAddressChanged(hint))) => {
1596                    self.inner
1597                        .handle_network_change(hint.as_deref().map(|x| x as _), self.runtime.now());
1598                }
1599                Poll::Ready(Some(ConnectionEvent::Proto(event))) => {
1600                    self.inner.handle_event(event);
1601                }
1602                Poll::Ready(Some(ConnectionEvent::Close { reason, error_code })) => {
1603                    self.close(error_code, reason, shared);
1604                }
1605                Poll::Ready(None) => {
1606                    return Err(ConnectionError::TransportError(TransportError::new(
1607                        TransportErrorCode::INTERNAL_ERROR,
1608                        "endpoint driver future was dropped".to_string(),
1609                    )));
1610                }
1611                Poll::Pending => {
1612                    return Ok(());
1613                }
1614            }
1615        }
1616    }
1617
1618    fn forward_app_events(&mut self, shared: &Shared) {
1619        while let Some(event) = self.inner.poll() {
1620            use proto::Event::*;
1621            match event {
1622                HandshakeDataReady => {
1623                    if let Some(x) = self.on_handshake_data.take() {
1624                        let _ = x.send(());
1625                    }
1626                }
1627                Connected => {
1628                    self.connected = true;
1629                    shared.connected.notify_waiters();
1630                    if let Some(x) = self.on_connected.take() {
1631                        // We don't care if the on-connected future was dropped
1632                        let _ = x.send(self.inner.accepted_0rtt());
1633                    }
1634                    if self.inner.side().is_client() && !self.inner.accepted_0rtt() {
1635                        // Wake up rejected 0-RTT streams so they can fail immediately with
1636                        // `ZeroRttRejected` errors.
1637                        wake_all(&mut self.blocked_writers);
1638                        wake_all(&mut self.blocked_readers);
1639                        wake_all_notify(&mut self.stopped);
1640                    }
1641                }
1642                HandshakeConfirmed => {
1643                    self.handshake_confirmed = true;
1644                    shared.handshake_confirmed.notify_waiters();
1645                }
1646                ConnectionLost { reason } => {
1647                    self.terminate(reason, shared);
1648                }
1649                Stream(StreamEvent::Writable { id }) => wake_stream(id, &mut self.blocked_writers),
1650                Stream(StreamEvent::Opened { dir: Dir::Uni }) => {
1651                    shared.stream_incoming[Dir::Uni as usize].notify_waiters();
1652                }
1653                Stream(StreamEvent::Opened { dir: Dir::Bi }) => {
1654                    shared.stream_incoming[Dir::Bi as usize].notify_waiters();
1655                }
1656                DatagramReceived => {
1657                    shared.datagram_received.notify_waiters();
1658                }
1659                DatagramsUnblocked => {
1660                    shared.datagrams_unblocked.notify_waiters();
1661                }
1662                Stream(StreamEvent::Readable { id }) => wake_stream(id, &mut self.blocked_readers),
1663                Stream(StreamEvent::Available { dir }) => {
1664                    // Might mean any number of streams are ready, so we wake up everyone
1665                    shared.stream_budget_available[dir as usize].notify_waiters();
1666                }
1667                Stream(StreamEvent::Finished { id }) => wake_stream_notify(id, &mut self.stopped),
1668                Stream(StreamEvent::Stopped { id, .. }) => {
1669                    wake_stream_notify(id, &mut self.stopped);
1670                    wake_stream(id, &mut self.blocked_writers);
1671                }
1672                Path(ref evt @ PathEvent::ObservedAddr { addr: observed, .. }) => {
1673                    self.path_events.send(evt.clone()).ok();
1674                    self.observed_external_addr.send_if_modified(|addr| {
1675                        let old = addr.replace(observed);
1676                        old != *addr
1677                    });
1678                }
1679                Path(ref evt @ PathEvent::Established { id, .. }) => {
1680                    self.path_events.send(evt.clone()).ok();
1681                    if let Some(sender) = self.open_path.remove(&id) {
1682                        sender.send_modify(|value| *value = Ok(()));
1683                    }
1684                }
1685                Path(
1686                    ref evt @ PathEvent::Discarded {
1687                        id, ref path_stats, ..
1688                    },
1689                ) => {
1690                    if self.path_refs.contains_key(&id) {
1691                        self.final_path_stats.insert(id, *path_stats.clone());
1692                    }
1693                    self.path_events.send(evt.clone()).ok();
1694                }
1695                Path(ref evt @ PathEvent::Abandoned { id, .. }) => {
1696                    if let Some(sender) = self.open_path.remove(&id) {
1697                        // We don't care for the reason why this path was closed here, because semantically
1698                        // all close reasons for a path that has not yet been opened equals to `ValidationFailed`.
1699                        // With the noq API, there is no way to application-close a not-yet-opened path, so
1700                        // `ApplicationClosed` cannot occur. And all other variants will only occur for paths
1701                        // that have already been opened.
1702                        // The previous iteration of this code had another event `PathEvent::LocallyClosed` which
1703                        // contained a `PathError`, but that was only ever set to `ValidationFailed`.
1704                        let error = PathError::ValidationFailed;
1705                        sender.send_modify(|value| *value = Err(error));
1706                    }
1707                    // this will happen also for already opened paths
1708                    self.path_events.send(evt.clone()).ok();
1709                }
1710                Path(evt @ PathEvent::RemoteStatus { .. }) => {
1711                    self.path_events.send(evt).ok();
1712                }
1713                NatTraversal(update) => {
1714                    self.nat_traversal_updates.send(update).ok();
1715                }
1716                _ => {
1717                    // PathEvent is #[non_exhaustive].
1718                    // It's possible that noq is built against a newer noq-proto version.
1719                    // In that case, we need to ignore path events we can't handle yet.
1720                    // But for tests, we expect noq and noq-proto to be in sync, so we
1721                    // should panic in case we don't actually handle new cases.
1722                    #[cfg(test)]
1723                    panic!("Unhandled PathEvent variant: {event:?}");
1724                }
1725            }
1726        }
1727    }
1728
1729    fn drive_timer(&mut self, cx: &mut Context<'_>) -> bool {
1730        let Some(deadline) = self.inner.poll_timeout() else {
1731            self.timer_deadline = None;
1732            return false;
1733        };
1734
1735        // Use the clock rather than the async timer to detect expiry: Sleep::poll
1736        // respects Tokio's cooperative budget and can return Pending for elapsed
1737        // deadlines.
1738        let now = self.runtime.now();
1739        if now >= deadline {
1740            self.inner.handle_timeout(now);
1741            self.timer_deadline = None;
1742            return true;
1743        }
1744
1745        match &mut self.timer {
1746            // Avoid resetting the timer when the deadline is unchanged.
1747            Some(delay) if self.timer_deadline != Some(deadline) => {
1748                delay.as_mut().reset(deadline);
1749            }
1750            None => {
1751                self.timer = Some(self.runtime.new_timer(deadline));
1752            }
1753            _ => {}
1754        }
1755        self.timer_deadline = Some(deadline);
1756
1757        let delay = self
1758            .timer
1759            .as_mut()
1760            .expect("timer must exist in this state")
1761            .as_mut();
1762        if delay.poll(cx).is_pending() {
1763            return false;
1764        }
1765
1766        // The deadline elapsed in the window between the clock check and poll.
1767        self.inner.handle_timeout(self.runtime.now());
1768        self.timer_deadline = None;
1769        true
1770    }
1771
1772    /// Wake up a blocked `Driver` task to process I/O
1773    pub(crate) fn wake(&mut self) {
1774        if let Some(x) = self.driver.take() {
1775            x.wake();
1776        }
1777    }
1778
1779    /// Used to wake up all blocked futures when the connection becomes closed for any reason
1780    fn terminate(&mut self, reason: ConnectionError, shared: &Shared) {
1781        self.error = Some(reason.clone());
1782        if let Some(x) = self.on_handshake_data.take() {
1783            let _ = x.send(());
1784        }
1785        wake_all(&mut self.blocked_writers);
1786        wake_all(&mut self.blocked_readers);
1787        shared.stream_budget_available[Dir::Uni as usize].notify_waiters();
1788        shared.stream_budget_available[Dir::Bi as usize].notify_waiters();
1789        shared.stream_incoming[Dir::Uni as usize].notify_waiters();
1790        shared.stream_incoming[Dir::Bi as usize].notify_waiters();
1791        shared.datagram_received.notify_waiters();
1792        shared.datagrams_unblocked.notify_waiters();
1793        if let Some(x) = self.on_connected.take() {
1794            let _ = x.send(false);
1795        }
1796        shared.handshake_confirmed.notify_waiters();
1797        wake_all_notify(&mut self.stopped);
1798        shared.closed.notify_waiters();
1799        // Send to the registered on_closed futures.
1800        if !self.on_closed.is_empty() {
1801            let closed = Closed::new(self, reason);
1802            for tx in self.on_closed.drain(..) {
1803                tx.send(closed.clone()).ok();
1804            }
1805        }
1806        shared.connected.notify_waiters();
1807    }
1808
1809    fn close(&mut self, error_code: VarInt, reason: Bytes, shared: &Shared) {
1810        self.inner.close(self.runtime.now(), error_code, reason);
1811        self.terminate(ConnectionError::LocallyClosed, shared);
1812        self.wake();
1813    }
1814
1815    /// Close for a reason other than the application's explicit request
1816    pub(crate) fn implicit_close(&mut self, shared: &Shared) {
1817        self.close(0u32.into(), Bytes::new(), shared);
1818    }
1819
1820    pub(crate) fn check_0rtt(&self) -> Result<(), ()> {
1821        if self.inner.is_handshaking()
1822            || self.inner.accepted_0rtt()
1823            || self.inner.side().is_server()
1824        {
1825            Ok(())
1826        } else {
1827            Err(())
1828        }
1829    }
1830
1831    /// Returns [`PathStats`] for a path, if available.
1832    ///
1833    /// This gets the stats from [`proto::Connection`]. If that returns `None`
1834    /// it gets them from `Self::final_path_stats` instead.
1835    pub(crate) fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> {
1836        self.inner
1837            .path_stats(path_id)
1838            .or_else(|| self.final_path_stats.get(&path_id).copied())
1839    }
1840
1841    /// Acquire a new [`PathRef`] for a path id, bumping its reference counter by 1.
1842    ///
1843    /// The returned [`PathRef`] is intended to be stored on a [`Path`] or [`WeakPathHandle`].
1844    /// Its reference count is automatically increased when cloned. When its owner is dropped,
1845    /// [`PathRef::on_drop`] must be called to decrement the refcount.
1846    ///
1847    /// [`WeakPathHandle`]: crate::path::WeakPathHandle
1848    pub(crate) fn acquire_path_ref(&mut self, path_id: PathId) -> PathRef {
1849        self.path_refs.entry(path_id).or_default().acquire(path_id)
1850    }
1851}
1852
1853impl Drop for State {
1854    fn drop(&mut self) {
1855        if !self.inner.is_drained() {
1856            // Ensure the endpoint can tidy up
1857            let _ = self
1858                .endpoint_events
1859                .send((self.handle, EndpointEvent::drained()));
1860        }
1861
1862        if !self.on_closed.is_empty()
1863            && let Some(reason) = self.error.clone()
1864        {
1865            // Ensure that all on_closed oneshot senders are triggered before dropping.
1866            let closed = Closed::new(self, reason);
1867            for tx in self.on_closed.drain(..) {
1868                tx.send(closed.clone()).ok();
1869            }
1870        }
1871    }
1872}
1873
1874impl fmt::Debug for State {
1875    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1876        f.debug_struct("State").field("inner", &self.inner).finish()
1877    }
1878}
1879
1880fn wake_stream(stream_id: StreamId, wakers: &mut FxHashMap<StreamId, Waker>) {
1881    if let Some(waker) = wakers.remove(&stream_id) {
1882        waker.wake();
1883    }
1884}
1885
1886fn wake_all(wakers: &mut FxHashMap<StreamId, Waker>) {
1887    wakers.drain().for_each(|(_, waker)| waker.wake())
1888}
1889
1890fn wake_stream_notify(stream_id: StreamId, wakers: &mut FxHashMap<StreamId, Arc<Notify>>) {
1891    if let Some(notify) = wakers.remove(&stream_id) {
1892        notify.notify_waiters()
1893    }
1894}
1895
1896fn wake_all_notify(wakers: &mut FxHashMap<StreamId, Arc<Notify>>) {
1897    wakers
1898        .drain()
1899        .for_each(|(_, notify)| notify.notify_waiters())
1900}
1901
1902/// Errors that can arise when sending a datagram
1903#[derive(Debug, Error, Clone, Eq, PartialEq)]
1904pub enum SendDatagramError {
1905    /// The peer does not support receiving datagram frames
1906    #[error("datagrams not supported by peer")]
1907    UnsupportedByPeer,
1908    /// Datagram support is disabled locally
1909    #[error("datagram support disabled")]
1910    Disabled,
1911    /// The datagram is larger than the connection can currently accommodate
1912    ///
1913    /// Indicates that the path MTU minus overhead or the limit advertised by the peer has been
1914    /// exceeded.
1915    #[error("datagram too large")]
1916    TooLarge,
1917    /// The connection was lost
1918    #[error("connection lost")]
1919    ConnectionLost(#[from] ConnectionError),
1920}
1921
1922/// The maximum amount of datagrams which will be produced in a single `drive_transmit` call
1923///
1924/// This limits the amount of CPU resources consumed by datagram generation,
1925/// and allows other tasks (like receiving ACKs) to run in between.
1926const MAX_TRANSMIT_DATAGRAMS: usize = 20;
1927
1928/// The maximum amount of datagrams that are sent in a single transmit
1929///
1930/// This can be lower than the maximum platform capabilities, to avoid excessive
1931/// memory allocations when calling `poll_transmit()`. Benchmarks have shown
1932/// that numbers around 10 are a good compromise.
1933const MAX_TRANSMIT_SEGMENTS: NonZeroUsize = NonZeroUsize::new(10).expect("known");