Skip to main content

quinn/
connection.rs

1use std::{
2    any::Any,
3    fmt,
4    future::Future,
5    io,
6    net::{IpAddr, SocketAddr},
7    pin::Pin,
8    sync::{
9        Arc,
10        atomic::{AtomicUsize, Ordering},
11    },
12    task::{Context, Poll, Waker, ready},
13};
14
15use bytes::Bytes;
16use pin_project_lite::pin_project;
17use rustc_hash::FxHashMap;
18use thiserror::Error;
19use tokio::sync::{Notify, futures::Notified, mpsc, oneshot};
20use tracing::{Instrument, Span, debug_span};
21
22use crate::{
23    ConnectionEvent, Duration, Instant, VarInt,
24    mutex::Mutex,
25    recv_stream::RecvStream,
26    runtime::{AsyncTimer, AsyncUdpSocket, Runtime, UdpPoller},
27    send_stream::SendStream,
28    udp_transmit,
29};
30use proto::{
31    ConnectionError, ConnectionHandle, ConnectionStats, Dir, EndpointEvent, Side, StreamEvent,
32    StreamId, congestion::Controller,
33};
34
35/// In-progress connection attempt future
36#[derive(Debug)]
37pub struct Connecting {
38    conn: Option<ConnectionRef>,
39    connected: oneshot::Receiver<bool>,
40    handshake_data_ready: Option<oneshot::Receiver<()>>,
41}
42
43impl Connecting {
44    pub(crate) fn new(
45        handle: ConnectionHandle,
46        conn: proto::Connection,
47        endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>,
48        conn_events: mpsc::UnboundedReceiver<ConnectionEvent>,
49        socket: Arc<dyn AsyncUdpSocket>,
50        runtime: Arc<dyn Runtime>,
51    ) -> Self {
52        let (on_handshake_data_send, on_handshake_data_recv) = oneshot::channel();
53        let (on_connected_send, on_connected_recv) = oneshot::channel();
54        let conn = ConnectionRef::new(
55            handle,
56            conn,
57            endpoint_events,
58            conn_events,
59            on_handshake_data_send,
60            on_connected_send,
61            socket,
62            runtime.clone(),
63        );
64
65        let driver = ConnectionDriver(conn.clone());
66        runtime.spawn(Box::pin(
67            async {
68                if let Err(e) = driver.await {
69                    tracing::error!("I/O error: {e}");
70                }
71            }
72            .instrument(Span::current()),
73        ));
74
75        Self {
76            conn: Some(conn),
77            connected: on_connected_recv,
78            handshake_data_ready: Some(on_handshake_data_recv),
79        }
80    }
81
82    /// Convert into a 0-RTT or 0.5-RTT connection at the cost of weakened security
83    ///
84    /// Returns `Ok` immediately if the local endpoint is able to attempt sending 0/0.5-RTT data.
85    /// If so, the returned [`Connection`] can be used to send application data without waiting for
86    /// the rest of the handshake to complete, at the cost of weakened cryptographic security
87    /// guarantees. The returned [`ZeroRttAccepted`] future resolves when the handshake does
88    /// complete, at which point subsequently opened streams and written data will have full
89    /// cryptographic protection.
90    ///
91    /// ## Outgoing
92    ///
93    /// For outgoing connections, the initial attempt to convert to a [`Connection`] which sends
94    /// 0-RTT data will proceed if the [`crypto::ClientConfig`][crate::crypto::ClientConfig]
95    /// attempts to resume a previous TLS session. However, **the remote endpoint may not actually
96    /// _accept_ the 0-RTT data**--yet still accept the connection attempt in general. This
97    /// possibility is conveyed through the [`ZeroRttAccepted`] future--when the handshake
98    /// completes, it resolves to true if the 0-RTT data was accepted and false if it was rejected.
99    /// If it was rejected, the existence of streams opened and other application data sent prior
100    /// to the handshake completing will not be conveyed to the remote application, and local
101    /// operations on them will return `ZeroRttRejected` errors.
102    ///
103    /// A server may reject 0-RTT data at its discretion, but accepting 0-RTT data requires the
104    /// relevant resumption state to be stored in the server, which servers may limit or lose for
105    /// various reasons including not persisting resumption state across server restarts.
106    ///
107    /// If manually providing a [`crypto::ClientConfig`][crate::crypto::ClientConfig], check your
108    /// implementation's docs for 0-RTT pitfalls.
109    ///
110    /// ## Incoming
111    ///
112    /// For incoming connections, conversion to 0.5-RTT will always fully succeed. `into_0rtt` will
113    /// always return `Ok` and the [`ZeroRttAccepted`] will always resolve to true.
114    ///
115    /// If manually providing a [`crypto::ServerConfig`][crate::crypto::ServerConfig], check your
116    /// implementation's docs for 0-RTT pitfalls.
117    ///
118    /// ## Security
119    ///
120    /// On outgoing connections, this enables transmission of 0-RTT data, which is vulnerable to
121    /// replay attacks, and should therefore never invoke non-idempotent operations.
122    ///
123    /// On incoming connections, this enables transmission of 0.5-RTT data, which may be sent
124    /// before TLS client authentication has occurred, and should therefore not be used to send
125    /// data for which client authentication is being used.
126    pub fn into_0rtt(mut self) -> Result<(Connection, ZeroRttAccepted), Self> {
127        // This lock borrows `self` and would normally be dropped at the end of this scope, so we'll
128        // have to release it explicitly before returning `self` by value.
129        let conn = (self.conn.as_mut().unwrap()).state.lock("into_0rtt");
130
131        let is_ok = conn.inner.has_0rtt() || conn.inner.side().is_server();
132        drop(conn);
133
134        if is_ok {
135            let conn = self.conn.take().unwrap();
136            Ok((Connection(conn), ZeroRttAccepted(self.connected)))
137        } else {
138            Err(self)
139        }
140    }
141
142    /// Parameters negotiated during the handshake
143    ///
144    /// The dynamic type returned is determined by the configured
145    /// [`Session`](proto::crypto::Session). For the default `rustls` session, the return value can
146    /// be [`downcast`](Box::downcast) to a
147    /// [`crypto::rustls::HandshakeData`](crate::crypto::rustls::HandshakeData).
148    pub async fn handshake_data(&mut self) -> Result<Box<dyn Any>, ConnectionError> {
149        // Taking &mut self allows us to use a single oneshot channel rather than dealing with
150        // potentially many tasks waiting on the same event. It's a bit of a hack, but keeps things
151        // simple.
152        if let Some(x) = self.handshake_data_ready.take() {
153            let _ = x.await;
154        }
155        let conn = self.conn.as_ref().unwrap();
156        let inner = conn.state.lock("handshake");
157        inner
158            .inner
159            .crypto_session()
160            .handshake_data()
161            .ok_or_else(|| {
162                inner
163                    .error
164                    .clone()
165                    .expect("spurious handshake data ready notification")
166            })
167    }
168
169    /// The local IP address which was used when the peer established
170    /// the connection
171    ///
172    /// This can be different from the address the endpoint is bound to, in case
173    /// the endpoint is bound to a wildcard address like `0.0.0.0` or `::`.
174    ///
175    /// This will return `None` for clients, or when the platform does not expose this
176    /// information. See [`quinn_udp::RecvMeta::dst_ip`](udp::RecvMeta::dst_ip) for a list of
177    /// supported platforms when using [`quinn_udp`](udp) for I/O, which is the default.
178    ///
179    /// Will panic if called after `poll` has returned `Ready`.
180    pub fn local_ip(&self) -> Option<IpAddr> {
181        let conn = self.conn.as_ref().unwrap();
182        let inner = conn.state.lock("local_ip");
183
184        inner.inner.local_ip()
185    }
186
187    /// The peer's UDP address
188    ///
189    /// Will panic if called after `poll` has returned `Ready`.
190    pub fn remote_address(&self) -> SocketAddr {
191        let conn_ref: &ConnectionRef = self.conn.as_ref().expect("used after yielding Ready");
192        conn_ref.state.lock("remote_address").inner.remote_address()
193    }
194}
195
196impl Future for Connecting {
197    type Output = Result<Connection, ConnectionError>;
198    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
199        Pin::new(&mut self.connected).poll(cx).map(|_| {
200            let conn = self.conn.take().unwrap();
201            let inner = conn.state.lock("connecting");
202            if inner.connected {
203                drop(inner);
204                Ok(Connection(conn))
205            } else {
206                Err(inner
207                    .error
208                    .clone()
209                    .expect("connected signaled without connection success or error"))
210            }
211        })
212    }
213}
214
215/// Future that completes when a connection is fully established
216///
217/// For clients, the resulting value indicates if 0-RTT was accepted. For servers, the resulting
218/// value is meaningless.
219pub struct ZeroRttAccepted(oneshot::Receiver<bool>);
220
221impl Future for ZeroRttAccepted {
222    type Output = bool;
223    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
224        Pin::new(&mut self.0).poll(cx).map(|x| x.unwrap_or(false))
225    }
226}
227
228/// A future that drives protocol logic for a connection
229///
230/// This future handles the protocol logic for a single connection, routing events from the
231/// `Connection` API object to the `Endpoint` task and the related stream-related interfaces.
232/// It also keeps track of outstanding timeouts for the `Connection`.
233///
234/// If the connection encounters an error condition, this future will yield an error. It will
235/// terminate (yielding `Ok(())`) if the connection was closed without error. Unlike other
236/// connection-related futures, this waits for the draining period to complete to ensure that
237/// packets still in flight from the peer are handled gracefully.
238#[must_use = "connection drivers must be spawned for their connections to function"]
239#[derive(Debug)]
240struct ConnectionDriver(ConnectionRef);
241
242impl Future for ConnectionDriver {
243    type Output = Result<(), io::Error>;
244
245    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
246        let conn = &mut *self.0.state.lock("poll");
247
248        let span = debug_span!("drive", id = conn.handle.0);
249        let _guard = span.enter();
250
251        if let Err(e) = conn.process_conn_events(&self.0.shared, cx) {
252            conn.terminate(e, &self.0.shared);
253            return Poll::Ready(Ok(()));
254        }
255        let mut keep_going = conn.drive_transmit(cx)?;
256        // If a timer expires, there might be more to transmit. When we transmit something, we
257        // might need to reset a timer. Hence, we must loop until neither happens.
258        keep_going |= conn.drive_timer(cx);
259        conn.forward_endpoint_events();
260        conn.forward_app_events(&self.0.shared);
261
262        if !conn.inner.is_drained() {
263            if keep_going {
264                // If the connection hasn't processed all tasks, schedule it again
265                cx.waker().wake_by_ref();
266            } else {
267                conn.driver = Some(cx.waker().clone());
268            }
269            return Poll::Pending;
270        }
271        if conn.error.is_none() {
272            unreachable!("drained connections always have an error");
273        }
274        Poll::Ready(Ok(()))
275    }
276}
277
278/// A QUIC connection.
279///
280/// If all references to a connection (including every clone of the `Connection` handle, streams of
281/// incoming streams, and the various stream types) have been dropped, then the connection will be
282/// automatically closed with an `error_code` of 0 and an empty `reason`. You can also close the
283/// connection explicitly by calling [`Connection::close()`].
284///
285/// Closing the connection immediately abandons efforts to deliver data to the peer.  Upon
286/// receiving CONNECTION_CLOSE the peer *may* drop any stream data not yet delivered to the
287/// application. [`Connection::close()`] describes in more detail how to gracefully close a
288/// connection without losing application data.
289///
290/// May be cloned to obtain another handle to the same connection.
291///
292/// [`Connection::close()`]: Connection::close
293#[derive(Debug, Clone)]
294pub struct Connection(ConnectionRef);
295
296impl Connection {
297    /// Initiate a new outgoing unidirectional stream.
298    ///
299    /// Streams are cheap and instantaneous to open unless blocked by flow control. As a
300    /// consequence, the peer won't be notified that a stream has been opened until the stream is
301    /// actually used.
302    pub fn open_uni(&self) -> OpenUni<'_> {
303        OpenUni {
304            conn: &self.0,
305            notify: self.0.shared.stream_budget_available[Dir::Uni as usize].notified(),
306        }
307    }
308
309    /// Initiate a new outgoing bidirectional stream.
310    ///
311    /// Streams are cheap and instantaneous to open unless blocked by flow control. As a
312    /// consequence, the peer won't be notified that a stream has been opened until the stream is
313    /// actually used. Calling [`open_bi()`] then waiting on the [`RecvStream`] without writing
314    /// anything to [`SendStream`] will never succeed.
315    ///
316    /// [`open_bi()`]: crate::Connection::open_bi
317    /// [`SendStream`]: crate::SendStream
318    /// [`RecvStream`]: crate::RecvStream
319    pub fn open_bi(&self) -> OpenBi<'_> {
320        OpenBi {
321            conn: &self.0,
322            notify: self.0.shared.stream_budget_available[Dir::Bi as usize].notified(),
323        }
324    }
325
326    /// Accept the next incoming uni-directional stream
327    pub fn accept_uni(&self) -> AcceptUni<'_> {
328        AcceptUni {
329            conn: &self.0,
330            notify: self.0.shared.stream_incoming[Dir::Uni as usize].notified(),
331        }
332    }
333
334    /// Accept the next incoming bidirectional stream
335    ///
336    /// **Important Note**: The `Connection` that calls [`open_bi()`] must write to its [`SendStream`]
337    /// before the other `Connection` is able to `accept_bi()`. Calling [`open_bi()`] then
338    /// waiting on the [`RecvStream`] without writing anything to [`SendStream`] will never succeed.
339    ///
340    /// [`accept_bi()`]: crate::Connection::accept_bi
341    /// [`open_bi()`]: crate::Connection::open_bi
342    /// [`SendStream`]: crate::SendStream
343    /// [`RecvStream`]: crate::RecvStream
344    pub fn accept_bi(&self) -> AcceptBi<'_> {
345        AcceptBi {
346            conn: &self.0,
347            notify: self.0.shared.stream_incoming[Dir::Bi as usize].notified(),
348        }
349    }
350
351    /// Receive an application datagram
352    pub fn read_datagram(&self) -> ReadDatagram<'_> {
353        ReadDatagram {
354            conn: &self.0,
355            notify: self.0.shared.datagram_received.notified(),
356        }
357    }
358
359    /// Wait for the connection to be closed for any reason
360    ///
361    /// Despite the return type's name, closed connections are often not an error condition at the
362    /// application layer. Cases that might be routine include [`ConnectionError::LocallyClosed`]
363    /// and [`ConnectionError::ApplicationClosed`].
364    pub async fn closed(&self) -> ConnectionError {
365        {
366            let conn = self.0.state.lock("closed");
367            if let Some(error) = conn.error.as_ref() {
368                return error.clone();
369            }
370            // Construct the future while the lock is held to ensure we can't miss a wakeup if
371            // the `Notify` is signaled immediately after we release the lock. `await` it after
372            // the lock guard is out of scope.
373            self.0.shared.closed.notified()
374        }
375        .await;
376        self.0
377            .state
378            .lock("closed")
379            .error
380            .as_ref()
381            .expect("closed without an error")
382            .clone()
383    }
384
385    /// If the connection is closed, the reason why.
386    ///
387    /// Returns `None` if the connection is still open.
388    pub fn close_reason(&self) -> Option<ConnectionError> {
389        self.0.state.lock("close_reason").error.clone()
390    }
391
392    /// Close the connection immediately.
393    ///
394    /// Pending operations will fail immediately with [`ConnectionError::LocallyClosed`]. No
395    /// more data is sent to the peer and the peer may drop buffered data upon receiving
396    /// the CONNECTION_CLOSE frame.
397    ///
398    /// `error_code` and `reason` are not interpreted, and are provided directly to the peer.
399    ///
400    /// `reason` will be truncated to fit in a single packet with overhead; to improve odds that it
401    /// is preserved in full, it should be kept under 1KiB.
402    ///
403    /// # Gracefully closing a connection
404    ///
405    /// Only the peer last receiving application data can be certain that all data is
406    /// delivered. The only reliable action it can then take is to close the connection,
407    /// potentially with a custom error code. The delivery of the final CONNECTION_CLOSE
408    /// frame is very likely if both endpoints stay online long enough, and
409    /// [`Endpoint::wait_idle()`] can be used to provide sufficient time. Otherwise, the
410    /// remote peer will time out the connection, provided that the idle timeout is not
411    /// disabled.
412    ///
413    /// The sending side can not guarantee all stream data is delivered to the remote
414    /// application. It only knows the data is delivered to the QUIC stack of the remote
415    /// endpoint. Once the local side sends a CONNECTION_CLOSE frame in response to calling
416    /// [`close()`] the remote endpoint may drop any data it received but is as yet
417    /// undelivered to the application, including data that was acknowledged as received to
418    /// the local endpoint.
419    ///
420    /// [`ConnectionError::LocallyClosed`]: crate::ConnectionError::LocallyClosed
421    /// [`Endpoint::wait_idle()`]: crate::Endpoint::wait_idle
422    /// [`close()`]: Connection::close
423    pub fn close(&self, error_code: VarInt, reason: &[u8]) {
424        let conn = &mut *self.0.state.lock("close");
425        conn.close(error_code, Bytes::copy_from_slice(reason), &self.0.shared);
426    }
427
428    /// Transmit `data` as an unreliable, unordered application datagram
429    ///
430    /// Application datagrams are a low-level primitive. They may be lost or delivered out of order,
431    /// and `data` must both fit inside a single QUIC packet and be smaller than the maximum
432    /// dictated by the peer.
433    ///
434    /// Previously queued datagrams which are still unsent may be discarded to make space for this
435    /// datagram, in order of oldest to newest.
436    pub fn send_datagram(&self, data: Bytes) -> Result<(), SendDatagramError> {
437        let conn = &mut *self.0.state.lock("send_datagram");
438        if let Some(ref x) = conn.error {
439            return Err(SendDatagramError::ConnectionLost(x.clone()));
440        }
441        use proto::SendDatagramError::*;
442        match conn.inner.datagrams().send(data, true) {
443            Ok(()) => {
444                conn.wake();
445                Ok(())
446            }
447            Err(e) => Err(match e {
448                Blocked(..) => unreachable!(),
449                UnsupportedByPeer => SendDatagramError::UnsupportedByPeer,
450                Disabled => SendDatagramError::Disabled,
451                TooLarge => SendDatagramError::TooLarge,
452            }),
453        }
454    }
455
456    /// Transmit `data` as an unreliable, unordered application datagram
457    ///
458    /// Unlike [`send_datagram()`], this method will wait for buffer space during congestion
459    /// conditions, which effectively prioritizes old datagrams over new datagrams.
460    ///
461    /// See [`send_datagram()`] for details.
462    ///
463    /// [`send_datagram()`]: Connection::send_datagram
464    pub fn send_datagram_wait(&self, data: Bytes) -> SendDatagram<'_> {
465        SendDatagram {
466            conn: &self.0,
467            data: Some(data),
468            notify: self.0.shared.datagrams_unblocked.notified(),
469        }
470    }
471
472    /// Compute the maximum size of datagrams that may be passed to [`send_datagram()`].
473    ///
474    /// Returns `None` if datagrams are unsupported by the peer or disabled locally.
475    ///
476    /// This may change over the lifetime of a connection according to variation in the path MTU
477    /// estimate. The peer can also enforce an arbitrarily small fixed limit, but if the peer's
478    /// limit is large this is guaranteed to be a little over a kilobyte at minimum.
479    ///
480    /// Not necessarily the maximum size of received datagrams.
481    ///
482    /// [`send_datagram()`]: Connection::send_datagram
483    pub fn max_datagram_size(&self) -> Option<usize> {
484        self.0
485            .state
486            .lock("max_datagram_size")
487            .inner
488            .datagrams()
489            .max_size()
490    }
491
492    /// Bytes available in the outgoing datagram buffer
493    ///
494    /// When greater than zero, calling [`send_datagram()`](Self::send_datagram) with a datagram of
495    /// at most this size is guaranteed not to cause older datagrams to be dropped.
496    pub fn datagram_send_buffer_space(&self) -> usize {
497        self.0
498            .state
499            .lock("datagram_send_buffer_space")
500            .inner
501            .datagrams()
502            .send_buffer_space()
503    }
504
505    /// The side of the connection (client or server)
506    pub fn side(&self) -> Side {
507        self.0.state.lock("side").inner.side()
508    }
509
510    /// The peer's UDP address
511    ///
512    /// If `ServerConfig::migration` is `true`, clients may change addresses at will, e.g. when
513    /// switching to a cellular internet connection.
514    pub fn remote_address(&self) -> SocketAddr {
515        self.0.state.lock("remote_address").inner.remote_address()
516    }
517
518    /// The local IP address which was used when the peer established
519    /// the connection
520    ///
521    /// This can be different from the address the endpoint is bound to, in case
522    /// the endpoint is bound to a wildcard address like `0.0.0.0` or `::`.
523    ///
524    /// This will return `None` for clients, or when the platform does not expose this
525    /// information. See [`quinn_udp::RecvMeta::dst_ip`](udp::RecvMeta::dst_ip) for a list of
526    /// supported platforms when using [`quinn_udp`](udp) for I/O, which is the default.
527    pub fn local_ip(&self) -> Option<IpAddr> {
528        self.0.state.lock("local_ip").inner.local_ip()
529    }
530
531    /// Current best estimate of this connection's latency (round-trip-time)
532    pub fn rtt(&self) -> Duration {
533        self.0.state.lock("rtt").inner.rtt()
534    }
535
536    /// Returns connection statistics
537    pub fn stats(&self) -> ConnectionStats {
538        self.0.state.lock("stats").inner.stats()
539    }
540
541    /// Current state of the congestion control algorithm, for debugging purposes
542    pub fn congestion_state(&self) -> Box<dyn Controller> {
543        self.0
544            .state
545            .lock("congestion_state")
546            .inner
547            .congestion_state()
548            .clone_box()
549    }
550
551    /// Parameters negotiated during the handshake
552    ///
553    /// Guaranteed to return `Some` on fully established connections or after
554    /// [`Connecting::handshake_data()`] succeeds. See that method's documentations for details on
555    /// the returned value.
556    ///
557    /// [`Connection::handshake_data()`]: crate::Connecting::handshake_data
558    pub fn handshake_data(&self) -> Option<Box<dyn Any>> {
559        self.0
560            .state
561            .lock("handshake_data")
562            .inner
563            .crypto_session()
564            .handshake_data()
565    }
566
567    /// Cryptographic identity of the peer
568    ///
569    /// The dynamic type returned is determined by the configured
570    /// [`Session`](proto::crypto::Session). For the default `rustls` session, the return value can
571    /// be [`downcast`](Box::downcast) to a <code>Vec<[rustls::pki_types::CertificateDer]></code>
572    pub fn peer_identity(&self) -> Option<Box<dyn Any>> {
573        self.0
574            .state
575            .lock("peer_identity")
576            .inner
577            .crypto_session()
578            .peer_identity()
579    }
580
581    /// A stable identifier for this connection
582    ///
583    /// Peer addresses and connection IDs can change, but this value will remain
584    /// fixed for the lifetime of the connection.
585    pub fn stable_id(&self) -> usize {
586        self.0.stable_id()
587    }
588
589    /// Update traffic keys spontaneously
590    ///
591    /// This primarily exists for testing purposes.
592    pub fn force_key_update(&self) {
593        self.0
594            .state
595            .lock("force_key_update")
596            .inner
597            .force_key_update()
598    }
599
600    /// Derive keying material from this connection's TLS session secrets.
601    ///
602    /// When both peers call this method with the same `label` and `context`
603    /// arguments and `output` buffers of equal length, they will get the
604    /// same sequence of bytes in `output`. These bytes are cryptographically
605    /// strong and pseudorandom, and are suitable for use as keying material.
606    ///
607    /// See [RFC5705](https://tools.ietf.org/html/rfc5705) for more information.
608    pub fn export_keying_material(
609        &self,
610        output: &mut [u8],
611        label: &[u8],
612        context: &[u8],
613    ) -> Result<(), proto::crypto::ExportKeyingMaterialError> {
614        self.0
615            .state
616            .lock("export_keying_material")
617            .inner
618            .crypto_session()
619            .export_keying_material(output, label, context)
620    }
621
622    /// Modify the number of remotely initiated unidirectional streams that may be concurrently open
623    ///
624    /// No streams may be opened by the peer unless fewer than `count` are already open. Large
625    /// `count`s increase both minimum and worst-case memory consumption.
626    pub fn set_max_concurrent_uni_streams(&self, count: VarInt) {
627        let mut conn = self.0.state.lock("set_max_concurrent_uni_streams");
628        conn.inner.set_max_concurrent_streams(Dir::Uni, count);
629        // May need to send MAX_STREAMS to make progress
630        conn.wake();
631    }
632
633    /// See [`proto::TransportConfig::send_window()`]
634    pub fn set_send_window(&self, send_window: u64) {
635        let mut conn = self.0.state.lock("set_send_window");
636        conn.inner.set_send_window(send_window);
637        conn.wake();
638    }
639
640    /// See [`proto::TransportConfig::receive_window()`]
641    pub fn set_receive_window(&self, receive_window: VarInt) {
642        let mut conn = self.0.state.lock("set_receive_window");
643        conn.inner.set_receive_window(receive_window);
644        conn.wake();
645    }
646
647    /// Modify the number of remotely initiated bidirectional streams that may be concurrently open
648    ///
649    /// No streams may be opened by the peer unless fewer than `count` are already open. Large
650    /// `count`s increase both minimum and worst-case memory consumption.
651    pub fn set_max_concurrent_bi_streams(&self, count: VarInt) {
652        let mut conn = self.0.state.lock("set_max_concurrent_bi_streams");
653        conn.inner.set_max_concurrent_streams(Dir::Bi, count);
654        // May need to send MAX_STREAMS to make progress
655        conn.wake();
656    }
657}
658
659pin_project! {
660    /// Future produced by [`Connection::open_uni`]
661    pub struct OpenUni<'a> {
662        conn: &'a ConnectionRef,
663        #[pin]
664        notify: Notified<'a>,
665    }
666}
667
668impl Future for OpenUni<'_> {
669    type Output = Result<SendStream, ConnectionError>;
670    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
671        let this = self.project();
672        let (conn, id, is_0rtt) = ready!(poll_open(ctx, this.conn, this.notify, Dir::Uni))?;
673        Poll::Ready(Ok(SendStream::new(conn, id, is_0rtt)))
674    }
675}
676
677pin_project! {
678    /// Future produced by [`Connection::open_bi`]
679    pub struct OpenBi<'a> {
680        conn: &'a ConnectionRef,
681        #[pin]
682        notify: Notified<'a>,
683    }
684}
685
686impl Future for OpenBi<'_> {
687    type Output = Result<(SendStream, RecvStream), ConnectionError>;
688    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
689        let this = self.project();
690        let (conn, id, is_0rtt) = ready!(poll_open(ctx, this.conn, this.notify, Dir::Bi))?;
691
692        Poll::Ready(Ok((
693            SendStream::new(conn.clone(), id, is_0rtt),
694            RecvStream::new(conn, id, is_0rtt),
695        )))
696    }
697}
698
699fn poll_open<'a>(
700    ctx: &mut Context<'_>,
701    conn: &'a ConnectionRef,
702    mut notify: Pin<&mut Notified<'a>>,
703    dir: Dir,
704) -> Poll<Result<(ConnectionRef, StreamId, bool), ConnectionError>> {
705    let mut state = conn.state.lock("poll_open");
706    if let Some(ref e) = state.error {
707        return Poll::Ready(Err(e.clone()));
708    } else if let Some(id) = state.inner.streams().open(dir) {
709        let is_0rtt = state.inner.side().is_client() && state.inner.is_handshaking();
710        drop(state); // Release the lock so clone can take it
711        return Poll::Ready(Ok((conn.clone(), id, is_0rtt)));
712    }
713    loop {
714        match notify.as_mut().poll(ctx) {
715            // `state` lock ensures we didn't race with readiness
716            Poll::Pending => return Poll::Pending,
717            // Spurious wakeup, get a new future
718            Poll::Ready(()) => {
719                notify.set(conn.shared.stream_budget_available[dir as usize].notified())
720            }
721        }
722    }
723}
724
725pin_project! {
726    /// Future produced by [`Connection::accept_uni`]
727    pub struct AcceptUni<'a> {
728        conn: &'a ConnectionRef,
729        #[pin]
730        notify: Notified<'a>,
731    }
732}
733
734impl Future for AcceptUni<'_> {
735    type Output = Result<RecvStream, ConnectionError>;
736
737    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
738        let this = self.project();
739        let (conn, id, is_0rtt) = ready!(poll_accept(ctx, this.conn, this.notify, Dir::Uni))?;
740        Poll::Ready(Ok(RecvStream::new(conn, id, is_0rtt)))
741    }
742}
743
744pin_project! {
745    /// Future produced by [`Connection::accept_bi`]
746    pub struct AcceptBi<'a> {
747        conn: &'a ConnectionRef,
748        #[pin]
749        notify: Notified<'a>,
750    }
751}
752
753impl Future for AcceptBi<'_> {
754    type Output = Result<(SendStream, RecvStream), ConnectionError>;
755
756    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
757        let this = self.project();
758        let (conn, id, is_0rtt) = ready!(poll_accept(ctx, this.conn, this.notify, Dir::Bi))?;
759        Poll::Ready(Ok((
760            SendStream::new(conn.clone(), id, is_0rtt),
761            RecvStream::new(conn, id, is_0rtt),
762        )))
763    }
764}
765
766fn poll_accept<'a>(
767    ctx: &mut Context<'_>,
768    conn: &'a ConnectionRef,
769    mut notify: Pin<&mut Notified<'a>>,
770    dir: Dir,
771) -> Poll<Result<(ConnectionRef, StreamId, bool), ConnectionError>> {
772    let mut state = conn.state.lock("poll_accept");
773    // Check for incoming streams before checking `state.error` so that already-received streams,
774    // which are necessarily finite, can be drained from a closed connection.
775    if let Some(id) = state.inner.streams().accept(dir) {
776        let is_0rtt = state.inner.is_handshaking();
777        state.wake(); // To send additional stream ID credit
778        drop(state); // Release the lock so clone can take it
779        return Poll::Ready(Ok((conn.clone(), id, is_0rtt)));
780    } else if let Some(ref e) = state.error {
781        return Poll::Ready(Err(e.clone()));
782    }
783    loop {
784        match notify.as_mut().poll(ctx) {
785            // `state` lock ensures we didn't race with readiness
786            Poll::Pending => return Poll::Pending,
787            // Spurious wakeup, get a new future
788            Poll::Ready(()) => notify.set(conn.shared.stream_incoming[dir as usize].notified()),
789        }
790    }
791}
792
793pin_project! {
794    /// Future produced by [`Connection::read_datagram`]
795    pub struct ReadDatagram<'a> {
796        conn: &'a ConnectionRef,
797        #[pin]
798        notify: Notified<'a>,
799    }
800}
801
802impl Future for ReadDatagram<'_> {
803    type Output = Result<Bytes, ConnectionError>;
804    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
805        let mut this = self.project();
806        let mut state = this.conn.state.lock("ReadDatagram::poll");
807        // Check for buffered datagrams before checking `state.error` so that already-received
808        // datagrams, which are necessarily finite, can be drained from a closed connection.
809        if let Some(x) = state.inner.datagrams().recv() {
810            return Poll::Ready(Ok(x));
811        } else if let Some(ref e) = state.error {
812            return Poll::Ready(Err(e.clone()));
813        }
814        loop {
815            match this.notify.as_mut().poll(ctx) {
816                // `state` lock ensures we didn't race with readiness
817                Poll::Pending => return Poll::Pending,
818                // Spurious wakeup, get a new future
819                Poll::Ready(()) => this
820                    .notify
821                    .set(this.conn.shared.datagram_received.notified()),
822            }
823        }
824    }
825}
826
827pin_project! {
828    /// Future produced by [`Connection::send_datagram_wait`]
829    pub struct SendDatagram<'a> {
830        conn: &'a ConnectionRef,
831        data: Option<Bytes>,
832        #[pin]
833        notify: Notified<'a>,
834    }
835}
836
837impl Future for SendDatagram<'_> {
838    type Output = Result<(), SendDatagramError>;
839    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
840        let mut this = self.project();
841        let mut state = this.conn.state.lock("SendDatagram::poll");
842        if let Some(ref e) = state.error {
843            return Poll::Ready(Err(SendDatagramError::ConnectionLost(e.clone())));
844        }
845        use proto::SendDatagramError::*;
846        match state
847            .inner
848            .datagrams()
849            .send(this.data.take().unwrap(), false)
850        {
851            Ok(()) => {
852                state.wake();
853                Poll::Ready(Ok(()))
854            }
855            Err(e) => Poll::Ready(Err(match e {
856                Blocked(data) => {
857                    this.data.replace(data);
858                    loop {
859                        match this.notify.as_mut().poll(ctx) {
860                            Poll::Pending => return Poll::Pending,
861                            // Spurious wakeup, get a new future
862                            Poll::Ready(()) => this
863                                .notify
864                                .set(this.conn.shared.datagrams_unblocked.notified()),
865                        }
866                    }
867                }
868                UnsupportedByPeer => SendDatagramError::UnsupportedByPeer,
869                Disabled => SendDatagramError::Disabled,
870                TooLarge => SendDatagramError::TooLarge,
871            })),
872        }
873    }
874}
875
876#[derive(Debug)]
877pub(crate) struct ConnectionRef(Arc<ConnectionInner>);
878
879impl ConnectionRef {
880    #[allow(clippy::too_many_arguments)]
881    fn new(
882        handle: ConnectionHandle,
883        conn: proto::Connection,
884        endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>,
885        conn_events: mpsc::UnboundedReceiver<ConnectionEvent>,
886        on_handshake_data: oneshot::Sender<()>,
887        on_connected: oneshot::Sender<bool>,
888        socket: Arc<dyn AsyncUdpSocket>,
889        runtime: Arc<dyn Runtime>,
890    ) -> Self {
891        Self(Arc::new(ConnectionInner {
892            state: Mutex::new(State {
893                inner: conn,
894                driver: None,
895                handle,
896                on_handshake_data: Some(on_handshake_data),
897                on_connected: Some(on_connected),
898                connected: false,
899                timer: None,
900                timer_deadline: None,
901                conn_events,
902                endpoint_events,
903                blocked_writers: FxHashMap::default(),
904                blocked_readers: FxHashMap::default(),
905                stopped: FxHashMap::default(),
906                error: None,
907                io_poller: socket.clone().create_io_poller(),
908                socket,
909                runtime,
910                send_buffer: Vec::new(),
911                buffered_transmit: None,
912            }),
913            shared: Shared::default(),
914        }))
915    }
916
917    fn stable_id(&self) -> usize {
918        &*self.0 as *const _ as usize
919    }
920}
921
922impl Clone for ConnectionRef {
923    fn clone(&self) -> Self {
924        self.shared.ref_count.fetch_add(1, Ordering::Relaxed);
925        Self(self.0.clone())
926    }
927}
928
929impl Drop for ConnectionRef {
930    fn drop(&mut self) {
931        if self.shared.ref_count.fetch_sub(1, Ordering::Relaxed) > 1 {
932            return;
933        }
934
935        let conn = &mut *self.state.lock("drop");
936
937        if !conn.inner.is_closed() {
938            // If the driver is alive, it's just it and us, so we'd better shut it down. If it's
939            // not, we can't do any harm. If there were any streams being opened, then either
940            // the connection will be closed for an unrelated reason or a fresh reference will
941            // be constructed for the newly opened stream.
942            conn.implicit_close(&self.shared);
943        }
944    }
945}
946
947impl std::ops::Deref for ConnectionRef {
948    type Target = ConnectionInner;
949    fn deref(&self) -> &Self::Target {
950        &self.0
951    }
952}
953
954#[derive(Debug)]
955pub(crate) struct ConnectionInner {
956    pub(crate) state: Mutex<State>,
957    pub(crate) shared: Shared,
958}
959
960#[derive(Debug, Default)]
961pub(crate) struct Shared {
962    /// Notified when new streams may be locally initiated due to an increase in stream ID flow
963    /// control budget
964    stream_budget_available: [Notify; 2],
965    /// Notified when the peer has initiated a new stream
966    stream_incoming: [Notify; 2],
967    datagram_received: Notify,
968    datagrams_unblocked: Notify,
969    closed: Notify,
970    /// Number of live handles that can used to initiate or handle I/O; excludes the driver
971    ref_count: AtomicUsize,
972}
973
974pub(crate) struct State {
975    pub(crate) inner: proto::Connection,
976    driver: Option<Waker>,
977    handle: ConnectionHandle,
978    on_handshake_data: Option<oneshot::Sender<()>>,
979    on_connected: Option<oneshot::Sender<bool>>,
980    connected: bool,
981    timer: Option<Pin<Box<dyn AsyncTimer>>>,
982    timer_deadline: Option<Instant>,
983    conn_events: mpsc::UnboundedReceiver<ConnectionEvent>,
984    endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>,
985    pub(crate) blocked_writers: FxHashMap<StreamId, Waker>,
986    pub(crate) blocked_readers: FxHashMap<StreamId, Waker>,
987    pub(crate) stopped: FxHashMap<StreamId, Arc<Notify>>,
988    /// Always set to Some before the connection becomes drained
989    pub(crate) error: Option<ConnectionError>,
990    socket: Arc<dyn AsyncUdpSocket>,
991    io_poller: Pin<Box<dyn UdpPoller>>,
992    runtime: Arc<dyn Runtime>,
993    send_buffer: Vec<u8>,
994    /// We buffer a transmit when the underlying I/O would block
995    buffered_transmit: Option<proto::Transmit>,
996}
997
998impl State {
999    fn drive_transmit(&mut self, cx: &mut Context) -> io::Result<bool> {
1000        let now = self.runtime.now();
1001        let mut transmits = 0;
1002
1003        let max_datagrams = self
1004            .socket
1005            .max_transmit_segments()
1006            .min(MAX_TRANSMIT_SEGMENTS);
1007
1008        loop {
1009            // Retry the last transmit, or get a new one.
1010            let t = match self.buffered_transmit.take() {
1011                Some(t) => t,
1012                None => {
1013                    self.send_buffer.clear();
1014                    self.send_buffer.reserve(self.inner.current_mtu() as usize);
1015                    match self
1016                        .inner
1017                        .poll_transmit(now, max_datagrams, &mut self.send_buffer)
1018                    {
1019                        Some(t) => {
1020                            transmits += match t.segment_size {
1021                                None => 1,
1022                                Some(s) => t.size.div_ceil(s), // round up
1023                            };
1024                            t
1025                        }
1026                        None => break,
1027                    }
1028                }
1029            };
1030
1031            if self.io_poller.as_mut().poll_writable(cx)?.is_pending() {
1032                // Retry after a future wakeup
1033                self.buffered_transmit = Some(t);
1034                return Ok(false);
1035            }
1036
1037            let len = t.size;
1038            let retry = match self
1039                .socket
1040                .try_send(&udp_transmit(&t, &self.send_buffer[..len]))
1041            {
1042                Ok(()) => false,
1043                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => true,
1044                Err(e) => return Err(e),
1045            };
1046            if retry {
1047                // We thought the socket was writable, but it wasn't. Retry so that either another
1048                // `poll_writable` call determines that the socket is indeed not writable and
1049                // registers us for a wakeup, or the send succeeds if this really was just a
1050                // transient failure.
1051                self.buffered_transmit = Some(t);
1052                continue;
1053            }
1054
1055            if transmits >= MAX_TRANSMIT_DATAGRAMS {
1056                // TODO: What isn't ideal here yet is that if we don't poll all
1057                // datagrams that could be sent we don't go into the `app_limited`
1058                // state and CWND continues to grow until we get here the next time.
1059                // See https://github.com/quinn-rs/quinn/issues/1126
1060                return Ok(true);
1061            }
1062        }
1063
1064        Ok(false)
1065    }
1066
1067    fn forward_endpoint_events(&mut self) {
1068        while let Some(event) = self.inner.poll_endpoint_events() {
1069            // If the endpoint driver is gone, noop.
1070            let _ = self.endpoint_events.send((self.handle, event));
1071        }
1072    }
1073
1074    /// If this returns `Err`, the endpoint is dead, so the driver should exit immediately.
1075    fn process_conn_events(
1076        &mut self,
1077        shared: &Shared,
1078        cx: &mut Context,
1079    ) -> Result<(), ConnectionError> {
1080        loop {
1081            match self.conn_events.poll_recv(cx) {
1082                Poll::Ready(Some(ConnectionEvent::Rebind(socket))) => {
1083                    self.socket = socket;
1084                    self.io_poller = self.socket.clone().create_io_poller();
1085                    self.inner.local_address_changed();
1086                }
1087                Poll::Ready(Some(ConnectionEvent::Proto(event))) => {
1088                    self.inner.handle_event(event);
1089                }
1090                Poll::Ready(Some(ConnectionEvent::Close { reason, error_code })) => {
1091                    self.close(error_code, reason, shared);
1092                }
1093                Poll::Ready(None) => {
1094                    return Err(ConnectionError::TransportError(proto::TransportError {
1095                        code: proto::TransportErrorCode::INTERNAL_ERROR,
1096                        frame: None,
1097                        reason: "endpoint driver future was dropped".to_string(),
1098                    }));
1099                }
1100                Poll::Pending => {
1101                    return Ok(());
1102                }
1103            }
1104        }
1105    }
1106
1107    fn forward_app_events(&mut self, shared: &Shared) {
1108        while let Some(event) = self.inner.poll() {
1109            use proto::Event::*;
1110            match event {
1111                HandshakeDataReady => {
1112                    if let Some(x) = self.on_handshake_data.take() {
1113                        let _ = x.send(());
1114                    }
1115                }
1116                Connected => {
1117                    self.connected = true;
1118                    if let Some(x) = self.on_connected.take() {
1119                        // We don't care if the on-connected future was dropped
1120                        let _ = x.send(self.inner.accepted_0rtt());
1121                    }
1122                    if self.inner.side().is_client() && !self.inner.accepted_0rtt() {
1123                        // Wake up rejected 0-RTT streams so they can fail immediately with
1124                        // `ZeroRttRejected` errors.
1125                        wake_all(&mut self.blocked_writers);
1126                        wake_all(&mut self.blocked_readers);
1127                        wake_all_notify(&mut self.stopped);
1128                    }
1129                }
1130                ConnectionLost { reason } => {
1131                    self.terminate(reason, shared);
1132                }
1133                Stream(StreamEvent::Writable { id }) => wake_stream(id, &mut self.blocked_writers),
1134                Stream(StreamEvent::Opened { dir: Dir::Uni }) => {
1135                    shared.stream_incoming[Dir::Uni as usize].notify_waiters();
1136                }
1137                Stream(StreamEvent::Opened { dir: Dir::Bi }) => {
1138                    shared.stream_incoming[Dir::Bi as usize].notify_waiters();
1139                }
1140                DatagramReceived => {
1141                    shared.datagram_received.notify_waiters();
1142                }
1143                DatagramsUnblocked => {
1144                    shared.datagrams_unblocked.notify_waiters();
1145                }
1146                Stream(StreamEvent::Readable { id }) => wake_stream(id, &mut self.blocked_readers),
1147                Stream(StreamEvent::Available { dir }) => {
1148                    // Might mean any number of streams are ready, so we wake up everyone
1149                    shared.stream_budget_available[dir as usize].notify_waiters();
1150                }
1151                Stream(StreamEvent::Finished { id }) => wake_stream_notify(id, &mut self.stopped),
1152                Stream(StreamEvent::Stopped { id, .. }) => {
1153                    wake_stream_notify(id, &mut self.stopped);
1154                    wake_stream(id, &mut self.blocked_writers);
1155                }
1156            }
1157        }
1158    }
1159
1160    fn drive_timer(&mut self, cx: &mut Context<'_>) -> bool {
1161        let Some(deadline) = self.inner.poll_timeout() else {
1162            self.timer_deadline = None;
1163            return false;
1164        };
1165
1166        // Use the clock rather than the async timer to detect expiry: Sleep::poll
1167        // respects Tokio's cooperative budget and can return Pending for elapsed
1168        // deadlines.
1169        let now = self.runtime.now();
1170        if now >= deadline {
1171            self.inner.handle_timeout(now);
1172            self.timer_deadline = None;
1173            return true;
1174        }
1175
1176        match &mut self.timer {
1177            // Avoid resetting the timer when the deadline is unchanged.
1178            Some(delay) if self.timer_deadline != Some(deadline) => {
1179                delay.as_mut().reset(deadline);
1180            }
1181            None => {
1182                self.timer = Some(self.runtime.new_timer(deadline));
1183            }
1184            _ => {}
1185        }
1186        self.timer_deadline = Some(deadline);
1187
1188        let delay = self
1189            .timer
1190            .as_mut()
1191            .expect("timer must exist in this state")
1192            .as_mut();
1193        if delay.poll(cx).is_pending() {
1194            return false;
1195        }
1196
1197        // The deadline elapsed in the window between the clock check and poll.
1198        self.inner.handle_timeout(self.runtime.now());
1199        self.timer_deadline = None;
1200        true
1201    }
1202
1203    /// Wake up a blocked `Driver` task to process I/O
1204    pub(crate) fn wake(&mut self) {
1205        if let Some(x) = self.driver.take() {
1206            x.wake();
1207        }
1208    }
1209
1210    /// Used to wake up all blocked futures when the connection becomes closed for any reason
1211    fn terminate(&mut self, reason: ConnectionError, shared: &Shared) {
1212        self.error = Some(reason.clone());
1213        if let Some(x) = self.on_handshake_data.take() {
1214            let _ = x.send(());
1215        }
1216        wake_all(&mut self.blocked_writers);
1217        wake_all(&mut self.blocked_readers);
1218        shared.stream_budget_available[Dir::Uni as usize].notify_waiters();
1219        shared.stream_budget_available[Dir::Bi as usize].notify_waiters();
1220        shared.stream_incoming[Dir::Uni as usize].notify_waiters();
1221        shared.stream_incoming[Dir::Bi as usize].notify_waiters();
1222        shared.datagram_received.notify_waiters();
1223        shared.datagrams_unblocked.notify_waiters();
1224        if let Some(x) = self.on_connected.take() {
1225            let _ = x.send(false);
1226        }
1227        wake_all_notify(&mut self.stopped);
1228        shared.closed.notify_waiters();
1229    }
1230
1231    fn close(&mut self, error_code: VarInt, reason: Bytes, shared: &Shared) {
1232        self.inner.close(self.runtime.now(), error_code, reason);
1233        self.terminate(ConnectionError::LocallyClosed, shared);
1234        self.wake();
1235    }
1236
1237    /// Close for a reason other than the application's explicit request
1238    pub(crate) fn implicit_close(&mut self, shared: &Shared) {
1239        self.close(0u32.into(), Bytes::new(), shared);
1240    }
1241
1242    pub(crate) fn check_0rtt(&self) -> Result<(), ()> {
1243        if self.inner.is_handshaking()
1244            || self.inner.accepted_0rtt()
1245            || self.inner.side().is_server()
1246        {
1247            Ok(())
1248        } else {
1249            Err(())
1250        }
1251    }
1252}
1253
1254impl Drop for State {
1255    fn drop(&mut self) {
1256        if !self.inner.is_drained() {
1257            // Ensure the endpoint can tidy up
1258            let _ = self
1259                .endpoint_events
1260                .send((self.handle, proto::EndpointEvent::drained()));
1261        }
1262    }
1263}
1264
1265impl fmt::Debug for State {
1266    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1267        f.debug_struct("State").field("inner", &self.inner).finish()
1268    }
1269}
1270
1271fn wake_stream(stream_id: StreamId, wakers: &mut FxHashMap<StreamId, Waker>) {
1272    if let Some(waker) = wakers.remove(&stream_id) {
1273        waker.wake();
1274    }
1275}
1276
1277fn wake_all(wakers: &mut FxHashMap<StreamId, Waker>) {
1278    wakers.drain().for_each(|(_, waker)| waker.wake())
1279}
1280
1281fn wake_stream_notify(stream_id: StreamId, wakers: &mut FxHashMap<StreamId, Arc<Notify>>) {
1282    if let Some(notify) = wakers.remove(&stream_id) {
1283        notify.notify_waiters()
1284    }
1285}
1286
1287fn wake_all_notify(wakers: &mut FxHashMap<StreamId, Arc<Notify>>) {
1288    wakers
1289        .drain()
1290        .for_each(|(_, notify)| notify.notify_waiters())
1291}
1292
1293/// Errors that can arise when sending a datagram
1294#[derive(Debug, Error, Clone, Eq, PartialEq)]
1295pub enum SendDatagramError {
1296    /// The peer does not support receiving datagram frames
1297    #[error("datagrams not supported by peer")]
1298    UnsupportedByPeer,
1299    /// Datagram support is disabled locally
1300    #[error("datagram support disabled")]
1301    Disabled,
1302    /// The datagram is larger than the connection can currently accommodate
1303    ///
1304    /// Indicates that the path MTU minus overhead or the limit advertised by the peer has been
1305    /// exceeded.
1306    #[error("datagram too large")]
1307    TooLarge,
1308    /// The connection was lost
1309    #[error("connection lost")]
1310    ConnectionLost(#[from] ConnectionError),
1311}
1312
1313/// The maximum amount of datagrams which will be produced in a single `drive_transmit` call
1314///
1315/// This limits the amount of CPU resources consumed by datagram generation,
1316/// and allows other tasks (like receiving ACKs) to run in between.
1317const MAX_TRANSMIT_DATAGRAMS: usize = 20;
1318
1319/// The maximum amount of datagrams that are sent in a single transmit
1320///
1321/// This can be lower than the maximum platform capabilities, to avoid excessive
1322/// memory allocations when calling `poll_transmit()`. Benchmarks have shown
1323/// that numbers around 10 are a good compromise.
1324const MAX_TRANSMIT_SEGMENTS: usize = 10;