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