diff --git a/pr/721/docs/help.html b/pr/721/docs/help.html index f35afe481..09d0ca8e7 100644 --- a/pr/721/docs/help.html +++ b/pr/721/docs/help.html @@ -1 +1 @@ -
pub enum ClosePathError {
+ClosePathError in noq - Rust ClosePathError
pub enum ClosePathError {
MultipathNotNegotiated,
ClosedPath,
LastOpenPath,
@@ -7,8 +7,8 @@
§ClosedPath
The path is already closed or was never opened
§LastOpenPath
Cannot close the last remaining open path via the local API.
Use Connection::close to end the connection instead.
-source. Read moresource. Read morepub enum ConnectionError {
+ConnectionError in noq - Rust ConnectionError
pub enum ConnectionError {
VersionMismatch,
TransportError(Error),
ConnectionClosed(ConnectionClose),
@@ -20,8 +20,8 @@ and §LocallyClosed
The local application closed the connection
§CidsExhausted
The connection could not be created because not enough of the CID space is available
Try using longer connection IDs.
-Trait Implementations§
Source§impl Clone for ConnectionError
Source§fn clone(&self) -> ConnectionError
Returns a duplicate of the value. Read more1.0.0 · Source§fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source. Read moreSource§impl Debug for ConnectionError
Source§impl Display for ConnectionError
Source§impl Error for ConnectionError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl From<Close> for ConnectionError
Source§fn from(x: Close) -> ConnectionError
Converts to this type from the input type.Source§impl From<CloseReason> for ConnectionError
Source§fn from(value: CloseReason) -> ConnectionError
Converts to this type from the input type.Source§impl From<ConnectionError> for ReadError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<ConnectionError> for ResetError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<ConnectionError> for SendDatagramError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<ConnectionError> for StoppedError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<ConnectionError> for WriteError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<Error> for ConnectionError
Source§fn from(source: Error) -> ConnectionError
Converts to this type from the input type.Source§impl PartialEq for ConnectionError
Source§impl Eq for ConnectionError
Source§impl StructuralPartialEq for ConnectionError
Auto Trait Implementations§
§impl !Freeze for ConnectionError
§impl !RefUnwindSafe for ConnectionError
§impl Send for ConnectionError
§impl Sync for ConnectionError
§impl Unpin for ConnectionError
§impl !UnwindSafe for ConnectionError
Blanket Implementations§
Trait Implementations§
Source§impl Clone for ConnectionError
Source§fn clone(&self) -> ConnectionError
Returns a duplicate of the value. Read more1.0.0 · Source§fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source. Read moreSource§impl Debug for ConnectionError
Source§impl Display for ConnectionError
Source§impl Error for ConnectionError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl From<Close> for ConnectionError
Source§fn from(x: Close) -> ConnectionError
Converts to this type from the input type.Source§impl From<CloseReason> for ConnectionError
Source§fn from(value: CloseReason) -> ConnectionError
Converts to this type from the input type.Source§impl From<ConnectionError> for ReadError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<ConnectionError> for ResetError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<ConnectionError> for SendDatagramError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<ConnectionError> for StoppedError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<ConnectionError> for WriteError
Source§fn from(source: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<Error> for ConnectionError
Source§fn from(source: Error) -> ConnectionError
Converts to this type from the input type.Source§impl PartialEq for ConnectionError
Source§impl Eq for ConnectionError
Source§impl StructuralPartialEq for ConnectionError
Auto Trait Implementations§
§impl !Freeze for ConnectionError
§impl !RefUnwindSafe for ConnectionError
§impl Send for ConnectionError
§impl Sync for ConnectionError
§impl Unpin for ConnectionError
§impl !UnwindSafe for ConnectionError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read moreSource§impl<T> CloneToUninit for Twhere
diff --git a/pr/721/docs/noq/enum.PathError.html b/pr/721/docs/noq/enum.PathError.html
index 3572f2677..ec52a5ab3 100644
--- a/pr/721/docs/noq/enum.PathError.html
+++ b/pr/721/docs/noq/enum.PathError.html
@@ -1,4 +1,4 @@
-PathError in noq - Rust PathError
pub enum PathError {
+PathError in noq - Rust PathError
pub enum PathError {
MultipathNotNegotiated,
ServerSideNotAllowed,
MaxPathIdReached,
@@ -12,8 +12,8 @@
§RemoteCidsExhausted
No remote CIDs available to open a new path
§ValidationFailed
Path could not be validated and will be abandoned
§InvalidRemoteAddress(SocketAddr)
The remote address for the path is not supported by the endpoint
-
Trait Implementations§
Source§impl Error for PathError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl Copy for PathError
Source§impl Eq for PathError
Source§impl StructuralPartialEq for PathError
Auto Trait Implementations§
§impl Freeze for PathError
§impl RefUnwindSafe for PathError
§impl Send for PathError
§impl Sync for PathError
§impl Unpin for PathError
§impl UnwindSafe for PathError
Blanket Implementations§
Trait Implementations§
Source§impl Error for PathError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl Copy for PathError
Source§impl Eq for PathError
Source§impl StructuralPartialEq for PathError
Auto Trait Implementations§
§impl Freeze for PathError
§impl RefUnwindSafe for PathError
§impl Send for PathError
§impl Sync for PathError
§impl Unpin for PathError
§impl UnwindSafe for PathError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read moreSource§impl<T> CloneToUninit for Twhere
diff --git a/pr/721/docs/noq/trait.NetworkChangeHint.html b/pr/721/docs/noq/trait.NetworkChangeHint.html
index 5e325c79f..130f9f72f 100644
--- a/pr/721/docs/noq/trait.NetworkChangeHint.html
+++ b/pr/721/docs/noq/trait.NetworkChangeHint.html
@@ -1,4 +1,4 @@
-NetworkChangeHint in noq - Rust NetworkChangeHint
pub trait NetworkChangeHint: Debug + 'static {
+NetworkChangeHint in noq - Rust NetworkChangeHint
pub trait NetworkChangeHint: Debug + 'static {
// Required method
fn is_path_recoverable(
&self,
@@ -6,7 +6,7 @@
network_path: FourTuple,
) -> bool;
}
Expand description
Hints when the caller identifies a network change.
-Required Methods§
Sourcefn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool
Inform the connection if a path may recover after a network change.
+Required Methods§
Sourcefn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool
Inform the connection if a path may recover after a network change.
After network changes, paths may not be recoverable. In this case, waiting for the path to
become idle may take longer than what is desirable. If Self::is_path_recoverable
returns false, a multipath-enabled, client-side connection will establish a new path to
diff --git a/pr/721/docs/noq_proto/enum.ClosePathError.html b/pr/721/docs/noq_proto/enum.ClosePathError.html
index c52cd9e6b..b749ea95f 100644
--- a/pr/721/docs/noq_proto/enum.ClosePathError.html
+++ b/pr/721/docs/noq_proto/enum.ClosePathError.html
@@ -1,4 +1,4 @@
-
ClosePathError in noq_proto - Rust ClosePathError
pub enum ClosePathError {
+ClosePathError in noq_proto - Rust ClosePathError
pub enum ClosePathError {
MultipathNotNegotiated,
ClosedPath,
LastOpenPath,
@@ -7,8 +7,8 @@
§ClosedPath
The path is already closed or was never opened
§LastOpenPath
Cannot close the last remaining open path via the local API.
Use Connection::close to end the connection instead.
-
Trait Implementations§
Source§impl Clone for ClosePathError
Source§fn clone(&self) -> ClosePathError
Returns a duplicate of the value. Read more1.0.0 · Source§fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source. Read moreSource§impl Debug for ClosePathError
Source§impl Display for ClosePathError
Source§impl Error for ClosePathError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl PartialEq for ClosePathError
Source§impl Eq for ClosePathError
Source§impl StructuralPartialEq for ClosePathError
Auto Trait Implementations§
§impl Freeze for ClosePathError
§impl RefUnwindSafe for ClosePathError
§impl Send for ClosePathError
§impl Sync for ClosePathError
§impl Unpin for ClosePathError
§impl UnwindSafe for ClosePathError
Blanket Implementations§
Trait Implementations§
Source§impl Clone for ClosePathError
Source§fn clone(&self) -> ClosePathError
Returns a duplicate of the value. Read more1.0.0 · Source§fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source. Read moreSource§impl Debug for ClosePathError
Source§impl Display for ClosePathError
Source§impl Error for ClosePathError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl PartialEq for ClosePathError
Source§impl Eq for ClosePathError
Source§impl StructuralPartialEq for ClosePathError
Auto Trait Implementations§
§impl Freeze for ClosePathError
§impl RefUnwindSafe for ClosePathError
§impl Send for ClosePathError
§impl Sync for ClosePathError
§impl Unpin for ClosePathError
§impl UnwindSafe for ClosePathError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read moreSource§impl<T> CloneToUninit for Twhere
diff --git a/pr/721/docs/noq_proto/enum.ConnectionError.html b/pr/721/docs/noq_proto/enum.ConnectionError.html
index 2e25bafc3..af12aaa86 100644
--- a/pr/721/docs/noq_proto/enum.ConnectionError.html
+++ b/pr/721/docs/noq_proto/enum.ConnectionError.html
@@ -1,4 +1,4 @@
-ConnectionError in noq_proto - Rust ConnectionError
pub enum ConnectionError {
+ConnectionError in noq_proto - Rust ConnectionError
pub enum ConnectionError {
VersionMismatch,
TransportError(TransportError),
ConnectionClosed(ConnectionClose),
@@ -20,8 +20,8 @@ and §LocallyClosed
The local application closed the connection
§CidsExhausted
The connection could not be created because not enough of the CID space is available
Try using longer connection IDs.
-Trait Implementations§
Source§impl Clone for ConnectionError
Source§fn clone(&self) -> ConnectionError
Returns a duplicate of the value. Read more1.0.0 · Source§fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source. Read moreSource§impl Debug for ConnectionError
Source§impl Display for ConnectionError
Source§impl Error for ConnectionError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl From<ConnectionError> for Error
Source§fn from(x: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<Error> for ConnectionError
Source§fn from(source: TransportError) -> Self
Converts to this type from the input type.Source§impl PartialEq for ConnectionError
Source§impl Eq for ConnectionError
Source§impl StructuralPartialEq for ConnectionError
Auto Trait Implementations§
§impl !Freeze for ConnectionError
§impl !RefUnwindSafe for ConnectionError
§impl Send for ConnectionError
§impl Sync for ConnectionError
§impl Unpin for ConnectionError
§impl !UnwindSafe for ConnectionError
Blanket Implementations§
Trait Implementations§
Source§impl Clone for ConnectionError
Source§fn clone(&self) -> ConnectionError
Returns a duplicate of the value. Read more1.0.0 · Source§fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source. Read moreSource§impl Debug for ConnectionError
Source§impl Display for ConnectionError
Source§impl Error for ConnectionError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl From<ConnectionError> for Error
Source§fn from(x: ConnectionError) -> Self
Converts to this type from the input type.Source§impl From<Error> for ConnectionError
Source§fn from(source: TransportError) -> Self
Converts to this type from the input type.Source§impl PartialEq for ConnectionError
Source§impl Eq for ConnectionError
Source§impl StructuralPartialEq for ConnectionError
Auto Trait Implementations§
§impl !Freeze for ConnectionError
§impl !RefUnwindSafe for ConnectionError
§impl Send for ConnectionError
§impl Sync for ConnectionError
§impl Unpin for ConnectionError
§impl !UnwindSafe for ConnectionError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read moreSource§impl<T> CloneToUninit for Twhere
diff --git a/pr/721/docs/noq_proto/enum.Event.html b/pr/721/docs/noq_proto/enum.Event.html
index 8101194fe..081cbd629 100644
--- a/pr/721/docs/noq_proto/enum.Event.html
+++ b/pr/721/docs/noq_proto/enum.Event.html
@@ -1,4 +1,4 @@
-Event in noq_proto - Rust Event
pub enum Event {
+Event in noq_proto - Rust Event
pub enum Event {
HandshakeDataReady,
Connected,
HandshakeConfirmed,
@@ -25,7 +25,7 @@ fail with §DatagramsUnblocked
One or more application datagrams have been sent after blocking
§Path(PathEvent)
(Multi)Path events
§NatTraversal(Event)
n0’s nat traversal events
-Trait Implementations§
Auto Trait Implementations§
§impl !Freeze for Event
§impl !RefUnwindSafe for Event
§impl Send for Event
§impl Sync for Event
§impl Unpin for Event
§impl !UnwindSafe for Event
Blanket Implementations§
Trait Implementations§
Auto Trait Implementations§
§impl !Freeze for Event
§impl !RefUnwindSafe for Event
§impl Send for Event
§impl Sync for Event
§impl Unpin for Event
§impl !UnwindSafe for Event
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read moreSource§impl<T> From<T> for T
Source§fn from(t: T) -> T
Returns the argument unchanged.
diff --git a/pr/721/docs/noq_proto/enum.PathError.html b/pr/721/docs/noq_proto/enum.PathError.html
index 273375382..419bdad7e 100644
--- a/pr/721/docs/noq_proto/enum.PathError.html
+++ b/pr/721/docs/noq_proto/enum.PathError.html
@@ -1,4 +1,4 @@
-PathError in noq_proto - Rust PathError
pub enum PathError {
+PathError in noq_proto - Rust PathError
pub enum PathError {
MultipathNotNegotiated,
ServerSideNotAllowed,
MaxPathIdReached,
@@ -12,8 +12,8 @@
§RemoteCidsExhausted
No remote CIDs available to open a new path
§ValidationFailed
Path could not be validated and will be abandoned
§InvalidRemoteAddress(SocketAddr)
The remote address for the path is not supported by the endpoint
-
Trait Implementations§
Source§impl Error for PathError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl Copy for PathError
Source§impl Eq for PathError
Source§impl StructuralPartialEq for PathError
Auto Trait Implementations§
§impl Freeze for PathError
§impl RefUnwindSafe for PathError
§impl Send for PathError
§impl Sync for PathError
§impl Unpin for PathError
§impl UnwindSafe for PathError
Blanket Implementations§
Trait Implementations§
Source§impl Error for PathError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl Copy for PathError
Source§impl Eq for PathError
Source§impl StructuralPartialEq for PathError
Auto Trait Implementations§
§impl Freeze for PathError
§impl RefUnwindSafe for PathError
§impl Send for PathError
§impl Sync for PathError
§impl Unpin for PathError
§impl UnwindSafe for PathError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read moreSource§impl<T> CloneToUninit for Twhere
diff --git a/pr/721/docs/noq_proto/enum.PathEvent.html b/pr/721/docs/noq_proto/enum.PathEvent.html
index c6f66dbd0..1857b04e6 100644
--- a/pr/721/docs/noq_proto/enum.PathEvent.html
+++ b/pr/721/docs/noq_proto/enum.PathEvent.html
@@ -41,7 +41,7 @@ changes the status.
Fields
This variant is marked as non-exhaustive
Non-exhaustive enum variants could have additional fields added in future. Therefore, non-exhaustive enum variants cannot be constructed in external crates and cannot be matched against.§id: PathIdPath over which the observed address was reported, PathId::ZERO when multipath is
not negotiated
§addr: SocketAddrThe address observed by the remote over this path
-
Trait Implementations§
Trait Implementations§
Source§impl Eq for PathEvent
Source§impl StructuralPartialEq for PathEvent
Auto Trait Implementations§
§impl Freeze for PathEvent
§impl RefUnwindSafe for PathEvent
§impl Send for PathEvent
§impl Sync for PathEvent
§impl Unpin for PathEvent
§impl UnwindSafe for PathEvent
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
diff --git a/pr/721/docs/noq_proto/struct.Connection.html b/pr/721/docs/noq_proto/struct.Connection.html
index 16c17705f..c1422adb6 100644
--- a/pr/721/docs/noq_proto/struct.Connection.html
+++ b/pr/721/docs/noq_proto/struct.Connection.html
@@ -33,7 +33,7 @@ increasing time. Specifically, calling Instant may be interleaved in any order with a
call to handle_event at that same instant; however
events or timeouts with different instants must not be interleaved.
-
Implementations§
Source§impl Connection
Sourcepub fn poll_timeout(&mut self) -> Option<Instant>
Returns the next time at which handle_timeout should be called
+Implementations§
Source§impl Connection
Sourcepub fn poll_timeout(&mut self) -> Option<Instant>
Returns the next time at which handle_timeout should be called
The value returned may change after:
- the application performed some I/O on the connection
@@ -113,7 +113,7 @@ idle time. Setting None disables the timeout and stops the timer.
) -> Result<Option<Duration>, ClosedPath>Sets the keep_alive_interval for a specific path
See TransportConfig::default_path_keep_alive_interval for details.
Returns the previous value of the setting.
-Sourcepub fn poll_transmit(
+
Sourcepub fn poll_transmit(
&mut self,
now: Instant,
max_datagrams: NonZeroUsize,
@@ -127,42 +127,42 @@ idle time. Setting None disables the timeout and stops the timer.
max_datagrams specifies how many datagrams can be returned inside a
single Transmit using GSO. This must be at least 1.
-
Sourcepub fn handle_event(&mut self, event: ConnectionEvent)
Process ConnectionEvents generated by the associated Endpoint
+Sourcepub fn handle_event(&mut self, event: ConnectionEvent)
Process ConnectionEvents generated by the associated Endpoint
Will execute protocol logic upon receipt of a connection event, in turn preparing signals
(including application Events, EndpointEvents and outgoing datagrams) that should be
extracted through the relevant methods.
-Sourcepub fn handle_timeout(&mut self, now: Instant)
Process timer expirations
+Sourcepub fn handle_timeout(&mut self, now: Instant)
Process timer expirations
Executes protocol logic, potentially preparing signals (including application Events,
EndpointEvents and outgoing datagrams) that should be extracted through the relevant
methods.
It is most efficient to call this immediately after the system clock reaches the latest
Instant that was output by poll_timeout; however spurious extra calls will simply
no-op and therefore are safe.
-Sourcepub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes)
Close a connection immediately
+Sourcepub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes)
Close a connection immediately
This does not ensure delivery of outstanding data. It is the application’s responsibility to
call this only when all important communications have been completed, e.g. by calling
SendStream::finish on outstanding streams and waiting for the corresponding
StreamEvent::Finished event.
If Streams::send_streams returns 0, all outstanding stream data has been
delivered. There may still be data from the peer that has not been received.
-Sourcepub fn stats(&mut self) -> ConnectionStats
Returns connection statistics
-Sourcepub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats>
Returns path statistics
-Sourcepub fn stats(&mut self) -> ConnectionStats
Returns connection statistics
+Sourcepub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats>
Returns path statistics
+Sourcepub fn ping(&mut self)
Ping the remote endpoint
Causes an ACK-eliciting packet to be transmitted on the connection.
-Sourcepub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath>
Ping the remote endpoint over a specific path
+Sourcepub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath>
Ping the remote endpoint over a specific path
Causes an ACK-eliciting packet to be transmitted on the path.
-Sourcepub fn force_key_update(&mut self)
Update traffic keys spontaneously
+Sourcepub fn force_key_update(&mut self)
Update traffic keys spontaneously
This can be useful for testing key updates, as they otherwise only happen infrequently.
-Sourcepub fn crypto_session(&self) -> &dyn Session
Get a session reference
-Sourcepub fn is_handshaking(&self) -> bool
Whether the connection is in the process of being established
+Sourcepub fn crypto_session(&self) -> &dyn Session
Get a session reference
+Sourcepub fn is_handshaking(&self) -> bool
Whether the connection is in the process of being established
If this returns false, the connection may be either established or closed, signaled by the
emission of a Connected or ConnectionLost
event respectively. Note that locally-initiated closes via close() do not
emit a ConnectionLost event.
For an established connection this essentially means the handshake is completed,
but not necessarily yet confirmed.
-Sourcepub fn is_closed(&self) -> bool
Whether the connection is closed
Closed connections cannot transport any further data. A connection becomes closed when
either peer application intentionally closes it, or when either transport layer detects an
error such as a time-out or certificate validation failure.
@@ -170,24 +170,24 @@ error such as a time-out or certificate validation failure.
connection is closed by the peer or due to an error. When the local application closes
the connection via close(), no ConnectionLost event is emitted;
instead, pending operations fail with ConnectionError::LocallyClosed.
-Sourcepub fn is_drained(&self) -> bool
Whether there is no longer any need to keep the connection around
+Sourcepub fn is_drained(&self) -> bool
Whether there is no longer any need to keep the connection around
Closed connections become drained after a brief timeout to absorb any remaining in-flight
packets from the peer. All drained connections have been closed.
-Sourcepub fn accepted_0rtt(&self) -> bool
For clients, if the peer accepted the 0-RTT data packets
+Sourcepub fn accepted_0rtt(&self) -> bool
For clients, if the peer accepted the 0-RTT data packets
The value is meaningless until after the handshake completes.
-Sourcepub fn has_pending_retransmits(&self) -> bool
Whether there are any pending retransmits
-Sourcepub fn path_observed_address(
+
Sourcepub fn has_pending_retransmits(&self) -> bool
Whether there are any pending retransmits
+Sourcepub fn path_observed_address(
&self,
path_id: PathId,
) -> Result<Option<SocketAddr>, ClosedPath>
Get the address observed by the remote over the given path
-Sourcepub fn rtt(&self, path_id: PathId) -> Option<Duration>
Current best estimate of this connection’s latency (round-trip-time)
-Sourcepub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller>
Current state of this connection’s congestion controller, for debugging purposes
-Sourcepub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt)
Modify the number of remotely initiated streams that may be concurrently open
+Sourcepub fn rtt(&self, path_id: PathId) -> Option<Duration>
Current best estimate of this connection’s latency (round-trip-time)
+Sourcepub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller>
Current state of this connection’s congestion controller, for debugging purposes
+Sourcepub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt)
Modify the number of remotely initiated streams that may be concurrently open
No streams may be opened by the peer unless fewer than count are already open. Large
counts increase both minimum and worst-case memory consumption.
-Sourcepub fn set_max_concurrent_paths(
+
Sourcepub fn set_max_concurrent_paths(
&mut self,
now: Instant,
count: NonZeroU32,
@@ -198,16 +198,16 @@ actively reduce paths they must be closed using TransportConfig) this can not enable
multipath and will fail.
-
Sourcepub fn max_concurrent_streams(&self, dir: Dir) -> u64
Current number of remotely initiated streams that may be concurrently open
+Sourcepub fn max_concurrent_streams(&self, dir: Dir) -> u64
Current number of remotely initiated streams that may be concurrently open
If the target for this limit is reduced using set_max_concurrent_streams,
it will not change immediately, even if fewer streams are open. Instead, it will
decrement by one for each time a remotely initiated stream of matching directionality is closed.
-Sourcepub fn set_send_window(&mut self, send_window: u64)
Sourcepub fn set_receive_window(&mut self, receive_window: VarInt)
Sourcepub fn is_multipath_negotiated(&self) -> bool
Whether the Multipath for QUIC extension is enabled.
+Sourcepub fn set_send_window(&mut self, send_window: u64)
Sourcepub fn set_receive_window(&mut self, receive_window: VarInt)
Sourcepub fn is_multipath_negotiated(&self) -> bool
Whether the Multipath for QUIC extension is enabled.
Multipath is only enabled after the handshake is completed and if it was enabled by both
peers.
-Sourcepub fn handle_network_change(
+
Sourcepub fn handle_network_change(
&mut self,
hint: Option<&dyn NetworkChangeHint>,
now: Instant,
@@ -222,26 +222,26 @@ paths as non recoverable when necessary accelerates connectivity re-establishmen
allow it altogether.
The optional hint allows callers to indicate when paths are non-recoverable and should be
migrated to new a PathId.
-
Sourcepub fn current_mtu(&self) -> u16
Storage size required for the largest packet that can be transmitted on all currently
+
Sourcepub fn current_mtu(&self) -> u16
Storage size required for the largest packet that can be transmitted on all currently
available paths
Buffers passed to Connection::poll_transmit should be at least this large.
When multipath is enabled, this value is the minimum MTU across all available paths.
-Sourcepub fn add_nat_traversal_address(
+
Sourcepub fn add_nat_traversal_address(
&mut self,
address: SocketAddr,
) -> Result<(), Error>
Add addresses the local endpoint considers are reachable for nat traversal.
-Sourcepub fn remove_nat_traversal_address(
+
Sourcepub fn remove_nat_traversal_address(
&mut self,
address: SocketAddr,
) -> Result<(), Error>
Removes an address the endpoing no longer considers reachable for nat traversal
Addresses not present in the set will be silently ignored.
-Sourcepub fn get_local_nat_traversal_addresses(
+
Sourcepub fn get_local_nat_traversal_addresses(
&self,
) -> Result<Vec<SocketAddr>, Error>
Get the current local nat traversal addresses
-Sourcepub fn get_remote_nat_traversal_addresses(
+
Sourcepub fn get_remote_nat_traversal_addresses(
&self,
) -> Result<Vec<SocketAddr>, Error>
Get the currently advertised nat traversal addresses by the server
-Sourcepub fn initiate_nat_traversal_round(
+
Sourcepub fn initiate_nat_traversal_round(
&mut self,
now: Instant,
) -> Result<Vec<SocketAddr>, Error>
Initiates a new nat traversal round
@@ -252,7 +252,7 @@ round is initiated, the previous one is cancelled.
4-tuple.
Returns the server addresses that are now being probed. If addresses fail due to
spurious errors, these might succeed later and not be returned in this set.
-
Trait Implementations§
Auto Trait Implementations§
§impl !Freeze for Connection
§impl !RefUnwindSafe for Connection
§impl Send for Connection
§impl Sync for Connection
§impl Unpin for Connection
§impl !UnwindSafe for Connection
Blanket Implementations§
Trait Implementations§
Auto Trait Implementations§
§impl !Freeze for Connection
§impl !RefUnwindSafe for Connection
§impl Send for Connection
§impl Sync for Connection
§impl Unpin for Connection
§impl !UnwindSafe for Connection
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read moreSource§impl<T> From<T> for T
Source§fn from(t: T) -> T
Returns the argument unchanged.
diff --git a/pr/721/docs/noq_proto/struct.MultipathNotNegotiated.html b/pr/721/docs/noq_proto/struct.MultipathNotNegotiated.html
index c24caca60..e40982545 100644
--- a/pr/721/docs/noq_proto/struct.MultipathNotNegotiated.html
+++ b/pr/721/docs/noq_proto/struct.MultipathNotNegotiated.html
@@ -1,5 +1,5 @@
-MultipathNotNegotiated in noq_proto - Rust MultipathNotNegotiated
pub struct MultipathNotNegotiated { /* private fields */ }
Expand description
Error when the multipath extension was not negotiated, but attempted to be used.
-Trait Implementations§
Source§impl Clone for MultipathNotNegotiated
Source§fn clone(&self) -> MultipathNotNegotiated
Returns a duplicate of the value. Read more1.0.0 · Source§fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source. Read moreSource§impl Debug for MultipathNotNegotiated
Source§impl Display for MultipathNotNegotiated
Source§impl Error for MultipathNotNegotiated
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl Copy for MultipathNotNegotiated
Auto Trait Implementations§
§impl Freeze for MultipathNotNegotiated
§impl RefUnwindSafe for MultipathNotNegotiated
§impl Send for MultipathNotNegotiated
§impl Sync for MultipathNotNegotiated
§impl Unpin for MultipathNotNegotiated
§impl UnwindSafe for MultipathNotNegotiated
Blanket Implementations§
Source§impl<T> Any for Twhere
+MultipathNotNegotiated in noq_proto - Rust MultipathNotNegotiated
pub struct MultipathNotNegotiated { /* private fields */ }
Expand description
Error when the multipath extension was not negotiated, but attempted to be used.
+Trait Implementations§
Source§impl Clone for MultipathNotNegotiated
Source§fn clone(&self) -> MultipathNotNegotiated
Returns a duplicate of the value. Read more1.0.0 · Source§fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source. Read moreSource§impl Debug for MultipathNotNegotiated
Source§impl Display for MultipathNotNegotiated
Source§impl Error for MultipathNotNegotiated
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl Copy for MultipathNotNegotiated
Auto Trait Implementations§
§impl Freeze for MultipathNotNegotiated
§impl RefUnwindSafe for MultipathNotNegotiated
§impl Send for MultipathNotNegotiated
§impl Sync for MultipathNotNegotiated
§impl Unpin for MultipathNotNegotiated
§impl UnwindSafe for MultipathNotNegotiated
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read moreSource§impl<T> CloneToUninit for Twhere
diff --git a/pr/721/docs/noq_proto/struct.TransportError.html b/pr/721/docs/noq_proto/struct.TransportError.html
index bebac1106..644d3a7cc 100644
--- a/pr/721/docs/noq_proto/struct.TransportError.html
+++ b/pr/721/docs/noq_proto/struct.TransportError.html
@@ -11,7 +11,7 @@
§reason: StringHuman-readable explanation of the reason
§crypto: Option<Arc<dyn Error + Send + Sync>>An underlying crypto (e.g. TLS) layer error
Implementations§
Trait Implementations§
Source§impl Error for Error
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl From<Error> for ConnectionClose
Source§fn from(x: TransportError) -> Self
Converts to this type from the input type.Source§impl From<Error> for ConnectionError
Source§fn from(source: TransportError) -> Self
Converts to this type from the input type.Source§impl From<Error> for TransportError
Trait Implementations§
Source§impl Error for Error
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
Returns the lower-level source of this error, if any. Read more1.0.0 · Source§fn description(&self) -> &str
👎Deprecated since 1.42.0: use the Display impl or to_string()Source§impl From<Error> for ConnectionClose
Source§fn from(x: TransportError) -> Self
Converts to this type from the input type.Source§impl From<Error> for ConnectionError
Source§fn from(source: TransportError) -> Self
Converts to this type from the input type.Source§impl From<Error> for TransportError
Source§impl Eq for Error
Auto Trait Implementations§
§impl Freeze for Error
§impl !RefUnwindSafe for Error
§impl Send for Error
§impl Sync for Error
§impl Unpin for Error
§impl !UnwindSafe for Error
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
diff --git a/pr/721/docs/noq_proto/trait.NetworkChangeHint.html b/pr/721/docs/noq_proto/trait.NetworkChangeHint.html
index 55368d4fc..9f4bee59d 100644
--- a/pr/721/docs/noq_proto/trait.NetworkChangeHint.html
+++ b/pr/721/docs/noq_proto/trait.NetworkChangeHint.html
@@ -1,4 +1,4 @@
-NetworkChangeHint in noq_proto - Rust NetworkChangeHint
pub trait NetworkChangeHint: Debug + 'static {
+NetworkChangeHint in noq_proto - Rust NetworkChangeHint
pub trait NetworkChangeHint: Debug + 'static {
// Required method
fn is_path_recoverable(
&self,
@@ -6,7 +6,7 @@
network_path: FourTuple,
) -> bool;
}
Expand description
Hints when the caller identifies a network change.
-Required Methods§
Sourcefn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool
Inform the connection if a path may recover after a network change.
+Required Methods§
Sourcefn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool
Inform the connection if a path may recover after a network change.
After network changes, paths may not be recoverable. In this case, waiting for the path to
become idle may take longer than what is desirable. If Self::is_path_recoverable
returns false, a multipath-enabled, client-side connection will establish a new path to
diff --git a/pr/721/docs/search.index/entry/5da1f57da7ac.js b/pr/721/docs/search.index/entry/1ee427fe586f.js
similarity index 99%
rename from pr/721/docs/search.index/entry/5da1f57da7ac.js
rename to pr/721/docs/search.index/entry/1ee427fe586f.js
index 84596674f..44d15b70b 100644
--- a/pr/721/docs/search.index/entry/5da1f57da7ac.js
+++ b/pr/721/docs/search.index/entry/1ee427fe586f.js
@@ -1 +1 @@
-rd_("Af[477,15,478,0,133,0,0]Ak[3173,15,3174,3174,134,0,0]Ag[477,15,478,0,4208,0,0]Al[3173,15,3174,1829,4209,0,0]Al[2029,15,2030,2030,4210,0,0]Al[3173,15,1731,1731,1470,0,0]Ao[1228,13,1229,1229,4047,3111,0]Am[477,13,478,3740,4898,3111,0]Am[477,13,478,4270,1458,3111,0]Al[477,13,478,1126,520,3111,0]Am[477,13,478,1126,4491,3111,0]Am[477,13,478,4157,4484,3111,0]Am[477,13,478,4157,3121,3111,0]Am[477,13,478,4157,3324,3111,0]Am[477,13,478,4157,4483,3111,0]Am[477,13,478,4162,3342,3111,0]Am[477,13,478,4162,4248,3111,0]Aj[477,13,478,0,1480,3111,0]Aj[477,13,478,0,5069,3111,0]Aj[477,13,478,0,1184,3111,0]Aj[477,13,478,0,1463,3111,0]Aj[477,13,478,0,3317,3111,0]Aj[477,13,478,0,3116,3111,0]Aj[477,13,478,0,4954,3111,0]Aj[477,13,478,0,3290,3111,0]Aj[477,13,478,0,2343,3111,0]Aj[477,13,478,0,3303,3111,0]Aj[477,13,478,0,3118,3111,0]Aj[477,13,478,0,4194,3111,0]Aj[477,13,478,0,4583,3111,0]Aj[477,13,478,0,3112,3111,0]Aj[477,13,478,0,4450,3111,0]Aj[477,13,478,0,4064,3111,0]Aj[477,13,478,0,4050,3111,0]Aj[477,13,478,0,3099,3111,0]Aj[477,13,478,0,4580,3111,0]Aj[477,13,478,0,4787,3111,0]Aj[477,13,478,0,4200,3111,0]Aj[477,13,478,0,4203,3111,0]Aj[477,13,478,0,4208,3111,0]Aj[477,13,478,0,4959,3111,0]Ai[477,13,478,0,526,3111,0]Ai[477,13,478,0,133,3111,0]Aj[477,13,478,0,2330,3111,0]Aj[477,13,478,0,3097,3111,0]Ak[477,13,1735,0,5223,3111,0]Ak[477,13,1818,0,1201,3111,0]Ao[3173,13,3174,1856,1481,3111,0]Ao[3173,13,3174,1856,5070,3111,0]Ao[3173,13,3174,3138,1185,3111,0]Ao[3173,13,3174,3147,4899,3111,0]Ao[3173,13,3174,1403,1464,3111,0]Ao[3173,13,3174,1403,3318,3111,0]Ao[3173,13,3174,1403,3117,3111,0]Ao[3173,13,3174,1403,4897,3111,0]Ao[3173,13,3174,1403,4955,3111,0]Ao[3173,13,3174,1403,3293,3111,0]Ao[3173,13,3174,1418,2344,3111,0]Ao[3173,13,3174,1418,3304,3111,0]Ao[3173,13,3174,1418,3119,3111,0]Ao[3173,13,3174,1152,3122,3111,0]Ao[3173,13,3174,1152,4374,3111,0]Ao[3173,13,3174,1157,3343,3111,0]Ao[3173,13,3174,1157,4063,3111,0]Ao[3173,13,3174,2044,4082,3111,0]Ao[3173,13,3174,2044,4485,3111,0]Ao[3173,13,3174,2044,4198,3111,0]Ao[3173,13,3174,3741,4584,3111,0]Ao[3173,13,3174,3741,3113,3111,0]Ao[3173,13,3174,3741,4451,3111,0]Ao[3173,13,3174,3276,4065,3111,0]Ao[3173,13,3174,1733,4051,3111,0]Ao[3173,13,3174,1393,3100,3111,0]Ao[3173,13,3174,1393,4466,3111,0]Ao[3173,13,3174,1393,3310,3111,0]Ao[3173,13,3174,1393,3332,3111,0]Ao[3173,13,3174,1393,4205,3111,0]Ao[3173,13,3174,1393,4582,3111,0]Ao[3173,13,3174,1393,4789,3111,0]Ao[3173,13,3174,2354,4793,3111,0]Ao[3173,13,3174,2354,4201,3111,0]Ao[3173,13,3174,1798,2316,3111,0]Ao[3173,13,3174,1798,4894,3111,0]Ao[3173,13,3174,1829,4204,3111,0]Ao[3173,13,3174,1829,4209,3111,0]Al[3173,13,3174,0,4489,3111,0]Al[3173,13,3174,0,4960,3111,0]An[3173,13,3174,3174,527,3111,0]An[3173,13,3174,3174,134,3111,0]Ao[3173,13,3174,3174,2331,3111,0]Ao[3173,13,3174,3174,3098,3111,0]Ao[3173,13,1731,1731,4380,3111,0]Ao[3173,13,5111,5111,5007,3111,0]Ao[3173,13,5111,5111,1203,3111,0]Ao[3173,13,1736,1736,5224,3111,0]Al[3173,13,1819,0,1202,3111,0]Ao[2029,13,2030,2030,4210,3111,0]Ai[477,13,478,1126,520,0,0]Aj[477,13,478,1126,4491,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5008,0,0]Aj[477,13,478,4162,3328,0,0]Ah[477,14,3114,0,4059,0,0]Ah[477,14,3114,0,3072,0,0]Ah[477,14,3114,0,3091,0,0]Ah[477,14,3114,0,4233,0,0]Ah[477,14,3114,0,4224,0,0]Ai[3173,14,3115,0,4060,0,0]Ai[3173,14,3115,0,3073,0,0]Ai[3173,14,3115,0,3092,0,0]Ai[3173,14,3115,0,4234,0,0]Ai[3173,14,3115,0,4225,0,0]Ai[3173,14,4081,0,2326,0,0]Ai[3173,14,4081,0,2346,0,0]Ai[3173,14,4081,0,2310,0,0]Ai[3173,14,4081,0,1901,0,0]Ae[1228,7,1229,0,0,0,0]Ah[3173,14,4595,0,516,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ae[2408,5,2409,0,0,0,0]Af[477,6,478,3174,0,0,0]Ae[3173,6,3174,0,0,0,0]Al[3173,15,1731,1731,1470,0,0]Ag[477,19,478,0,1480,0,0]Ag[477,19,478,0,1463,0,0]Al[3173,19,3174,1856,1481,0,0]Al[3173,19,3174,1403,1464,0,0]Ae[1228,5,1229,0,0,0,0]Ae[1127,5,1725,0,0,0,0]Ae[1127,5,1824,0,0,0,0]Af[477,15,478,0,133,0,0]Ak[3173,15,3174,3174,134,0,0]Ai[477,13,478,0,2343,127,0]Ai[477,13,478,0,3303,127,0]Ai[477,13,478,0,4587,127,0]An[3173,13,3174,1418,2344,127,0]An[3173,13,3174,1418,3304,127,0]An[3173,13,3174,1418,4588,127,0]Ai[477,13,478,0,1480,144,0]Ai[477,13,478,0,1463,144,0]Ai[477,13,478,0,4064,144,0]Ai[477,13,478,0,4203,144,0]Ah[477,13,478,0,526,144,0]Ah[477,13,478,0,133,144,0]Ai[477,13,478,0,2330,144,0]An[3173,13,3174,1856,1481,144,0]An[3173,13,3174,3147,4899,144,0]An[3173,13,3174,1403,1464,144,0]An[3173,13,3174,1152,3122,144,0]An[3173,13,3174,1152,4374,144,0]An[3173,13,3174,1157,3343,144,0]An[3173,13,3174,3276,4065,144,0]An[3173,13,3174,2354,4793,144,0]An[3173,13,3174,1798,4894,144,0]An[3173,13,3174,1829,4204,144,0]Am[3173,13,3174,3174,527,144,0]Am[3173,13,3174,3174,134,144,0]An[3173,13,3174,3174,2331,144,0]Ag[477,13,478,0,2330,0,0]Al[3173,13,3174,3174,2331,0,0]Ai[3173,14,4081,0,1460,0,0]Ai[3173,14,4081,0,3081,0,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Al[2029,14,2030,2030,2328,0,0]Al[2029,14,2030,2030,2342,0,0]An[1228,13,1229,1229,141,1191,0]Ao[1228,13,1229,1229,4075,1191,0]Ao[1228,13,1229,1229,4047,1191,0]Ao[1228,13,1417,1417,4486,1191,0]Ao[4088,13,4089,4089,5161,1191,0]Am[477,13,478,4270,5065,1191,0]Am[477,13,478,3740,3295,1191,0]Am[477,13,478,3740,3297,1191,0]Am[477,13,478,3740,1450,1191,0]Am[477,13,478,3740,5072,1191,0]Db[477,13,478,3740,4898,1873,0,\"impl-Display-for-SendDatagramError\"]D`[477,13,478,3740,4898,1191,0,\"impl-Debug-for-SendDatagramError\"]Am[477,13,478,2353,2308,1191,0]Am[477,13,478,2353,4347,1191,0]Cg[477,13,478,4270,1458,1873,0,\"impl-Display-for-Lagged\"]Ce[477,13,478,4270,1458,1191,0,\"impl-Debug-for-Lagged\"]Am[477,13,478,4270,3316,1191,0]Am[477,13,478,4270,5000,1191,0]Am[477,13,478,2385,2312,1191,0]Ck[477,13,478,2385,3325,1873,0,\"impl-Display-for-RetryError\"]Ci[477,13,478,2385,3325,1191,0,\"impl-Debug-for-RetryError\"]Am[477,13,478,2385,4465,1191,0]Al[477,13,478,1126,520,1191,0]Am[477,13,478,1126,4491,1191,0]Am[477,13,478,4157,3322,1191,0]Am[477,13,478,4157,5008,1191,0]Cm[477,13,478,4157,4484,1191,0,\"impl-Debug-for-ReadToEndError\"]Co[477,13,478,4157,4484,1873,0,\"impl-Display-for-ReadToEndError\"]Cj[477,13,478,4157,3121,1873,0,\"impl-Display-for-ReadError\"]Ch[477,13,478,4157,3121,1191,0,\"impl-Debug-for-ReadError\"]Ci[477,13,478,4157,3324,1191,0,\"impl-Debug-for-ResetError\"]Ck[477,13,478,4157,3324,1873,0,\"impl-Display-for-ResetError\"]Cm[477,13,478,4157,4483,1191,0,\"impl-Debug-for-ReadExactError\"]Co[477,13,478,4157,4483,1873,0,\"impl-Display-for-ReadExactError\"]Am[477,13,478,1431,4249,1191,0]Am[477,13,478,1169,4078,1191,0]Am[477,13,478,4162,3328,1191,0]Ck[477,13,478,4162,3342,1873,0,\"impl-Display-for-WriteError\"]Ci[477,13,478,4162,3342,1191,0,\"impl-Debug-for-WriteError\"]Cm[477,13,478,4162,4248,1873,0,\"impl-Display-for-StoppedError\"]Ck[477,13,478,4162,4248,1191,0,\"impl-Debug-for-StoppedError\"]Am[477,13,478,4162,1903,1191,0]Cd[477,13,478,0,1480,1873,0,\"impl-Display-for-VarInt\"]Cb[477,13,478,0,1480,1191,0,\"impl-Debug-for-VarInt\"]Db[477,13,478,0,5069,1873,0,\"impl-Display-for-VarIntBoundsExceeded\"]D`[477,13,478,0,5069,1191,0,\"impl-Debug-for-VarIntBoundsExceeded\"]Aj[477,13,478,0,1184,1191,0]Cd[477,13,478,0,1463,1873,0,\"impl-Display-for-PathId\"]Cb[477,13,478,0,1463,1191,0,\"impl-Debug-for-PathId\"]Aj[477,13,478,0,3317,1191,0]Aj[477,13,478,0,3116,1191,0]Cn[477,13,478,0,4954,1191,0,\"impl-Debug-for-SetPathStatusError\"]D`[477,13,478,0,4954,1873,0,\"impl-Display-for-SetPathStatusError\"]Cf[477,13,478,0,3290,1191,0,\"impl-Debug-for-ClosedPath\"]Ch[477,13,478,0,3290,1873,0,\"impl-Display-for-ClosedPath\"]Aj[477,13,478,0,2343,1191,0]Aj[477,13,478,0,3303,1191,0]Aj[477,13,478,0,3118,1191,0]Aj[477,13,478,0,4587,1191,0]Ch[477,13,478,0,4194,1191,0,\"impl-Debug-for-ClosedStream\"]Cj[477,13,478,0,4194,1873,0,\"impl-Display-for-ClosedStream\"]Cm[477,13,478,0,4583,1873,0,\"impl-Display-for-ConnectionError\"]Ck[477,13,478,0,4583,1191,0,\"impl-Debug-for-ConnectionError\"]Cg[477,13,478,0,3112,1873,0,\"impl-Display-for-PathError\"]Ce[477,13,478,0,3112,1191,0,\"impl-Debug-for-PathError\"]Cl[477,13,478,0,4450,1873,0,\"impl-Display-for-ClosePathError\"]Cj[477,13,478,0,4450,1191,0,\"impl-Debug-for-ClosePathError\"]Aj[477,13,478,0,4597,1191,0]Aj[477,13,478,0,4606,1191,0]Aj[477,13,478,0,4924,1191,0]Aj[477,13,478,0,4939,1191,0]Aj[477,13,478,0,4064,1191,0]Aj[477,13,478,0,4460,1191,0]Aj[477,13,478,0,4242,1191,0]Aj[477,13,478,0,5126,1191,0]Aj[477,13,478,0,4188,1191,0]Cg[477,13,478,0,4050,1191,0,\"impl-Debug-for-ConfigError\"]Ci[477,13,478,0,4050,1873,0,\"impl-Display-for-ConfigError\"]Cg[477,13,478,0,3099,1873,0,\"impl-Display-for-FrameType\"]Ce[477,13,478,0,3099,1191,0,\"impl-Debug-for-FrameType\"]Cm[477,13,478,0,4580,1873,0,\"impl-Display-for-ConnectionClose\"]Ck[477,13,478,0,4580,1191,0,\"impl-Debug-for-ConnectionClose\"]Cn[477,13,478,0,4787,1873,0,\"impl-Display-for-ApplicationClose\"]Cl[477,13,478,0,4787,1191,0,\"impl-Debug-for-ApplicationClose\"]Cj[477,13,478,0,4200,1873,0,\"impl-Display-for-ConnectError\"]Ch[477,13,478,0,4200,1191,0,\"impl-Debug-for-ConnectError\"]Cj[477,13,478,0,4203,1873,0,\"impl-Display-for-ConnectionId\"]Ch[477,13,478,0,4203,1191,0,\"impl-Debug-for-ConnectionId\"]Aj[477,13,478,0,4208,1191,0]D`[477,13,478,0,4959,1873,0,\"impl-Display-for-TransportErrorCode\"]Cn[477,13,478,0,4959,1191,0,\"impl-Debug-for-TransportErrorCode\"]Aj[477,13,478,0,3306,1191,0]Aj[477,13,478,0,4821,1191,0]Ai[477,13,478,0,526,1191,0]C`[477,13,478,0,133,1873,0,\"impl-Display-for-Dir\"]Bn[477,13,478,0,133,1191,0,\"impl-Debug-for-Dir\"]Cf[477,13,478,0,2330,1873,0,\"impl-Display-for-StreamId\"]Cd[477,13,478,0,2330,1191,0,\"impl-Debug-for-StreamId\"]Aj[477,13,478,0,2340,1191,0]Cg[477,13,478,0,3097,1873,0,\"impl-Display-for-FourTuple\"]Ce[477,13,478,0,3097,1191,0,\"impl-Debug-for-FourTuple\"]Aj[477,13,3735,0,501,1191,0]Ak[477,13,3735,0,3286,1191,0]Ak[477,13,3735,0,1188,1191,0]Ak[477,13,3735,0,4055,1191,0]Ak[477,13,3735,0,1886,1191,0]Ak[477,13,3735,0,4366,1191,0]Ak[477,13,1735,0,5223,1191,0]Ak[477,13,1735,0,4053,1191,0]Ak[477,13,1735,0,4963,1191,0]Cd[477,13,1818,0,1201,1873,0,\"impl-Display-for-Error\"]Cb[477,13,1818,0,1201,1191,0,\"impl-Debug-for-Error\"]Dc[477,13,1818,0,5063,1873,0,\"impl-Display-for-NoInitialCipherSuite\"]Da[477,13,1818,0,5063,1191,0,\"impl-Debug-for-NoInitialCipherSuite\"]Ao[3173,13,3174,3741,3298,1191,0]Ao[3173,13,3174,2354,2309,1191,0]Cg[3173,13,3174,1856,1481,1191,0,\"impl-Debug-for-VarInt\"]Ci[3173,13,3174,1856,1481,1873,0,\"impl-Display-for-VarInt\"]Dg[3173,13,3174,1856,5070,1873,0,\"impl-Display-for-VarIntBoundsExceeded\"]De[3173,13,3174,1856,5070,1191,0,\"impl-Debug-for-VarIntBoundsExceeded\"]Ao[3173,13,3174,3138,1185,1191,0]Dd[3173,13,3174,3147,4899,1873,0,\"impl-Display-for-SendDatagramError\"]Db[3173,13,3174,3147,4899,1191,0,\"impl-Debug-for-SendDatagramError\"]Cg[3173,13,3174,1403,1464,1191,0,\"impl-Debug-for-PathId\"]Ci[3173,13,3174,1403,1464,1873,0,\"impl-Display-for-PathId\"]Ao[3173,13,3174,1403,4238,1191,0]Ao[3173,13,3174,1403,3318,1191,0]Ao[3173,13,3174,1403,3117,1191,0]Ao[3173,13,3174,1403,4897,1191,0]Dc[3173,13,3174,1403,4955,1191,0,\"impl-Debug-for-SetPathStatusError\"]De[3173,13,3174,1403,4955,1873,0,\"impl-Display-for-SetPathStatusError\"]Cm[3173,13,3174,1403,3293,1873,0,\"impl-Display-for-ClosedPath\"]Ck[3173,13,3174,1403,3293,1191,0,\"impl-Debug-for-ClosedPath\"]Ao[3173,13,3174,1418,2344,1191,0]Ao[3173,13,3174,1418,3304,1191,0]Ao[3173,13,3174,1418,3119,1191,0]Ao[3173,13,3174,1418,4588,1191,0]Cj[3173,13,3174,1152,3122,1191,0,\"impl-Debug-for-ReadError\"]Cl[3173,13,3174,1152,3122,1873,0,\"impl-Display-for-ReadError\"]Cn[3173,13,3174,1152,4374,1191,0,\"impl-Debug-for-ReadableError\"]D`[3173,13,3174,1152,4374,1873,0,\"impl-Display-for-ReadableError\"]Cm[3173,13,3174,1157,3343,1873,0,\"impl-Display-for-WriteError\"]Ck[3173,13,3174,1157,3343,1191,0,\"impl-Debug-for-WriteError\"]Cn[3173,13,3174,1157,4063,1873,0,\"impl-Display-for-FinishError\"]Cl[3173,13,3174,1157,4063,1191,0,\"impl-Debug-for-FinishError\"]Ao[3173,13,3174,2044,4082,1191,0]Ao[3173,13,3174,2044,4485,1191,0]Cm[3173,13,3174,2044,4198,1191,0,\"impl-Debug-for-ClosedStream\"]Co[3173,13,3174,2044,4198,1873,0,\"impl-Display-for-ClosedStream\"]Db[3173,13,3174,3741,4584,1873,0,\"impl-Display-for-ConnectionError\"]D`[3173,13,3174,3741,4584,1191,0,\"impl-Debug-for-ConnectionError\"]Cl[3173,13,3174,3741,3113,1873,0,\"impl-Display-for-PathError\"]Cj[3173,13,3174,3741,3113,1191,0,\"impl-Debug-for-PathError\"]Da[3173,13,3174,3741,4451,1873,0,\"impl-Display-for-ClosePathError\"]Co[3173,13,3174,3741,4451,1191,0,\"impl-Debug-for-ClosePathError\"]Di[3173,13,3174,3741,5157,1873,0,\"impl-Display-for-MultipathNotNegotiated\"]Dg[3173,13,3174,3741,5157,1191,0,\"impl-Debug-for-MultipathNotNegotiated\"]Ao[3173,13,3174,3741,1206,1191,0]Ao[3173,13,3174,1148,4598,1191,0]Ao[3173,13,3174,3276,4607,1191,0]Ao[3173,13,3174,3276,4925,1191,0]Ao[3173,13,3174,3276,4940,1191,0]Ao[3173,13,3174,3276,4065,1191,0]Ao[3173,13,3174,1733,4461,1191,0]Ao[3173,13,3174,1733,4244,1191,0]Ao[3173,13,3174,1733,5127,1191,0]Ao[3173,13,3174,1733,4190,1191,0]Cl[3173,13,3174,1733,4051,1191,0,\"impl-Debug-for-ConfigError\"]Cn[3173,13,3174,1733,4051,1873,0,\"impl-Display-for-ConfigError\"]Cj[3173,13,3174,1393,3100,1191,0,\"impl-Debug-for-FrameType\"]Cl[3173,13,3174,1393,3100,1873,0,\"impl-Display-for-FrameType\"]Co[3173,13,3174,1393,4466,1191,0,\"impl-Debug-for-InvalidFrameId\"]Da[3173,13,3174,1393,4466,1873,0,\"impl-Display-for-InvalidFrameId\"]Cm[3173,13,3174,1393,3310,1873,0,\"impl-Display-for-MaybeFrame\"]Ck[3173,13,3174,1393,3310,1191,0,\"impl-Debug-for-MaybeFrame\"]Cm[3173,13,3174,1393,3332,1873,0,\"impl-Display-for-StreamInfo\"]Ck[3173,13,3174,1393,3332,1191,0,\"impl-Debug-for-StreamInfo\"]Co[3173,13,3174,1393,4205,1873,0,\"impl-Display-for-DatagramInfo\"]Cm[3173,13,3174,1393,4205,1191,0,\"impl-Debug-for-DatagramInfo\"]D`[3173,13,3174,1393,4582,1191,0,\"impl-Debug-for-ConnectionClose\"]Db[3173,13,3174,1393,4582,1873,0,\"impl-Display-for-ConnectionClose\"]Dc[3173,13,3174,1393,4789,1873,0,\"impl-Display-for-ApplicationClose\"]Da[3173,13,3174,1393,4789,1191,0,\"impl-Debug-for-ApplicationClose\"]Ck[3173,13,3174,1393,2302,1873,0,\"impl-Display-for-Datagram\"]Ci[3173,13,3174,1393,2302,1191,0,\"impl-Debug-for-Datagram\"]Ao[3173,13,3174,2354,4793,1191,0]Ao[3173,13,3174,2354,2313,1191,0]Cm[3173,13,3174,2354,4201,1191,0,\"impl-Debug-for-ConnectError\"]Co[3173,13,3174,2354,4201,1873,0,\"impl-Display-for-ConnectError\"]Ao[3173,13,3174,2354,4045,1191,0]Cm[3173,13,3174,2354,3326,1873,0,\"impl-Display-for-RetryError\"]Ck[3173,13,3174,2354,3326,1191,0,\"impl-Debug-for-RetryError\"]Ao[3173,13,3174,1798,4369,1191,0]Ao[3173,13,3174,1798,4596,1191,0]Ao[3173,13,3174,1798,5160,1191,0]Ao[3173,13,3174,1798,2316,1191,0]Dd[3173,13,3174,1798,4894,1873,0,\"impl-Display-for-PacketDecodeError\"]Db[3173,13,3174,1798,4894,1191,0,\"impl-Debug-for-PacketDecodeError\"]Ao[3173,13,3174,1829,4586,1191,0]Ao[3173,13,3174,1829,4346,1191,0]Cm[3173,13,3174,1829,4204,1191,0,\"impl-Debug-for-ConnectionId\"]Co[3173,13,3174,1829,4204,1873,0,\"impl-Display-for-ConnectionId\"]Ao[3173,13,3174,1829,4209,1191,0]Ce[3173,13,3174,0,4489,1873,0,\"impl-Display-for-Error\"]Cc[3173,13,3174,0,4489,1191,0,\"impl-Debug-for-Error\"]Cd[3173,13,3174,0,4960,1873,0,\"impl-Display-for-Code\"]Cb[3173,13,3174,0,4960,1191,0,\"impl-Debug-for-Code\"]Ao[3173,13,3174,4387,3307,1191,0]Ao[3173,13,3174,4387,5262,1191,0]Ao[3173,13,3174,4995,4822,1191,0]An[3173,13,3174,3174,527,1191,0]Cc[3173,13,3174,3174,134,1191,0,\"impl-Debug-for-Dir\"]Ce[3173,13,3174,3174,134,1873,0,\"impl-Display-for-Dir\"]Ci[3173,13,3174,3174,2331,1191,0,\"impl-Debug-for-StreamId\"]Ck[3173,13,3174,3174,2331,1873,0,\"impl-Display-for-StreamId\"]Ao[3173,13,3174,3174,2341,1191,0]Cl[3173,13,3174,3174,3098,1873,0,\"impl-Display-for-FourTuple\"]Cj[3173,13,3174,3174,3098,1191,0,\"impl-Debug-for-FourTuple\"]D`[3173,13,1731,1731,4380,1873,0,\"impl-Display-for-UnexpectedEnd\"]Cn[3173,13,1731,1731,4380,1191,0,\"impl-Debug-for-UnexpectedEnd\"]Ao[3173,13,5111,5111,5007,1191,0]Cf[3173,13,5111,5111,1203,1191,0,\"impl-Debug-for-Error\"]Ch[3173,13,5111,5111,1203,1873,0,\"impl-Display-for-Error\"]Ao[3173,13,1736,1736,5224,1191,0]Ao[3173,13,1736,1736,4054,1191,0]Ao[3173,13,1736,1736,4966,1191,0]Ce[3173,13,1819,0,1202,1873,0,\"impl-Display-for-Error\"]Cc[3173,13,1819,0,1202,1191,0,\"impl-Debug-for-Error\"]De[3173,13,1819,1819,5064,1191,0,\"impl-Debug-for-NoInitialCipherSuite\"]Dg[3173,13,1819,1819,5064,1873,0,\"impl-Display-for-NoInitialCipherSuite\"]Am[3173,13,3736,535,502,1191,0]An[3173,13,3736,535,3287,1191,0]Ao[3173,13,3736,1389,1189,1191,0]Ao[3173,13,3736,1389,4056,1191,0]Ao[3173,13,3736,2408,1887,1191,0]Ao[3173,13,3736,2408,4367,1191,0]Cf[3173,13,4853,4853,1204,1191,0,\"impl-Debug-for-Error\"]Ch[3173,13,4853,4853,1204,1873,0,\"impl-Display-for-Error\"]Ao[3173,13,4853,4853,1207,1191,0]An[2029,13,2030,431,4490,1191,0]Ao[2029,13,2030,2030,2328,1191,0]Ao[2029,13,2030,2030,2342,1191,0]Ao[2029,13,2030,2030,4210,1191,0]Aj[477,13,478,4270,5065,0,0]Al[3173,13,3174,1403,4238,0,0]Ag[477,14,478,0,2343,0,0]Al[3173,14,3174,1418,2344,0,0]Al[3173,13,3174,1798,4369,0,0]Al[3173,14,3174,1798,5160,0,0]Ah[3173,14,4595,0,516,0,0]Al[2029,14,2030,2030,2328,0,0]Ag[477,13,478,0,5126,0,0]Al[3173,13,3174,1733,5127,0,0]8Al[1228,13,1417,1417,4486,0,0]Al[4088,13,4089,4089,5161,0,0]Ag[477,13,478,0,4338,0,0]Aj[477,13,478,2353,2308,0,0]Ag[477,13,478,0,3319,0,0]Ag[477,13,478,0,4597,0,0]Ag[477,13,478,0,4460,0,0]Ag[477,13,478,0,4242,0,0]Ag[477,13,478,0,4188,0,0]Ag[477,13,478,0,4203,0,0]Ag[477,13,478,0,4821,0,0]Ag[477,13,478,0,2330,0,0]Ag[477,13,478,0,3097,0,0]Ah[477,13,3735,0,1188,0,0]Ah[477,13,3735,0,1886,0,0]Al[3173,13,3174,4616,4339,0,0]Al[3173,13,3174,1148,3320,0,0]Al[3173,13,3174,2354,2309,0,0]Al[3173,13,3174,1798,5288,0,0]Al[3173,13,3174,4387,5257,0,0]Al[3173,13,3174,1148,4598,0,0]Al[3173,13,3174,1733,4461,0,0]Al[3173,13,3174,1733,4244,0,0]Al[3173,13,3174,1733,4190,0,0]Al[3173,13,3174,1798,4369,0,0]Al[3173,13,3174,1829,4204,0,0]Ai[3173,13,3174,0,4489,0,0]Al[3173,13,3174,4387,5262,0,0]Al[3173,13,3174,4995,4822,0,0]Al[3173,13,3174,3174,2331,0,0]Al[3173,13,3174,3174,3098,0,0]Al[3173,13,3736,1389,1189,0,0]Al[3173,13,3736,2408,1887,0,0]Ak[2029,13,2030,431,4490,0,0]Al[1127,13,4305,4305,5209,0,0]Al[1127,13,4305,4305,5210,0,0]Aa[477,3,0,0,0,0,0]Ah[477,13,478,0,526,140,0]Am[3173,13,3174,3174,527,140,0]Ag[477,12,478,0,3335,0,0]Aj[477,13,478,2036,1898,0,0]0Am[477,13,478,1431,4249,1898,0]Aj[477,13,478,0,4378,3335,0]Al[3173,12,3174,1733,3336,0,0]Ao[3173,13,3174,1733,4379,3336,0]Aj[477,13,478,3740,3297,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,13,3174,3741,3298,0,0]Al[3173,14,3174,1418,3119,0,0]Ae[1127,7,1725,0,0,0,0]Ae[1127,7,1824,0,0,0,0]Ac[477,4,478,0,0,0,0]Af[477,5,3735,535,0,0,0]Ag[3173,5,3736,535,0,0,0]Al[1127,15,1128,1128,4999,0,0]Ag[477,15,478,0,4208,0,0]Al[3173,15,3174,1829,4209,0,0]Al[2029,15,2030,2030,4210,0,0]210Ag[477,5,1735,1736,0,0,0]Ae[3173,5,1736,0,0,0,0]Al[3173,15,3174,1798,4596,0,0]Al[3173,15,3174,1393,3310,0,0]Af[477,5,478,1126,0,0,0]Al[3173,15,3174,3741,1206,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Aj[477,15,478,4157,4484,0,0]Af[477,6,478,3174,0,0,0]Ae[3173,6,3174,0,0,0,0]Ag[477,19,478,0,1463,0,0]Al[3173,19,3174,1403,1464,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ah[477,14,3114,0,4224,0,0]Ai[3173,14,3115,0,4225,0,0]Al[2029,14,2030,2030,2328,0,0]Aa[536,3,0,0,0,0,0]Ai[3173,14,3174,0,4489,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Al[3173,14,3174,1393,2302,0,0]Al[477,13,478,3740,2323,504,0]Al[477,13,478,2385,2312,504,0]Ak[477,13,478,1126,520,504,0]Al[477,13,478,1126,4491,504,0]Al[477,13,478,4157,3322,504,0]Al[477,13,478,4162,3328,504,0]An[3173,13,3174,1152,1446,504,0]Am[1228,13,1229,1229,141,511,0]An[1228,13,1229,1229,4075,511,0]An[1228,13,1229,1229,4047,511,0]An[1228,13,1417,1417,4083,511,0]An[1228,13,1417,1417,1221,511,0]An[1228,13,1417,1417,4486,511,0]Ak[536,13,537,537,4048,511,0]An[4088,13,4089,4089,5161,511,0]Al[477,13,478,3740,4611,511,0]Al[477,13,478,3740,2323,511,0]Ai[477,13,478,0,4338,511,0]Al[477,13,478,4270,5065,511,0]Al[477,13,478,1126,2324,511,0]Al[477,13,478,1126,4785,511,0]Al[477,13,478,3740,3295,511,0]Al[477,13,478,3740,3297,511,0]Al[477,13,478,3740,1889,511,0]Al[477,13,478,3740,1459,511,0]Al[477,13,478,3740,3076,511,0]Al[477,13,478,3740,2296,511,0]Al[477,13,478,3740,4232,511,0]Al[477,13,478,3740,4239,511,0]Al[477,13,478,3740,1450,511,0]Al[477,13,478,3740,5072,511,0]Al[477,13,478,3740,4898,511,0]0Al[477,13,478,2353,2308,511,0]Al[477,13,478,2353,4347,511,0]Al[477,13,478,2353,1437,511,0]Al[477,13,478,4270,1458,511,0]Al[477,13,478,4270,3316,511,0]Al[477,13,478,4270,5000,511,0]Al[477,13,478,2385,2312,511,0]Al[477,13,478,2385,3325,511,0]Al[477,13,478,2385,4465,511,0]Ak[477,13,478,1126,520,511,0]Al[477,13,478,1126,4491,511,0]Al[477,13,478,4157,3322,511,0]Al[477,13,478,4157,5008,511,0]Al[477,13,478,4157,4484,511,0]0Df[477,13,478,4157,3121,511,0,\"impl-From%3CResetError%3E-for-ReadError\"]Al[477,13,478,4157,3121,511,0]Dk[477,13,478,4157,3121,511,0,\"impl-From%3CConnectionError%3E-for-ReadError\"]Al[477,13,478,4157,3324,511,0]0Al[477,13,478,4157,4483,511,0]0Al[477,13,478,1431,4249,511,0]Al[477,13,478,1169,4078,511,0]Al[477,13,478,4162,3328,511,0]Di[477,13,478,4162,3342,511,0,\"impl-From%3CClosedStream%3E-for-WriteError\"]Di[477,13,478,4162,3342,511,0,\"impl-From%3CStoppedError%3E-for-WriteError\"]Dl[477,13,478,4162,3342,511,0,\"impl-From%3CConnectionError%3E-for-WriteError\"]Al[477,13,478,4162,3342,511,0]Al[477,13,478,4162,4248,511,0]0Al[477,13,478,4162,1903,511,0]Ai[477,13,478,0,3319,511,0]Ai[477,13,478,0,4378,511,0]Ai[477,13,478,0,4795,511,0]Ai[477,13,478,0,4603,511,0]Ai[477,13,478,0,4222,511,0]Ai[477,13,478,0,4474,511,0]Cn[477,13,478,0,1480,511,0,\"impl-From%3CStreamId%3E-for-VarInt\"]Dh[477,13,478,0,1480,511,0,\"impl-From%3CTransportErrorCode%3E-for-VarInt\"]Ci[477,13,478,0,1480,511,0,\"impl-From%3Cu32%3E-for-VarInt\"]Ci[477,13,478,0,1480,511,0,\"impl-From%3Cu16%3E-for-VarInt\"]Ch[477,13,478,0,1480,511,0,\"impl-From%3Cu8%3E-for-VarInt\"]Ai[477,13,478,0,1480,511,0]Ai[477,13,478,0,5069,511,0]Ai[477,13,478,0,1184,511,0]Ai[477,13,478,0,1463,511,0]0Ai[477,13,478,0,3317,511,0]Ai[477,13,478,0,3116,511,0]Ai[477,13,478,0,4954,511,0]Ai[477,13,478,0,3290,511,0]Ai[477,13,478,0,2343,511,0]Ai[477,13,478,0,3303,511,0]Ai[477,13,478,0,3118,511,0]Ai[477,13,478,0,4587,511,0]Ai[477,13,478,0,4194,511,0]Dj[477,13,478,0,4583,511,0,\"impl-From%3CCloseReason%3E-for-ConnectionError\"]Ai[477,13,478,0,4583,511,0]Dd[477,13,478,0,4583,511,0,\"impl-From%3CClose%3E-for-ConnectionError\"]Dm[477,13,478,0,4583,511,0,\"impl-From%3CTransportError%3E-for-ConnectionError\"]Ai[477,13,478,0,3112,511,0]Ai[477,13,478,0,4450,511,0]Ai[477,13,478,0,4597,511,0]Ai[477,13,478,0,4606,511,0]Ai[477,13,478,0,4924,511,0]Ai[477,13,478,0,4939,511,0]Ai[477,13,478,0,4064,511,0]0Ai[477,13,478,0,4460,511,0]Ai[477,13,478,0,4242,511,0]Ai[477,13,478,0,5126,511,0]Ai[477,13,478,0,4188,511,0]Ai[477,13,478,0,4050,511,0]Dj[477,13,478,0,4050,511,0,\"impl-From%3CTryFromIntError%3E-for-ConfigError\"]Do[477,13,478,0,4050,511,0,\"impl-From%3CVarIntBoundsExceeded%3E-for-ConfigError\"]Ai[477,13,478,0,3099,511,0]Ai[477,13,478,0,4580,511,0]0Ai[477,13,478,0,4787,511,0]Ai[477,13,478,0,4200,511,0]0Ai[477,13,478,0,4203,511,0]Ai[477,13,478,0,4208,511,0]Ai[477,13,478,0,4959,511,0]0Ai[477,13,478,0,3306,511,0]Ai[477,13,478,0,4821,511,0]Ah[477,13,478,0,526,511,0]Ah[477,13,478,0,133,511,0]Ai[477,13,478,0,2330,511,0]0Ai[477,13,478,0,2340,511,0]Ai[477,13,478,0,3097,511,0]0Ai[477,13,3735,0,501,511,0]Aj[477,13,3735,0,3286,511,0]Aj[477,13,3735,0,1188,511,0]Aj[477,13,3735,0,4055,511,0]Aj[477,13,3735,0,1886,511,0]Aj[477,13,3735,0,4366,511,0]Aj[477,13,3735,0,4885,511,0]Aj[477,13,1735,0,1881,511,0]Ai[477,13,1735,0,514,511,0]Aj[477,13,1735,0,5223,511,0]Aj[477,13,1735,0,4053,511,0]Aj[477,13,1735,0,4963,511,0]Aj[477,13,1818,0,3337,511,0]Aj[477,13,1818,0,4349,511,0]Aj[477,13,1818,0,1201,511,0]Dd[477,13,1818,0,1201,511,0,\"impl-From%3CPeerMisbehaved%3E-for-Error\"]D`[477,13,1818,0,1201,511,0,\"impl-From%3COtherError%3E-for-Error\"]De[477,13,1818,0,1201,511,0,\"impl-From%3CGetRandomFailed%3E-for-Error\"]De[477,13,1818,0,1201,511,0,\"impl-From%3CSystemTimeError%3E-for-Error\"]Do[477,13,1818,0,1201,511,0,\"impl-From%3CEncryptedClientHelloError%3E-for-Error\"]Dm[477,13,1818,0,1201,511,0,\"impl-From%3CCertRevocationListError%3E-for-Error\"]Df[477,13,1818,0,1201,511,0,\"impl-From%3CCertificateError%3E-for-Error\"]Do[477,13,1818,0,1201,511,0,\"impl-From%3CUnsupportedOperationError%3E-for-Error\"]Df[477,13,1818,0,1201,511,0,\"impl-From%3CInconsistentKeys%3E-for-Error\"]Df[477,13,1818,0,1201,511,0,\"impl-From%3CPeerIncompatible%3E-for-Error\"]Dd[477,13,1818,0,1201,511,0,\"impl-From%3CInvalidMessage%3E-for-Error\"]Aj[477,13,1818,0,4817,511,0]Aj[477,13,1818,0,5063,511,0]Aj[477,13,1818,0,4819,511,0]Am[2408,13,2409,2409,132,511,0]An[2408,13,2409,2409,2299,511,0]An[3173,13,3174,4616,4339,511,0]An[3173,13,3174,3147,3089,511,0]An[3173,13,3174,1152,1446,511,0]An[3173,13,3174,2044,1907,511,0]An[3173,13,3174,2044,3323,511,0]An[3173,13,3174,2044,3329,511,0]An[3173,13,3174,3741,3298,511,0]An[3173,13,3174,1148,3320,511,0]An[3173,13,3174,1733,4379,511,0]An[3173,13,3174,2354,2309,511,0]An[3173,13,3174,2354,4345,511,0]An[3173,13,3174,2354,4796,511,0]An[3173,13,3174,2354,4357,511,0]An[3173,13,3174,1798,5288,511,0]An[3173,13,3174,4387,5257,511,0]An[3173,13,3174,1430,4604,511,0]An[3173,13,3174,1430,4223,511,0]An[3173,13,3174,1430,4475,511,0]Co[3173,13,3174,1856,1481,511,0,\"impl-From%3CCode%3E-for-VarInt\"]Cm[3173,13,3174,1856,1481,511,0,\"impl-From%3Cu8%3E-for-VarInt\"]Cn[3173,13,3174,1856,1481,511,0,\"impl-From%3Cu16%3E-for-VarInt\"]Cn[3173,13,3174,1856,1481,511,0,\"impl-From%3Cu32%3E-for-VarInt\"]Dc[3173,13,3174,1856,1481,511,0,\"impl-From%3CStreamId%3E-for-VarInt\"]An[3173,13,3174,1856,1481,511,0]An[3173,13,3174,1856,5070,511,0]An[3173,13,3174,3138,1185,511,0]An[3173,13,3174,3147,4899,511,0]An[3173,13,3174,1403,1464,511,0]0An[3173,13,3174,1403,4238,511,0]An[3173,13,3174,1403,3318,511,0]An[3173,13,3174,1403,3117,511,0]An[3173,13,3174,1403,4897,511,0]An[3173,13,3174,1403,4955,511,0]An[3173,13,3174,1403,3293,511,0]An[3173,13,3174,1418,2344,511,0]An[3173,13,3174,1418,3304,511,0]An[3173,13,3174,1418,3119,511,0]An[3173,13,3174,1418,4588,511,0]An[3173,13,3174,1152,3122,511,0]An[3173,13,3174,1152,4374,511,0]An[3173,13,3174,1157,3343,511,0]An[3173,13,3174,1157,4063,511,0]An[3173,13,3174,2044,4082,511,0]An[3173,13,3174,2044,4485,511,0]An[3173,13,3174,2044,4198,511,0]An[3173,13,3174,3741,4584,511,0]0An[3173,13,3174,3741,3113,511,0]An[3173,13,3174,3741,4451,511,0]An[3173,13,3174,3741,5157,511,0]An[3173,13,3174,3741,1206,511,0]0An[3173,13,3174,1148,4598,511,0]An[3173,13,3174,3276,4607,511,0]An[3173,13,3174,3276,4925,511,0]An[3173,13,3174,3276,4940,511,0]An[3173,13,3174,3276,4065,511,0]0An[3173,13,3174,1733,4461,511,0]An[3173,13,3174,1733,4244,511,0]An[3173,13,3174,1733,5127,511,0]An[3173,13,3174,1733,4190,511,0]Do[3173,13,3174,1733,4051,511,0,\"impl-From%3CTryFromIntError%3E-for-ConfigError\"]An[3173,13,3174,1733,4051,511,0]Ed[3173,13,3174,1733,4051,511,0,\"impl-From%3CVarIntBoundsExceeded%3E-for-ConfigError\"]An[3173,13,3174,1393,3100,511,0]An[3173,13,3174,1393,4466,511,0]An[3173,13,3174,1393,3310,511,0]An[3173,13,3174,1393,3332,511,0]An[3173,13,3174,1393,4205,511,0]An[3173,13,3174,1393,4582,511,0]0An[3173,13,3174,1393,4789,511,0]An[3173,13,3174,1393,2302,511,0]An[3173,13,3174,2354,4793,511,0]An[3173,13,3174,2354,2313,511,0]An[3173,13,3174,2354,4201,511,0]0An[3173,13,3174,2354,4045,511,0]An[3173,13,3174,2354,3326,511,0]An[3173,13,3174,1798,4369,511,0]An[3173,13,3174,1798,4596,511,0]An[3173,13,3174,1798,5160,511,0]An[3173,13,3174,1798,2316,511,0]An[3173,13,3174,1798,4894,511,0]0An[3173,13,3174,1829,4586,511,0]An[3173,13,3174,1829,4346,511,0]An[3173,13,3174,1829,4204,511,0]An[3173,13,3174,1829,4209,511,0]Ak[3173,13,3174,0,4489,511,0]0Ak[3173,13,3174,0,4960,511,0]0An[3173,13,3174,4387,3307,511,0]An[3173,13,3174,4387,5262,511,0]An[3173,13,3174,4995,4822,511,0]Am[3173,13,3174,3174,527,511,0]Am[3173,13,3174,3174,134,511,0]An[3173,13,3174,3174,2331,511,0]0An[3173,13,3174,3174,2341,511,0]An[3173,13,3174,3174,3098,511,0]0An[3173,13,1731,1731,4380,511,0]An[3173,13,5111,5111,5007,511,0]An[3173,13,5111,5111,1203,511,0]0An[3173,13,1736,1736,1882,511,0]Am[3173,13,1736,1736,515,511,0]An[3173,13,1736,1736,5224,511,0]An[3173,13,1736,1736,4054,511,0]An[3173,13,1736,1736,4966,511,0]An[3173,13,1819,1819,3338,511,0]An[3173,13,1819,1819,4350,511,0]E`[3173,13,1819,0,1202,511,0,\"impl-From%3CUnsupportedOperationError%3E-for-Error\"]Dg[3173,13,1819,0,1202,511,0,\"impl-From%3CCertificateError%3E-for-Error\"]Ak[3173,13,1819,0,1202,511,0]Dg[3173,13,1819,0,1202,511,0,\"impl-From%3CInconsistentKeys%3E-for-Error\"]De[3173,13,1819,0,1202,511,0,\"impl-From%3CInvalidMessage%3E-for-Error\"]De[3173,13,1819,0,1202,511,0,\"impl-From%3CPeerMisbehaved%3E-for-Error\"]Df[3173,13,1819,0,1202,511,0,\"impl-From%3CGetRandomFailed%3E-for-Error\"]Df[3173,13,1819,0,1202,511,0,\"impl-From%3CSystemTimeError%3E-for-Error\"]E`[3173,13,1819,0,1202,511,0,\"impl-From%3CEncryptedClientHelloError%3E-for-Error\"]Dn[3173,13,1819,0,1202,511,0,\"impl-From%3CCertRevocationListError%3E-for-Error\"]Dg[3173,13,1819,0,1202,511,0,\"impl-From%3CPeerIncompatible%3E-for-Error\"]Da[3173,13,1819,0,1202,511,0,\"impl-From%3COtherError%3E-for-Error\"]An[3173,13,1819,1819,4818,511,0]An[3173,13,1819,1819,5064,511,0]An[3173,13,1819,1819,4820,511,0]Al[3173,13,3736,535,502,511,0]Am[3173,13,3736,535,3287,511,0]An[3173,13,3736,1389,1189,511,0]An[3173,13,3736,1389,4056,511,0]An[3173,13,3736,2408,1887,511,0]An[3173,13,3736,2408,4367,511,0]An[3173,13,3736,3736,4886,511,0]An[3173,13,4853,4853,1204,511,0]An[3173,13,4853,4853,1207,511,0]An[2029,13,2030,2030,3341,511,0]0Am[2029,13,2030,431,4490,511,0]An[2029,13,2030,2030,2328,511,0]An[2029,13,2030,2030,2342,511,0]An[2029,13,2030,2030,4210,511,0]An[1127,13,1128,1128,3086,511,0]An[1127,13,1128,1128,4999,511,0]Am[1127,13,1725,1725,142,511,0]An[1127,13,1419,1419,1222,511,0]An[1127,13,1419,1419,4084,511,0]An[1127,13,1419,1419,4592,511,0]An[1127,13,4305,4305,5209,511,0]An[1127,13,4305,4305,5210,511,0]Am[1127,13,1824,1824,143,511,0]Ai[477,13,478,0,1480,512,0]Ai[477,13,478,0,1463,512,0]Ai[477,13,478,0,4064,512,0]Ai[477,13,478,0,4203,512,0]Ah[477,13,478,0,526,512,0]Ah[477,13,478,0,133,512,0]Ai[477,13,478,0,2330,512,0]Ai[477,13,478,0,3097,512,0]An[3173,13,3174,1856,1481,512,0]An[3173,13,3174,3147,4899,512,0]An[3173,13,3174,1403,1464,512,0]An[3173,13,3174,1152,3122,512,0]An[3173,13,3174,1152,4374,512,0]An[3173,13,3174,1157,3343,512,0]An[3173,13,3174,3276,4065,512,0]An[3173,13,3174,2354,4793,512,0]An[3173,13,3174,1798,4894,512,0]An[3173,13,3174,1829,4204,512,0]Am[3173,13,3174,3174,527,512,0]Am[3173,13,3174,3174,134,512,0]An[3173,13,3174,3174,2331,512,0]An[3173,13,3174,3174,3098,512,0]Am[1228,13,1229,1229,141,513,0]An[1228,13,1229,1229,4075,513,0]An[1228,13,1229,1229,4047,513,0]An[1228,13,1417,1417,4083,513,0]An[1228,13,1417,1417,1221,513,0]An[1228,13,1417,1417,4486,513,0]Ak[536,13,537,537,4048,513,0]An[4088,13,4089,4089,5161,513,0]Al[477,13,478,3740,4611,513,0]Al[477,13,478,3740,2323,513,0]Ai[477,13,478,0,4338,513,0]Al[477,13,478,4270,5065,513,0]Al[477,13,478,1126,2324,513,0]Al[477,13,478,1126,4785,513,0]Al[477,13,478,3740,3295,513,0]Al[477,13,478,3740,3297,513,0]Al[477,13,478,3740,1889,513,0]Al[477,13,478,3740,1459,513,0]Al[477,13,478,3740,3076,513,0]Al[477,13,478,3740,2296,513,0]Al[477,13,478,3740,4232,513,0]Al[477,13,478,3740,4239,513,0]Al[477,13,478,3740,1450,513,0]Al[477,13,478,3740,5072,513,0]Al[477,13,478,3740,4898,513,0]Al[477,13,478,2353,2308,513,0]Al[477,13,478,2353,4347,513,0]Al[477,13,478,2353,1437,513,0]Al[477,13,478,4270,1458,513,0]Al[477,13,478,4270,3316,513,0]Al[477,13,478,4270,5000,513,0]Al[477,13,478,2385,2312,513,0]Al[477,13,478,2385,3325,513,0]Al[477,13,478,2385,4465,513,0]Ak[477,13,478,1126,520,513,0]Al[477,13,478,1126,4491,513,0]Al[477,13,478,4157,3322,513,0]Al[477,13,478,4157,5008,513,0]Al[477,13,478,4157,4484,513,0]Al[477,13,478,4157,3121,513,0]Al[477,13,478,4157,3324,513,0]Al[477,13,478,4157,4483,513,0]Al[477,13,478,1431,4249,513,0]Al[477,13,478,1169,4078,513,0]Al[477,13,478,4162,3328,513,0]Al[477,13,478,4162,3342,513,0]Al[477,13,478,4162,4248,513,0]Al[477,13,478,4162,1903,513,0]Ai[477,13,478,0,3319,513,0]Ai[477,13,478,0,4378,513,0]Ai[477,13,478,0,4795,513,0]Ai[477,13,478,0,4603,513,0]Ai[477,13,478,0,4222,513,0]Ai[477,13,478,0,4474,513,0]Ai[477,13,478,0,1480,513,0]Ai[477,13,478,0,5069,513,0]Ai[477,13,478,0,1184,513,0]Ai[477,13,478,0,1463,513,0]Ai[477,13,478,0,3317,513,0]Ai[477,13,478,0,3116,513,0]Ai[477,13,478,0,4954,513,0]Ai[477,13,478,0,3290,513,0]Ai[477,13,478,0,2343,513,0]Ai[477,13,478,0,3303,513,0]Ai[477,13,478,0,3118,513,0]Ai[477,13,478,0,4587,513,0]Ai[477,13,478,0,4194,513,0]Ai[477,13,478,0,4583,513,0]Ai[477,13,478,0,3112,513,0]Ai[477,13,478,0,4450,513,0]Ai[477,13,478,0,4597,513,0]Ai[477,13,478,0,4606,513,0]Ai[477,13,478,0,4924,513,0]Ai[477,13,478,0,4939,513,0]Ai[477,13,478,0,4064,513,0]Ai[477,13,478,0,4460,513,0]Ai[477,13,478,0,4242,513,0]Ai[477,13,478,0,5126,513,0]Ai[477,13,478,0,4188,513,0]Ai[477,13,478,0,4050,513,0]Ai[477,13,478,0,3099,513,0]Ai[477,13,478,0,4580,513,0]Ai[477,13,478,0,4787,513,0]Ai[477,13,478,0,4200,513,0]Ai[477,13,478,0,4203,513,0]Ai[477,13,478,0,4208,513,0]Ai[477,13,478,0,4959,513,0]Ai[477,13,478,0,3306,513,0]Ai[477,13,478,0,4821,513,0]Ah[477,13,478,0,526,513,0]Ah[477,13,478,0,133,513,0]Ai[477,13,478,0,2330,513,0]Ai[477,13,478,0,2340,513,0]Ai[477,13,478,0,3097,513,0]Ai[477,13,3735,0,501,513,0]Aj[477,13,3735,0,3286,513,0]Aj[477,13,3735,0,1188,513,0]Aj[477,13,3735,0,4055,513,0]Aj[477,13,3735,0,1886,513,0]Aj[477,13,3735,0,4366,513,0]Aj[477,13,3735,0,4885,513,0]Aj[477,13,1735,0,1881,513,0]Ai[477,13,1735,0,514,513,0]Aj[477,13,1735,0,5223,513,0]Aj[477,13,1735,0,4053,513,0]Aj[477,13,1735,0,4963,513,0]Aj[477,13,1818,0,3337,513,0]Aj[477,13,1818,0,4349,513,0]Aj[477,13,1818,0,1201,513,0]Aj[477,13,1818,0,4817,513,0]Aj[477,13,1818,0,5063,513,0]Aj[477,13,1818,0,4819,513,0]Am[2408,13,2409,2409,132,513,0]An[2408,13,2409,2409,2299,513,0]An[3173,13,3174,4616,4339,513,0]An[3173,13,3174,3147,3089,513,0]An[3173,13,3174,1152,1446,513,0]An[3173,13,3174,2044,1907,513,0]An[3173,13,3174,2044,3323,513,0]An[3173,13,3174,2044,3329,513,0]An[3173,13,3174,3741,3298,513,0]An[3173,13,3174,1148,3320,513,0]An[3173,13,3174,1733,4379,513,0]An[3173,13,3174,2354,2309,513,0]An[3173,13,3174,2354,4345,513,0]An[3173,13,3174,2354,4796,513,0]An[3173,13,3174,2354,4357,513,0]An[3173,13,3174,1798,5288,513,0]An[3173,13,3174,4387,5257,513,0]An[3173,13,3174,1430,4604,513,0]An[3173,13,3174,1430,4223,513,0]An[3173,13,3174,1430,4475,513,0]An[3173,13,3174,1856,1481,513,0]An[3173,13,3174,1856,5070,513,0]An[3173,13,3174,3138,1185,513,0]An[3173,13,3174,3147,4899,513,0]An[3173,13,3174,1403,1464,513,0]An[3173,13,3174,1403,4238,513,0]An[3173,13,3174,1403,3318,513,0]An[3173,13,3174,1403,3117,513,0]An[3173,13,3174,1403,4897,513,0]An[3173,13,3174,1403,4955,513,0]An[3173,13,3174,1403,3293,513,0]An[3173,13,3174,1418,2344,513,0]An[3173,13,3174,1418,3304,513,0]An[3173,13,3174,1418,3119,513,0]An[3173,13,3174,1418,4588,513,0]An[3173,13,3174,1152,3122,513,0]An[3173,13,3174,1152,4374,513,0]An[3173,13,3174,1157,3343,513,0]An[3173,13,3174,1157,4063,513,0]An[3173,13,3174,2044,4082,513,0]An[3173,13,3174,2044,4485,513,0]An[3173,13,3174,2044,4198,513,0]An[3173,13,3174,3741,4584,513,0]An[3173,13,3174,3741,3113,513,0]An[3173,13,3174,3741,4451,513,0]An[3173,13,3174,3741,5157,513,0]An[3173,13,3174,3741,1206,513,0]An[3173,13,3174,1148,4598,513,0]An[3173,13,3174,3276,4607,513,0]An[3173,13,3174,3276,4925,513,0]An[3173,13,3174,3276,4940,513,0]An[3173,13,3174,3276,4065,513,0]An[3173,13,3174,1733,4461,513,0]An[3173,13,3174,1733,4244,513,0]An[3173,13,3174,1733,5127,513,0]An[3173,13,3174,1733,4190,513,0]An[3173,13,3174,1733,4051,513,0]An[3173,13,3174,1393,3100,513,0]An[3173,13,3174,1393,4466,513,0]An[3173,13,3174,1393,3310,513,0]An[3173,13,3174,1393,3332,513,0]An[3173,13,3174,1393,4205,513,0]An[3173,13,3174,1393,4582,513,0]An[3173,13,3174,1393,4789,513,0]An[3173,13,3174,1393,2302,513,0]An[3173,13,3174,2354,4793,513,0]An[3173,13,3174,2354,2313,513,0]An[3173,13,3174,2354,4201,513,0]An[3173,13,3174,2354,4045,513,0]An[3173,13,3174,2354,3326,513,0]An[3173,13,3174,1798,4369,513,0]An[3173,13,3174,1798,4596,513,0]An[3173,13,3174,1798,5160,513,0]An[3173,13,3174,1798,2316,513,0]An[3173,13,3174,1798,4894,513,0]An[3173,13,3174,1829,4586,513,0]An[3173,13,3174,1829,4346,513,0]An[3173,13,3174,1829,4204,513,0]An[3173,13,3174,1829,4209,513,0]Ak[3173,13,3174,0,4489,513,0]Ak[3173,13,3174,0,4960,513,0]An[3173,13,3174,4387,3307,513,0]An[3173,13,3174,4387,5262,513,0]An[3173,13,3174,4995,4822,513,0]Am[3173,13,3174,3174,527,513,0]Am[3173,13,3174,3174,134,513,0]An[3173,13,3174,3174,2331,513,0]An[3173,13,3174,3174,2341,513,0]An[3173,13,3174,3174,3098,513,0]An[3173,13,1731,1731,4380,513,0]An[3173,13,5111,5111,5007,513,0]An[3173,13,5111,5111,1203,513,0]An[3173,13,1736,1736,1882,513,0]Am[3173,13,1736,1736,515,513,0]An[3173,13,1736,1736,5224,513,0]An[3173,13,1736,1736,4054,513,0]An[3173,13,1736,1736,4966,513,0]An[3173,13,1819,1819,3338,513,0]An[3173,13,1819,1819,4350,513,0]Ak[3173,13,1819,0,1202,513,0]An[3173,13,1819,1819,4818,513,0]An[3173,13,1819,1819,5064,513,0]An[3173,13,1819,1819,4820,513,0]Al[3173,13,3736,535,502,513,0]Am[3173,13,3736,535,3287,513,0]An[3173,13,3736,1389,1189,513,0]An[3173,13,3736,1389,4056,513,0]An[3173,13,3736,2408,1887,513,0]An[3173,13,3736,2408,4367,513,0]An[3173,13,3736,3736,4886,513,0]An[3173,13,4853,4853,1204,513,0]An[3173,13,4853,4853,1207,513,0]An[2029,13,2030,2030,3341,513,0]Am[2029,13,2030,431,4490,513,0]An[2029,13,2030,2030,2328,513,0]An[2029,13,2030,2030,2342,513,0]An[2029,13,2030,2030,4210,513,0]An[1127,13,1128,1128,3086,513,0]An[1127,13,1128,1128,4999,513,0]Am[1127,13,1725,1725,142,513,0]An[1127,13,1419,1419,1222,513,0]An[1127,13,1419,1419,4084,513,0]An[1127,13,1419,1419,4592,513,0]An[1127,13,4305,4305,5209,513,0]An[1127,13,4305,4305,5210,513,0]Am[1127,13,1824,1824,143,513,0]Ac[536,7,537,0,0,0,0]Ae[4088,7,4089,0,0,0,0]Ae[4390,7,4391,0,0,0,0]Ae[2408,7,2409,0,0,0,0]Ae[4917,7,4918,0,0,0,0]Al[3173,13,3174,1152,1446,0,0]Ao[3173,13,3174,2354,4357,2314,0]Ah[477,12,1735,0,4887,0,0]Al[3173,13,3174,2044,1907,0,0]Al[3173,12,1736,1736,4888,0,0]Aj[477,13,478,3740,3297,0,0]Ab[1127,3,0,0,0,0,0]Ai[477,13,478,1126,520,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,13,3174,3741,3298,0,0]Al[3173,14,3174,1418,3304,0,0]Aj[477,12,478,2036,3282,0,0]Am[477,13,478,3740,4611,1455,0]Am[477,13,478,3740,2323,1455,0]Am[477,13,478,1126,2324,1455,0]Am[477,13,478,3740,3295,1455,0]Am[477,13,478,3740,1889,1455,0]Am[477,13,478,3740,1459,1455,0]Am[477,13,478,3740,3076,1455,0]Am[477,13,478,3740,2296,1455,0]Am[477,13,478,3740,4232,1455,0]Am[477,13,478,3740,4239,1455,0]Am[477,13,478,2353,1437,1455,0]Am[477,13,478,2385,4465,1455,0]Am[477,13,478,4162,1903,1455,0]?Aj[477,13,478,4157,3322,0,0]Al[3173,13,3174,2044,3323,0,0]Al[3173,13,5111,5111,5007,0,0]Al[3173,13,3174,3147,3089,0,0]Ak[2029,13,2030,431,4490,0,0]Ah[477,12,1735,0,4887,0,0]Al[3173,12,1736,1736,4888,0,0]32Ag[477,13,478,0,5126,0,0]Al[3173,13,3174,1733,5127,0,0]Aj[477,13,478,3740,3297,0,0]Al[3173,13,3174,3741,3298,0,0]Ah[477,12,1735,0,1877,0,0]Al[3173,12,1736,1736,1878,0,0]Al[1228,14,1417,1417,4486,0,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Ai[3173,14,4595,0,1218,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5008,0,0]Al[3173,13,3174,2044,3323,0,0]Ag[477,12,478,0,3339,0,0]Aj[477,13,478,0,4474,3339,0]Aj[477,13,478,0,4821,3339,0]Al[3173,12,3174,1430,3340,0,0]Ao[3173,13,3174,1430,4475,3340,0]Ao[3173,13,3174,4995,4822,3340,0]Af[477,5,478,3138,0,0,0]Ah[3173,5,3174,3138,0,0,0]Ag[477,5,3735,1389,0,0,0]Ah[3173,5,3736,1389,0,0,0]Al[1127,15,1128,1128,4999,0,0]Ag[477,6,1818,1392,0,0,0]Ah[3173,6,1819,1392,0,0,0]Ae[3173,6,5111,0,0,0,0]Ae[3173,6,4853,0,0,0,0]Ah[3173,6,3174,3741,0,0,0]1Al[3173,15,3174,1393,3310,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Aj[477,15,478,4157,3121,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,1152,3122,0,0]Al[3173,15,3174,3741,4584,0,0]Al[3173,15,3174,1798,4596,0,0]0Ae[1228,5,1417,0,0,0,0]Ae[1127,5,1419,0,0,0,0]Al[1228,15,1229,1229,4075,0,0]Ag[477,13,478,0,4795,0,0]Al[3173,13,3174,2354,4796,0,0]Ab[1228,3,0,0,0,0,0]Ah[477,12,3735,0,4883,0,0]Ak[477,13,3735,0,3286,4883,0]Ak[477,13,3735,0,4055,4883,0]Ak[477,13,3735,0,4366,4883,0]Al[3173,12,3736,3736,4884,0,0]An[3173,13,3736,535,3287,4884,0]Ao[3173,13,3736,1389,4056,4884,0]Ao[3173,13,3736,2408,4367,4884,0]Al[1127,13,1128,1128,4999,0,0]Ag[477,14,478,0,1184,0,0]Ag[477,14,478,0,2343,0,0]Al[3173,14,3174,3138,1185,0,0]Al[3173,14,3174,1418,2344,0,0]Al[3173,14,3174,2354,4045,0,0]An[1228,13,1229,1229,141,1186,0]Ao[1228,13,1229,1229,4075,1186,0]Ao[1228,13,1229,1229,4047,1186,0]Am[477,13,478,3740,3297,1186,0]Am[477,13,478,3740,1450,1186,0]Am[477,13,478,3740,5072,1186,0]Am[477,13,478,3740,4898,1186,0]Am[477,13,478,2353,2308,1186,0]Am[477,13,478,2353,4347,1186,0]Am[477,13,478,4270,1458,1186,0]Al[477,13,478,1126,520,1186,0]Am[477,13,478,1126,4491,1186,0]Am[477,13,478,4157,4484,1186,0]Am[477,13,478,4157,3121,1186,0]Am[477,13,478,4157,3324,1186,0]Am[477,13,478,4157,4483,1186,0]Am[477,13,478,4162,3342,1186,0]Am[477,13,478,4162,4248,1186,0]Aj[477,13,478,0,1480,1186,0]Aj[477,13,478,0,5069,1186,0]Aj[477,13,478,0,1463,1186,0]Aj[477,13,478,0,3317,1186,0]Aj[477,13,478,0,3116,1186,0]Aj[477,13,478,0,4954,1186,0]Aj[477,13,478,0,3290,1186,0]Aj[477,13,478,0,2343,1186,0]Aj[477,13,478,0,3303,1186,0]Aj[477,13,478,0,3118,1186,0]Aj[477,13,478,0,4587,1186,0]Aj[477,13,478,0,4194,1186,0]Aj[477,13,478,0,4583,1186,0]Aj[477,13,478,0,3112,1186,0]Aj[477,13,478,0,4450,1186,0]Aj[477,13,478,0,4606,1186,0]Aj[477,13,478,0,4924,1186,0]Aj[477,13,478,0,4939,1186,0]Aj[477,13,478,0,4064,1186,0]Aj[477,13,478,0,4460,1186,0]Aj[477,13,478,0,4242,1186,0]Aj[477,13,478,0,5126,1186,0]Aj[477,13,478,0,4188,1186,0]Aj[477,13,478,0,4050,1186,0]Aj[477,13,478,0,3099,1186,0]Aj[477,13,478,0,4580,1186,0]Aj[477,13,478,0,4787,1186,0]Aj[477,13,478,0,4200,1186,0]Aj[477,13,478,0,4203,1186,0]Aj[477,13,478,0,4208,1186,0]Aj[477,13,478,0,4959,1186,0]Aj[477,13,478,0,3306,1186,0]Ai[477,13,478,0,526,1186,0]Ai[477,13,478,0,133,1186,0]Aj[477,13,478,0,2330,1186,0]Aj[477,13,478,0,3097,1186,0]Aj[477,13,3735,0,501,1186,0]Ak[477,13,3735,0,3286,1186,0]Ak[477,13,3735,0,1188,1186,0]Ak[477,13,3735,0,4055,1186,0]Ak[477,13,3735,0,1886,1186,0]Ak[477,13,3735,0,4366,1186,0]Ak[477,13,1818,0,1201,1186,0]Ak[477,13,1818,0,4817,1186,0]Ak[477,13,1818,0,5063,1186,0]Ak[477,13,1818,0,4819,1186,0]Ao[3173,13,3174,1856,1481,1186,0]Ao[3173,13,3174,1856,5070,1186,0]Ao[3173,13,3174,3147,4899,1186,0]Ao[3173,13,3174,1403,1464,1186,0]Ao[3173,13,3174,1403,4238,1186,0]Ao[3173,13,3174,1403,3318,1186,0]Ao[3173,13,3174,1403,3117,1186,0]Ao[3173,13,3174,1403,4897,1186,0]Ao[3173,13,3174,1403,4955,1186,0]Ao[3173,13,3174,1403,3293,1186,0]Ao[3173,13,3174,1418,2344,1186,0]Ao[3173,13,3174,1418,3304,1186,0]Ao[3173,13,3174,1418,3119,1186,0]Ao[3173,13,3174,1418,4588,1186,0]Ao[3173,13,3174,1152,3122,1186,0]Ao[3173,13,3174,1152,4374,1186,0]Ao[3173,13,3174,1157,3343,1186,0]Ao[3173,13,3174,1157,4063,1186,0]Ao[3173,13,3174,2044,4485,1186,0]Ao[3173,13,3174,2044,4198,1186,0]Ao[3173,13,3174,3741,4584,1186,0]Ao[3173,13,3174,3741,3113,1186,0]Ao[3173,13,3174,3741,4451,1186,0]Ao[3173,13,3174,3741,5157,1186,0]Ao[3173,13,3174,3276,4607,1186,0]Ao[3173,13,3174,3276,4925,1186,0]Ao[3173,13,3174,3276,4940,1186,0]Ao[3173,13,3174,3276,4065,1186,0]Ao[3173,13,3174,1733,4461,1186,0]Ao[3173,13,3174,1733,4244,1186,0]Ao[3173,13,3174,1733,5127,1186,0]Ao[3173,13,3174,1733,4190,1186,0]Ao[3173,13,3174,1733,4051,1186,0]Ao[3173,13,3174,1393,3100,1186,0]Ao[3173,13,3174,1393,3310,1186,0]Ao[3173,13,3174,1393,3332,1186,0]Ao[3173,13,3174,1393,4205,1186,0]Ao[3173,13,3174,1393,4582,1186,0]Ao[3173,13,3174,1393,4789,1186,0]Ao[3173,13,3174,1393,2302,1186,0]Ao[3173,13,3174,2354,4793,1186,0]Ao[3173,13,3174,2354,4201,1186,0]Ao[3173,13,3174,1798,4596,1186,0]Ao[3173,13,3174,1798,5160,1186,0]Ao[3173,13,3174,1798,2316,1186,0]Ao[3173,13,3174,1798,4894,1186,0]Ao[3173,13,3174,1829,4204,1186,0]Ao[3173,13,3174,1829,4209,1186,0]Al[3173,13,3174,0,4489,1186,0]Al[3173,13,3174,0,4960,1186,0]Ao[3173,13,3174,4387,3307,1186,0]Ao[3173,13,3174,4387,5262,1186,0]An[3173,13,3174,3174,527,1186,0]An[3173,13,3174,3174,134,1186,0]Ao[3173,13,3174,3174,2331,1186,0]Ao[3173,13,3174,3174,3098,1186,0]Ao[3173,13,1731,1731,4380,1186,0]Ao[3173,13,5111,5111,5007,1186,0]Ao[3173,13,5111,5111,1203,1186,0]Al[3173,13,1819,0,1202,1186,0]Ao[3173,13,1819,1819,4818,1186,0]Ao[3173,13,1819,1819,5064,1186,0]Ao[3173,13,1819,1819,4820,1186,0]Am[3173,13,3736,535,502,1186,0]An[3173,13,3736,535,3287,1186,0]Ao[3173,13,3736,1389,1189,1186,0]Ao[3173,13,3736,1389,4056,1186,0]Ao[3173,13,3736,2408,1887,1186,0]Ao[3173,13,3736,2408,4367,1186,0]Ao[3173,13,4853,4853,1207,1186,0]Ao[2029,13,2030,2030,2328,1186,0]Ao[2029,13,2030,2030,2342,1186,0]Ao[2029,13,2030,2030,4210,1186,0]Ao[1127,13,1128,1128,4999,1186,0]Ao[1127,13,1419,1419,4592,1186,0]Ao[1127,13,4305,4305,5209,1186,0]Ao[1127,13,4305,4305,5210,1186,0]Aj[477,13,478,3740,3297,0,0]Aj[477,13,478,2353,2308,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,0,4203,1192,0]Ao[3173,13,3174,1829,4204,1192,0]Ai[3173,14,3174,0,4489,0,0]Ag[477,13,478,0,2330,0,0]Al[3173,13,3174,3174,2331,0,0]Ag[477,13,478,0,4208,0,0]Al[3173,13,3174,1829,4209,0,0]Ah[477,14,1735,0,1881,0,0]Al[3173,14,1736,1736,1882,0,0]Al[3173,12,3174,1798,4930,0,0]Ao[3173,13,3174,1798,5288,4930,0];Al[1228,13,1417,1417,1221,0,0]Ai[536,13,537,537,4048,0,0]Al[1127,13,1419,1419,1222,0,0]Aj[477,12,478,2036,3282,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2309,0,0]Aj[477,12,478,2036,1898,0,0]Am[477,13,478,1431,4249,1898,0]Am[477,13,478,1169,4078,1898,0]Ae[1228,2,1229,0,0,0,0]Ak[1228,14,1229,1229,141,0,0]Aj[477,13,478,3740,3297,0,0]Aj[477,13,478,2353,2308,0,0]Ai[477,13,478,1126,520,0,0]Aj[477,14,478,3740,1450,0,0]Al[3173,13,3174,3741,3298,0,0]Ae[1127,2,1128,0,0,0,0]Ag[477,13,478,0,3319,0,0]Al[3173,13,3174,1148,3320,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]Al[3173,13,5111,5111,5007,0,0]Af[477,5,478,2353,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Al[1228,15,1229,1229,4047,0,0]0Ag[477,15,478,0,3317,0,0]Al[3173,15,3174,1403,3318,0,0]Ah[3173,5,3174,1152,0,0,0]Af[477,15,478,0,526,0,0]Al[2408,15,2409,2409,2299,0,0]Ak[3173,15,3174,3174,527,0,0]Af[477,5,478,3740,0,0,0]Al[3173,15,4853,4853,1204,0,0]:9Af[477,5,478,4270,0,0,0]2Al[3173,15,3174,2044,4082,0,0]Af[477,5,478,1403,0,0,0]Ah[3173,5,3174,1403,0,0,0]Ae[3173,8,1731,0,0,0,0]987?Al[3173,15,3174,3741,1206,0,0]?Af[477,5,478,1856,0,0,0]Ah[3173,5,3174,1856,0,0,0]Aj[477,13,478,2353,2308,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2044,1907,0,0]Al[3173,13,3174,2354,2309,0,0]An[1228,13,1229,1229,141,1444,0]Ao[1228,13,1229,1229,4075,1444,0]Ao[1228,13,1229,1229,4047,1444,0]Ao[1228,13,1417,1417,4083,1444,0]Ao[1228,13,1417,1417,1221,1444,0]Ao[1228,13,1417,1417,4486,1444,0]Al[536,13,537,537,4048,1444,0]Ao[4088,13,4089,4089,5161,1444,0]Am[477,13,478,3740,4611,1444,0]Am[477,13,478,3740,2323,1444,0]Aj[477,13,478,0,4338,1444,0]Am[477,13,478,4270,5065,1444,0]Am[477,13,478,1126,2324,1444,0]Am[477,13,478,1126,4785,1444,0]Am[477,13,478,3740,3295,1444,0]Am[477,13,478,3740,3297,1444,0]Am[477,13,478,3740,1889,1444,0]Am[477,13,478,3740,1459,1444,0]Am[477,13,478,3740,3076,1444,0]Am[477,13,478,3740,2296,1444,0]Am[477,13,478,3740,4232,1444,0]Am[477,13,478,3740,4239,1444,0]Am[477,13,478,3740,1450,1444,0]Am[477,13,478,3740,5072,1444,0]Am[477,13,478,3740,4898,1444,0]Am[477,13,478,2353,2308,1444,0]Am[477,13,478,2353,4347,1444,0]Am[477,13,478,2353,1437,1444,0]Am[477,13,478,4270,1458,1444,0]Am[477,13,478,4270,3316,1444,0]Am[477,13,478,4270,5000,1444,0]Am[477,13,478,2385,2312,1444,0]Am[477,13,478,2385,3325,1444,0]Am[477,13,478,2385,4465,1444,0]Al[477,13,478,1126,520,1444,0]Am[477,13,478,1126,4491,1444,0]Am[477,13,478,4157,3322,1444,0]Am[477,13,478,4157,5008,1444,0]Am[477,13,478,4157,4484,1444,0]Am[477,13,478,4157,3121,1444,0]Am[477,13,478,4157,3324,1444,0]Am[477,13,478,4157,4483,1444,0]Am[477,13,478,1431,4249,1444,0]Am[477,13,478,1169,4078,1444,0]Am[477,13,478,4162,3328,1444,0]Am[477,13,478,4162,3342,1444,0]Am[477,13,478,4162,4248,1444,0]Am[477,13,478,4162,1903,1444,0]Aj[477,13,478,0,3319,1444,0]Aj[477,13,478,0,4378,1444,0]Aj[477,13,478,0,4795,1444,0]Aj[477,13,478,0,4603,1444,0]Aj[477,13,478,0,4222,1444,0]Aj[477,13,478,0,4474,1444,0]Aj[477,13,478,0,1480,1444,0]Aj[477,13,478,0,5069,1444,0]Aj[477,13,478,0,1184,1444,0]Aj[477,13,478,0,1463,1444,0]Aj[477,13,478,0,3317,1444,0]Aj[477,13,478,0,3116,1444,0]Aj[477,13,478,0,4954,1444,0]Aj[477,13,478,0,3290,1444,0]Aj[477,13,478,0,2343,1444,0]Aj[477,13,478,0,3303,1444,0]Aj[477,13,478,0,3118,1444,0]Aj[477,13,478,0,4587,1444,0]Aj[477,13,478,0,4194,1444,0]Aj[477,13,478,0,4583,1444,0]Aj[477,13,478,0,3112,1444,0]Aj[477,13,478,0,4450,1444,0]Aj[477,13,478,0,4597,1444,0]Aj[477,13,478,0,4606,1444,0]Aj[477,13,478,0,4924,1444,0]Aj[477,13,478,0,4939,1444,0]Aj[477,13,478,0,4064,1444,0]Aj[477,13,478,0,4460,1444,0]Aj[477,13,478,0,4242,1444,0]Aj[477,13,478,0,5126,1444,0]Aj[477,13,478,0,4188,1444,0]Aj[477,13,478,0,4050,1444,0]Aj[477,13,478,0,3099,1444,0]Aj[477,13,478,0,4580,1444,0]Aj[477,13,478,0,4787,1444,0]Aj[477,13,478,0,4200,1444,0]Aj[477,13,478,0,4203,1444,0]Aj[477,13,478,0,4208,1444,0]Aj[477,13,478,0,4959,1444,0]Aj[477,13,478,0,3306,1444,0]Aj[477,13,478,0,4821,1444,0]Ai[477,13,478,0,526,1444,0]Ai[477,13,478,0,133,1444,0]Aj[477,13,478,0,2330,1444,0]Aj[477,13,478,0,2340,1444,0]Aj[477,13,478,0,3097,1444,0]Aj[477,13,3735,0,501,1444,0]Ak[477,13,3735,0,3286,1444,0]Ak[477,13,3735,0,1188,1444,0]Ak[477,13,3735,0,4055,1444,0]Ak[477,13,3735,0,1886,1444,0]Ak[477,13,3735,0,4366,1444,0]Ak[477,13,3735,0,4885,1444,0]Ak[477,13,1735,0,1881,1444,0]Aj[477,13,1735,0,514,1444,0]Ak[477,13,1735,0,5223,1444,0]Ak[477,13,1735,0,4053,1444,0]Ak[477,13,1735,0,4963,1444,0]Ak[477,13,1818,0,3337,1444,0]Ak[477,13,1818,0,4349,1444,0]Ak[477,13,1818,0,1201,1444,0]Ak[477,13,1818,0,4817,1444,0]Ak[477,13,1818,0,5063,1444,0]Ak[477,13,1818,0,4819,1444,0]An[2408,13,2409,2409,132,1444,0]Ao[2408,13,2409,2409,2299,1444,0]Ao[3173,13,3174,4616,4339,1444,0]Ao[3173,13,3174,3147,3089,1444,0]Ao[3173,13,3174,1152,1446,1444,0]Ao[3173,13,3174,2044,1907,1444,0]Ao[3173,13,3174,2044,3323,1444,0]Ao[3173,13,3174,2044,3329,1444,0]Ao[3173,13,3174,3741,3298,1444,0]Ao[3173,13,3174,1148,3320,1444,0]Ao[3173,13,3174,1733,4379,1444,0]Ao[3173,13,3174,2354,2309,1444,0]Ao[3173,13,3174,2354,4345,1444,0]Ao[3173,13,3174,2354,4796,1444,0]Ao[3173,13,3174,2354,4357,1444,0]Ao[3173,13,3174,1798,5288,1444,0]Ao[3173,13,3174,4387,5257,1444,0]Ao[3173,13,3174,1430,4604,1444,0]Ao[3173,13,3174,1430,4223,1444,0]Ao[3173,13,3174,1430,4475,1444,0]Ao[3173,13,3174,1856,1481,1444,0]Ao[3173,13,3174,1856,5070,1444,0]Ao[3173,13,3174,3138,1185,1444,0]Ao[3173,13,3174,3147,4899,1444,0]Ao[3173,13,3174,1403,1464,1444,0]Ao[3173,13,3174,1403,4238,1444,0]Ao[3173,13,3174,1403,3318,1444,0]Ao[3173,13,3174,1403,3117,1444,0]Ao[3173,13,3174,1403,4897,1444,0]Ao[3173,13,3174,1403,4955,1444,0]Ao[3173,13,3174,1403,3293,1444,0]Ao[3173,13,3174,1418,2344,1444,0]Ao[3173,13,3174,1418,3304,1444,0]Ao[3173,13,3174,1418,3119,1444,0]Ao[3173,13,3174,1418,4588,1444,0]Ao[3173,13,3174,1152,3122,1444,0]Ao[3173,13,3174,1152,4374,1444,0]Ao[3173,13,3174,1157,3343,1444,0]Ao[3173,13,3174,1157,4063,1444,0]Ao[3173,13,3174,2044,4082,1444,0]Ao[3173,13,3174,2044,4485,1444,0]Ao[3173,13,3174,2044,4198,1444,0]Ao[3173,13,3174,3741,4584,1444,0]Ao[3173,13,3174,3741,3113,1444,0]Ao[3173,13,3174,3741,4451,1444,0]Ao[3173,13,3174,3741,5157,1444,0]Ao[3173,13,3174,3741,1206,1444,0]Ao[3173,13,3174,1148,4598,1444,0]Ao[3173,13,3174,3276,4607,1444,0]Ao[3173,13,3174,3276,4925,1444,0]Ao[3173,13,3174,3276,4940,1444,0]Ao[3173,13,3174,3276,4065,1444,0]Ao[3173,13,3174,1733,4461,1444,0]Ao[3173,13,3174,1733,4244,1444,0]Ao[3173,13,3174,1733,5127,1444,0]Ao[3173,13,3174,1733,4190,1444,0]Ao[3173,13,3174,1733,4051,1444,0]Ao[3173,13,3174,1393,3100,1444,0]Ao[3173,13,3174,1393,4466,1444,0]Ao[3173,13,3174,1393,3310,1444,0]Ao[3173,13,3174,1393,3332,1444,0]Ao[3173,13,3174,1393,4205,1444,0]Ao[3173,13,3174,1393,4582,1444,0]Ao[3173,13,3174,1393,4789,1444,0]Ao[3173,13,3174,1393,2302,1444,0]Ao[3173,13,3174,2354,4793,1444,0]Ao[3173,13,3174,2354,2313,1444,0]Ao[3173,13,3174,2354,4201,1444,0]Ao[3173,13,3174,2354,4045,1444,0]Ao[3173,13,3174,2354,3326,1444,0]Ao[3173,13,3174,1798,4369,1444,0]Ao[3173,13,3174,1798,4596,1444,0]Ao[3173,13,3174,1798,5160,1444,0]Ao[3173,13,3174,1798,2316,1444,0]Ao[3173,13,3174,1798,4894,1444,0]Ao[3173,13,3174,1829,4586,1444,0]Ao[3173,13,3174,1829,4346,1444,0]Ao[3173,13,3174,1829,4204,1444,0]Ao[3173,13,3174,1829,4209,1444,0]Al[3173,13,3174,0,4489,1444,0]Al[3173,13,3174,0,4960,1444,0]Ao[3173,13,3174,4387,3307,1444,0]Ao[3173,13,3174,4387,5262,1444,0]Ao[3173,13,3174,4995,4822,1444,0]An[3173,13,3174,3174,527,1444,0]An[3173,13,3174,3174,134,1444,0]Ao[3173,13,3174,3174,2331,1444,0]Ao[3173,13,3174,3174,2341,1444,0]Ao[3173,13,3174,3174,3098,1444,0]Ao[3173,13,1731,1731,4380,1444,0]Ao[3173,13,5111,5111,5007,1444,0]Ao[3173,13,5111,5111,1203,1444,0]Ao[3173,13,1736,1736,1882,1444,0]An[3173,13,1736,1736,515,1444,0]Ao[3173,13,1736,1736,5224,1444,0]Ao[3173,13,1736,1736,4054,1444,0]Ao[3173,13,1736,1736,4966,1444,0]Ao[3173,13,1819,1819,3338,1444,0]Ao[3173,13,1819,1819,4350,1444,0]Al[3173,13,1819,0,1202,1444,0]Ao[3173,13,1819,1819,4818,1444,0]Ao[3173,13,1819,1819,5064,1444,0]Ao[3173,13,1819,1819,4820,1444,0]Am[3173,13,3736,535,502,1444,0]An[3173,13,3736,535,3287,1444,0]Ao[3173,13,3736,1389,1189,1444,0]Ao[3173,13,3736,1389,4056,1444,0]Ao[3173,13,3736,2408,1887,1444,0]Ao[3173,13,3736,2408,4367,1444,0]Ao[3173,13,3736,3736,4886,1444,0]Ao[3173,13,4853,4853,1204,1444,0]Ao[3173,13,4853,4853,1207,1444,0]Ao[2029,13,2030,2030,3341,1444,0]An[2029,13,2030,431,4490,1444,0]Ao[2029,13,2030,2030,2328,1444,0]Ao[2029,13,2030,2030,2342,1444,0]Ao[2029,13,2030,2030,4210,1444,0]Ao[1127,13,1128,1128,3086,1444,0]Ao[1127,13,1128,1128,4999,1444,0]An[1127,13,1725,1725,142,1444,0]Ao[1127,13,1419,1419,1222,1444,0]Ao[1127,13,1419,1419,4084,1444,0]Ao[1127,13,1419,1419,4592,1444,0]Ao[1127,13,4305,4305,5209,1444,0]Ao[1127,13,4305,4305,5210,1444,0]An[1127,13,1824,1824,143,1444,0]Ak[1228,14,1229,1229,141,0,0]Ac[536,7,537,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Ae[1127,2,1128,0,0,0,0]Ae[4917,7,4918,0,0,0,0]Aj[477,13,478,3740,3297,0,0]Ae[3173,2,3174,0,0,0,0]Al[3173,13,3174,2354,2309,0,0]Af[477,2,478,3174,0,0,0]Ag[477,13,478,0,4959,0,0]Ag[477,14,478,0,3303,0,0]Ag[477,14,478,0,4242,0,0]5Ai[3173,13,3174,0,4960,0,0]Al[3173,14,3174,1418,3304,0,0]Al[3173,14,3174,1733,4244,0,0]Ai[3173,14,3174,0,4489,0,0]Aj[477,13,478,0,1480,3090,0]Aj[477,13,478,0,1463,3090,0]Aj[477,13,478,0,3099,3090,0]Aj[477,13,478,0,4959,3090,0]Aj[477,13,478,0,2330,3090,0]Ao[3173,13,3174,1856,1481,3090,0]Ao[3173,13,3174,1403,1464,3090,0]Ao[3173,13,3174,1393,3100,3090,0]Ao[3173,13,3174,1393,3310,3090,0]Al[3173,13,3174,1798,4596,0,0]Al[3173,13,3174,0,4960,3090,0]Ao[3173,13,3174,3174,2331,3090,0]Al[3173,12,1731,1731,3090,0,0]Al[2029,14,2030,2030,2328,0,0]Aj[477,13,478,0,1480,3095,0]Aj[477,13,478,0,1463,3095,0]Aj[477,13,478,0,3099,3095,0]Aj[477,13,478,0,4959,3095,0]Aj[477,13,478,0,2330,3095,0]Ao[3173,13,3174,1856,1481,3095,0]Ao[3173,13,3174,1403,1464,3095,0]Ao[3173,13,3174,1393,3100,3095,0]Ao[3173,13,3174,1393,3310,3095,0]Ao[3173,13,3174,1393,2302,3095,0]Al[3173,13,3174,0,4960,3095,0]Ao[3173,13,3174,3174,2331,3095,0]Al[3173,12,1731,1731,3095,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]Al[1127,13,1419,1419,4084,0,0]Al[3173,13,3174,2354,2309,0,0]Ag[477,14,1735,0,514,0,0]Ak[3173,14,1736,1736,515,0,0]Aj[477,13,478,2385,2312,0,0]3Ag[477,12,478,0,3339,0,0]Aj[477,13,478,0,4474,3339,0]Aj[477,13,478,0,4821,3339,0]Al[3173,12,3174,1430,3340,0,0]Ao[3173,13,3174,1430,4475,3340,0]Ao[3173,13,3174,4995,4822,3340,0]Al[1127,14,1128,1128,3086,0,0]Ag[477,14,478,0,1184,0,0]Al[3173,14,3174,3138,1185,0,0]Ah[477,13,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,13,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Ag[477,14,1735,0,514,0,0]Ak[3173,14,1736,1736,515,0,0]Ai[3173,14,4595,0,4827,0,0]Aj[477,14,478,3740,1450,0,0]Ag[477,14,478,0,4580,0,0]Ag[477,14,478,0,4787,0,0]Ah[477,14,3114,0,3072,0,0]Al[3173,14,3174,1393,4582,0,0]Al[3173,14,3174,1393,4789,0,0]Ai[3173,14,3174,0,4489,0,0]Ai[3173,14,1205,0,4453,0,0]Ai[3173,14,3115,0,3073,0,0]Aj[477,13,478,2353,2308,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2309,0,0]Ag[477,13,478,0,3097,0,0]Ah[477,14,1735,0,1881,0,0]Al[3173,13,3174,3174,3098,0,0]Al[3173,14,1736,1736,1882,0,0]Ac[477,4,478,0,0,0,0]Ag[477,2,1735,1736,0,0,0]Ae[3173,4,3174,0,0,0,0]Ae[3173,2,1736,0,0,0,0]Ac[536,7,537,0,0,0,0];Ae[1127,2,1128,0,0,0,0]Ae[4917,7,4918,0,0,0,0]Am[477,13,478,3740,4898,1194,0]Am[477,13,478,4157,4484,1194,0]Am[477,13,478,4157,3121,1194,0]Am[477,13,478,4157,3324,1194,0]Am[477,13,478,4157,4483,1194,0]Am[477,13,478,4162,3342,1194,0]Am[477,13,478,4162,4248,1194,0]Aj[477,13,478,0,4583,1194,0]Ao[3173,13,3174,3741,4584,1194,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Al[2029,14,2030,2030,2342,0,0]Ai[477,13,478,1126,520,0,0]Ah[477,14,3114,0,4233,0,0]Ai[3173,14,3115,0,4234,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Al[2029,14,2030,2030,2328,0,0]Ag[477,14,478,0,3118,0,0]Ag[477,14,478,0,4587,0,0]Al[3173,14,3174,1418,3119,0,0]Al[3173,14,3174,1418,4588,0,0]3210Ah[477,12,1735,0,1877,0,0]Al[3173,12,1736,1736,1878,0,0]Ah[477,12,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,12,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Al[3173,15,3174,3147,4899,0,0]Al[3173,15,3174,1152,3122,0,0]Al[3173,15,3174,1157,3343,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Ah[477,10,1735,1736,0,0,0]Af[3173,10,1736,0,0,0,0]Al[3173,15,3174,1798,4596,0,0]Ag[477,5,1735,1736,0,0,0]Ae[3173,5,1736,0,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ag[477,5,3735,2408,0,0,0]Ah[3173,5,3736,2408,0,0,0]Al[1127,15,1128,1128,4999,0,0]Af[477,5,478,3740,0,0,0]5454Ag[477,10,478,2036,0,0,0];:Aj[477,15,478,4162,3342,0,0]Af[477,5,478,4162,0,0,0]Al[3173,15,3174,1157,3343,0,0]Al[3173,15,3174,1157,4063,0,0]Al[3173,15,3174,2044,4082,0,0]Ah[3173,5,3174,2044,0,0,0]Aj[477,15,478,4157,4484,0,0]Al[3173,15,3174,1393,3310,0,0]Al[3173,15,3174,1798,2316,0,0]Ag[477,12,478,0,5117,0,0]Al[3173,12,3174,4387,5118,0,0]Ao[3173,13,3174,4387,5257,5118,0]Ao[3173,13,3174,4387,5262,5118,0]Ak[1228,14,1229,1229,141,0,0]An[1228,13,1229,1229,141,4452,0]An[2408,13,2409,2409,132,4452,0]Ak[2408,14,2409,2409,132,0,0]Ao[1127,13,1128,1128,3086,4452,0]An[1127,13,1725,1725,142,4452,0]An[1127,13,1824,1824,143,4452,0]Aj[477,13,478,0,1480,3294,0]Aj[477,13,478,0,1463,3294,0]Aj[477,13,478,0,4064,3294,0]Aj[477,13,478,0,4203,3294,0]Ai[477,13,478,0,526,3294,0]Ai[477,13,478,0,133,3294,0]Aj[477,13,478,0,2330,3294,0]Ao[3173,13,3174,1856,1481,3294,0]Ao[3173,13,3174,3147,4899,3294,0]Ao[3173,13,3174,1403,1464,3294,0]Ao[3173,13,3174,1152,3122,3294,0]Ao[3173,13,3174,1152,4374,3294,0]Ao[3173,13,3174,1157,3343,3294,0]Ao[3173,13,3174,3276,4065,3294,0]Ao[3173,13,3174,2354,4793,3294,0]Ao[3173,13,3174,1798,4894,3294,0]Ao[3173,13,3174,1829,4204,3294,0]An[3173,13,3174,3174,527,3294,0]An[3173,13,3174,3174,134,3294,0]Ao[3173,13,3174,3174,2331,3294,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]Aj[477,13,478,2385,2312,0,0]Ah[477,12,1735,0,3109,0,0]Ah[477,12,1735,0,3102,0,0]Al[3173,13,3174,2354,2313,0,0]Al[3173,12,1736,1736,3110,0,0]Al[3173,12,1736,1736,3103,0,0]Ao[1228,13,1417,1417,4083,1872,0]Ao[1228,13,1417,1417,1221,1872,0]Al[536,13,537,537,4048,1872,0]Aj[477,13,478,0,4338,1872,0]Am[477,13,478,2353,4347,1872,0]Aj[477,13,478,0,1480,1872,0]Aj[477,13,478,0,1463,1872,0]Aj[477,13,478,0,3317,1872,0]Aj[477,13,478,0,3290,1872,0]Aj[477,13,478,0,2343,1872,0]Aj[477,13,478,0,3303,1872,0]Aj[477,13,478,0,3118,1872,0]Aj[477,13,478,0,4587,1872,0]Aj[477,13,478,0,4194,1872,0]Aj[477,13,478,0,4606,1872,0]Aj[477,13,478,0,4924,1872,0]Aj[477,13,478,0,4939,1872,0]Aj[477,13,478,0,4064,1872,0]Aj[477,13,478,0,4460,1872,0]Aj[477,13,478,0,5126,1872,0]Aj[477,13,478,0,4821,1872,0]Ak[477,13,3735,0,3286,1872,0]Ak[477,13,3735,0,4055,1872,0]Ak[477,13,3735,0,4366,1872,0]Ak[477,13,3735,0,4885,1872,0]Ao[3173,13,3174,4616,4339,1872,0]Ao[3173,13,3174,4387,5257,1872,0]Ao[3173,13,3174,1856,1481,1872,0]Ao[3173,13,3174,1403,1464,1872,0]Ao[3173,13,3174,1403,3318,1872,0]Ao[3173,13,3174,1403,3293,1872,0]Ao[3173,13,3174,1418,2344,1872,0]Ao[3173,13,3174,1418,3304,1872,0]Ao[3173,13,3174,1418,3119,1872,0]Ao[3173,13,3174,1418,4588,1872,0]Ao[3173,13,3174,2044,4485,1872,0]Ao[3173,13,3174,2044,4198,1872,0]Ao[3173,13,3174,3276,4607,1872,0]Ao[3173,13,3174,3276,4925,1872,0]Ao[3173,13,3174,3276,4940,1872,0]Ao[3173,13,3174,3276,4065,1872,0]Ao[3173,13,3174,1733,4461,1872,0]Ao[3173,13,3174,1733,5127,1872,0]Ao[3173,13,3174,4387,5262,1872,0]Ao[3173,13,3174,4995,4822,1872,0]An[3173,13,3736,535,3287,1872,0]Ao[3173,13,3736,1389,4056,1872,0]Ao[3173,13,3736,2408,4367,1872,0]Ao[3173,13,3736,3736,4886,1872,0]Ao[2029,13,2030,2030,2328,1872,0]Ao[1127,13,1419,1419,1222,1872,0]Ao[1127,13,1419,1419,4592,1872,0]Al[3173,13,3174,1829,4346,0,0]Al[3173,13,3174,1798,4369,0,0]Al[3173,13,3174,1798,4596,0,0]Al[3173,14,3174,1798,5160,0,0]Ai[3173,14,4893,0,4961,0,0]Ah[3173,14,4595,0,516,0,0]Ai[3173,14,4595,0,1216,0,0]Ai[3173,14,4595,0,1218,0,0]Ai[3173,14,4595,0,4827,0,0]Ah[477,12,1735,0,3109,0,0]Ah[477,12,1735,0,3102,0,0]Al[3173,12,1736,1736,3110,0,0]Al[3173,12,1736,1736,3103,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5008,0,0]Ah[477,13,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,13,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ab[2029,3,0,0,0,0,0]:6Aj[477,13,478,3740,3297,0,0]Aj[477,13,478,1126,2324,0,0]Al[3173,14,3174,1798,5160,0,0]Ai[3173,14,4893,0,4961,0,0]Ah[3173,14,4595,0,516,0,0]Ai[3173,14,4595,0,1216,0,0]Ai[3173,14,4595,0,4827,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]Ak[1228,14,1229,1229,141,0,0]Al[1228,14,1417,1417,1221,0,0]Al[3173,13,3174,3741,3298,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Am[1228,13,1229,1229,141,128,0]An[1228,13,1229,1229,4075,128,0]An[1228,13,1229,1229,4047,128,0]An[1228,13,1417,1417,4083,128,0]An[1228,13,1417,1417,1221,128,0]An[1228,13,1417,1417,4486,128,0]Ak[536,13,537,537,4048,128,0]An[4088,13,4089,4089,5161,128,0]Al[477,13,478,3740,4611,128,0]Al[477,13,478,3740,2323,128,0]Ai[477,13,478,0,4338,128,0]Al[477,13,478,4270,5065,128,0]Al[477,13,478,1126,2324,128,0]Al[477,13,478,1126,4785,128,0]Al[477,13,478,3740,3295,128,0]Al[477,13,478,3740,3297,128,0]Al[477,13,478,3740,1889,128,0]Al[477,13,478,3740,1459,128,0]Al[477,13,478,3740,3076,128,0]Al[477,13,478,3740,2296,128,0]Al[477,13,478,3740,4232,128,0]Al[477,13,478,3740,4239,128,0]Al[477,13,478,3740,1450,128,0]Al[477,13,478,3740,5072,128,0]Al[477,13,478,3740,4898,128,0]Al[477,13,478,2353,2308,128,0]Al[477,13,478,2353,4347,128,0]Al[477,13,478,2353,1437,128,0]Al[477,13,478,4270,1458,128,0]Al[477,13,478,4270,3316,128,0]Al[477,13,478,4270,5000,128,0]Al[477,13,478,2385,2312,128,0]Al[477,13,478,2385,3325,128,0]Al[477,13,478,2385,4465,128,0]Ak[477,13,478,1126,520,128,0]Al[477,13,478,1126,4491,128,0]Al[477,13,478,4157,3322,128,0]Al[477,13,478,4157,5008,128,0]Al[477,13,478,4157,4484,128,0]Al[477,13,478,4157,3121,128,0]Al[477,13,478,4157,3324,128,0]Al[477,13,478,4157,4483,128,0]Al[477,13,478,1431,4249,128,0]Al[477,13,478,1169,4078,128,0]Al[477,13,478,4162,3328,128,0]Al[477,13,478,4162,3342,128,0]Al[477,13,478,4162,4248,128,0]Al[477,13,478,4162,1903,128,0]Ai[477,13,478,0,3319,128,0]Ai[477,13,478,0,4378,128,0]Ai[477,13,478,0,4795,128,0]Ai[477,13,478,0,4603,128,0]Ai[477,13,478,0,4222,128,0]Ai[477,13,478,0,4474,128,0]Ai[477,13,478,0,1480,128,0]Ai[477,13,478,0,5069,128,0]Ai[477,13,478,0,1184,128,0]Ai[477,13,478,0,1463,128,0]Ai[477,13,478,0,3317,128,0]Ai[477,13,478,0,3116,128,0]Ai[477,13,478,0,4954,128,0]Ai[477,13,478,0,3290,128,0]Ai[477,13,478,0,2343,128,0]Ai[477,13,478,0,3303,128,0]Ai[477,13,478,0,3118,128,0]Ai[477,13,478,0,4587,128,0]Ai[477,13,478,0,4194,128,0]Ai[477,13,478,0,4583,128,0]Ai[477,13,478,0,3112,128,0]Ai[477,13,478,0,4450,128,0]Ai[477,13,478,0,4597,128,0]Ai[477,13,478,0,4606,128,0]Ai[477,13,478,0,4924,128,0]Ai[477,13,478,0,4939,128,0]Ai[477,13,478,0,4064,128,0]Ai[477,13,478,0,4460,128,0]Ai[477,13,478,0,4242,128,0]Ai[477,13,478,0,5126,128,0]Ai[477,13,478,0,4188,128,0]Ai[477,13,478,0,4050,128,0]Ai[477,13,478,0,3099,128,0]Ai[477,13,478,0,4580,128,0]Ai[477,13,478,0,4787,128,0]Ai[477,13,478,0,4200,128,0]Ai[477,13,478,0,4203,128,0]Ai[477,13,478,0,4208,128,0]Ai[477,13,478,0,4959,128,0]Ai[477,13,478,0,3306,128,0]Ai[477,13,478,0,4821,128,0]Ah[477,13,478,0,526,128,0]Ah[477,13,478,0,133,128,0]Ai[477,13,478,0,2330,128,0]Ai[477,13,478,0,2340,128,0]Ai[477,13,478,0,3097,128,0]Ai[477,13,3735,0,501,128,0]Aj[477,13,3735,0,3286,128,0]Aj[477,13,3735,0,1188,128,0]Aj[477,13,3735,0,4055,128,0]Aj[477,13,3735,0,1886,128,0]Aj[477,13,3735,0,4366,128,0]Aj[477,13,3735,0,4885,128,0]Aj[477,13,1735,0,1881,128,0]Ai[477,13,1735,0,514,128,0]Aj[477,13,1735,0,5223,128,0]Aj[477,13,1735,0,4053,128,0]Aj[477,13,1735,0,4963,128,0]Aj[477,13,1818,0,3337,128,0]Aj[477,13,1818,0,4349,128,0]Aj[477,13,1818,0,1201,128,0]Aj[477,13,1818,0,4817,128,0]Aj[477,13,1818,0,5063,128,0]Aj[477,13,1818,0,4819,128,0]Am[2408,13,2409,2409,132,128,0]An[2408,13,2409,2409,2299,128,0]An[3173,13,3174,4616,4339,128,0]An[3173,13,3174,3147,3089,128,0]An[3173,13,3174,1152,1446,128,0]An[3173,13,3174,2044,1907,128,0]An[3173,13,3174,2044,3323,128,0]An[3173,13,3174,2044,3329,128,0]An[3173,13,3174,3741,3298,128,0]An[3173,13,3174,1148,3320,128,0]An[3173,13,3174,1733,4379,128,0]An[3173,13,3174,2354,2309,128,0]An[3173,13,3174,2354,4345,128,0]An[3173,13,3174,2354,4796,128,0]An[3173,13,3174,2354,4357,128,0]An[3173,13,3174,1798,5288,128,0]An[3173,13,3174,4387,5257,128,0]An[3173,13,3174,1430,4604,128,0]An[3173,13,3174,1430,4223,128,0]An[3173,13,3174,1430,4475,128,0]An[3173,13,3174,1856,1481,128,0]An[3173,13,3174,1856,5070,128,0]An[3173,13,3174,3138,1185,128,0]An[3173,13,3174,3147,4899,128,0]An[3173,13,3174,1403,1464,128,0]An[3173,13,3174,1403,4238,128,0]An[3173,13,3174,1403,3318,128,0]An[3173,13,3174,1403,3117,128,0]An[3173,13,3174,1403,4897,128,0]An[3173,13,3174,1403,4955,128,0]An[3173,13,3174,1403,3293,128,0]An[3173,13,3174,1418,2344,128,0]An[3173,13,3174,1418,3304,128,0]An[3173,13,3174,1418,3119,128,0]An[3173,13,3174,1418,4588,128,0]An[3173,13,3174,1152,3122,128,0]An[3173,13,3174,1152,4374,128,0]An[3173,13,3174,1157,3343,128,0]An[3173,13,3174,1157,4063,128,0]An[3173,13,3174,2044,4082,128,0]An[3173,13,3174,2044,4485,128,0]An[3173,13,3174,2044,4198,128,0]An[3173,13,3174,3741,4584,128,0]An[3173,13,3174,3741,3113,128,0]An[3173,13,3174,3741,4451,128,0]An[3173,13,3174,3741,5157,128,0]An[3173,13,3174,3741,1206,128,0]An[3173,13,3174,1148,4598,128,0]An[3173,13,3174,3276,4607,128,0]An[3173,13,3174,3276,4925,128,0]An[3173,13,3174,3276,4940,128,0]An[3173,13,3174,3276,4065,128,0]An[3173,13,3174,1733,4461,128,0]An[3173,13,3174,1733,4244,128,0]An[3173,13,3174,1733,5127,128,0]An[3173,13,3174,1733,4190,128,0]An[3173,13,3174,1733,4051,128,0]An[3173,13,3174,1393,3100,128,0]An[3173,13,3174,1393,4466,128,0]An[3173,13,3174,1393,3310,128,0]An[3173,13,3174,1393,3332,128,0]An[3173,13,3174,1393,4205,128,0]An[3173,13,3174,1393,4582,128,0]An[3173,13,3174,1393,4789,128,0]An[3173,13,3174,1393,2302,128,0]An[3173,13,3174,2354,4793,128,0]An[3173,13,3174,2354,2313,128,0]An[3173,13,3174,2354,4201,128,0]An[3173,13,3174,2354,4045,128,0]An[3173,13,3174,2354,3326,128,0]An[3173,13,3174,1798,4369,128,0]An[3173,13,3174,1798,4596,128,0]An[3173,13,3174,1798,5160,128,0]An[3173,13,3174,1798,2316,128,0]An[3173,13,3174,1798,4894,128,0]An[3173,13,3174,1829,4586,128,0]An[3173,13,3174,1829,4346,128,0]An[3173,13,3174,1829,4204,128,0]An[3173,13,3174,1829,4209,128,0]Ak[3173,13,3174,0,4489,128,0]Ak[3173,13,3174,0,4960,128,0]An[3173,13,3174,4387,3307,128,0]An[3173,13,3174,4387,5262,128,0]An[3173,13,3174,4995,4822,128,0]Am[3173,13,3174,3174,527,128,0]Am[3173,13,3174,3174,134,128,0]An[3173,13,3174,3174,2331,128,0]An[3173,13,3174,3174,2341,128,0]An[3173,13,3174,3174,3098,128,0]An[3173,13,1731,1731,4380,128,0]An[3173,13,5111,5111,5007,128,0]An[3173,13,5111,5111,1203,128,0]An[3173,13,1736,1736,1882,128,0]Am[3173,13,1736,1736,515,128,0]An[3173,13,1736,1736,5224,128,0]An[3173,13,1736,1736,4054,128,0]An[3173,13,1736,1736,4966,128,0]An[3173,13,1819,1819,3338,128,0]An[3173,13,1819,1819,4350,128,0]Ak[3173,13,1819,0,1202,128,0]An[3173,13,1819,1819,4818,128,0]An[3173,13,1819,1819,5064,128,0]An[3173,13,1819,1819,4820,128,0]Al[3173,13,3736,535,502,128,0]Am[3173,13,3736,535,3287,128,0]An[3173,13,3736,1389,1189,128,0]An[3173,13,3736,1389,4056,128,0]An[3173,13,3736,2408,1887,128,0]An[3173,13,3736,2408,4367,128,0]An[3173,13,3736,3736,4886,128,0]An[3173,13,4853,4853,1204,128,0]An[3173,13,4853,4853,1207,128,0]An[2029,13,2030,2030,3341,128,0]Am[2029,13,2030,431,4490,128,0]An[2029,13,2030,2030,2328,128,0]An[2029,13,2030,2030,2342,128,0]An[2029,13,2030,2030,4210,128,0]An[1127,13,1128,1128,3086,128,0]An[1127,13,1128,1128,4999,128,0]Am[1127,13,1725,1725,142,128,0]An[1127,13,1419,1419,1222,128,0]An[1127,13,1419,1419,4084,128,0]An[1127,13,1419,1419,4592,128,0]An[1127,13,4305,4305,5209,128,0]An[1127,13,4305,4305,5210,128,0]Am[1127,13,1824,1824,143,128,0]Aj[477,13,478,3740,5072,0,0]Aj[477,13,478,1126,4491,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Al[3173,14,3174,1798,5160,0,0]Ai[3173,14,4893,0,4961,0,0]Ah[3173,14,4595,0,516,0,0]Ai[3173,14,4595,0,1216,0,0]Af[477,5,478,3740,0,0,0]Al[1228,15,1229,1229,4047,0,0]Ae[2408,6,2409,0,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Aj[477,15,478,3740,4898,0,0]Al[3173,15,3174,3147,4899,0,0]Af[477,5,478,2353,0,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,2044,4082,0,0]Af[477,5,478,2385,0,0,0]2Ah[3173,6,3174,1798,0,0,0]Ag[477,19,478,0,1480,0,0]Al[3173,19,3174,1856,1481,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]=Ah[477,12,1735,0,4243,0,0]>Ak[477,13,1818,0,4819,4243,0]>Al[3173,12,1736,1736,4245,0,0]>Ao[3173,13,1819,1819,4820,4245,0]Ao[1127,13,4305,4305,5210,4245,0]An[2408,13,2409,2409,132,4066,0]Ao[2408,13,2409,2409,2299,4066,0]Ag[477,14,478,0,3118,0,0]Ag[477,14,478,0,4587,0,0]Al[3173,14,3174,1418,3119,0,0]Al[3173,14,3174,1418,4588,0,0]Ag[477,13,478,0,4242,0,0]Al[3173,13,3174,1733,4244,0,0]Aj[477,13,478,2036,4448,0,0]0Ak[2029,13,2030,431,4490,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,3741,3298,0,0]Al[1127,13,1419,1419,4592,0,0]Ae[1127,2,1128,0,0,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2313,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]6Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]32Ak[1228,14,1229,1229,141,0,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Al[2029,14,2030,2030,2342,0,0]Ah[477,14,3735,0,4885,0,0]Al[3173,14,3736,3736,4886,0,0]Al[3173,13,3174,2044,1907,0,0]Al[3173,13,3174,4387,5257,0,0]Al[3173,13,3174,4387,5262,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]>=Al[1228,14,1417,1417,1221,0,0]Ai[536,14,537,537,4048,0,0]Ah[477,13,1818,0,4817,0,0]Ah[477,13,1818,0,4819,0,0]Al[3173,13,1819,1819,4818,0,0]Al[3173,13,1819,1819,4820,0,0]6Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Af[477,5,478,4616,0,0,0]Ah[3173,5,3174,4616,0,0,0]Ag[477,15,478,0,4583,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,3741,4584,0,0]Al[3173,15,3174,2354,4201,0,0]Ah[3173,6,3174,2354,0,0,0]Ah[3173,5,3174,1829,0,0,0]Af[477,5,478,2353,0,0,0]Aj[477,15,478,4157,4483,0,0]Ag[477,5,1818,1819,0,0,0]Ae[3173,5,1819,0,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,1798,4894,0,0]?=5454Al[3173,15,3174,2354,4345,0,0]Ag[477,5,3735,2408,0,0,0]Ah[3173,5,3736,2408,0,0,0]Ah[3173,5,3174,1798,0,0,0]98Ah[3173,6,3174,1152,0,0,0]:9Af[477,5,478,1733,0,0,0]Ah[3173,5,3174,1733,0,0,0]Ae[3173,5,1731,0,0,0,0]Al[3173,13,3174,3741,3298,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Al[1127,14,1128,1128,3086,0,0]Ae[3173,2,3174,0,0,0,0]Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Aj[477,12,478,2036,4448,0,0]Ab[4390,3,0,0,0,0,0]Ak[1228,14,1229,1229,141,0,0]Al[1228,14,1417,1417,4083,0,0]98Aj[477,13,478,2385,3325,0,0]Al[3173,13,3174,2354,3326,0,0]Ag[477,13,478,0,4924,0,0]Al[3173,13,3174,3276,4925,0,0];==;:Ak[1228,14,1229,1229,141,0,0]21Al[1127,14,1128,1128,3086,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5008,0,0]Al[3173,13,3174,2044,3323,0,0]Aj[477,13,478,3740,3295,0,0]Aj[477,13,478,2385,2312,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,2354,2313,0,0]<;Ag[477,13,478,0,1480,0,0]Ag[477,13,478,0,1463,0,0]Al[3173,13,3174,1856,1481,0,0]Al[3173,13,3174,1403,1464,0,0]20Ae[1228,7,1417,0,0,0,0]?>Al[1228,14,1417,1417,1221,0,0]Ao[1127,13,1128,1128,4999,3127,0]Ag[477,15,478,0,3099,0,0]Af[477,5,478,1393,0,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Af[477,6,478,3741,0,0,0]Ah[3173,6,3174,3741,0,0,0]Al[3173,15,3174,2354,4345,0,0]Ah[3173,5,3174,1829,0,0,0]Af[477,5,478,1418,0,0,0]Ah[3173,5,3174,1418,0,0,0]97Ae[1127,5,1419,0,0,0,0]:8Ah[3173,6,3174,1798,0,0,0]Af[477,5,478,1148,0,0,0]Ah[3173,5,3174,1148,0,0,0]Al[3173,15,3174,1403,4897,0,0]Af[477,5,478,1430,0,0,0]Ah[3173,5,3174,1430,0,0,0]Af[477,5,478,3276,0,0,0]Ah[3173,5,3174,3276,0,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,3741,4584,0,0]Af[477,5,478,3740,0,0,0]Aj[477,15,478,4157,3121,0,0]Aj[477,15,478,4157,3324,0,0]Aj[477,15,478,4162,3342,0,0]Aj[477,15,478,4162,4248,0,0]An[1228,13,1229,1229,141,4344,0]Ao[1228,13,1229,1229,4075,4344,0]Ao[1228,13,1229,1229,4047,4344,0]Am[477,13,478,3740,3297,4344,0]Am[477,13,478,3740,1450,4344,0]Am[477,13,478,3740,5072,4344,0]Am[477,13,478,3740,4898,4344,0]Am[477,13,478,2353,2308,4344,0]Am[477,13,478,2353,4347,4344,0]Am[477,13,478,4270,1458,4344,0]Al[477,13,478,1126,520,4344,0]Am[477,13,478,1126,4491,4344,0]Am[477,13,478,4157,4484,4344,0]Am[477,13,478,4157,3121,4344,0]Am[477,13,478,4157,3324,4344,0]Am[477,13,478,4157,4483,4344,0]Am[477,13,478,4162,3342,4344,0]Am[477,13,478,4162,4248,4344,0]Aj[477,13,478,0,1480,4344,0]Aj[477,13,478,0,5069,4344,0]Aj[477,13,478,0,1463,4344,0]Aj[477,13,478,0,3317,4344,0]Aj[477,13,478,0,3116,4344,0]Aj[477,13,478,0,4954,4344,0]Aj[477,13,478,0,3290,4344,0]Aj[477,13,478,0,2343,4344,0]Aj[477,13,478,0,3303,4344,0]Aj[477,13,478,0,3118,4344,0]Aj[477,13,478,0,4587,4344,0]Aj[477,13,478,0,4194,4344,0]Aj[477,13,478,0,4583,4344,0]Aj[477,13,478,0,3112,4344,0]Aj[477,13,478,0,4450,4344,0]Aj[477,13,478,0,4606,4344,0]Aj[477,13,478,0,4924,4344,0]Aj[477,13,478,0,4939,4344,0]Aj[477,13,478,0,4064,4344,0]Aj[477,13,478,0,4460,4344,0]Aj[477,13,478,0,4242,4344,0]Aj[477,13,478,0,5126,4344,0]Aj[477,13,478,0,4188,4344,0]Aj[477,13,478,0,4050,4344,0]Aj[477,13,478,0,3099,4344,0]Aj[477,13,478,0,4580,4344,0]Aj[477,13,478,0,4787,4344,0]Aj[477,13,478,0,4200,4344,0]Aj[477,13,478,0,4203,4344,0]Aj[477,13,478,0,4208,4344,0]Aj[477,13,478,0,4959,4344,0]Aj[477,13,478,0,3306,4344,0]Ai[477,13,478,0,526,4344,0]Ai[477,13,478,0,133,4344,0]Aj[477,13,478,0,2330,4344,0]Aj[477,13,478,0,3097,4344,0]Aj[477,13,3735,0,501,4344,0]Ak[477,13,3735,0,3286,4344,0]Ak[477,13,3735,0,1188,4344,0]Ak[477,13,3735,0,4055,4344,0]Ak[477,13,3735,0,1886,4344,0]Ak[477,13,3735,0,4366,4344,0]Ak[477,13,1818,0,1201,4344,0]Ak[477,13,1818,0,4817,4344,0]Ak[477,13,1818,0,5063,4344,0]Ak[477,13,1818,0,4819,4344,0]Ao[3173,13,3174,1856,1481,4344,0]Ao[3173,13,3174,1856,5070,4344,0]Ao[3173,13,3174,3147,4899,4344,0]Ao[3173,13,3174,1403,1464,4344,0]Ao[3173,13,3174,1403,4238,4344,0]Ao[3173,13,3174,1403,3318,4344,0]Ao[3173,13,3174,1403,3117,4344,0]Ao[3173,13,3174,1403,4897,4344,0]Ao[3173,13,3174,1403,4955,4344,0]Ao[3173,13,3174,1403,3293,4344,0]Ao[3173,13,3174,1418,2344,4344,0]Ao[3173,13,3174,1418,3304,4344,0]Ao[3173,13,3174,1418,3119,4344,0]Ao[3173,13,3174,1418,4588,4344,0]Ao[3173,13,3174,1152,3122,4344,0]Ao[3173,13,3174,1152,4374,4344,0]Ao[3173,13,3174,1157,3343,4344,0]Ao[3173,13,3174,1157,4063,4344,0]Ao[3173,13,3174,2044,4485,4344,0]Ao[3173,13,3174,2044,4198,4344,0]Ao[3173,13,3174,3741,4584,4344,0]Ao[3173,13,3174,3741,3113,4344,0]Ao[3173,13,3174,3741,4451,4344,0]Ao[3173,13,3174,3741,5157,4344,0]Ao[3173,13,3174,3276,4607,4344,0]Ao[3173,13,3174,3276,4925,4344,0]Ao[3173,13,3174,3276,4940,4344,0]Ao[3173,13,3174,3276,4065,4344,0]Ao[3173,13,3174,1733,4461,4344,0]Ao[3173,13,3174,1733,4244,4344,0]Ao[3173,13,3174,1733,5127,4344,0]Ao[3173,13,3174,1733,4190,4344,0]Ao[3173,13,3174,1733,4051,4344,0]Ao[3173,13,3174,1393,3100,4344,0]Ao[3173,13,3174,1393,3310,4344,0]Ao[3173,13,3174,1393,3332,4344,0]Ao[3173,13,3174,1393,4205,4344,0]Ao[3173,13,3174,1393,4582,4344,0]Ao[3173,13,3174,1393,4789,4344,0]Ao[3173,13,3174,1393,2302,4344,0]Ao[3173,13,3174,2354,4793,4344,0]Ao[3173,13,3174,2354,4201,4344,0]Ao[3173,13,3174,1798,4596,4344,0]Ao[3173,13,3174,1798,5160,4344,0]Ao[3173,13,3174,1798,2316,4344,0]Ao[3173,13,3174,1798,4894,4344,0]Ao[3173,13,3174,1829,4204,4344,0]Ao[3173,13,3174,1829,4209,4344,0]Al[3173,13,3174,0,4489,4344,0]Al[3173,13,3174,0,4960,4344,0]Ao[3173,13,3174,4387,3307,4344,0]Ao[3173,13,3174,4387,5262,4344,0]An[3173,13,3174,3174,527,4344,0]An[3173,13,3174,3174,134,4344,0]Ao[3173,13,3174,3174,2331,4344,0]Ao[3173,13,3174,3174,3098,4344,0]Ao[3173,13,1731,1731,4380,4344,0]Ao[3173,13,5111,5111,5007,4344,0]Ao[3173,13,5111,5111,1203,4344,0]Al[3173,13,1819,0,1202,4344,0]Ao[3173,13,1819,1819,4818,4344,0]Ao[3173,13,1819,1819,5064,4344,0]Ao[3173,13,1819,1819,4820,4344,0]Am[3173,13,3736,535,502,4344,0]An[3173,13,3736,535,3287,4344,0]Ao[3173,13,3736,1389,1189,4344,0]Ao[3173,13,3736,1389,4056,4344,0]Ao[3173,13,3736,2408,1887,4344,0]Ao[3173,13,3736,2408,4367,4344,0]Ao[3173,13,4853,4853,1207,4344,0]Ao[2029,13,2030,2030,2328,4344,0]Ao[2029,13,2030,2030,2342,4344,0]Ao[2029,13,2030,2030,4210,4344,0]Ao[1127,13,1128,1128,4999,4344,0]Ao[1127,13,1419,1419,4592,4344,0]Ao[1127,13,4305,4305,5209,4344,0]Ao[1127,13,4305,4305,5210,4344,0]Af[477,7,478,2036,0,0,0]Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Al[2029,14,2030,2030,2328,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]10Ae[1127,7,1128,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Ae[4390,7,4391,0,0,0,0]Ae[1228,7,1229,0,0,0,0]Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,3740,3297,0,0]1Al[3173,13,3174,2044,4485,0,0]Al[1228,13,1417,1417,1221,0,0]Al[1228,14,1417,1417,4083,0,0]Aj[477,12,478,2036,1898,0,0]Am[477,13,478,1431,4249,1898,0]Am[477,13,478,1169,4078,1898,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Af[477,5,478,1126,0,0,0]Ag[477,15,478,0,3099,0,0]Af[477,5,478,1393,0,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,3741,4584,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,3741,1206,0,0]Af[477,5,478,2354,0,0,0]2Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]32Ag[477,15,478,0,3112,0,0]Al[3173,15,3174,3741,3113,0,0]Ag[477,15,478,0,3099,0,0]?0?0?43Ag[477,5,1818,1819,0,0,0]Ae[3173,5,1819,0,0,0,0]10Af[477,5,478,4995,0,0,0]Ah[3173,5,3174,4995,0,0,0]Al[3173,15,4853,4853,1204,0,0]7Al[3173,15,3174,1403,4897,0,0]7Al[3173,15,3174,1798,4596,0,0]Ag[477,12,478,0,2336,0,0]Aj[477,13,478,0,4338,2336,0]Aj[477,13,478,0,4222,2336,0]Al[3173,12,3174,1430,2337,0,0]Ao[3173,13,3174,4616,4339,2337,0]Ao[3173,13,3174,1430,4223,2337,0]Ae[4088,7,4089,0,0,0,0]Aj[477,13,478,3740,3297,0,0]Al[3173,13,3174,3741,3298,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]32An[1228,13,1229,1229,141,4462,0]An[2408,13,2409,2409,132,4462,0]Ao[2408,13,2409,2409,2299,4462,0]Ao[1127,13,1128,1128,3086,4462,0]An[1127,13,1725,1725,142,4462,0]An[1127,13,1824,1824,143,4462,0]Ak[2029,13,2030,431,4490,0,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]:9Ae[3173,2,3174,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]?>43Aj[477,13,478,4157,3322,0,0]Ae[4390,7,4391,0,0,0,0]7Al[1127,14,1128,1128,3086,0,0]80Ae[1228,7,1229,0,0,0,0]Ag[477,13,478,0,4242,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4244,0,0]Al[3173,13,3174,1733,4190,0,0]Ag[477,14,478,0,4242,0,0]Al[3173,14,3174,1733,4244,0,0]53Aj[477,13,478,4162,3328,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,1403,4897,0,0]Al[3173,15,3174,3741,4584,0,0]Ah[477,10,3735,3736,0,0,0]Af[3173,10,3736,0,0,0,0]Ag[477,5,3735,3736,0,0,0]Ae[3173,5,3736,0,0,0,0]Ah[477,10,1735,1736,0,0,0]Af[3173,10,1736,0,0,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,10,478,3741,0,0,0]Ai[3173,10,3174,3741,0,0,0]Ah[3173,6,3174,1798,0,0,0]Ah[3173,6,3174,1403,0,0,0]Af[477,6,478,3740,0,0,0]Ah[3173,6,3174,3147,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]10Aj[477,15,478,3740,4898,0,0]Al[3173,15,3174,3147,4899,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Ah[477,14,3735,0,4885,0,0]Al[3173,14,3736,3736,4886,0,0]Aj[477,13,478,3740,3297,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]10Al[3173,13,3174,3147,3089,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]Ab[4917,3,0,0,0,0,0]Ao[1127,13,1128,1128,4999,3127,0]3Aj[477,13,478,4162,3328,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Af[477,5,478,3276,0,0,0]Ah[3173,5,3174,3276,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]54Ai[3173,10,3174,1798,0,0,0]Al[3173,15,3174,3741,1206,0,0]7600Al[3173,15,3174,1152,4374,0,0]4365Al[3173,15,4853,4853,1204,0,0]Ae[1127,9,1128,0,0,0,0]:9Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]<;<;Af[477,6,478,1403,0,0,0]Ah[3173,6,3174,1403,0,0,0]32Al[1228,15,1229,1229,4075,0,0]Ac[477,5,478,0,0,0,0]Ae[3173,5,3174,0,0,0,0]Ag[477,15,478,0,4200,0,0]Ag[477,5,1735,1736,0,0,0]Al[3173,15,3174,2354,4201,0,0]Al[3173,15,3174,1798,4894,0,0]Ae[3173,5,1736,0,0,0,0]An[1228,13,1229,1229,141,4452,0]An[2408,13,2409,2409,132,4452,0]Ao[1127,13,1128,1128,3086,4452,0]An[1127,13,1725,1725,142,4452,0]An[1127,13,1824,1824,143,4452,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ag[477,13,478,0,1480,0,0]Al[3173,13,3174,1856,1481,0,0]Aj[477,14,478,2353,4347,0,0]Aj[477,13,478,3740,5072,0,0]Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Ag[477,13,478,0,4338,0,0]Al[3173,13,3174,4616,4339,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]7Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,3740,3297,0,0]Ah[477,13,1818,0,4817,0,0]Ah[477,13,1818,0,4819,0,0]Al[3173,13,1819,1819,4818,0,0]Al[3173,13,1819,1819,4820,0,0]45;:Ao[4088,13,4089,4089,5161,4953,0]Ag[477,13,478,0,4597,0,0]Al[3173,13,3174,1148,4598,0,0]Ae[1127,6,1128,0,0,0,0]Af[477,5,478,4270,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]10Ag[477,15,478,0,3112,0,0]Al[3173,15,3174,3741,3113,0,0]Ae[3173,5,5111,0,0,0,0]Af[477,5,478,4157,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Al[3173,15,4853,4853,1204,0,0]Aj[477,14,478,2353,4347,0,0]Ai[477,13,478,0,526,3078,0]Ai[477,13,478,0,133,3078,0]An[3173,13,3174,3174,527,3078,0]An[3173,13,3174,3174,134,3078,0]Ao[2408,13,2409,2409,2299,3333,0]Ag[477,13,478,0,4939,0,0]Al[3173,13,3174,3276,4940,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Aj[477,13,478,3740,3297,0,0]Ag[477,12,478,0,4891,0,0]Al[3173,12,3174,3741,4892,0,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Ah[477,12,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,12,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Aj[477,14,478,2353,4347,0,0]Al[3173,13,3174,2044,1907,0,0]Ah[3173,2,4385,4161,0,0,0]Ae[1228,7,1229,0,0,0,0]==Ai[477,13,478,1126,520,0,0]Ak[2029,13,2030,431,4490,0,0]032Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Ae[3173,2,3174,0,0,0,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Ag[477,10,478,4387,0,0,0]Ai[3173,10,3174,4387,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Af[477,5,478,1733,0,0,0]Ah[3173,5,3174,1733,0,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,3741,3298,0,0]Al[3173,13,3174,2354,2309,0,0]Ah[477,13,3735,0,4366,0,0]Al[3173,13,3736,2408,4367,0,0]Aj[477,13,478,2036,3125,0,0]0Aj[477,13,478,3740,3297,0,0]5Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Al[1127,14,1128,1128,3086,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Al[3173,15,4853,4853,1204,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]10Ag[477,15,478,0,4954,0,0]Ag[477,15,478,0,3112,0,0]Ag[477,15,478,0,4450,0,0]Al[3173,15,3174,1403,4955,0,0]Al[3173,15,3174,3741,3113,0,0]Al[3173,15,3174,3741,4451,0,0]Ah[3173,5,3174,3741,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1798,0,0,0]Ae[4088,5,4089,0,0,0,0]Al[1127,13,1128,1128,3086,0,0]Aj[477,13,478,3740,3297,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Ah[3173,7,5042,5041,0,0,0]0Al[3173,13,3174,3741,3298,0,0]6Ai[477,13,478,1126,520,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ao[4088,13,4089,4089,5161,4953,0]0Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]10Ag[477,13,478,0,4924,0,0]Al[3173,13,3174,3276,4925,0,0]Am[1228,13,1229,1229,141,499,0]Am[2408,13,2409,2409,132,499,0]An[1127,13,1128,1128,3086,499,0]Am[1127,13,1725,1725,142,499,0]Am[1127,13,1824,1824,143,499,0]??Ah[477,13,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Al[3173,13,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ai[477,13,478,1126,520,0,0]An[1228,13,1229,1229,141,4462,0]An[2408,13,2409,2409,132,4462,0]Ao[2408,13,2409,2409,2299,4462,0]Ao[1127,13,1128,1128,3086,4462,0]An[1127,13,1725,1725,142,4462,0]An[1127,13,1824,1824,143,4462,0]Ag[477,13,478,0,4242,0,0]Al[3173,13,3174,1733,4244,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ae[1127,5,4305,0,0,0,0]0Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Aj[477,13,478,2353,2308,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2313,0,0]Al[3173,13,3174,3741,3298,0,0]Ao[4088,13,4089,4089,5161,4953,0];:Ag[477,5,1735,1736,0,0,0]Ae[3173,5,1736,0,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]?>?>Aj[477,13,478,3740,3297,0,0]6Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ae[4088,7,4089,0,0,0,0]Ae[4390,7,4391,0,0,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]?Ah[477,12,1735,0,4243,0,0]>Ak[477,13,1818,0,4819,4243,0]>Al[3173,12,1736,1736,4245,0,0]>Ao[3173,13,1819,1819,4820,4245,0]Ao[1127,13,4305,4305,5210,4245,0]An[2408,13,2409,2409,132,4066,0]Ao[2408,13,2409,2409,2299,4066,0]Ag[477,14,478,0,3118,0,0]Ag[477,14,478,0,4587,0,0]Al[3173,14,3174,1418,3119,0,0]Al[3173,14,3174,1418,4588,0,0]Ag[477,13,478,0,4242,0,0]Al[3173,13,3174,1733,4244,0,0]Aj[477,13,478,2036,4448,0,0]0Ak[2029,13,2030,431,4490,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,3741,3298,0,0]Al[1127,13,1419,1419,4592,0,0]Ae[1127,2,1128,0,0,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2313,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]6Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]32Ak[1228,14,1229,1229,141,0,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Al[2029,14,2030,2030,2342,0,0]Ah[477,14,3735,0,4885,0,0]Al[3173,14,3736,3736,4886,0,0]Al[3173,13,3174,2044,1907,0,0]Al[3173,13,3174,4387,5257,0,0]Al[3173,13,3174,4387,5262,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]>=Al[1228,14,1417,1417,1221,0,0]Ai[536,14,537,537,4048,0,0]Ah[477,13,1818,0,4817,0,0]Ah[477,13,1818,0,4819,0,0]Al[3173,13,1819,1819,4818,0,0]Al[3173,13,1819,1819,4820,0,0]6Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Af[477,5,478,4616,0,0,0]Ah[3173,5,3174,4616,0,0,0]Ag[477,15,478,0,4583,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,3741,4584,0,0]Al[3173,15,3174,2354,4201,0,0]Ah[3173,6,3174,2354,0,0,0]Ah[3173,5,3174,1829,0,0,0]Af[477,5,478,2353,0,0,0]Aj[477,15,478,4157,4483,0,0]Ag[477,5,1818,1819,0,0,0]Ae[3173,5,1819,0,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,1798,4894,0,0]?=5454Al[3173,15,3174,2354,4345,0,0]Ag[477,5,3735,2408,0,0,0]Ah[3173,5,3736,2408,0,0,0]Ah[3173,5,3174,1798,0,0,0]98Ah[3173,6,3174,1152,0,0,0]:9Af[477,5,478,1733,0,0,0]Ah[3173,5,3174,1733,0,0,0]Ae[3173,5,1731,0,0,0,0]Al[3173,13,3174,3741,3298,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Al[1127,14,1128,1128,3086,0,0]Ae[3173,2,3174,0,0,0,0]Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Aj[477,12,478,2036,4448,0,0]Ab[4390,3,0,0,0,0,0]Ak[1228,14,1229,1229,141,0,0]Al[1228,14,1417,1417,4083,0,0]98Aj[477,13,478,2385,3325,0,0]Al[3173,13,3174,2354,3326,0,0]Ag[477,13,478,0,4924,0,0]Al[3173,13,3174,3276,4925,0,0];==;:Ak[1228,14,1229,1229,141,0,0]21Al[1127,14,1128,1128,3086,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5008,0,0]Al[3173,13,3174,2044,3323,0,0]Aj[477,13,478,3740,3295,0,0]Aj[477,13,478,2385,2312,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,2354,2313,0,0]<;Ag[477,13,478,0,1480,0,0]Ag[477,13,478,0,1463,0,0]Al[3173,13,3174,1856,1481,0,0]Al[3173,13,3174,1403,1464,0,0]20Ae[1228,7,1417,0,0,0,0]?>Al[1228,14,1417,1417,1221,0,0]Ao[1127,13,1128,1128,4999,3127,0]Ag[477,15,478,0,3099,0,0]Af[477,5,478,1393,0,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Af[477,6,478,3741,0,0,0]Ah[3173,6,3174,3741,0,0,0]Al[3173,15,3174,2354,4345,0,0]Ah[3173,5,3174,1829,0,0,0]Af[477,5,478,1418,0,0,0]Ah[3173,5,3174,1418,0,0,0]97Ae[1127,5,1419,0,0,0,0]:8Ah[3173,6,3174,1798,0,0,0]Af[477,5,478,1148,0,0,0]Ah[3173,5,3174,1148,0,0,0]Al[3173,15,3174,1403,4897,0,0]Af[477,5,478,1430,0,0,0]Ah[3173,5,3174,1430,0,0,0]Af[477,5,478,3276,0,0,0]Ah[3173,5,3174,3276,0,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,3741,4584,0,0]Af[477,5,478,3740,0,0,0]Aj[477,15,478,4157,3121,0,0]Aj[477,15,478,4157,3324,0,0]Aj[477,15,478,4162,3342,0,0]Aj[477,15,478,4162,4248,0,0]An[1228,13,1229,1229,141,4344,0]Ao[1228,13,1229,1229,4075,4344,0]Ao[1228,13,1229,1229,4047,4344,0]Am[477,13,478,3740,3297,4344,0]Am[477,13,478,3740,1450,4344,0]Am[477,13,478,3740,5072,4344,0]Am[477,13,478,3740,4898,4344,0]Am[477,13,478,2353,2308,4344,0]Am[477,13,478,2353,4347,4344,0]Am[477,13,478,4270,1458,4344,0]Al[477,13,478,1126,520,4344,0]Am[477,13,478,1126,4491,4344,0]Am[477,13,478,4157,4484,4344,0]Am[477,13,478,4157,3121,4344,0]Am[477,13,478,4157,3324,4344,0]Am[477,13,478,4157,4483,4344,0]Am[477,13,478,4162,3342,4344,0]Am[477,13,478,4162,4248,4344,0]Aj[477,13,478,0,1480,4344,0]Aj[477,13,478,0,5069,4344,0]Aj[477,13,478,0,1463,4344,0]Aj[477,13,478,0,3317,4344,0]Aj[477,13,478,0,3116,4344,0]Aj[477,13,478,0,4954,4344,0]Aj[477,13,478,0,3290,4344,0]Aj[477,13,478,0,2343,4344,0]Aj[477,13,478,0,3303,4344,0]Aj[477,13,478,0,3118,4344,0]Aj[477,13,478,0,4587,4344,0]Aj[477,13,478,0,4194,4344,0]Aj[477,13,478,0,4583,4344,0]Aj[477,13,478,0,3112,4344,0]Aj[477,13,478,0,4450,4344,0]Aj[477,13,478,0,4606,4344,0]Aj[477,13,478,0,4924,4344,0]Aj[477,13,478,0,4939,4344,0]Aj[477,13,478,0,4064,4344,0]Aj[477,13,478,0,4460,4344,0]Aj[477,13,478,0,4242,4344,0]Aj[477,13,478,0,5126,4344,0]Aj[477,13,478,0,4188,4344,0]Aj[477,13,478,0,4050,4344,0]Aj[477,13,478,0,3099,4344,0]Aj[477,13,478,0,4580,4344,0]Aj[477,13,478,0,4787,4344,0]Aj[477,13,478,0,4200,4344,0]Aj[477,13,478,0,4203,4344,0]Aj[477,13,478,0,4208,4344,0]Aj[477,13,478,0,4959,4344,0]Aj[477,13,478,0,3306,4344,0]Ai[477,13,478,0,526,4344,0]Ai[477,13,478,0,133,4344,0]Aj[477,13,478,0,2330,4344,0]Aj[477,13,478,0,3097,4344,0]Aj[477,13,3735,0,501,4344,0]Ak[477,13,3735,0,3286,4344,0]Ak[477,13,3735,0,1188,4344,0]Ak[477,13,3735,0,4055,4344,0]Ak[477,13,3735,0,1886,4344,0]Ak[477,13,3735,0,4366,4344,0]Ak[477,13,1818,0,1201,4344,0]Ak[477,13,1818,0,4817,4344,0]Ak[477,13,1818,0,5063,4344,0]Ak[477,13,1818,0,4819,4344,0]Ao[3173,13,3174,1856,1481,4344,0]Ao[3173,13,3174,1856,5070,4344,0]Ao[3173,13,3174,3147,4899,4344,0]Ao[3173,13,3174,1403,1464,4344,0]Ao[3173,13,3174,1403,4238,4344,0]Ao[3173,13,3174,1403,3318,4344,0]Ao[3173,13,3174,1403,3117,4344,0]Ao[3173,13,3174,1403,4897,4344,0]Ao[3173,13,3174,1403,4955,4344,0]Ao[3173,13,3174,1403,3293,4344,0]Ao[3173,13,3174,1418,2344,4344,0]Ao[3173,13,3174,1418,3304,4344,0]Ao[3173,13,3174,1418,3119,4344,0]Ao[3173,13,3174,1418,4588,4344,0]Ao[3173,13,3174,1152,3122,4344,0]Ao[3173,13,3174,1152,4374,4344,0]Ao[3173,13,3174,1157,3343,4344,0]Ao[3173,13,3174,1157,4063,4344,0]Ao[3173,13,3174,2044,4485,4344,0]Ao[3173,13,3174,2044,4198,4344,0]Ao[3173,13,3174,3741,4584,4344,0]Ao[3173,13,3174,3741,3113,4344,0]Ao[3173,13,3174,3741,4451,4344,0]Ao[3173,13,3174,3741,5157,4344,0]Ao[3173,13,3174,3276,4607,4344,0]Ao[3173,13,3174,3276,4925,4344,0]Ao[3173,13,3174,3276,4940,4344,0]Ao[3173,13,3174,3276,4065,4344,0]Ao[3173,13,3174,1733,4461,4344,0]Ao[3173,13,3174,1733,4244,4344,0]Ao[3173,13,3174,1733,5127,4344,0]Ao[3173,13,3174,1733,4190,4344,0]Ao[3173,13,3174,1733,4051,4344,0]Ao[3173,13,3174,1393,3100,4344,0]Ao[3173,13,3174,1393,3310,4344,0]Ao[3173,13,3174,1393,3332,4344,0]Ao[3173,13,3174,1393,4205,4344,0]Ao[3173,13,3174,1393,4582,4344,0]Ao[3173,13,3174,1393,4789,4344,0]Ao[3173,13,3174,1393,2302,4344,0]Ao[3173,13,3174,2354,4793,4344,0]Ao[3173,13,3174,2354,4201,4344,0]Ao[3173,13,3174,1798,4596,4344,0]Ao[3173,13,3174,1798,5160,4344,0]Ao[3173,13,3174,1798,2316,4344,0]Ao[3173,13,3174,1798,4894,4344,0]Ao[3173,13,3174,1829,4204,4344,0]Ao[3173,13,3174,1829,4209,4344,0]Al[3173,13,3174,0,4489,4344,0]Al[3173,13,3174,0,4960,4344,0]Ao[3173,13,3174,4387,3307,4344,0]Ao[3173,13,3174,4387,5262,4344,0]An[3173,13,3174,3174,527,4344,0]An[3173,13,3174,3174,134,4344,0]Ao[3173,13,3174,3174,2331,4344,0]Ao[3173,13,3174,3174,3098,4344,0]Ao[3173,13,1731,1731,4380,4344,0]Ao[3173,13,5111,5111,5007,4344,0]Ao[3173,13,5111,5111,1203,4344,0]Al[3173,13,1819,0,1202,4344,0]Ao[3173,13,1819,1819,4818,4344,0]Ao[3173,13,1819,1819,5064,4344,0]Ao[3173,13,1819,1819,4820,4344,0]Am[3173,13,3736,535,502,4344,0]An[3173,13,3736,535,3287,4344,0]Ao[3173,13,3736,1389,1189,4344,0]Ao[3173,13,3736,1389,4056,4344,0]Ao[3173,13,3736,2408,1887,4344,0]Ao[3173,13,3736,2408,4367,4344,0]Ao[3173,13,4853,4853,1207,4344,0]Ao[2029,13,2030,2030,2328,4344,0]Ao[2029,13,2030,2030,2342,4344,0]Ao[2029,13,2030,2030,4210,4344,0]Ao[1127,13,1128,1128,4999,4344,0]Ao[1127,13,1419,1419,4592,4344,0]Ao[1127,13,4305,4305,5209,4344,0]Ao[1127,13,4305,4305,5210,4344,0]Af[477,7,478,2036,0,0,0]Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Al[2029,14,2030,2030,2328,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]10Ae[1127,7,1128,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Ae[4390,7,4391,0,0,0,0]Ae[1228,7,1229,0,0,0,0]Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,3740,3297,0,0]1Al[3173,13,3174,2044,4485,0,0]Al[1228,13,1417,1417,1221,0,0]Al[1228,14,1417,1417,4083,0,0]Aj[477,12,478,2036,1898,0,0]Am[477,13,478,1431,4249,1898,0]Am[477,13,478,1169,4078,1898,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Af[477,5,478,1126,0,0,0]Ag[477,15,478,0,3099,0,0]Af[477,5,478,1393,0,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,3741,4584,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,3741,1206,0,0]Af[477,5,478,2354,0,0,0]2Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]32Ag[477,15,478,0,3112,0,0]Al[3173,15,3174,3741,3113,0,0]Ag[477,15,478,0,3099,0,0]?0?0?43Ag[477,5,1818,1819,0,0,0]Ae[3173,5,1819,0,0,0,0]10Af[477,5,478,4995,0,0,0]Ah[3173,5,3174,4995,0,0,0]Al[3173,15,4853,4853,1204,0,0]7Al[3173,15,3174,1403,4897,0,0]7Al[3173,15,3174,1798,4596,0,0]Ag[477,12,478,0,2336,0,0]Aj[477,13,478,0,4338,2336,0]Aj[477,13,478,0,4222,2336,0]Al[3173,12,3174,1430,2337,0,0]Ao[3173,13,3174,4616,4339,2337,0]Ao[3173,13,3174,1430,4223,2337,0]Ae[4088,7,4089,0,0,0,0]Aj[477,13,478,3740,3297,0,0]Al[3173,13,3174,3741,3298,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]32An[1228,13,1229,1229,141,4462,0]An[2408,13,2409,2409,132,4462,0]Ao[2408,13,2409,2409,2299,4462,0]Ao[1127,13,1128,1128,3086,4462,0]An[1127,13,1725,1725,142,4462,0]An[1127,13,1824,1824,143,4462,0]Ak[2029,13,2030,431,4490,0,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]:9Ae[3173,2,3174,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]?>43Aj[477,13,478,4157,3322,0,0]Ae[4390,7,4391,0,0,0,0]7Al[1127,14,1128,1128,3086,0,0]80Ae[1228,7,1229,0,0,0,0]Ag[477,13,478,0,4242,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4244,0,0]Al[3173,13,3174,1733,4190,0,0]Ag[477,14,478,0,4242,0,0]Al[3173,14,3174,1733,4244,0,0]53Aj[477,13,478,4162,3328,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,1403,4897,0,0]Al[3173,15,3174,3741,4584,0,0]Ah[477,10,3735,3736,0,0,0]Af[3173,10,3736,0,0,0,0]Ag[477,5,3735,3736,0,0,0]Ae[3173,5,3736,0,0,0,0]Ah[477,10,1735,1736,0,0,0]Af[3173,10,1736,0,0,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,10,478,3741,0,0,0]Ai[3173,10,3174,3741,0,0,0]Ah[3173,6,3174,1798,0,0,0]Ah[3173,6,3174,1403,0,0,0]Af[477,6,478,3740,0,0,0]Ah[3173,6,3174,3147,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]10Aj[477,15,478,3740,4898,0,0]Al[3173,15,3174,3147,4899,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Ah[477,14,3735,0,4885,0,0]Al[3173,14,3736,3736,4886,0,0]Aj[477,13,478,3740,3297,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]10Al[3173,13,3174,3147,3089,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]Ab[4917,3,0,0,0,0,0]Ao[1127,13,1128,1128,4999,3127,0]3Aj[477,13,478,4162,3328,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Af[477,5,478,3276,0,0,0]Ah[3173,5,3174,3276,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]54Ai[3173,10,3174,1798,0,0,0]Al[3173,15,3174,3741,1206,0,0]7600Al[3173,15,3174,1152,4374,0,0]4365Al[3173,15,4853,4853,1204,0,0]Ae[1127,9,1128,0,0,0,0]:9Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]<;<;Af[477,6,478,1403,0,0,0]Ah[3173,6,3174,1403,0,0,0]32Al[1228,15,1229,1229,4075,0,0]Ac[477,5,478,0,0,0,0]Ae[3173,5,3174,0,0,0,0]Ag[477,15,478,0,4200,0,0]Ag[477,5,1735,1736,0,0,0]Al[3173,15,3174,2354,4201,0,0]Al[3173,15,3174,1798,4894,0,0]Ae[3173,5,1736,0,0,0,0]An[1228,13,1229,1229,141,4452,0]An[2408,13,2409,2409,132,4452,0]Ao[1127,13,1128,1128,3086,4452,0]An[1127,13,1725,1725,142,4452,0]An[1127,13,1824,1824,143,4452,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ag[477,13,478,0,1480,0,0]Al[3173,13,3174,1856,1481,0,0]Aj[477,14,478,2353,4347,0,0]Aj[477,13,478,3740,5072,0,0]Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Ag[477,13,478,0,4338,0,0]Al[3173,13,3174,4616,4339,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]7Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,3740,3297,0,0]Ah[477,13,1818,0,4817,0,0]Ah[477,13,1818,0,4819,0,0]Al[3173,13,1819,1819,4818,0,0]Al[3173,13,1819,1819,4820,0,0]45;:Ao[4088,13,4089,4089,5161,4953,0]Ag[477,13,478,0,4597,0,0]Al[3173,13,3174,1148,4598,0,0]Ae[1127,6,1128,0,0,0,0]Af[477,5,478,4270,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]10Ag[477,15,478,0,3112,0,0]Al[3173,15,3174,3741,3113,0,0]Ae[3173,5,5111,0,0,0,0]Af[477,5,478,4157,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Al[3173,15,4853,4853,1204,0,0]Aj[477,14,478,2353,4347,0,0]Ai[477,13,478,0,526,3078,0]Ai[477,13,478,0,133,3078,0]An[3173,13,3174,3174,527,3078,0]An[3173,13,3174,3174,134,3078,0]Ao[2408,13,2409,2409,2299,3333,0]Ag[477,13,478,0,4939,0,0]Al[3173,13,3174,3276,4940,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Aj[477,13,478,3740,3297,0,0]Ag[477,12,478,0,4891,0,0]Al[3173,12,3174,3741,4892,0,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Ah[477,12,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,12,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Aj[477,14,478,2353,4347,0,0]Al[3173,13,3174,2044,1907,0,0]Ah[3173,2,4385,4161,0,0,0]Ae[1228,7,1229,0,0,0,0]==Ai[477,13,478,1126,520,0,0]Ak[2029,13,2030,431,4490,0,0]032Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Ae[3173,2,3174,0,0,0,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Ag[477,10,478,4387,0,0,0]Ai[3173,10,3174,4387,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Af[477,5,478,1733,0,0,0]Ah[3173,5,3174,1733,0,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,3741,3298,0,0]Al[3173,13,3174,2354,2309,0,0]Ah[477,13,3735,0,4366,0,0]Al[3173,13,3736,2408,4367,0,0]Aj[477,13,478,2036,3125,0,0]0Aj[477,13,478,3740,3297,0,0]5Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Al[1127,14,1128,1128,3086,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Al[3173,15,4853,4853,1204,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]10Ag[477,15,478,0,4954,0,0]Ag[477,15,478,0,3112,0,0]Ag[477,15,478,0,4450,0,0]Al[3173,15,3174,1403,4955,0,0]Al[3173,15,3174,3741,3113,0,0]Al[3173,15,3174,3741,4451,0,0]Ah[3173,5,3174,3741,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1798,0,0,0]Ae[4088,5,4089,0,0,0,0]Al[1127,13,1128,1128,3086,0,0]Aj[477,13,478,3740,3297,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Ah[3173,7,5042,5041,0,0,0]0Al[3173,13,3174,3741,3298,0,0]6Ai[477,13,478,1126,520,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ao[4088,13,4089,4089,5161,4953,0]0Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]10Ag[477,13,478,0,4924,0,0]Al[3173,13,3174,3276,4925,0,0]Am[1228,13,1229,1229,141,499,0]Am[2408,13,2409,2409,132,499,0]An[1127,13,1128,1128,3086,499,0]Am[1127,13,1725,1725,142,499,0]Am[1127,13,1824,1824,143,499,0]??Ah[477,13,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Al[3173,13,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ai[477,13,478,1126,520,0,0]An[1228,13,1229,1229,141,4462,0]An[2408,13,2409,2409,132,4462,0]Ao[2408,13,2409,2409,2299,4462,0]Ao[1127,13,1128,1128,3086,4462,0]An[1127,13,1725,1725,142,4462,0]An[1127,13,1824,1824,143,4462,0]Ag[477,13,478,0,4242,0,0]Al[3173,13,3174,1733,4244,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ae[1127,5,4305,0,0,0,0]0Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Aj[477,13,478,2353,2308,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2313,0,0]Al[3173,13,3174,3741,3298,0,0]Ao[4088,13,4089,4089,5161,4953,0];:Ag[477,5,1735,1736,0,0,0]Ae[3173,5,1736,0,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]?>?>Aj[477,13,478,3740,3297,0,0]6Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ae[4088,7,4089,0,0,0,0]Ae[4390,7,4391,0,0,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]?>>>>A`[\"{IFfBCAb}\",[]]?A`[\"{KIbBFL`}\",[]]A`[\"{cc{}}\",[\"T\"]]0000A`[\"{KIbABCf}\",[]]111Aa[\"{AJ@fAHCd}\",[]]22A`[\"{BBChIFf}\",[]]33333333A`[\"{BHMnIFd}\",[]]A`[\"{BEFlIFd}\",[]]5A`[\"{BEHbIFd}\",[]]A`[\"{BBNfIFd}\",[]]A`[\"{BBOhIFd}\",[]]A`[\"{BCMjIFd}\",[]]A`[\"{BCOdIFd}\",[]]A`[\"{BHLlIFd}\",[]]A`[\"{BHGfIFd}\",[]]A`[\"{BEIlIFd}\",[]]A`[\"{AIN`IFd}\",[]]>>>>>>>>>>>>An[\"{{{AHO`{c}}}AJAjCNh}\",[\"S\"]]??????????????Bm[\"{{{AHO`{KI`}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bk[\"{{{AHO`{KFn}}{AHO`{CGbc}}}ICjKF`}\",[\"H\"]]Bn[\"{{{AHO`{AOL`}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{B@Mf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{DAl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{A@j}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{ABCd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AHCb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{KIb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BFDf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bk[\"{{{AHO`{KG`}}{AHO`{CGbc}}}ICjKF`}\",[\"H\"]]Bn[\"{{{AHO`{AHFd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BBBl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AJAn}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AOLb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BEGb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BFCl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{B@Mh}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{DAn}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{A@l}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{ABCf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AHCd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Aa[\"{{}c{}}\",[\"U\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n[\"{{}ICj}\",[]]0000Cc[\"{{{AHO`{CGbKDl}}KCb}{{KGd{{KFl{IDb}}AHFd}}}}\",[]]Cf[\"{{{AHO`{CGbBB@j}}}{{KFl{c}}}{}}\",[\"Iterator::Item\"]]Dl[\"{{{AHO`{BFBn}}ICh{AHO`{CGb{K@j{Oh}}}}}{{KGd{{AHO`{{K@j{Oh}}}}AOJj}}}}\",[]]Bi[\"{{{AHO`{CGbNNf}}A@l}{{KFl{ABCf}}}}\",[]]Dl[\"{{{AHO`{BFC`}}ICh{AHO`{CGb{K@j{Oh}}}}}{{KGd{{AHO`{{K@j{Oh}}}}AOJl}}}}\",[]]Bf[\"{{{AHO`{AILb}}KFn}{{KFl{DA`}}}}\",[]]Bf[\"{{{AHO`{DA`}}}{{KGd{ICjAIKd}}}}\",[]]A`[\"{AILnCNb}\",[]]Am[\"{{{AHO`{CGbAILd}}}ICj}\",[]]A`[\"{AIM`CNb}\",[]]Ck[\"{{{ABb{{AHO`{CGbAIJd}}}}{AHO`{CGbNIn}}}{{DAh{ICj}}}}\",[]]Dk[\"{{{ABb{{AHO`{CGbBD@f}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbABBf}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbABBh}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAIKn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbNLb}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbKFf}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAH@h}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAAO`}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBAA`}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBAAn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbKCj}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBBNb}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbNMn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Bf[\"{{{AHO`{CGbAILd}}}{{KFl{IFl}}}}\",[]]De[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{Oh}}}}}{{KGd{{KFl{KCb}}AHFb}}}}\",[]]Bm[\"{{{AHO`{CGbAIOf}}DC`}{{KGd{KDlBBBl}}}}\",[]]C`[\"{{DAn{AHO`{CGbc}}}{{KGd{BGAnIFf}}}A@f}\",[\"R\"]]Bf[\"{{{AHO`{CGbAHBb}}}{{KFl{ICn}}}}\",[]]Ec[\"{{{AHO`{BCAd}}AJAj{AHO`{CGb{K@j{AIMh}}}}{AHO`{CGb{K@j{ABC`}}}}}{{KGf{KCb}}}}\",[]]Cn[\"{{{AHO`{BFBn}}ICh{AHO`{CGb{ABh{Oh}}}}}{{KGd{ICjAOJj}}}}\",[]]Cn[\"{{{AHO`{BFC`}}ICh{AHO`{CGb{ABh{Oh}}}}}{{KGd{ICjAOJl}}}}\",[]]C`[\"{{{AHO`{CGbAHBb}}ICnDC`}{{KGd{ICjBFDf}}}}\",[]]Cc[\"{{{AHO`{BCAd}}AJAj{AHO`{ABDl}}}{{KGf{ICj}}}}\",[]]Bn[\"{{{AHO`{CGbBH@l}}CN`}{{AHO`{CGbBH@l}}}}\",[]]Bn[\"{{{AHO`{CGbBH@n}}CN`}{{AHO`{CGbBH@n}}}}\",[]]Aj[\"{{{AHO`{AILb}}}DAl}\",[]]Aj[\"{{{AHO`{AILd}}}DAn}\",[]]Cn[\"{{{AHO`{NJj}}{AHO`{{K@j{Oh}}}}{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Cn[\"{{{AHO`{NJl}}{AHO`{{K@j{Oh}}}}{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]A`[\"{BC@lCNb}\",[]]A`[\"{ABDhKCb}\",[]]A`[\"{ABDjKCb}\",[]]o[\"{IHdDC`}\",[]]Bm[\"{{{AHO`{CGbAIOd}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbBGB`}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAIOf}}KIb}{{KGd{ICjB@Ll}}}}\",[]]Bn[\"{{{AHO`{AJAf}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BBOd}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BEJj}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{AJAh}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BBOf}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BEJl}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bd[\"{{{AHO`{BEGf}}}{{KFl{BB@h}}}}\",[]]Bd[\"{{{AHO`{BEGh}}}{{KFl{BB@j}}}}\",[]]Bi[\"{{{A@b{BFBf}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{AIJl}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{AOJn}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{BBAl}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{BFBh}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{AIJn}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{AOK`}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{BBAn}}NK`CMn}{{A@d{AILh}}}}\",[]]Aj[\"{BG@n{{A@b{BFBh}}}}\",[]]o[\"{ID`ICn}\",[]]A`[\"{ABDnCNb}\",[]]o[\"{IDbICn}\",[]]A`[\"{ABE`CNb}\",[]]Aa[\"{AOIjBCM`}\",[]]Ai[\"{{{AHO`{AAj}}}AAj}\",[]]Ak[\"{{{AHO`{AOMf}}}AOMf}\",[]]Ak[\"{{{AHO`{AOIn}}}AOIn}\",[]]Ak[\"{{{AHO`{AILb}}}AILb}\",[]]Ai[\"{{{AHO`{KEd}}}KEd}\",[]]Ak[\"{{{AHO`{BGJ`}}}BGJ`}\",[]]Ak[\"{{{AHO`{BFDd}}}BFDd}\",[]]Ak[\"{{{AHO`{AB@h}}}AB@h}\",[]]Ak[\"{{{AHO`{BAOf}}}BAOf}\",[]]Ai[\"{{{AHO`{KFd}}}KFd}\",[]]Ai[\"{{{AHO`{DA`}}}DA`}\",[]]Ak[\"{{{AHO`{BCAf}}}BCAf}\",[]]Ak[\"{{{AHO`{BC@h}}}BC@h}\",[]]Ak[\"{{{AHO`{AHFb}}}AHFb}\",[]]Ak[\"{{{AHO`{AIOh}}}AIOh}\",[]]Ak[\"{{{AHO`{BC@f}}}BC@f}\",[]]Ak[\"{{{AHO`{AJAl}}}AJAl}\",[]]Ak[\"{{{AHO`{BAC`}}}BAC`}\",[]]Ai[\"{{{AHO`{KI`}}}KI`}\",[]]Ak[\"{{{AHO`{BGIj}}}BGIj}\",[]]Ai[\"{{{AHO`{KFn}}}KFn}\",[]]Ak[\"{{{AHO`{AINj}}}AINj}\",[]]Ak[\"{{{AHO`{AHEh}}}AHEh}\",[]]Ak[\"{{{AHO`{BFKd}}}BFKd}\",[]]Ak[\"{{{AHO`{AIKd}}}AIKd}\",[]]Ak[\"{{{AHO`{ABDn}}}ABDn}\",[]]Ak[\"{{{AHO`{AILn}}}AILn}\",[]]Ak[\"{{{AHO`{AHEl}}}AHEl}\",[]]Ak[\"{{{AHO`{BCMf}}}BCMf}\",[]]Ak[\"{{{AHO`{B@Ld}}}B@Ld}\",[]]Ak[\"{{{AHO`{BCLn}}}BCLn}\",[]]Ak[\"{{{AHO`{AHE`}}}AHE`}\",[]]Ak[\"{{{AHO`{BBLd}}}BBLd}\",[]]Ak[\"{{{AHO`{BCOl}}}BCOl}\",[]]Ak[\"{{{AHO`{BFGh}}}BFGh}\",[]]Ak[\"{{{AHO`{BFIf}}}BFIf}\",[]]Ak[\"{{{AHO`{AOL`}}}AOL`}\",[]]Ak[\"{{{AHO`{BBMh}}}BBMh}\",[]]Ak[\"{{{AHO`{BABd}}}BABd}\",[]]Ak[\"{{{AHO`{BH@l}}}BH@l}\",[]]Ak[\"{{{AHO`{B@Kh}}}B@Kh}\",[]]Ak[\"{{{AHO`{AOJd}}}AOJd}\",[]]Ak[\"{{{AHO`{AHCf}}}AHCf}\",[]]Ak[\"{{{AHO`{BCLh}}}BCLh}\",[]]Ak[\"{{{AHO`{BEFf}}}BEFf}\",[]]Ak[\"{{{AHO`{B@M`}}}B@M`}\",[]]Ak[\"{{{AHO`{B@Mf}}}B@Mf}\",[]]Ak[\"{{{AHO`{B@N`}}}B@N`}\",[]]Ak[\"{{{AHO`{BFKn}}}BFKn}\",[]]Ak[\"{{{AHO`{AIMd}}}AIMd}\",[]]Ai[\"{{{AHO`{DAl}}}DAl}\",[]]Ai[\"{{{AHO`{A@j}}}A@j}\",[]]Ak[\"{{{AHO`{ABCd}}}ABCd}\",[]]Ak[\"{{{AHO`{AHCb}}}AHCb}\",[]]Ai[\"{{{AHO`{CNj}}}CNj}\",[]]Ak[\"{{{AHO`{AIJl}}}AIJl}\",[]]Ai[\"{{{AHO`{IDh}}}IDh}\",[]]Ak[\"{{{AHO`{AOJn}}}AOJn}\",[]]Ai[\"{{{AHO`{NKl}}}NKl}\",[]]Ak[\"{{{AHO`{BBAl}}}BBAl}\",[]]Ai[\"{{{AHO`{IFb}}}IFb}\",[]]Ak[\"{{{AHO`{BEJb}}}BEJb}\",[]]Ak[\"{{{AHO`{BGHn}}}BGHn}\",[]]Ak[\"{{{AHO`{BEJf}}}BEJf}\",[]]Ai[\"{{{AHO`{KIb}}}KIb}\",[]]Ak[\"{{{AHO`{BGIl}}}BGIl}\",[]]Ak[\"{{{AHO`{BFDf}}}BFDf}\",[]]Ai[\"{{{AHO`{KG`}}}KG`}\",[]]Ak[\"{{{AHO`{BAAl}}}BAAl}\",[]]Ak[\"{{{AHO`{AINl}}}AINl}\",[]]Ak[\"{{{AHO`{AHEj}}}AHEj}\",[]]Ak[\"{{{AHO`{BFDb}}}BFDb}\",[]]Ak[\"{{{AHO`{BFKf}}}BFKf}\",[]]Ak[\"{{{AHO`{AIKj}}}AIKj}\",[]]Ak[\"{{{AHO`{ABE`}}}ABE`}\",[]]Ak[\"{{{AHO`{AIM`}}}AIM`}\",[]]Ak[\"{{{AHO`{AHEn}}}AHEn}\",[]]Ak[\"{{{AHO`{BCMh}}}BCMh}\",[]]Ak[\"{{{AHO`{AHFd}}}AHFd}\",[]]Ak[\"{{{AHO`{BBBl}}}BBBl}\",[]]Ak[\"{{{AHO`{AJAn}}}AJAn}\",[]]Ak[\"{{{AHO`{AOKn}}}AOKn}\",[]]Ak[\"{{{AHO`{BC@j}}}BC@j}\",[]]Ak[\"{{{AHO`{B@Ll}}}B@Ll}\",[]]Ak[\"{{{AHO`{BCM`}}}BCM`}\",[]]Ak[\"{{{AHO`{AHEb}}}AHEb}\",[]]Ak[\"{{{AHO`{BBLf}}}BBLf}\",[]]Ak[\"{{{AHO`{BHDj}}}BHDj}\",[]]Ak[\"{{{AHO`{BCOn}}}BCOn}\",[]]Ak[\"{{{AHO`{BFGj}}}BFGj}\",[]]Ak[\"{{{AHO`{BFIh}}}BFIh}\",[]]Ak[\"{{{AHO`{AOLb}}}AOLb}\",[]]Ak[\"{{{AHO`{BBMj}}}BBMj}\",[]]Ak[\"{{{AHO`{BABh}}}BABh}\",[]]Ak[\"{{{AHO`{BH@n}}}BH@n}\",[]]Ak[\"{{{AHO`{B@Kl}}}B@Kl}\",[]]Ak[\"{{{AHO`{AOJf}}}AOJf}\",[]]Ak[\"{{{AHO`{AHCh}}}AHCh}\",[]]Ak[\"{{{AHO`{AIMl}}}AIMl}\",[]]Ak[\"{{{AHO`{AJ@h}}}AJ@h}\",[]]Ak[\"{{{AHO`{B@Mj}}}B@Mj}\",[]]Ak[\"{{{AHO`{BCLl}}}BCLl}\",[]]Ak[\"{{{AHO`{BEFj}}}BEFj}\",[]]Ak[\"{{{AHO`{AAOl}}}AAOl}\",[]]Ak[\"{{{AHO`{BEGb}}}BEGb}\",[]]Ak[\"{{{AHO`{B@Mb}}}B@Mb}\",[]]Ak[\"{{{AHO`{BCNh}}}BCNh}\",[]]Ak[\"{{{AHO`{BHE`}}}BHE`}\",[]]Ak[\"{{{AHO`{ABAh}}}ABAh}\",[]]Ak[\"{{{AHO`{BFCl}}}BFCl}\",[]]Ak[\"{{{AHO`{B@Mh}}}B@Mh}\",[]]Ak[\"{{{AHO`{B@Nb}}}B@Nb}\",[]]Ak[\"{{{AHO`{BCAb}}}BCAb}\",[]]Ak[\"{{{AHO`{BFL`}}}BFL`}\",[]]Ak[\"{{{AHO`{AIMf}}}AIMf}\",[]]Ak[\"{{{AHO`{BIAl}}}BIAl}\",[]]Ai[\"{{{AHO`{DAn}}}DAn}\",[]]Ai[\"{{{AHO`{A@l}}}A@l}\",[]]Ak[\"{{{AHO`{ABCf}}}ABCf}\",[]]Ak[\"{{{AHO`{AHCd}}}AHCd}\",[]]Ak[\"{{{AHO`{BBCh}}}BBCh}\",[]]Ak[\"{{{AHO`{BGAn}}}BGAn}\",[]]Ai[\"{{{AHO`{IFf}}}IFf}\",[]]Ai[\"{{{AHO`{IFd}}}IFd}\",[]]Ak[\"{{{AHO`{BEJd}}}BEJd}\",[]]Ak[\"{{{AHO`{BGI`}}}BGI`}\",[]]Ak[\"{{{AHO`{BEJh}}}BEJh}\",[]]Ai[\"{{{AHO`{CNl}}}CNl}\",[]]Ak[\"{{{AHO`{AIJn}}}AIJn}\",[]]Ai[\"{{{AHO`{IDj}}}IDj}\",[]]Ak[\"{{{AHO`{AOK`}}}AOK`}\",[]]Ai[\"{{{AHO`{NKn}}}NKn}\",[]]Ak[\"{{{AHO`{BBAn}}}BBAn}\",[]]Ai[\"{{{AHO`{IFn}}}IFn}\",[]]Ak[\"{{{AHO`{ABC`}}}ABC`}\",[]]Ak[\"{{{AHO`{ABDl}}}ABDl}\",[]]Ak[\"{{{AHO`{B@Nd}}}B@Nd}\",[]]Ak[\"{{{AHO`{BG@n}}}BG@n}\",[]]Ak[\"{{{AHO`{BCN`}}}BCN`}\",[]]Ak[\"{{{AHO`{BHKb}}}BHKb}\",[]]Ak[\"{{{AHO`{BHKd}}}BHKd}\",[]]Bn[\"{{{AHO`{AILb}}KI`{AHO`{{K@j{Oh}}}}}ICj}\",[]]Bn[\"{{{AHO`{AB@h}}KI`{AHO`{{K@j{Oh}}}}}ICj}\",[]]Bf[\"{{{AHO`{DA`}}}{{KGd{ICjBBLd}}}}\",[]]Bf[\"{{{AHO`{CGbAILd}}NK`KIbICn}ICj}\",[]]Bj[\"{{{AHO`{B@Mf}}}{{AHO`{{K@j{Oh}}}}}}\",[]]Bj[\"{{{AHO`{B@Mh}}}{{AHO`{{K@j{Oh}}}}}}\",[]]Aa[\"{BCAbAIMl}\",[]]A`[\"{ABCdCNb}\",[]]A`[\"{ABCfCNb}\",[]]A`[\"{B@N`DC`}\",[]]A`[\"{B@NbDC`}\",[]]l[\"{NKb}\",[]]l[\"{NKd}\",[]]Cf[\"{{{AHO`{BFHd}}{AHO`{CGbA@f}}}{{KGd{B@MhBFCl}}}}\",[]]Cf[\"{{{AHO`{BIE`}}{AHO`{CGbA@f}}}{{KGd{B@MhBFCl}}}}\",[]]Bc[\"{{{AHO`{AILd}}}{{ABh{KG`}}}}\",[]]Bd[\"{{{AHO`{IHj}}{AHO`{CMl}}}ICj}\",[]]Am[\"{{{AHO`{AOJ`}}KCb}ICj}\",[]]Ai[\"{{{AHO`{IHl}}}ICj}\",[]]Bg[\"{{{ABb{{AHO`{CGbAIJd}}}}NK`}ICj}\",[]]Bm[\"{{{AHO`{CGbAJ@`}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAJ@b}}KIb}{{KGd{ICjB@Ll}}}}\",[]]Am[\"{ABA`{{KGd{ICjAIOj}}}}\",[]]Dc[\"{{{AHO`{CGbAB@j}}ABAb{AHO`{CGb{ABh{Oh}}}}}{{KGd{ABDjAIOl}}}}\",[]]Bj[\"{{{AHO`{NMd}}{ABb{{A@d{KEn}}}}}ICj}\",[]]Bk[\"{{{AHO`{BACb}}{ABb{{A@d{KEn}}}}}ICj}\",[]]Bk[\"{{{AHO`{AOMl}}{ABb{{A@d{KEn}}}}}ICj}\",[]]o[\"{AAjDC`}\",[]]Ak[\"{{{AHO`{AILb}}}BCMf}\",[]]Ak[\"{{{AHO`{AB@h}}}BAOf}\",[]]Aj[\"{{{AHO`{DA`}}}AHEl}\",[]]A`[\"{KEdBCMf}\",[]]An[\"{{{AHO`{CGbAILd}}}BCMh}\",[]]Ce[\"{{{AHO`{CGbAINn}}{KFl{KHl}}}{{AHO`{CGbAINn}}}}\",[]]Ce[\"{{{AHO`{CGbAIO`}}{KFl{KHl}}}{{AHO`{CGbAIO`}}}}\",[]]Ck[\"{{{AHO`{CGbAJ@`}}{AHO`{{K@j{Oh}}}}}{{KGd{KCbAJAl}}}}\",[]]Ck[\"{{{AHO`{CGbAJ@b}}{AHO`{{K@j{Oh}}}}}{{KGd{KCbAJAn}}}}\",[]]Bl[\"{{{AHO`{BGAn}}{AHO`{CGbc}}}ICjKDj}\",[\"W\"]]Aj[\"{{{AHO`{AB@h}}}KCj}\",[]]An[\"{ABA`{{KGd{AIKnBCLn}}}}\",[]]Bi[\"{{{AHO`{CGbNNf}}A@l}{{KFl{ABCf}}}}\",[]]Fj[\"{{{AHO`{CGbAB@j}}ABAbNK`{AHO`{CGb{ABh{Oh}}}}{KFl{{A@b{BABh}}}}}{{KGd{{KC`{BEGbAILd}}{A@d{AOIj}}}}}}\",[]]Am[\"{AHO`{{AHO`{c}}}{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A`[\"{AAjAOIn}\",[]]Bc[\"{{AJ@fBBLbAAj}{{KGh{AOJ`}}}}\",[]]Aj[\"{AJ@f{{KGf{AB@h}}}}\",[]]Ba[\"{{}{{KGd{ICj{A@d{IEd}}}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BCLn}\",[]]Be[\"{{{AHO`{AB@j}}}{{AHO`{BBMj}}}}\",[]]o[\"{OhBFKn}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{BABdA@b}\",[]]o[\"{OhBFL`}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{BABhA@b}\",[]]A`[\"{BCAbKFl}\",[]]Bm[\"{{{AHO`{CGbc}}}{{KGd{KI`BBCh}}}A@f}\",[\"B\"]]Bm[\"{{{AHO`{CGbc}}}{{KGd{KFnBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{AHCfBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{BFKnBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{ABCdBBCh}}}A@f}\",[\"B\"]]Bi[\"{{{AHO`{CGbc}}}{{KGl{KIb}}}A@f}\",[\"B\"]]Bi[\"{{{AHO`{CGbc}}}{{KGl{KG`}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AHCh}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AIMl}}}A@f}\",[\"B\"]]Ek[\"{{{AHO`{CGb{KEl{AAOb}}}}{AHO`{c}}{AHO`{{K@j{CN`}}}}DC`}{{KGd{BCNhBFCl}}}{BFHdIHh}}\",[\"\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{BFL`}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{ABCf}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AHBd}}}A@f}\",[\"B\"]]A`[\"{ABC`KFl}\",[]]Bk[\"{{{AHO`{KI`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KFn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHCf}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{BFKn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{ABCd}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KIb}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KG`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHCh}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AIMl}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AAOl}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{BFL`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{ABCf}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHBn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bj[\"{{{AHO`{CGbAJ@`}}}{{KGd{ICjB@Ld}}}}\",[]]Bj[\"{{{AHO`{CGbAJ@b}}}{{KGd{ICjAOKn}}}}\",[]]An[\"{{{AHO`{AONh}}AB@d}ICj}\",[]]Ea[\"{{{AHO`{CGbAB@j}}NK`AHCd{KFl{B@Nb}}AAOb{AHO`{CGb{ABh{Oh}}}}}{{KFl{BAOb}}}}\",[]]o[\"{D@dNKb}\",[]]o[\"{D@fNKd}\",[]]A`[\"{ABA`ICj}\",[]]Ba[\"{{{AHO`{CGbAB@j}}ABAb}ICj}\",[]]Bh[\"{{{AHO`{AJAf}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BBOd}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BEJj}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{AJAh}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BBOf}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BEJl}}{AHO`{CMl}}ICn}ICj}\",[]]A`[\"{AHAlDC`}\",[]]o[\"{ID`CNb}\",[]]o[\"{IDbCNb}\",[]]Ch[\"{{{AHO`{CGbAILf}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbCNj}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbIDh}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbNKl}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Ch[\"{{{AHO`{CGbAILh}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbCNl}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbIDj}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbNKn}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]o[\"{D@dNKb}\",[]]o[\"{D@fNKd}\",[]]o[\"{BEKfOh}\",[]]A`[\"{KEdBCLn}\",[]]A`[\"{BCLhICn}\",[]]A`[\"{BEFfICn}\",[]]Aa[\"{AH@`BFD`}\",[]]A`[\"{BCLlICn}\",[]]A`[\"{BEFjICn}\",[]]A`[\"{BCAbKHl}\",[]]Aa[\"{BBLjBCM`}\",[]]Aa[\"{AH@bBFDb}\",[]]Bg[\"{{{AHO`{AB@h}}AHFl}{{KGf{ICj}}}}\",[]]A`[\"{ABA`ICj}\",[]]Cf[\"{{{AHO`{CGbAB@j}}ABAb{AHO`{CGb{ABh{Oh}}}}}ABDj}\",[]]Ak[\"{{{AHO`{AHCb}}}AJ@f}\",[]]l[\"{NKb}\",[]]Ak[\"{{{AHO`{AHCd}}}AJ@f}\",[]]l[\"{NKd}\",[]]An[\"{{AB@fAAj}{{KGh{ICj}}}}\",[]]B`[\"{{BABdAJ@f}{{KGf{AB@h}}}}\",[]]Bc[\"{BABb{{KGd{ICj{A@d{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BFDd}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BC@h}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AHFb}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AIOh}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BC@f}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AJAl}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BAC`}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BCLn}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BCM`}}}{{KFl{{AHO`{IEd}}}}}}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABDlKFl}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AINjAIKd}}}}\",[]]Aa[\"{BAAbAINj}\",[]]Aa[\"{BAAdAINl}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{ABC`KCb}\",[]]Aa[\"{AHElABDn}\",[]]Aa[\"{BCMfABDn}\",[]]Aa[\"{AHEnABE`}\",[]]Aa[\"{BCMhABE`}\",[]]3210Dh[\"{{{AHO`{NJj}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAOJj}}}}\",[]]Dh[\"{{{AHO`{NJl}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAOJl}}}}\",[]]Aj[\"{{{AHO`{AILf}}}CNb}\",[]]Ai[\"{{{AHO`{CNj}}}CNb}\",[]]Ai[\"{{{AHO`{IDh}}}CNb}\",[]]Ai[\"{{{AHO`{NKl}}}CNb}\",[]]Aj[\"{{{AHO`{AILh}}}CNb}\",[]]Ai[\"{{{AHO`{CNl}}}CNb}\",[]]Ai[\"{{{AHO`{IDj}}}CNb}\",[]]Ai[\"{{{AHO`{NKn}}}CNb}\",[]]Aj[\"{{{AHO`{BGOj}}}KCb}\",[]]Aj[\"{{{AHO`{BGOl}}}KCb}\",[]]Aj[\"{{{AHO`{BIAb}}}KCb}\",[]]Aj[\"{{{AHO`{BIAl}}}KCb}\",[]]o[\"{AAjKCb}\",[]]n[\"{{}NIl}\",[]]0A`[\"{A@hAAOf}\",[]]111Ba[\"{{AHO`{AHO`{c}}}ABBj{}}\",[\"K\"]]0000000000000000000Cg[\"{{{AHO`{AB@h}}AJ@f{AHO`{CMl}}}{{KGd{AIKnB@M`}}}}\",[]]Dl[\"{{{AHO`{CGbAB@j}}NK`B@KlAJ@f{AHO`{CMl}}}{{KGd{{KC`{BEGbAILd}}B@Mb}}}}\",[]]Bd[\"{{{AHO`{ABA`}}}{{KFl{BEGf}}}}\",[]]Dm[\"{{{AHO`{AHDj}}KFnCNb{AHO`{{K@j{Oh}}}}{AHO`{CGbAAOb}}}{{KGd{ICjAOJj}}}}\",[]]Ca[\"{{{AHO`{AHCl}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Bd[\"{{{AHO`{ABAb}}}{{KFl{BEGh}}}}\",[]]Dm[\"{{{AHO`{AHDl}}KG`CNb{AHO`{{K@j{Oh}}}}{AHO`{CGbAAOb}}}{{KGd{ICjAOJl}}}}\",[]]Ca[\"{{{AHO`{AHCn}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]o[\"{{}AONf}\",[]]n[\"{{}IHj}\",[]]o[\"{{}AOJ`}\",[]]o[\"{{}BANd}\",[]]o[\"{{}BAOf}\",[]]n[\"{{}KI`}\",[]]n[\"{{}KFn}\",[]]o[\"{{}AINj}\",[]]o[\"{{}AIKd}\",[]]o[\"{{}ABDn}\",[]]o[\"{{}AILn}\",[]]o[\"{{}AHEl}\",[]]o[\"{{}BCMf}\",[]]o[\"{{}B@Ld}\",[]]o[\"{{}BCOl}\",[]]o[\"{{}BFGh}\",[]]o[\"{{}BFIf}\",[]]o[\"{{}AOL`}\",[]]o[\"{{}BBMh}\",[]]o[\"{{}BH@l}\",[]]o[\"{{}BEJj}\",[]]o[\"{{}AIJl}\",[]]o[\"{{}AOJn}\",[]]o[\"{{}BBAl}\",[]]o[\"{{}BFBj}\",[]]o[\"{{}BANf}\",[]]o[\"{{}BIAb}\",[]]n[\"{{}KIb}\",[]]n[\"{{}KG`}\",[]]o[\"{{}AINl}\",[]]o[\"{{}AIKj}\",[]]o[\"{{}ABE`}\",[]]o[\"{{}AIM`}\",[]]o[\"{{}AHEn}\",[]]o[\"{{}BCMh}\",[]]o[\"{{}BC@j}\",[]]o[\"{{}B@Ll}\",[]]o[\"{{}BCOn}\",[]]o[\"{{}BFGj}\",[]]o[\"{{}BFIh}\",[]]o[\"{{}AOLb}\",[]]o[\"{{}BBMj}\",[]]o[\"{{}BH@n}\",[]]o[\"{{}BIAl}\",[]]o[\"{{}BEJl}\",[]]o[\"{{}AIJn}\",[]]o[\"{{}AOK`}\",[]]o[\"{{}BBAn}\",[]]o[\"{{}BFBl}\",[]]o[\"{{}ABC`}\",[]]n[\"{{}IHl}\",[]]o[\"{{}BCN`}\",[]]o[\"{{}BAOd}\",[]]Ak[\"{{{AHO`{BBBb}}}B@Mh}\",[]]Ak[\"{{{AHO`{BCNh}}}B@Mh}\",[]]Aa[\"{BHE`B@Mh}\",[]]Aa[\"{BFLbB@Mh}\",[]]A`[\"{D@hB@Mh}\",[]]A`[\"{IH`B@Mh}\",[]]A`[\"{IHdB@Mh}\",[]]Aa[\"{BEKfB@Mh}\",[]]Cg[\"{{{AHO`{AHDj}}KFnCNb{AHO`{CGb{K@j{Oh}}}}KCb}ICj}\",[]]Ca[\"{{{AHO`{AHCl}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Cg[\"{{{AHO`{AHDl}}KG`CNb{AHO`{CGb{K@j{Oh}}}}KCb}ICj}\",[]]Ca[\"{{{AHO`{AHCn}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Aj[\"{{{AHO`{AIOd}}}DC`}\",[]]Aj[\"{{{AHO`{BGB`}}}DC`}\",[]]Ak[\"{{{AHO`{AILf}}}BFBj}\",[]]Aj[\"{{{AHO`{CNj}}}BFBj}\",[]]Aj[\"{{{AHO`{IDh}}}BFBj}\",[]]Aj[\"{{{AHO`{NKl}}}BFBj}\",[]]Ak[\"{{{AHO`{AILh}}}BFBl}\",[]]Aj[\"{{{AHO`{CNl}}}BFBl}\",[]]Aj[\"{{{AHO`{IDj}}}BFBl}\",[]]Aj[\"{{{AHO`{NKn}}}BFBl}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CMn}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CMn}{{AHO`{CGbBCOn}}}}\",[]]Bf[\"{{{AHO`{CGbAILf}}NK`CNbCNb}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}NK`CNbCNb}ICj}\",[]]Aj[\"{{{AHO`{AILb}}}KFf}\",[]]Bc[\"{{{AHO`{ABBh}}}{{KFl{KFn}}}}\",[]]Aa[\"{BHE`B@Mh}\",[]]Aa[\"{BFLbB@Mh}\",[]]A`[\"{D@hB@Mh}\",[]]A`[\"{IH`B@Mh}\",[]]Aa[\"{BEKfB@Mh}\",[]]Aj[\"{{{AHO`{AJ@`}}}NMn}\",[]]Bn[\"{{{AHO`{AJ@b}}}{{KGd{{KFl{KIb}}B@Ll}}}}\",[]]o[\"{AAjKCb}\",[]]o[\"{IHjKCb}\",[]]Am[\"{{{AHO`{CGbAILd}}}NNf}\",[]]Aj[\"{{{AHO`{AHDj}}}KCb}\",[]]Aj[\"{{{AHO`{AHDl}}}KCb}\",[]]A`[\"{AHO`KHn}\",[]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bd[\"{{{AHO`{BGJ`}}}{{KFl{AILb}}}}\",[]]Bc[\"{{{AHO`{BCAf}}}{{KFl{DA`}}}}\",[]]Bn[\"{{{AHO`{CGbB@Kh}}CN`}{{AHO`{CGbB@Kh}}}}\",[]]Bn[\"{{{AHO`{CGbB@Kl}}CN`}{{AHO`{CGbB@Kl}}}}\",[]]A`[\"{BHE`CN`}\",[]]A`[\"{BFLbCN`}\",[]]o[\"{D@hCN`}\",[]]o[\"{IH`CN`}\",[]]A`[\"{AHAlKFl}\",[]]Aa[\"{ABDlAHO`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aa[\"{BC@lAB@d}\",[]]A`[\"{KDlBC@j}\",[]]Aa[\"{AHElAILn}\",[]]Aa[\"{BCMfAILn}\",[]]Aa[\"{AHEnAIM`}\",[]]Aa[\"{BCMhAIM`}\",[]]3210Bh[\"{{{AHO`{CGbc}}KCb}B@Mf{A@fIHh}}\",[\"\"]]Bh[\"{{{AHO`{CGbc}}KCb}B@Mh{A@fIHh}}\",[\"\"]]o[\"{{}BCNj}\",[]]o[\"{{}BCNl}\",[]]A`[\"{CNbBIAb}\",[]]Cd[\"{{{AHO`{CMl}}}{{KGh{AOMfc}}}{}}\",[\"FromStr::Err\"]]Cd[\"{{{AHO`{CMl}}}{{KGh{AOInc}}}{}}\",[\"FromStr::Err\"]]o[\"{CN`KI`}\",[]]o[\"{CN`KIb}\",[]]Al[\"{CNb{{KGd{KI`BGIj}}}}\",[]]Al[\"{CNb{{KGd{KIbBGIl}}}}\",[]]Aa[\"{BGGnAOJh}\",[]]Aa[\"{BIEbBB@b}\",[]]Aa[\"{BGH`AOJh}\",[]]Aa[\"{BIEdBB@b}\",[]]Af[\"{{}{{KFl{Ab}}}}\",[]]0000Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBFIf}}AB@d}{{AHO`{CGbBFIf}}}}\",[]]Bo[\"{{{AHO`{CGbBFIh}}AB@d}{{AHO`{CGbBFIh}}}}\",[]]Bb[\"{{{A@d{AILf}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{CNj}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{IDh}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{NKl}}}{{A@d{A@`}}}}\",[]]Bb[\"{{{A@d{AILh}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{CNl}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{IDj}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{NKn}}}{{A@d{A@`}}}}\",[]]Aj[\"{{{AHO`{BGJ`}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBH@l}}AB@d}{{AHO`{CGbBH@l}}}}\",[]]Bo[\"{{{AHO`{CGbBH@n}}AB@d}{{AHO`{CGbBH@n}}}}\",[]]Bc[\"{{{AHO`{AIKn}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{ABA`}}}{{KFl{KFb}}}}\",[]]Bm[\"{{{AHO`{DA`}}}{{KGd{{KFl{KFb}}AIKd}}}}\",[]]Bc[\"{{{AHO`{AHCb}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{ABAb}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{AHCd}}}{{KFl{KFb}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bc[\"{{{AHO`{AHBb}}}{{KFl{KCb}}}}\",[]]Am[\"{{{AHO`{AONh}}KCb}ICj}\",[]]Aj[\"{{{AHO`{AILb}}}NLb}\",[]]Bg[\"{{{AHO`{AJ@`}}}{{KGd{CElB@Ld}}}}\",[]]Bg[\"{{{AHO`{AJ@b}}}{{KGd{CElB@Ll}}}}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]]A`[\"{AHAlKFl}\",[]]A`[\"{AOIjKFl}\",[]]Ck[\"{{{AHO`{CGbBBMh}}{KFl{{IIh{Oh}}}}}{{AHO`{CGbBBMh}}}}\",[]]Ck[\"{{{AHO`{CGbBBMj}}{KFl{{IIh{Oh}}}}}{{AHO`{CGbBBMj}}}}\",[]]A`[\"{BFBjKFl}\",[]]A`[\"{BFBlKFl}\",[]]Ac[\"{AHO`c{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Ao[\"{c{{KGd{e}}}{}{}}\",[\"U\",\"T\"]]000000000000000000000000000000000000000000000000000000Al[\"{CNb{{KGd{KI`BGIj}}}}\",[]]Al[\"{ICh{{KGd{KI`BGIj}}}}\",[]]Al[\"{KCb{{KGd{KI`BGIj}}}}\",[]]3333333333333333333Aj[\"{AB@d{{KGd{AOL`}}}}\",[]]444444Ai[\"{CNb{{KGd{AHCf}}}}\",[]]55555555555555555555555555555Bc[\"{{{A@b{B@Kd}}}{{KGd{BEJb}}}}\",[]]Aj[\"{B@Kd{{KGd{BEJb}}}}\",[]]77Bc[\"{{{A@b{BAB`}}}{{KGd{BEJf}}}}\",[]]Aj[\"{BAB`{{KGd{BEJf}}}}\",[]]999999999999999999999Al[\"{ICh{{KGd{KIbBGIl}}}}\",[]]Al[\"{KCb{{KGd{KIbBGIl}}}}\",[]];Al[\"{CNb{{KGd{KIbBGIl}}}}\",[]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Bm[\"{B@Kd{{KGd{BEJdc}}}{}}\",[\"TryFrom::Error\"]]Cf[\"{{{A@b{B@Kd}}}{{KGd{BEJdc}}}{}}\",[\"TryFrom::Error\"]]Ao[\"{c{{KGd{e}}}{}{}}\",[\"U\",\"T\"]]00Cf[\"{{{A@b{BAB`}}}{{KGd{BEJhc}}}{}}\",[\"TryFrom::Error\"]]Bm[\"{BAB`{{KGd{BEJhc}}}{}}\",[\"TryFrom::Error\"]]22222222222222222222222Aj[\"{{}{{KGd{c}}}{}}\",[\"U\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cd[\"{{{ABb{{AHO`{CGbc}}}}{AHO`{CGbNIn}}}DAh{}}\",[\"F\"]]000000000Cc[\"{{{AHO`{BCAd}}AJAj{AHO`{ABDl}}}{{KGf{ICj}}}}\",[]]Bk[\"{{{AHO`{BGOj}}B@Mf}{{KGd{ICjAIMd}}}}\",[]]Bk[\"{{{AHO`{BGOl}}B@Mh}{{KGd{ICjAIMf}}}}\",[]]0Bk[\"{{{AHO`{BIAb}}B@Mh}{{KGd{ICjAIMf}}}}\",[]]Ak[\"{{{AHO`{AILb}}}AAO`}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{KI`IF`}}}}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{DAlIF`}}}}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{A@jIF`}}}}\",[]]Bj[\"{{{AHO`{CGbBACd}}}{{KGd{ABCdIF`}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{KIb}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{DAn}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{A@l}}}}\",[]]Bg[\"{{{AHO`{CGbBACd}}}{{KGj{ABCf}}}}\",[]]Aa[\"{AOInBGIh}\",[]]Bd[\"{{{AHO`{AILf}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{CNj}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{IDh}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{NKl}}}{{A@d{AILf}}}}\",[]]Bd[\"{{{AHO`{AILh}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{CNl}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{IDj}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{NKn}}}{{A@d{AILh}}}}\",[]]A`[\"{ABDnCNb}\",[]]An[\"{{{AHO`{CGbAILd}}}AHBb}\",[]]A`[\"{ABE`CNb}\",[]]C`[\"{{{AHO`{CGbB@Mf}}}{{AHO`{CGb{K@j{Oh}}}}}}\",[]]C`[\"{{{AHO`{CGbB@Mh}}}{{AHO`{CGb{K@j{Oh}}}}}}\",[]]Ah[\"{Oh{{KFl{B@N`}}}}\",[]]Ah[\"{Oh{{KFl{B@Nb}}}}\",[]]Ah[\"{Oh{{KFl{B@Nd}}}}\",[]]A`[\"{ABCdDAl}\",[]]A`[\"{ABCfDAn}\",[]]Bi[\"{AIKn{{KGd{{KC`{AILbBD@f}}AIKn}}}}\",[]]Aa[\"{{}c{}}\",[\"I\"]]o[\"{DAlDC`}\",[]]o[\"{DAnDC`}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]21Aj[\"{{{AHO`{ABA`}}}DC`}\",[]]Aj[\"{{{AHO`{ABAb}}}DC`}\",[]]Bn[\"{{{AHO`{CGbBABd}}DC`}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}DC`}{{AHO`{CGbBABh}}}}\",[]]Bm[\"{{{AHO`{NMd}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]Bn[\"{{{AHO`{BACb}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]Bn[\"{{{AHO`{AOMl}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Ak[\"{{{AHO`{AILb}}}ABBf}\",[]]Bo[\"{{{AHO`{AILb}}cAINj}ABBh{{D@b{AHCb}}}}\",[\"\"]]Ce[\"{{{AHO`{CGbAILd}}AHCdAINlNK`}{{KGd{KG`AHEb}}}}\",[]]43Bm[\"{{{AHO`{CGbAILd}}KG`}{{KGd{ICjAIKj}}}}\",[]]E`[\"{{{ABb{{AHO`{CGbBGIb}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbBEFb}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbAINh}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbBGA`}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbAIOd}}}}{AHO`{CGbNIn}}{AHO`{CGbNLn}}}{{DAh{{KGf{ICj}}}}}}\",[]]Ec[\"{{{AHO`{CGbAIOd}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{Oh}}}}}{{DAh{{KGd{KCbAHFb}}}}}}\",[]]Ef[\"{{{ABb{{AHO`{CGbAIOd}}}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{Oh}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]Fg[\"{{{AHO`{CGbBBL`}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{AIMh}}}}{AHO`{CGb{K@j{ABC`}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]Dn[\"{{{ABb{{AHO`{CGbAHFj}}}}{AHO`{ABDl}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]>=Ce[\"{{{AHO`{CGbBBMh}}{A@b{NJj}}}{{AHO`{CGbBBMh}}}}\",[]]Ce[\"{{{AHO`{CGbBBMj}}{A@b{NJl}}}{{AHO`{CGbBBMj}}}}\",[]]Cj[\"{{{AHO`{BABf}}CN`B@Mf{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BEJf}}CN`B@Mf{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BABj}}CN`B@Mh{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BEJh}}CN`B@Mh{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BHKd}}CN`B@Md{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Bb[\"{KCb{{KC`{KCb{KFl{KCb}}}}}}\",[]]000Aj[\"{{{AHO`{AILb}}}KCb}\",[]]A`[\"{AHO`KHl}\",[]]0000000000000000000000000000000000000000000000000000000000000000000Cf[\"{{{AHO`{CGbBABd}}{A@b{BFBn}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{BFC`}}}{{AHO`{CGbBABh}}}}\",[]]A`[\"{BHE`IGf}\",[]]A`[\"{BABdA@b}\",[]]A`[\"{BABhA@b}\",[]]Aj[\"{{{AHO`{AB@h}}}ICj}\",[]]Ck[\"{{{AHO`{CGbAJ@`}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAJAl}}}}\",[]]n[\"{{}KCb}\",[]]Ak[\"{{{AHO`{AILb}}}AH@h}\",[]]Ba[\"{{{AHO`{CGbABDn}}ABDn}ICj}\",[]]Ba[\"{{{AHO`{CGbAILn}}AILn}ICj}\",[]]Ba[\"{{{AHO`{CGbBCMf}}AHEl}ICj}\",[]]Ba[\"{{{AHO`{CGbABE`}}ABE`}ICj}\",[]]Ba[\"{{{AHO`{CGbAIM`}}AIM`}ICj}\",[]]Ba[\"{{{AHO`{CGbBCMh}}AHEn}ICj}\",[]]Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bi[\"{{{AHO`{CGb}}}{{AHO`{CGbc}}}{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bg[\"{{{AHO`{AIOd}}}{{KGd{CNbB@Ld}}}}\",[]]Bg[\"{{{AHO`{AIOf}}}{{KGd{CNbB@Ll}}}}\",[]]Bc[\"{{AHO`{AHO`{CGbc}}}ICj{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cc[\"{{{AHO`{CGbAILd}}NK`KG`KIb}{{KGd{ICjBBLf}}}}\",[]]A`[\"{AHAlDC`}\",[]]B`[\"{{AHO`{AHO`{c}}}DC`{}}\",[\"K\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Aa[\"{BCLhBFKn}\",[]]A`[\"{BEFfKI`}\",[]]Aa[\"{BCLlBFL`}\",[]]A`[\"{BEFjKIb}\",[]]A`[\"{BFAnKIb}\",[]]A`[\"{BCNnKIb}\",[]]o[\"{NMjKIb}\",[]]Aa[\"{BCLhAIMj}\",[]]Aa[\"{BCLlAIMl}\",[]]o[\"{KI`CNb}\",[]]o[\"{KIbCNb}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Aj[\"{{{AHO`{BAOd}}}DC`}\",[]]Bd[\"{{{AHO`{BBL`}}}{{KGf{AJ@f}}}}\",[]]Bd[\"{{{AHO`{AB@h}}}{{KGf{AJ@f}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{BCMfCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BCMhCNb}\",[]]Cc[\"{{{AHO`{BCN`}}{AHO`{AIOn}}CNb}{{A@b{AONh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bg[\"{{{AHO`{AILb}}KFn}{{KFl{AHEl}}}}\",[]]o[\"{KEdABh}\",[]]A`[\"{AHBfA@d}\",[]]Bj[\"{{{AHO`{CGbAILd}}KG`}{{KFl{AHEn}}}}\",[]]A`[\"{AHBhA@d}\",[]]Db[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]00Eg[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}{AHO`{{K@j{Oh}}}}}{{DAh{{KGd{KCbAJAl}}}}}}\",[]]Ec[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}{AHO`{{K@j{Oh}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]0Bm[\"{{{AHO`{IHl}}{AHO`{D@n}}}{{KGf{ICj}}}}\",[]]Cd[\"{{{AHO`{CGbAIOd}}KCb}{{KGd{{KFl{ICn}}AHFb}}}}\",[]]Cd[\"{{{AHO`{CGbBGB`}}KCb}{{KGd{{KFl{ID`}}AHFb}}}}\",[]]Cn[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{Oh}}}}}{{KGd{ICjBC@f}}}}\",[]]Bk[\"{{{AHO`{DA`}}AINj}{{KGd{AINjBFKd}}}}\",[]]Bn[\"{{{AHO`{CGbAINn}}NK`}{{AHO`{CGbAINn}}}}\",[]]Bn[\"{{{AHO`{CGbAIO`}}NK`}{{AHO`{CGbAIO`}}}}\",[]]A`[\"{BC@lAG`}\",[]]o[\"{IHjCNb}\",[]]o[\"{{}AJ@f}\",[]]0o[\"{{}AHO`}\",[]]Bk[\"{{ABA`{A@b{BABd}}}{{KGd{AIKnBCLn}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bh[\"{{{AHO`{AHAl}}AJ@f}{{KGh{AHFl}}}}\",[]]A`[\"{AHElCMn}\",[]]Aj[\"{{{AHO`{AILd}}}CMn}\",[]]A`[\"{AHEnCMn}\",[]]Ce[\"{{{AHO`{CGbAINn}}{KFl{KHl}}}{{AHO`{CGbAINn}}}}\",[]]Ce[\"{{{AHO`{CGbAIO`}}{KFl{KHl}}}{{AHO`{CGbAIO`}}}}\",[]]Aa[\"{ABDhAJ@f}\",[]]Aa[\"{ABDjAJ@f}\",[]]Aa[\"{ABDlAJ@f}\",[]]Aa[\"{AJ@fAHCb}\",[]]Aa[\"{AJ@fAHCd}\",[]]o[\"{AAjCMn}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CMn}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CMn}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlCMn}\",[]]Bo[\"{{{AHO`{CGbBCOl}}AB@d}{{AHO`{CGbBCOl}}}}\",[]]Bo[\"{{{AHO`{CGbBCOn}}AB@d}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]k[\"{{}}\",[]]0000000000Bh[\"{ABA`c{}}\",[\"IntoFuture::IntoFuture\"]]11Aj[\"{{{AHO`{BAOd}}}DC`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]o[\"{AAjKCb}\",[]]Ao[\"{{AHO`c}{{NKf{c}}}{}}\",[\"S\"]]0C`[\"{{{AHO`{CGbAILf}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bo[\"{{{AHO`{CGbCNj}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]C`[\"{{{AHO`{CGbAILh}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bo[\"{{{AHO`{CGbCNl}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bk[\"{{{AHO`{CGbIHl}}NK`{AHO`{BCN`}}}ICj}\",[]]A`[\"{BFBjKFl}\",[]]A`[\"{BFBlKFl}\",[]]Bn[\"{{{AHO`{KI`}}{AHO`{KI`}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KFn}}{AHO`{KFn}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AOL`}}{AHO`{AOL`}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{B@Mf}}{AHO`{B@Mf}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{DAl}}{AHO`{DAl}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{A@j}}{AHO`{A@j}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{ABCd}}{AHO`{ABCd}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KIb}}{AHO`{KIb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BFDf}}{AHO`{BFDf}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KG`}}{AHO`{KG`}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AHFd}}{AHO`{AHFd}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BBBl}}{AHO`{BBBl}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AJAn}}{AHO`{AJAn}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AOLb}}{AHO`{AOLb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BEGb}}{AHO`{BEGb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BFCl}}{AHO`{BFCl}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{B@Mh}}{AHO`{B@Mh}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{DAn}}{AHO`{DAn}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{A@l}}{AHO`{A@l}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{ABCf}}{AHO`{ABCf}}}{{KFl{ABBj}}}}\",[]]Ak[\"{{{AHO`{AILb}}}AINh}\",[]]Bk[\"{{{AHO`{AILd}}KG`}{{KGd{AINlAIKj}}}}\",[]]Cc[\"{{{AHO`{CGbAIOd}}KCb}{{KGd{{ABh{Oh}}BC@h}}}}\",[]]Bb[\"{{{AHO`{CGbAILd}}ABCf}AIOf}\",[]]Aj[\"{{{AHO`{AHCl}}}KCb}\",[]]Aj[\"{{{AHO`{AHCn}}}KCb}\",[]]Bb[\"{{{AHO`{CGbAILd}}ABCf}AJ@b}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CNb}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CNb}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]]Cf[\"{{{AHO`{CGbBABd}}{A@b{AJ@n}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{AJA`}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kh}}{A@b{AJAf}}}{{AHO`{CGbB@Kh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kl}}{A@b{AJAh}}}{{AHO`{CGbB@Kl}}}}\",[]]o[\"{AAjCNb}\",[]]Bn[\"{{{AHO`{CGbBFIf}}CMn}{{AHO`{CGbBFIf}}}}\",[]]Bn[\"{{{AHO`{CGbBFIh}}CMn}{{AHO`{CGbBFIh}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BGJ`}\",[]]Aj[\"{{{AHO`{DA`}}}BCAf}\",[]]Aj[\"{{{A@b{BABf}}}BABd}\",[]]Aj[\"{{{A@b{BABj}}}BABh}\",[]]Aj[\"{{BCNjc}BCNjABCn}\",[\"\"]]Aj[\"{{BCNlc}BCNlABCn}\",[\"\"]]Bm[\"{{{AHO`{CGbAJ@`}}ICn}{{KGd{ICjAJAl}}}}\",[]]n[\"{{}KFb}\",[]]o[\"{NIlNIl}\",[]]0000Bd[\"{{{AHO`{BGOj}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BGOl}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BIAb}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BIAl}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{AILb}}}{{KFl{BCLn}}}}\",[]]Ck[\"{{{AHO`{AB@h}}B@KhAJ@f{AHO`{CMl}}}{{KGd{AIKnB@M`}}}}\",[]]Ak[\"{{{AHO`{BAAl}}}AB@d}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]An[\"{{AIObDC`}{{KGh{KCb}}}}\",[]]Cl[\"{{{AHO`{NMf}}}{{KFl{{KC`{{A@d{AHCl}}{A@d{AHDj}}}}}}}}\",[]]Cm[\"{{{AHO`{AJAb}}}{{KFl{{KC`{{A@d{AHCl}}{A@d{AHDj}}}}}}}}\",[]]Cl[\"{{{AHO`{NMh}}}{{KFl{{KC`{{A@d{AHCn}}{A@d{AHDl}}}}}}}}\",[]]Cm[\"{{{AHO`{AJAd}}}{{KFl{{KC`{{A@d{AHCn}}{A@d{AHDl}}}}}}}}\",[]]A`[\"{BGGnABh}\",[]]A`[\"{BIEbABh}\",[]]A`[\"{BGH`ABh}\",[]]A`[\"{BIEdABh}\",[]]An[\"{{{AHO`{CGbBGOj}}}B@Mf}\",[]]An[\"{{{AHO`{CGbBGOl}}}B@Mh}\",[]]An[\"{{{AHO`{CGbBIAb}}}B@Mh}\",[]]An[\"{{{AHO`{CGbBIAl}}}B@Mh}\",[]]Ak[\"{{{AHO`{BCAd}}}B@Oj}\",[]]Ba[\"{{{AHO`{CGbAILd}}BCMd}ICj}\",[]]Bo[\"{{{AHO`{CGbAB@j}}BEGbBAOd}{{KFl{BCMd}}}}\",[]]B`[\"{{{AHO`{NMf}}B@MfDAl}D@d}\",[]]Bn[\"{{{AHO`{BABf}}CN`B@Mf}{{KGd{D@dBFLf}}}}\",[]]Ba[\"{{{AHO`{AJAb}}B@MfDAl}D@d}\",[]]Bn[\"{{{AHO`{BEJf}}CN`B@Mf}{{KGd{D@dBFLf}}}}\",[]]B`[\"{{{AHO`{NMh}}B@MhDAn}D@f}\",[]]Bn[\"{{{AHO`{BABj}}CN`B@Mh}{{KGd{D@fBFLl}}}}\",[]]Ba[\"{{{AHO`{AJAd}}B@MhDAn}D@f}\",[]]Bn[\"{{{AHO`{BEJh}}CN`B@Mh}{{KGd{D@fBFLl}}}}\",[]]Bn[\"{{{AHO`{BHKd}}CN`B@Md}{{KGd{D@fBFLl}}}}\",[]]Aj[\"{{}{{NM`{c}}}{}}\",[\"T\"]]0A`[\"{AHElCNb}\",[]]A`[\"{BCMfCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BCMhCNb}\",[]]Bn[\"{{{AHO`{CGbBABd}}KCb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}KCb}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{BBL`}}}DC`}\",[]]0Aj[\"{{{AHO`{BCAd}}}DC`}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AHCbAIKd}}}}\",[]]Bk[\"{{{AHO`{AILd}}KG`}{{KGd{AHCdAIKj}}}}\",[]]Cc[\"{{{AHO`{BCN`}}{AHO`{AIOb}}CNb}{{A@b{AONh}}}}\",[]]Ak[\"{{{AHO`{ABA`}}}B@Mf}\",[]]Ak[\"{{{AHO`{ABAb}}}B@Mh}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bf[\"{{{AHO`{CGbAILd}}}{{KFl{NK`}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{A@b{AOLn}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{A@b{AOM`}}}{{AHO`{CGbBCOn}}}}\",[]]43A`[\"{AAjAOMf}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABDlKFl}\",[]]A`[\"{BFBjKFl}\",[]]A`[\"{BFBlKFl}\",[]]Ai[\"{{{AHO`{NNf}}}KCb}\",[]]Bo[\"{{{AHO`{CGbBIAb}}AB@d}{{AHO`{CGbBIAb}}}}\",[]]Bo[\"{{{AHO`{CGbBIAl}}AB@d}{{AHO`{CGbBIAl}}}}\",[]]Bj[\"{{{AHO`{AJ@`}}CEl}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAJ@b}}CEl}{{KGd{ICjB@Ll}}}}\",[]]?>A`[\"{IHjAONf}\",[]]A`[\"{AOJ`IHj}\",[]]Bj[\"{{{A@b{B@Kd}}IHn}{{KGd{BEJbBGHn}}}}\",[]]Bj[\"{{{A@b{BAB`}}IHn}{{KGd{BEJfBGHn}}}}\",[]]Bj[\"{{{A@b{B@Kd}}IHn}{{KGd{BEJdBGI`}}}}\",[]]Bj[\"{{{A@b{BAB`}}IHn}{{KGd{BEJhBGI`}}}}\",[]]Dj[\"{{{AHO`{CGbAJ@b}}{AHO`{CGb{AHO`{CGb{K@j{ICn}}}}}}}{{KGd{KCbAJAn}}}}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{AHAlDC`}\",[]]Cd[\"{{{AHO`{CGbBBMh}}{A@b{A`}}}{{AHO`{CGbBBMh}}}}\",[]]Cd[\"{{{AHO`{CGbBBMj}}{A@b{A`}}}{{AHO`{CGbBBMj}}}}\",[]]Bk[\"{{{AHO`{BBL`}}}{{ABb{{A@d{AHFj}}}}}}\",[]]o[\"{AAjCNb}\",[]]Aa[\"{AONfAHD`}\",[]]76Aa[\"{AIOjABA`}\",[]]Aa[\"{AIOlABAb}\",[]]Cf[\"{{{AHO`{CGbBFGh}}{KFl{AB@d}}}{{AHO`{CGbBFGh}}}}\",[]]Cf[\"{{{AHO`{CGbBFGj}}{KFl{AB@d}}}{{AHO`{CGbBFGj}}}}\",[]]9;:An[\"{{{AHO`{AONh}}AB@d}ICj}\",[]]B`[\"{{{AHO`{CGbAILf}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbCNj}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbIDh}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbNKl}}CMn}ICj}\",[]]B`[\"{{{AHO`{CGbAILh}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbCNl}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbIDj}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbNKn}}CMn}ICj}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Bj[\"{{{AHO`{AILb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMf}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMh}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAd}}}{{KFl{{A@d{A@`}}}}}}\",[]]Db[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]Db[\"{{{AHO`{CGbAILd}}NK`B@Oj{AHO`{CGb{ABh{Oh}}}}}{{KFl{ABDj}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{AHO`{CMl}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{AHO`{CMl}}}{{AHO`{CGbBCOn}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BAA`}\",[]]Bj[\"{{{AHO`{AILb}}ICn}{{KGd{ICjBFDd}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Ai[\"{{{AHO`{NJj}}}KCb}\",[]]Ai[\"{{{AHO`{NJl}}}KCb}\",[]]Dh[\"{{{AHO`{B@Kj}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMf}}B@M`}}}}\",[]]Cb[\"{{{AHO`{BABf}}CN`{AHO`{BGAn}}}{{A@d{NMf}}}}\",[]]Dh[\"{{{AHO`{BEJb}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMf}}B@M`}}}}\",[]]Cb[\"{{{AHO`{BEJf}}CN`{AHO`{BGAn}}}{{A@d{NMf}}}}\",[]]Dh[\"{{{AHO`{B@Kn}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMh}}B@Mb}}}}\",[]]Cb[\"{{{AHO`{BABj}}CN`{AHO`{BGAn}}}{{A@d{NMh}}}}\",[]]Dh[\"{{{AHO`{BEJd}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMh}}B@Mb}}}}\",[]]Cb[\"{{{AHO`{BEJh}}CN`{AHO`{BGAn}}}{{A@d{NMh}}}}\",[]]Dh[\"{{{AHO`{BHKb}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMh}}B@Ln}}}}\",[]]Cb[\"{{{AHO`{BHKd}}CN`{AHO`{BGAn}}}{{A@d{NMh}}}}\",[]]Dd[\"{{{ABb{{AHO`{CGbc}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{KGd}}}}}{}}\",[\"S\"]]0Bn[\"{{AJ@fBBLbAAj}{{KGh{{KC`{AB@fAIL`}}}}}}\",[]]Bd[\"{{{AHO`{AILd}}}{{AHO`{NMh}}}}\",[]]A`[\"{AOJ`IHj}\",[]]Cb[\"{{{AHO`{AOLn}}DAlAJ@fB@MfNK`}{{KFl{AINn}}}}\",[]]Cb[\"{{{AHO`{BCNj}}DAlAJ@fB@MfNK`}{{KFl{AINn}}}}\",[]]Cb[\"{{{AHO`{AOM`}}DAnAJ@fB@MhNK`}{{KFl{AIO`}}}}\",[]]Cb[\"{{{AHO`{BCNl}}DAnAJ@fB@MhNK`}{{KFl{AIO`}}}}\",[]]B`[\"{{{AHO`{CGbAILd}}NK`}ICj}\",[]]Ca[\"{{{AHO`{CGbAIKn}}}{{KGd{{A@d{A@`}}BCLn}}}}\",[]]Bj[\"{{{AHO`{AILb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMf}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMh}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAd}}}{{KFl{{A@d{A@`}}}}}}\",[]]o[\"{AILnOh}\",[]]o[\"{AIM`Oh}\",[]]Ai[\"{{{AHO`{CMl}}}DC`}\",[]]Aj[\"{{{AHO`{AILf}}}CNb}\",[]]Ai[\"{{{AHO`{CNj}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAIJl}}CNb}{{AHO`{CGbAIJl}}}}\",[]]Ai[\"{{{AHO`{IDh}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAOJn}}CNb}{{AHO`{CGbAOJn}}}}\",[]]Ai[\"{{{AHO`{NKl}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAl}}CNb}{{AHO`{CGbBBAl}}}}\",[]]Aj[\"{{{AHO`{AILh}}}CNb}\",[]]Ai[\"{{{AHO`{CNl}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAIJn}}CNb}{{AHO`{CGbAIJn}}}}\",[]]Ai[\"{{{AHO`{IDj}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAOK`}}CNb}{{AHO`{CGbAOK`}}}}\",[]]Ai[\"{{{AHO`{NKn}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAn}}CNb}{{AHO`{CGbBBAn}}}}\",[]]Aa[\"{AIOdBGB`}\",[]]Ai[\"{{{AHO`{NMf}}}DC`}\",[]]Aj[\"{{{AHO`{AJAb}}}DC`}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Ai[\"{{{AHO`{NMh}}}DC`}\",[]]Aj[\"{{{AHO`{AJAd}}}DC`}\",[]]Co[\"{{{AHO`{NMf}}B@Mf{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]D`[\"{{{AHO`{AJAb}}B@Mf{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]Co[\"{{{AHO`{NMh}}B@Mh{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]D`[\"{{{AHO`{AJAd}}B@Mh{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]Bn[\"{{{AHO`{CGbBFIf}}CMn}{{AHO`{CGbBFIf}}}}\",[]]Bn[\"{{{AHO`{CGbBFIh}}CMn}{{AHO`{CGbBFIh}}}}\",[]]Cd[\"{{{AHO`{CGbNMf}}}{{KFl{{NKb{{A@d{AHDj}}}}}}}}\",[]]Ce[\"{{{AHO`{CGbAJAb}}}{{KFl{{NKb{{A@d{AHDj}}}}}}}}\",[]]Cd[\"{{{AHO`{CGbNMh}}}{{KFl{{NKd{{A@d{AHDl}}}}}}}}\",[]]Ce[\"{{{AHO`{CGbAJAd}}}{{KFl{{NKd{{A@d{AHDl}}}}}}}}\",[]]Bf[\"{{{AHO`{CGbAILf}}CMnCNbNK`}ICj}\",[]]Be[\"{{{AHO`{CGbCNj}}CMnCNbNK`}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}CMnCNbNK`}ICj}\",[]]Be[\"{{{AHO`{CGbCNl}}CMnCNbNK`}ICj}\",[]]Bf[\"{{{AHO`{CGbAILf}}NK`CMnCNb}ICj}\",[]]Be[\"{{{AHO`{CGbCNj}}NK`CMnCNb}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}NK`CMnCNb}ICj}\",[]]Be[\"{{{AHO`{CGbCNl}}NK`CMnCNb}ICj}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]De[\"{{{AHO`{CGbBCOl}}c{AHO`{CMl}}}{{AHO`{CGbBCOl}}}{{ICl{D@n}}}}\",[\"\"]]De[\"{{{AHO`{CGbBCOn}}c{AHO`{CMl}}}{{AHO`{CGbBCOn}}}{{ICl{D@n}}}}\",[\"\"]]Ci[\"{{{AHO`{CGbNMf}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`IEn}}}}\",[]]Cj[\"{{{AHO`{CGbAJAb}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`IEn}}}}\",[]]Cj[\"{{{AHO`{CGbNMh}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`BCAb}}}}\",[]]Ck[\"{{{AHO`{CGbAJAd}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`BCAb}}}}\",[]]o[\"{AAjDC`}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KI`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KIb}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]Ca[\"{{{AHO`{CGbAIOd}}}{{KGd{{KFl{KI`}}AIOh}}}}\",[]]Ca[\"{{{AHO`{CGbBGB`}}}{{KGd{{KFl{KI`}}AIOh}}}}\",[]]Ca[\"{{{AHO`{CGbAIOf}}}{{KGd{{KFl{KIb}}B@Ll}}}}\",[]]Ak[\"{{{AHO`{AIKn}}}AJ@f}\",[]]Ak[\"{{{AHO`{ABA`}}}AJ@f}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AJ@fAIKd}}}}\",[]]Ak[\"{{{AHO`{ABAb}}}AJ@f}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]B`[\"{{KI`c}KI`{{D@b{KI`}}}}\",[\"\"]]B`[\"{{KFnc}KFn{{D@b{KFn}}}}\",[\"\"]]B`[\"{{KIbc}KIb{{D@b{KIb}}}}\",[\"\"]]B`[\"{{KG`c}KG`{{D@b{KG`}}}}\",[\"\"]]20Ae[\"{{AB@dCNb}AG`}\",[]]Bn[\"{{{AHO`{CGbBCOl}}AFn}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}AFn}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{IHjAB@d}\",[]]B`[\"{{}{{AHO`{{K@j{BG@n}}}}}}\",[]]An[\"{{AHO`{ONf{CGbOh}}}ICj}\",[]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000An[\"{{}{{KFl{{A@b{NMd}}}}}}\",[]]Bn[\"{{{AHO`{CGbBBMh}}DC`}{{AHO`{CGbBBMh}}}}\",[]]Bn[\"{{{AHO`{CGbBBMj}}DC`}{{AHO`{CGbBBMj}}}}\",[]]Aj[\"{{{AHO`{AHDj}}}CNb}\",[]]Aj[\"{{{AHO`{AHDl}}}CNb}\",[]]A`[\"{ABC`KFl}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Bf[\"{{{AHO`{CMl}}}{{KGh{CNbBBB`}}}}\",[]]Bn[\"{{{AHO`{AB@h}}{A@d{BBL`}}}{{KGf{ICj}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Cj[\"{{{AHO`{NMb}}BBLbBBBj{AHO`{AAj}}}{{KC`{AJ@fAB@f}}}}\",[]]Cb[\"{{{AHO`{CGbAILd}}KG`AINl}{{KGd{AINlBFKf}}}}\",[]]Am[\"{{{AHO`{AILb}}CNb}ICj}\",[]]B`[\"{{{AHO`{CGbAILd}}CNb}ICj}\",[]]A`[\"{BC@jDC`}\",[]]B`[\"{{{AHO`{CGbIHj}}BC@l}ICj}\",[]]Aa[\"{AONfAHD`}\",[]]Bn[\"{{{AHO`{NMd}}AHFl}{{KGf{{A@d{BBL`}}}}}}\",[]]Bo[\"{{{AHO`{BACb}}AHFl}{{KGf{{A@d{BBL`}}}}}}\",[]]Bo[\"{{{AHO`{AOMl}}AHFl}{{KGf{{A@d{BBL`}}}}}}\",[]]Ci[\"{{{AHO`{CGbNMf}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@d}}}}\",[]]Cj[\"{{{AHO`{CGbAJAb}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@d}}}}\",[]]Ci[\"{{{AHO`{CGbNMh}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@f}}}}\",[]]Cj[\"{{{AHO`{CGbAJAd}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@f}}}}\",[]]Cb[\"{{{AHO`{ABD`}}IChAJ@lAB@d}{{KGd{ICjBCOf}}}}\",[]]Cb[\"{{{AHO`{BANd}}IChAJ@lAB@d}{{KGd{ICjBCOf}}}}\",[]]Cb[\"{{{AHO`{B@Ol}}IChAJ@lAB@d}{{KGd{ICjBCOf}}}}\",[]]Cb[\"{{{AHO`{ABDb}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Cb[\"{{{AHO`{BANf}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Cb[\"{{{AHO`{B@On}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Al[\"{{}{{KGd{B@KfBGI`}}}}\",[]]Bn[\"{{{AHO`{AILb}}KFn}{{KFl{{A@d{AILf}}}}}}\",[]]Bo[\"{{{AHO`{AILd}}KG`}{{KFl{{AHO`{AILh}}}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aj[\"{{{AHO`{AILb}}}ICj}\",[]]Am[\"{{{AHO`{CGbAILd}}}ICj}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAjIEj}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{A@hIEj}}}}\",[]]Bg[\"{{{AHO`{AIJb}}}{{KGd{AAOfIEj}}}}\",[]]Bg[\"{{{AHO`{AIJb}}}{{KGd{AHAlIEj}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAlIEj}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAnIEj}}}}\",[]]Ak[\"{{{AHO`{BCAd}}}B@Oj}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{AOL`}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AOLb}}}{{AHO`{CGbBCOn}}}}\",[]]<;Aj[\"{{{AHO`{AB@h}}}KCb}\",[]]Aj[\"{{{AHO`{AB@j}}}KCb}\",[]]Bo[\"{{{AHO`{AILb}}cAINj}ABBh{{D@b{AHCb}}}}\",[\"\"]]Co[\"{{{AHO`{CGbAILd}}AHCdAINlNK`}{{KGd{{KC`{KG`DC`}}AHEb}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CN`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CN`}{{AHO`{CGbBCOn}}}}\",[]]Df[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{ICn}}}}}{{KGd{{KFl{KCb}}AHFb}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Bg[\"{{{AHO`{BCAd}}AJAj}{{KGf{KCb}}}}\",[]]A`[\"{AHAlCNb}\",[]]10Aj[\"{{{AHO`{AAj}}}BCOj}\",[]]Cf[\"{{{AHO`{CGbBABd}}{A@b{BCOl}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kh}}{A@b{BCOl}}}{{AHO`{CGbB@Kh}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{BCOn}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kl}}{A@b{BCOn}}}{{AHO`{CGbB@Kl}}}}\",[]]Aa[\"{BABdBH@l}\",[]]Aa[\"{BABhBH@n}\",[]]Bj[\"{{{ABh{BBLb}}BBBj}{{KGd{BABdIFb}}}}\",[]]Bj[\"{{{ABh{BBLb}}BBBj}{{KGd{BABhIFd}}}}\",[]]Co[\"{{{AHO`{CGbAJ@`}}{AHO`{CGb{K@j{ICn}}}}}{{KGd{ICjAJAl}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BFBjCNb}\",[]]A`[\"{BFBlCNb}\",[]]Bc[\"{{{AHO`{AILb}}}{{KFl{KCb}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Aj[\"{{{AHO`{AHBb}}}KCb}\",[]]Be[\"{{{AHO`{AB@h}}{KFl{BABd}}}ICj}\",[]]Bo[\"{{{AHO`{CGbAB@j}}{KFl{{A@b{BABh}}}}}ICj}\",[]]Bd[\"{{{AHO`{BG@n}}}{{KFl{BBBh}}}}\",[]]Aj[\"{{{AHO`{AB@h}}}ICj}\",[]]Dj[\"{{{AHO`{CGbAJ@`}}{AHO`{CGb{AHO`{CGb{K@j{ICn}}}}}}}{{KGd{KCbAJAl}}}}\",[]]o[\"{{}AHO`}\",[]]n[\"{{}NIl}\",[]]0000Bn[\"{{{AHO`{CGbBCOl}}KCb}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KCb}{{AHO`{CGbBCOn}}}}\",[]]o[\"{CNbKI`}\",[]]o[\"{CNbKIb}\",[]]A`[\"{BAOfCNb}\",[]]Bf[\"{{{AHO`{BGJ`}}{AHO`{BGJ`}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBBMh}}AB@d}{{AHO`{CGbBBMh}}}}\",[]]Bo[\"{{{AHO`{CGbBBMj}}AB@d}{{AHO`{CGbBBMj}}}}\",[]]Ae[\"{{KCbCNb}BANd}\",[]]Ae[\"{{KCbCNb}BANf}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]7Bg[\"{{{AHO`{AILd}}KG`}{{KFl{AINl}}}}\",[]]An[\"{{{AHO`{AILb}}ICn}BAAn}\",[]]Bm[\"{{{AHO`{CGbBEJb}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJf}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJd}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJh}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Am[\"{{{AHO`{AILb}}KI`}ICj}\",[]]B`[\"{{{AHO`{CGbAILd}}KIb}ICj}\",[]]Ce[\"{{{AHO`{CGbBBMh}}{ABh{CN`}}}{{AHO`{CGbBBMh}}}}\",[]]Ce[\"{{{AHO`{CGbBBMj}}{ABh{CN`}}}{{AHO`{CGbBBMj}}}}\",[]]Fg[\"{{{AHO`{BHEb}}{AHO`{BBLb}}{AHO`{{K@j{BBLb}}}}{AHO`{AJ@d}}{AHO`{{K@j{Oh}}}}ABEb}{{KGd{BFK`IEf}}}}\",[]]Af[\"{{BCNjNK`}BCNj}\",[]]Af[\"{{BCNlNK`}BCNl}\",[]]A`[\"{BAOfCNb}\",[]]Al[\"{BACd{{KGd{DAlIF`}}}}\",[]]Al[\"{BACd{{KGd{A@jIF`}}}}\",[]]Ai[\"{BACd{{KGj{DAn}}}}\",[]]Ai[\"{BACd{{KGj{A@l}}}}\",[]]o[\"{NIlNIl}\",[]]Bo[\"{{{AHO`{CGbBFIf}}AB@d}{{AHO`{CGbBFIf}}}}\",[]]Bo[\"{{{AHO`{CGbBFIh}}AB@d}{{AHO`{CGbBFIh}}}}\",[]]Bb[\"{{{AHO`{NMf}}}{{KFl{DC`}}}}\",[]]Bc[\"{{{AHO`{AJAb}}}{{KFl{DC`}}}}\",[]]Bb[\"{{{AHO`{NMh}}}{{KFl{DC`}}}}\",[]]Bc[\"{{{AHO`{AJAd}}}{{KFl{DC`}}}}\",[]]Bg[\"{{{AHO`{AILb}}}{{KGd{ICjBCLn}}}}\",[]]Ba[\"{{{AHO`{BFCf}}KFnAHCb}DC`}\",[]]Ba[\"{{{AHO`{BFCh}}KG`AHCd}DC`}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{AB@d}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AB@d}}}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Bo[\"{{{AHO`{CGbAILf}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbCNj}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbIDh}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbNKl}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bo[\"{{{AHO`{CGbAILh}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbCNl}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbIDj}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbNKn}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]A`[\"{BAOfCNb}\",[]]Al[\"{{{AHO`{NNf}}A@l}CNb}\",[]]Bi[\"{{{AHO`{CGbAIOn}}CNb}{{KGh{ICj}}}}\",[]]<;A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Cf[\"{{{AHO`{CGbBCOl}}{KFl{BFGh}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{BFGj}}}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAjIEj}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{A@hIEj}}}}\",[]]Bj[\"{{{AHO`{CGbAIJb}}}{{KGd{AAOfIEj}}}}\",[]]Bj[\"{{{AHO`{CGbAIJb}}}{{KGd{AHAlIEj}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAlIEj}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAnIEj}}}}\",[]]Cd[\"{{{A@b{AIL`}}CNbDC`}{{KGh{{KC`{BC@lBC@l}}}}}}\",[]]Bn[\"{{{AHO`{CGbBABd}}CNb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}CNb}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{AILb}}}DC`}\",[]]Ak[\"{{{AHO`{BBL`}}}B@Oj}\",[]]0Ci[\"{{{AHO`{CGbBBMh}}CMn}{{KGd{{AHO`{CGbBBMh}}AOJd}}}}\",[]]Ci[\"{{{AHO`{CGbBBMj}}CMn}{{KGd{{AHO`{CGbBBMj}}AOJf}}}}\",[]]A`[\"{AHAlCMn}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{BFIf}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{BFIh}}}{{AHO`{CGbBCOn}}}}\",[]]Bg[\"{{{AHO`{CGbAILd}}}{{KFl{BAOd}}}}\",[]]Cf[\"{{{AHO`{CGbBABd}}{KFl{BABl}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{KFl{BABl}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbBABd}}{KFl{BABn}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{KFl{BABn}}}{{AHO`{CGbBABh}}}}\",[]]Cd[\"{{}{{KGd{{KC`{{ABh{BBLb}}BBBj}}{A@d{IEd}}}}}}\",[]]Bn[\"{{{AHO`{CGbBFGh}}KI`}{{AHO`{CGbBFGh}}}}\",[]]Bn[\"{{{AHO`{CGbBFGj}}KIb}{{AHO`{CGbBFGj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bo[\"{{{AHO`{CGbBABd}}AB@d}{{AHO`{CGbBABd}}}}\",[]]Bo[\"{{{AHO`{CGbBABh}}AB@d}{{AHO`{CGbBABh}}}}\",[]]Ci[\"{{{AHO`{DA`}}{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKd}}}}\",[]]Bj[\"{{{AHO`{BCAd}}AJAjKCb}{{KGf{ICj}}}}\",[]]054Bm[\"{{{AHO`{NMf}}}{{KGd{{KFl{BGAn}}IEn}}}}\",[]]Bn[\"{{{AHO`{AJAb}}}{{KGd{{KFl{BGAn}}IEn}}}}\",[]]Bn[\"{{{AHO`{NMh}}}{{KGd{{KFl{BGAn}}BCAb}}}}\",[]]Bo[\"{{{AHO`{AJAd}}}{{KGd{{KFl{BGAn}}BCAb}}}}\",[]]Aj[\"{{{AHO`{AHDj}}}CNb}\",[]]Aj[\"{{{AHO`{AHDl}}}CNb}\",[]]Bl[\"{{{AHO`{AB@h}}{KFl{{A@b{BFCf}}}}}ICj}\",[]]Cc[\"{{{AHO`{CGbAILd}}{KFl{{AHO`{BFCh}}}}NK`}ICj}\",[]]Aj[\"{{{AHO`{AB@j}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAl}}AFn}{{AHO`{CGbBBAl}}}}\",[]]Bn[\"{{{AHO`{CGbBBAn}}AFn}{{AHO`{CGbBBAn}}}}\",[]]Ak[\"{{{AHO`{AHFj}}}B@Oj}\",[]]0Ak[\"{{{AHO`{AILb}}}BGA`}\",[]]Cb[\"{{{AHO`{AILd}}KG`}{{KGd{{KFl{AJ@f}}AIKj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KI`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KIb}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]Bo[\"{{{AHO`{AHAl}}{AHO`{CMl}}}{{KGf{BCOj}}}}\",[]]Em[\"{{{AHO`{AILb}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHLn}}}}\",[]]El[\"{{{AHO`{NMf}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHLn}}}}\",[]]Em[\"{{{AHO`{AJAb}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHLn}}}}\",[]]El[\"{{{AHO`{NMh}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHM`}}}}\",[]]Em[\"{{{AHO`{AJAd}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHM`}}}}\",[]]Am[\"{{{AHO`{CGbAHB`}}}ICj}\",[]]0Am[\"{{{AHO`{AILd}}A@l}CNb}\",[]]Ak[\"{{{AHO`{AILb}}}BGIb}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{BEFbAIKd}}}}\",[]]>=E`[\"{{{AHO`{BHEb}}{AHO`{{K@j{Oh}}}}{AHO`{BBLb}}{AHO`{BGOn}}}{{KGd{BHGhIEf}}}}\",[]]0Bg[\"{{{A@b{BBCb}}}{{KGd{B@KhBGIn}}}}\",[]]Bg[\"{{{A@b{BBCb}}}{{KGd{B@KlBGIn}}}}\",[]]Bn[\"{{{AHO`{CGbBFGh}}KI`}{{AHO`{CGbBFGh}}}}\",[]]Bn[\"{{{AHO`{CGbBFGj}}KIb}{{AHO`{CGbBFGj}}}}\",[]]o[\"{NIlNIl}\",[]]0000Aj[\"{{{AHO`{AILd}}}DC`}\",[]]0Bd[\"{{{AHO`{CGbAILf}}CNbAB@d}ICj}\",[]]Bc[\"{{{AHO`{CGbCNj}}CNbAB@d}ICj}\",[]]Bd[\"{{{AHO`{CGbAILh}}CNbAB@d}ICj}\",[]]Bc[\"{{{AHO`{CGbCNl}}CNbAB@d}ICj}\",[]]Ci[\"{{{AHO`{DA`}}{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKd}}}}\",[]]Cd[\"{{{AHO`{CGbAAj}}{AHO`{AIJb}}}{{KGd{ICjIEj}}}}\",[]]Cd[\"{{{AHO`{CGbA@h}}{AHO`{AIJb}}}{{KGd{ICjIEj}}}}\",[]]Ce[\"{{{AHO`{CGbAAOf}}{AHO`{AIJb}}}{{KGd{ICjIEj}}}}\",[]]Ce[\"{{{AHO`{CGbAHAl}}{AHO`{AIJb}}}{{KGd{ICjIEj}}}}\",[]]Cd[\"{{{AHO`{CGbAAl}}{AHO`{AIJb}}}{{KGd{ICjIEj}}}}\",[]]Cd[\"{{{AHO`{CGbAAn}}{AHO`{AIJb}}}{{KGd{ICjIEj}}}}\",[]]Bo[\"{{{AHO`{CGbBABd}}BH@l}{{AHO`{CGbBABd}}}}\",[]]Bo[\"{{{AHO`{CGbBABh}}BH@n}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{BBMh}}}CNb}\",[]]Aj[\"{{{AHO`{BBMj}}}CNb}\",[]]Cd[\"{{{AHO`{CGbB@Kh}}{A@b{A`}}}{{AHO`{CGbB@Kh}}}}\",[]]Cd[\"{{{AHO`{CGbB@Kl}}{A@b{A`}}}{{AHO`{CGbB@Kl}}}}\",[]]Cl[\"{{BBMh{KFl{BABd}}{A@d{BBL`}}{A@b{NMd}}}{{KGf{AB@h}}}}\",[]]Aj[\"{{{AHO`{ABA`}}}DC`}\",[]]Aj[\"{{{AHO`{ABAb}}}DC`}\",[]]Ca[\"{{{AHO`{CGbAILd}}NK`AIMn}{{KGd{ICjBHDj}}}}\",[]]Bd[\"{{{AHO`{BHEb}}}{{ABh{BCOb}}}}\",[]]Bj[\"{{{AHO`{AILb}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bm[\"{{{AHO`{CGbAILd}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KCb}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KCb}{{AHO`{CGbBCOn}}}}\",[]]Bm[\"{{}{{KGd{{KC`{BBLbBFJb}}{A@d{IEd}}}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]An[\"{{{AHO`{AB@h}}B@Kh}ICj}\",[]]Dc[\"{{{AHO`{CGbAILd}}NK`KG`{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKj}}}}\",[]]o[\"{{}AHO`}\",[]]Aj[\"{{{AHO`{AILb}}}KCb}\",[]]Bn[\"{{{AHO`{CGbBABd}}CNb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}CNb}{{AHO`{CGbBABh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KI`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KIb}{{AHO`{CGbBCOn}}}}\",[]]:Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bc[\"{{{AHO`{CGbAILd}}A@lKIb}ICj}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Ak[\"{{}{{KGd{B@KhIFb}}}}\",[]]Ak[\"{{}{{KGd{B@KlIFd}}}}\",[]]6587Cg[\"{{{AHO`{CGbAAj}}{AHO`{CGbAIJb}}}{{KGd{ICjIEj}}}}\",[]]Cg[\"{{{AHO`{CGbA@h}}{AHO`{CGbAIJb}}}{{KGd{ICjIEj}}}}\",[]]Ch[\"{{{AHO`{CGbAAOf}}{AHO`{CGbAIJb}}}{{KGd{ICjIEj}}}}\",[]]Ch[\"{{{AHO`{CGbAHAl}}{AHO`{CGbAIJb}}}{{KGd{ICjIEj}}}}\",[]]Cg[\"{{{AHO`{CGbAAl}}{AHO`{CGbAIJb}}}{{KGd{ICjIEj}}}}\",[]]Cg[\"{{{AHO`{CGbAAn}}{AHO`{CGbAIJb}}}{{KGd{ICjIEj}}}}\",[]]n[\"{{}ICj}\",[]]Ce[\"{{{AHO`{CGbBCOl}}{KFl{KCb}}}{{AHO`{CGbBCOl}}}}\",[]]Ce[\"{{{AHO`{CGbBCOn}}{KFl{KCb}}}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{AILb}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Cd[\"{{{AHO`{CGbAILd}}NK`}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Am[\"{{{AHO`{CGbAILf}}}ICj}\",[]]Al[\"{{{AHO`{CGbCNj}}}ICj}\",[]]Al[\"{{{AHO`{CGbIDh}}}ICj}\",[]]Am[\"{{{AHO`{CGbAILh}}}ICj}\",[]]Al[\"{{{AHO`{CGbCNl}}}ICj}\",[]]Al[\"{{{AHO`{CGbIDj}}}ICj}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Bj[\"{{{AHO`{AILb}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bm[\"{{{AHO`{CGbAILd}}AJ@f}{{KGd{ICjIFh}}}}\",[]]D`[\"{{{AHO`{CGbAILd}}KG`{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKj}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{A@b{BFBf}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{A@b{BFBh}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{AB@d}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AB@d}}}{{AHO`{CGbBCOn}}}}\",[]]Ce[\"{{{AHO`{CGbBCOl}}{KFl{CNb}}}{{AHO`{CGbBCOl}}}}\",[]]Ce[\"{{{AHO`{CGbBCOn}}{KFl{CNb}}}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]];Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Am[\"{{{AHO`{AILb}}KI`}ICj}\",[]]o[\"{NIlNIl}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CN`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CN`}{{AHO`{CGbBCOn}}}}\",[]]310;:54Bn[\"{{{AHO`{AILb}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Bn[\"{{{AHO`{AILd}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]10Bm[\"{{{AHO`{CGbBCOl}}Oh}{{AHO`{CGbBCOl}}}}\",[]]Bm[\"{{{AHO`{CGbBCOn}}Oh}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{BGAnKFl}\",[]]")
\ No newline at end of file
+rd_("Bf[\"{{{AHO`{AOIn}}{AHO`{AOIn}}}DC`}\",[]]Bf[\"{{{AHO`{BFDd}}{AHO`{BFDd}}}DC`}\",[]]Bd[\"{{{AHO`{KFd}}{AHO`{KFd}}}DC`}\",[]]Bd[\"{{{AHO`{DA`}}{AHO`{DA`}}}DC`}\",[]]Bf[\"{{{AHO`{BCAf}}{AHO`{BCAf}}}DC`}\",[]]Bf[\"{{{AHO`{BC@h}}{AHO`{BC@h}}}DC`}\",[]]Bf[\"{{{AHO`{AHFb}}{AHO`{AHFb}}}DC`}\",[]]Bf[\"{{{AHO`{AIOh}}{AHO`{AIOh}}}DC`}\",[]]Bf[\"{{{AHO`{BC@f}}{AHO`{BC@f}}}DC`}\",[]]Bf[\"{{{AHO`{AJAl}}{AHO`{AJAl}}}DC`}\",[]]Bf[\"{{{AHO`{BAC`}}{AHO`{BAC`}}}DC`}\",[]]Bd[\"{{{AHO`{KI`}}{AHO`{KI`}}}DC`}\",[]]Bf[\"{{{AHO`{BGIj}}{AHO`{BGIj}}}DC`}\",[]]Bd[\"{{{AHO`{ID`}}{AHO`{ID`}}}DC`}\",[]]Bd[\"{{{AHO`{KFn}}{AHO`{KFn}}}DC`}\",[]]Bf[\"{{{AHO`{AINj}}{AHO`{AINj}}}DC`}\",[]]Bf[\"{{{AHO`{AHEh}}{AHO`{AHEh}}}DC`}\",[]]Bf[\"{{{AHO`{BFKd}}{AHO`{BFKd}}}DC`}\",[]]Bf[\"{{{AHO`{AIKd}}{AHO`{AIKd}}}DC`}\",[]]Bf[\"{{{AHO`{ABDn}}{AHO`{ABDn}}}DC`}\",[]]Bf[\"{{{AHO`{AILn}}{AHO`{AILn}}}DC`}\",[]]Bf[\"{{{AHO`{AHEl}}{AHO`{AHEl}}}DC`}\",[]]Bf[\"{{{AHO`{B@Ld}}{AHO`{B@Ld}}}DC`}\",[]]Bf[\"{{{AHO`{BCLn}}{AHO`{BCLn}}}DC`}\",[]]Bf[\"{{{AHO`{AHE`}}{AHO`{AHE`}}}DC`}\",[]]Bf[\"{{{AHO`{BBLd}}{AHO`{BBLd}}}DC`}\",[]]Bf[\"{{{AHO`{AOL`}}{AHO`{AOL`}}}DC`}\",[]]Bf[\"{{{AHO`{AOJd}}{AHO`{AOJd}}}DC`}\",[]]Bf[\"{{{AHO`{AHCf}}{AHO`{AHCf}}}DC`}\",[]]Bf[\"{{{AHO`{BCLh}}{AHO`{BCLh}}}DC`}\",[]]Bf[\"{{{AHO`{BEFf}}{AHO`{BEFf}}}DC`}\",[]]Bf[\"{{{AHO`{B@M`}}{AHO`{B@M`}}}DC`}\",[]]Bf[\"{{{AHO`{B@Mf}}{AHO`{B@Mf}}}DC`}\",[]]Bf[\"{{{AHO`{B@N`}}{AHO`{B@N`}}}DC`}\",[]]Bf[\"{{{AHO`{BFKn}}{AHO`{BFKn}}}DC`}\",[]]Bd[\"{{{AHO`{DAl}}{AHO`{DAl}}}DC`}\",[]]Bd[\"{{{AHO`{A@j}}{AHO`{A@j}}}DC`}\",[]]Bf[\"{{{AHO`{ABCd}}{AHO`{ABCd}}}DC`}\",[]]Bf[\"{{{AHO`{AHCb}}{AHO`{AHCb}}}DC`}\",[]]Bf[\"{{{AHO`{BHLn}}{AHO`{BHLn}}}DC`}\",[]]Bd[\"{{{AHO`{IFb}}{AHO`{IFb}}}DC`}\",[]]Bd[\"{{{AHO`{KIb}}{AHO`{KIb}}}DC`}\",[]]Bf[\"{{{AHO`{BGIl}}{AHO`{BGIl}}}DC`}\",[]]Bd[\"{{{AHO`{IDb}}{AHO`{IDb}}}DC`}\",[]]Bf[\"{{{AHO`{BFDf}}{AHO`{BFDf}}}DC`}\",[]]Bd[\"{{{AHO`{KG`}}{AHO`{KG`}}}DC`}\",[]]Bf[\"{{{AHO`{AINl}}{AHO`{AINl}}}DC`}\",[]]Bf[\"{{{AHO`{AHEj}}{AHO`{AHEj}}}DC`}\",[]]Bf[\"{{{AHO`{BFDb}}{AHO`{BFDb}}}DC`}\",[]]Bf[\"{{{AHO`{BFKf}}{AHO`{BFKf}}}DC`}\",[]]Bf[\"{{{AHO`{AIKj}}{AHO`{AIKj}}}DC`}\",[]]Bf[\"{{{AHO`{ABE`}}{AHO`{ABE`}}}DC`}\",[]]Bf[\"{{{AHO`{AIM`}}{AHO`{AIM`}}}DC`}\",[]]Bf[\"{{{AHO`{AHEn}}{AHO`{AHEn}}}DC`}\",[]]Bf[\"{{{AHO`{AHFd}}{AHO`{AHFd}}}DC`}\",[]]Bf[\"{{{AHO`{BBBl}}{AHO`{BBBl}}}DC`}\",[]]Bf[\"{{{AHO`{AJAn}}{AHO`{AJAn}}}DC`}\",[]]Bf[\"{{{AHO`{AOKn}}{AHO`{AOKn}}}DC`}\",[]]Bf[\"{{{AHO`{AONd}}{AHO`{AONd}}}DC`}\",[]]Bf[\"{{{AHO`{BC@j}}{AHO`{BC@j}}}DC`}\",[]]Bf[\"{{{AHO`{B@Ll}}{AHO`{B@Ll}}}DC`}\",[]]Bf[\"{{{AHO`{BCM`}}{AHO`{BCM`}}}DC`}\",[]]Bf[\"{{{AHO`{AHEb}}{AHO`{AHEb}}}DC`}\",[]]Bf[\"{{{AHO`{BBLf}}{AHO`{BBLf}}}DC`}\",[]]Bf[\"{{{AHO`{AOLb}}{AHO`{AOLb}}}DC`}\",[]]Bf[\"{{{AHO`{AOJf}}{AHO`{AOJf}}}DC`}\",[]]Bf[\"{{{AHO`{AHCh}}{AHO`{AHCh}}}DC`}\",[]]Bf[\"{{{AHO`{BBNd}}{AHO`{BBNd}}}DC`}\",[]]Bf[\"{{{AHO`{AIMl}}{AHO`{AIMl}}}DC`}\",[]]Bf[\"{{{AHO`{AJ@h}}{AHO`{AJ@h}}}DC`}\",[]]Bf[\"{{{AHO`{B@Mj}}{AHO`{B@Mj}}}DC`}\",[]]Bf[\"{{{AHO`{BCLl}}{AHO`{BCLl}}}DC`}\",[]]Bf[\"{{{AHO`{BEFj}}{AHO`{BEFj}}}DC`}\",[]]Bf[\"{{{AHO`{BEGb}}{AHO`{BEGb}}}DC`}\",[]]Bf[\"{{{AHO`{B@Mb}}{AHO`{B@Mb}}}DC`}\",[]]Bf[\"{{{AHO`{ABAh}}{AHO`{ABAh}}}DC`}\",[]]Bf[\"{{{AHO`{BFCl}}{AHO`{BFCl}}}DC`}\",[]]Bf[\"{{{AHO`{B@Mh}}{AHO`{B@Mh}}}DC`}\",[]]Bf[\"{{{AHO`{B@Nb}}{AHO`{B@Nb}}}DC`}\",[]]Bf[\"{{{AHO`{BCAb}}{AHO`{BCAb}}}DC`}\",[]]Bf[\"{{{AHO`{BFL`}}{AHO`{BFL`}}}DC`}\",[]]Bd[\"{{{AHO`{DAn}}{AHO`{DAn}}}DC`}\",[]]Bd[\"{{{AHO`{A@l}}{AHO`{A@l}}}DC`}\",[]]Bf[\"{{{AHO`{ABCf}}{AHO`{ABCf}}}DC`}\",[]]Bf[\"{{{AHO`{AHCd}}{AHO`{AHCd}}}DC`}\",[]]Bf[\"{{{AHO`{BBCh}}{AHO`{BBCh}}}DC`}\",[]]Bf[\"{{{AHO`{BGAn}}{AHO`{BGAn}}}DC`}\",[]]Bd[\"{{{AHO`{IFf}}{AHO`{IFf}}}DC`}\",[]]Bf[\"{{{AHO`{BHM`}}{AHO`{BHM`}}}DC`}\",[]]Bd[\"{{{AHO`{IFd}}{AHO`{IFd}}}DC`}\",[]]Bf[\"{{{AHO`{B@Nd}}{AHO`{B@Nd}}}DC`}\",[]]Ai[\"{{{AHO`{DA`}}}KFn}\",[]]Aj[\"{{{AHO`{BCAf}}}KFn}\",[]]Ak[\"{{{AHO`{AIOd}}}ABCd}\",[]]Ak[\"{{{AHO`{BGB`}}}ABCd}\",[]]Ak[\"{{{AHO`{AJ@`}}}ABCd}\",[]]A`[\"{AOKfKFn}\",[]]A`[\"{AH@`KFn}\",[]]A`[\"{AHBfKFn}\",[]]A`[\"{BAAbKFn}\",[]]A`[\"{BA@`KFn}\",[]]A`[\"{AOKhKG`}\",[]]A`[\"{AH@bKG`}\",[]]A`[\"{AHBhKG`}\",[]]A`[\"{BAAdKG`}\",[]]A`[\"{BA@bKG`}\",[]]Aa[\"{ABBlABCf}\",[]]Aa[\"{ABEdABCf}\",[]]Aa[\"{AB@lABCf}\",[]]A`[\"{NMjABCf}\",[]]A`[\"{AOMfNMb}\",[]]A`[\"{D@hABAh}\",[]]Ac[\"{{ABDnABDn}}\",[]]Ac[\"{{AILnAILn}}\",[]]Ac[\"{{BCMfAHEl}}\",[]]Bc[\"{{ABE`ABE`}c{}}\",[\"Add::Output\"]]Bc[\"{{AIM`AIM`}c{}}\",[\"Add::Output\"]]Bc[\"{{BCMhAHEn}c{}}\",[\"Add::Output\"]]Be[\"{{{AHO`{KI`}}{AHO`{KI`}}}ABBj}\",[]]Be[\"{{{AHO`{KFn}}{AHO`{KFn}}}ABBj}\",[]]Bg[\"{{{AHO`{AOL`}}{AHO`{AOL`}}}ABBj}\",[]]Bg[\"{{{AHO`{B@Mf}}{AHO`{B@Mf}}}ABBj}\",[]]Be[\"{{{AHO`{DAl}}{AHO`{DAl}}}ABBj}\",[]]Be[\"{{{AHO`{A@j}}{AHO`{A@j}}}ABBj}\",[]]Bg[\"{{{AHO`{ABCd}}{AHO`{ABCd}}}ABBj}\",[]]Be[\"{{{AHO`{KIb}}{AHO`{KIb}}}ABBj}\",[]]Bg[\"{{{AHO`{BFDf}}{AHO`{BFDf}}}ABBj}\",[]]Be[\"{{{AHO`{KG`}}{AHO`{KG`}}}ABBj}\",[]]Bg[\"{{{AHO`{AHFd}}{AHO`{AHFd}}}ABBj}\",[]]Bg[\"{{{AHO`{BBBl}}{AHO`{BBBl}}}ABBj}\",[]]Bg[\"{{{AHO`{AJAn}}{AHO`{AJAn}}}ABBj}\",[]]Bg[\"{{{AHO`{AOLb}}{AHO`{AOLb}}}ABBj}\",[]]Bg[\"{{{AHO`{BEGb}}{AHO`{BEGb}}}ABBj}\",[]]Bg[\"{{{AHO`{BFCl}}{AHO`{BFCl}}}ABBj}\",[]]Bg[\"{{{AHO`{B@Mh}}{AHO`{B@Mh}}}ABBj}\",[]]Be[\"{{{AHO`{DAn}}{AHO`{DAn}}}ABBj}\",[]]Be[\"{{{AHO`{A@l}}{AHO`{A@l}}}ABBj}\",[]]Bg[\"{{{AHO`{ABCf}}{AHO`{ABCf}}}ABBj}\",[]]A`[\"{ABCdA@j}\",[]]A`[\"{ABCfA@l}\",[]]o[\"{KFhA@l}\",[]]A`[\"{AHAbA@l}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABC`KFl}\",[]]A`[\"{ABDlKFl}\",[]]Bh[\"{{{AHO`{AAj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOMf}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOIn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BC@l}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BHEb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BGIb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIKn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AILb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{KEd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BGJ`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFDd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AB@h}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BAOf}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{KFd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AINh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BGA`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABA`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIOj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBNb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{DA`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCAf}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIOd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BGB`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BC@h}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AHFb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AIOh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BC@f}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BACb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOMl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AJ@`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AJAl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BAC`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{NMn}}{AHO`{CGbAHC`}}}KGb}\",[]]Cd[\"{{{AHO`{KI`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BGIj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Cd[\"{{{AHO`{ID`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{KFn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AINj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AHEh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFKd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AIKd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{ABDn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AILn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AHEl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BCMf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{B@Ld}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BCLn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AHE`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BBLd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BCNj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BCOl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFGh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFIf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AOL`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BBMh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BABd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BH@l}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{B@Kh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AOJd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AHCf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BCLh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BEFf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{B@M`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{B@Mf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{B@N`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFKn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AIMd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BEJj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{DAl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{A@j}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{ABCd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{ABDh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AHCb}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Cd[\"{{{AHO`{CNj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AIJl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{IDh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AOJn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{NKl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BBAl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BHLn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AOJj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFLf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{IFb}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BGHn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Bi[\"{{{AHO`{AILd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AB@j}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{KIb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BGIl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{IDb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFDf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{KG`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BAAl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AINl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AHEj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFDb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFKf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AIKj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{ABE`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIM`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AHEn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCMh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AHFd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBBl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AJAn}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AOKn}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AONd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BC@j}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Ll}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BCM`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AHEb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBLf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BHDj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{IFl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCNl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCOn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFGj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFIh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOLb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BBMj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BABh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BH@n}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Kl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOJf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AHCh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBNd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AIMl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AJ@h}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{B@Mj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BCLl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BEFj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AAOl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BEGb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABAb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Mb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AOIj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIOl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBBb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCNh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BHE`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABAh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFCl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BCMd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BAOd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Mh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{B@Nb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCAb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BFL`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AIMf}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BIAl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BEJl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{DAn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{A@l}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{ABCf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{ABDj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AHCd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBCh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BGAn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{IFf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BHM`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOJl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFLl}}{AHO`{CGbAHC`}}}KGb}\",[]]Cd[\"{{{AHO`{IFd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Bi[\"{{{AHO`{BGI`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{CNl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIJn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{IDj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOK`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{NKn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BBAn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{IFh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{IFn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCAd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABC`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABDl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Nd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bd[\"{{{AHO`{BGIb}}}{{KFl{AJ@f}}}}\",[]]Ak[\"{{{AHO`{BAAl}}}AB@d}\",[]]A`[\"{ABDnCNb}\",[]]A`[\"{ABE`CNb}\",[]]Aj[\"{{{AHO`{BBBb}}}KCb}\",[]]A`[\"{BHE`CNb}\",[]]o[\"{D@hCNb}\",[]]A`[\"{ABC`KCb}\",[]]Cf[\"{{{AHO`{CGbBH@l}}{A@b{ABD`}}}{{AHO`{CGbBH@l}}}}\",[]]Cf[\"{{{AHO`{CGbBH@n}}{A@b{ABDb}}}{{AHO`{CGbBH@n}}}}\",[]]8Af[\"{{AB@dCNb}BC@l}\",[]]Ah[\"{{}{{A@b{BHEb}}}}\",[]]Ae[\"{{KCbCN`}BANd}\",[]]Ce[\"{{BBMh{KFl{BABd}}AHFl{A@b{NMd}}}{{KGf{AB@h}}}}\",[]]Ai[\"{{{A@d{IIb}}}AINn}\",[]]A`[\"{NLlBCNj}\",[]]Ai[\"{{{A@b{NJj}}}BBMh}\",[]]Be[\"{{{A@b{BABf}}{A@b{BFBn}}}BABd}\",[]]Aj[\"{{{A@b{B@Kj}}}B@Kh}\",[]]B`[\"{{{AHO`{{K@j{Oh}}}}}B@Mf}\",[]]Ae[\"{{CN`KCb}BEJj}\",[]]Ah[\"{{DAlA@jCNb}ABCd}\",[]]Am[\"{{AJ@f{KFl{KFb}}}AHCb}\",[]]Ao[\"{{{A@b{AOJn}}NK`CMn}IDh}\",[]]Ao[\"{{{A@b{BBAl}}NK`CMn}NKl}\",[]]Ae[\"{{KCbCN`}BANf}\",[]]Ai[\"{{{A@d{IIb}}}AIO`}\",[]]Bo[\"{{{A@b{BBMj}}{KFl{{A@b{BABh}}}}DC`}AB@j}\",[]]A`[\"{KCbBIE`}\",[]]o[\"{{}BIAb}\",[]]A`[\"{NLlBCNl}\",[]]Ai[\"{{{A@b{NJl}}}BBMj}\",[]]Be[\"{{{A@b{BABj}}{A@b{BFC`}}}BABh}\",[]]Aj[\"{{{A@b{B@Kn}}}B@Kl}\",[]]Ek[\"{{AAOb{AHO`{c}}{AHO`{{K@j{CN`}}}}DC`}{{KGd{{KC`{BBBb{KFl{AAOb}}}}BFCl}}}{BFHdIHh}}\",[\"\"]]B`[\"{{{AHO`{{K@j{Oh}}}}}B@Mh}\",[]]Af[\"{{BFL`KHl}BCAb}\",[]]A`[\"{KCbBIAl}\",[]]Ae[\"{{CN`KCb}BEJl}\",[]]Ah[\"{{DAnA@lCNb}ABCf}\",[]]Am[\"{{AJ@f{KFl{KFb}}}AHCd}\",[]]Ao[\"{{{A@b{AOK`}}NK`CMn}IDj}\",[]]Ao[\"{{{A@b{BBAn}}NK`CMn}NKn}\",[]]Aj[\"{AJAj{{KGf{BCAd}}}}\",[]]Aa[\"{BEJdBHKb}\",[]]Aa[\"{BEJhBHKd}\",[]]o[\"{DAlDAl}\",[]]o[\"{DAnDAn}\",[]]Ak[\"{{{AHO`{AJ@n}}}AJ@l}\",[]]Ai[\"{{{AHO`{NMd}}}NK`}\",[]]0Aj[\"{{{AHO`{BACb}}}NK`}\",[]]Ak[\"{{{AHO`{BBCd}}}AJ@l}\",[]]Ak[\"{{{AHO`{AJA`}}}AJ@l}\",[]]Ak[\"{{{AHO`{BBCf}}}AJ@l}\",[]]Bg[\"{{{AHO`{AILb}}KFn}{{KFl{AB@d}}}}\",[]]Aa[\"{AHElAB@d}\",[]]Bg[\"{{{AHO`{AILd}}KG`}{{KFl{AB@d}}}}\",[]]Aa[\"{AHEnAB@d}\",[]]Ah[\"{AAl{{KGh{ICj}}}}\",[]]Ah[\"{AAn{{KGh{ICj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aa[\"{BA@`AJ@f}\",[]]Aa[\"{BA@bAJ@f}\",[]]Aa[\"{ABC`AJ@f}\",[]]Aa[\"{BCAbBFL`}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{AAOlICn}\",[]]Am[\"{{{AHO`{CGbABBf}}}ICj}\",[]]Am[\"{{{AHO`{CGbABA`}}}ICj}\",[]]Al[\"{{{AHO`{CGbDA`}}}ICj}\",[]]Am[\"{{{AHO`{CGbBCAf}}}ICj}\",[]]Am[\"{{{AHO`{CGbAIOd}}}ICj}\",[]]Am[\"{{{AHO`{CGbAJ@`}}}ICj}\",[]]Al[\"{{{AHO`{CGbKDl}}}ICj}\",[]]A`[\"{cc{}}\",[\"T\"]]000000000000000000000000Aa[\"{BCLnBFDd}\",[]]1111111111111Aa[\"{AHFbBC@h}\",[]]2Aa[\"{AIOhAHFb}\",[]]3Aa[\"{BCLnAHFb}\",[]]Aa[\"{BCLnAIOh}\",[]]55Aa[\"{AHFbBC@f}\",[]]666Aa[\"{B@LdAJAl}\",[]]Aa[\"{BAC`AJAl}\",[]]Aa[\"{BCLnAJAl}\",[]]9Aa[\"{BCLnBAC`}\",[]]::::::::A`[\"{ABCdKI`}\",[]]A`[\"{BFKnKI`}\",[]]o[\"{CN`KI`}\",[]]o[\"{CMnKI`}\",[]]n[\"{OhKI`}\",[]]????Al[\"{cKFn{{D@b{CN`}}}}\",[\"T\"]]A`[\"{cc{}}\",[\"T\"]]00000000Aa[\"{AOJbBCLn}\",[]]1A`[\"{IDfBCLn}\",[]]A`[\"{IElBCLn}\",[]]3333333A`[\"{KI`AOL`}\",[]]44444Aa[\"{BD@`AOJd}\",[]]Aa[\"{BGIjAOJd}\",[]]66A`[\"{IElBCLh}\",[]]7Aa[\"{BFLfB@M`}\",[]]8888A`[\"{KI`BFKn}\",[]]9999A`[\"{KI`ABCd}\",[]]::Aa[\"{AJ@fAHCb}\",[]];;;;;;;;;;;;;;;;A`[\"{BBOhIFb}\",[]]A`[\"{AIN`IFb}\",[]]A`[\"{BCMjIFb}\",[]]A`[\"{BCOdIFb}\",[]]A`[\"{BHLlIFb}\",[]]A`[\"{BHGfIFb}\",[]]A`[\"{BEFlIFb}\",[]]A`[\"{BHMnIFb}\",[]]A`[\"{BEHbIFb}\",[]]A`[\"{BEIlIFb}\",[]]A`[\"{BBNfIFb}\",[]]A`[\"{cc{}}\",[\"T\"]]0000000000000000000000A`[\"{BFL`KIb}\",[]]n[\"{OhKIb}\",[]]o[\"{CMnKIb}\",[]]o[\"{CN`KIb}\",[]]A`[\"{ABCfKIb}\",[]]5555Al[\"{cKG`{{D@b{CN`}}}}\",[\"T\"]]666666666666666666Aa[\"{BCAbBCM`}\",[]]7777A`[\"{AHEjIFl}\",[]]888888A`[\"{KIbAOLb}\",[]]9999Aa[\"{BD@`AOJf}\",[]]:Aa[\"{BGIlAOJf}\",[]];;;;;Aa[\"{BCAbBCLl}\",[]]<<<<<>>>>A`[\"{IFfBCAb}\",[]]?A`[\"{KIbBFL`}\",[]]A`[\"{cc{}}\",[\"T\"]]0000A`[\"{KIbABCf}\",[]]111Aa[\"{AJ@fAHCd}\",[]]22A`[\"{BBChIFf}\",[]]33333333A`[\"{BHMnIFd}\",[]]A`[\"{BEFlIFd}\",[]]5A`[\"{BEHbIFd}\",[]]A`[\"{BBNfIFd}\",[]]A`[\"{BBOhIFd}\",[]]A`[\"{BCMjIFd}\",[]]A`[\"{BCOdIFd}\",[]]A`[\"{BHLlIFd}\",[]]A`[\"{BHGfIFd}\",[]]A`[\"{BEIlIFd}\",[]]A`[\"{AIN`IFd}\",[]]>>>>>>>>>>>>An[\"{{{AHO`{c}}}AJAjCNh}\",[\"S\"]]??????????????Bm[\"{{{AHO`{KI`}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bk[\"{{{AHO`{KFn}}{AHO`{CGbc}}}ICjKF`}\",[\"H\"]]Bn[\"{{{AHO`{AOL`}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{B@Mf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{DAl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{A@j}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{ABCd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AHCb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{KIb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BFDf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bk[\"{{{AHO`{KG`}}{AHO`{CGbc}}}ICjKF`}\",[\"H\"]]Bn[\"{{{AHO`{AHFd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BBBl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AJAn}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AOLb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BEGb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BFCl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{B@Mh}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{DAn}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{A@l}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{ABCf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AHCd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Aa[\"{{}c{}}\",[\"U\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n[\"{{}ICj}\",[]]0000Cc[\"{{{AHO`{CGbKDl}}KCb}{{KGd{{KFl{IDb}}AHFd}}}}\",[]]Cf[\"{{{AHO`{CGbBB@j}}}{{KFl{c}}}{}}\",[\"Iterator::Item\"]]Dl[\"{{{AHO`{BFBn}}ICh{AHO`{CGb{K@j{Oh}}}}}{{KGd{{AHO`{{K@j{Oh}}}}AOJj}}}}\",[]]Bi[\"{{{AHO`{CGbNNf}}A@l}{{KFl{ABCf}}}}\",[]]Dl[\"{{{AHO`{BFC`}}ICh{AHO`{CGb{K@j{Oh}}}}}{{KGd{{AHO`{{K@j{Oh}}}}AOJl}}}}\",[]]Bf[\"{{{AHO`{AILb}}KFn}{{KFl{DA`}}}}\",[]]Bf[\"{{{AHO`{DA`}}}{{KGd{ICjAIKd}}}}\",[]]A`[\"{AILnCNb}\",[]]Am[\"{{{AHO`{CGbAILd}}}ICj}\",[]]A`[\"{AIM`CNb}\",[]]Ck[\"{{{ABb{{AHO`{CGbAIJd}}}}{AHO`{CGbNIn}}}{{DAh{ICj}}}}\",[]]Dk[\"{{{ABb{{AHO`{CGbBD@f}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbABBf}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbABBh}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAIKn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbNLb}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbKFf}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAH@h}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAAO`}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBAA`}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBAAn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbKCj}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBBNb}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbNMn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Bf[\"{{{AHO`{CGbAILd}}}{{KFl{IFl}}}}\",[]]De[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{Oh}}}}}{{KGd{{KFl{KCb}}AHFb}}}}\",[]]Bm[\"{{{AHO`{CGbAIOf}}DC`}{{KGd{KDlBBBl}}}}\",[]]C`[\"{{DAn{AHO`{CGbc}}}{{KGd{BGAnIFf}}}A@f}\",[\"R\"]]Bf[\"{{{AHO`{CGbAHBb}}}{{KFl{ICn}}}}\",[]]Ec[\"{{{AHO`{BCAd}}AJAj{AHO`{CGb{K@j{AIMh}}}}{AHO`{CGb{K@j{ABC`}}}}}{{KGf{KCb}}}}\",[]]Cn[\"{{{AHO`{BFBn}}ICh{AHO`{CGb{ABh{Oh}}}}}{{KGd{ICjAOJj}}}}\",[]]Cn[\"{{{AHO`{BFC`}}ICh{AHO`{CGb{ABh{Oh}}}}}{{KGd{ICjAOJl}}}}\",[]]C`[\"{{{AHO`{CGbAHBb}}ICnDC`}{{KGd{ICjBFDf}}}}\",[]]Cc[\"{{{AHO`{BCAd}}AJAj{AHO`{ABDl}}}{{KGf{ICj}}}}\",[]]Bn[\"{{{AHO`{CGbBH@l}}CN`}{{AHO`{CGbBH@l}}}}\",[]]Bn[\"{{{AHO`{CGbBH@n}}CN`}{{AHO`{CGbBH@n}}}}\",[]]Aj[\"{{{AHO`{AILb}}}DAl}\",[]]Aj[\"{{{AHO`{AILd}}}DAn}\",[]]Cn[\"{{{AHO`{NJj}}{AHO`{{K@j{Oh}}}}{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Cn[\"{{{AHO`{NJl}}{AHO`{{K@j{Oh}}}}{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]A`[\"{BC@lCNb}\",[]]A`[\"{ABDhKCb}\",[]]A`[\"{ABDjKCb}\",[]]o[\"{IHdDC`}\",[]]Bm[\"{{{AHO`{CGbAIOd}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbBGB`}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAIOf}}KIb}{{KGd{ICjB@Ll}}}}\",[]]Bn[\"{{{AHO`{AJAf}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BBOd}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BEJj}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{AJAh}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BBOf}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BEJl}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bd[\"{{{AHO`{BEGf}}}{{KFl{BB@h}}}}\",[]]Bd[\"{{{AHO`{BEGh}}}{{KFl{BB@j}}}}\",[]]Bi[\"{{{A@b{BFBf}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{AIJl}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{AOJn}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{BBAl}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{BFBh}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{AIJn}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{AOK`}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{BBAn}}NK`CMn}{{A@d{AILh}}}}\",[]]Aj[\"{BG@n{{A@b{BFBh}}}}\",[]]o[\"{ID`ICn}\",[]]A`[\"{ABDnCNb}\",[]]o[\"{IDbICn}\",[]]A`[\"{ABE`CNb}\",[]]Aa[\"{AOIjBCM`}\",[]]Ai[\"{{{AHO`{AAj}}}AAj}\",[]]Ak[\"{{{AHO`{AOMf}}}AOMf}\",[]]Ak[\"{{{AHO`{AOIn}}}AOIn}\",[]]Ak[\"{{{AHO`{AILb}}}AILb}\",[]]Ai[\"{{{AHO`{KEd}}}KEd}\",[]]Ak[\"{{{AHO`{BGJ`}}}BGJ`}\",[]]Ak[\"{{{AHO`{BFDd}}}BFDd}\",[]]Ak[\"{{{AHO`{AB@h}}}AB@h}\",[]]Ak[\"{{{AHO`{BAOf}}}BAOf}\",[]]Ai[\"{{{AHO`{KFd}}}KFd}\",[]]Ai[\"{{{AHO`{DA`}}}DA`}\",[]]Ak[\"{{{AHO`{BCAf}}}BCAf}\",[]]Ak[\"{{{AHO`{BC@h}}}BC@h}\",[]]Ak[\"{{{AHO`{AHFb}}}AHFb}\",[]]Ak[\"{{{AHO`{AIOh}}}AIOh}\",[]]Ak[\"{{{AHO`{BC@f}}}BC@f}\",[]]Ak[\"{{{AHO`{AJAl}}}AJAl}\",[]]Ak[\"{{{AHO`{BAC`}}}BAC`}\",[]]Ai[\"{{{AHO`{KI`}}}KI`}\",[]]Ak[\"{{{AHO`{BGIj}}}BGIj}\",[]]Ai[\"{{{AHO`{KFn}}}KFn}\",[]]Ak[\"{{{AHO`{AINj}}}AINj}\",[]]Ak[\"{{{AHO`{AHEh}}}AHEh}\",[]]Ak[\"{{{AHO`{BFKd}}}BFKd}\",[]]Ak[\"{{{AHO`{AIKd}}}AIKd}\",[]]Ak[\"{{{AHO`{ABDn}}}ABDn}\",[]]Ak[\"{{{AHO`{AILn}}}AILn}\",[]]Ak[\"{{{AHO`{AHEl}}}AHEl}\",[]]Ak[\"{{{AHO`{BCMf}}}BCMf}\",[]]Ak[\"{{{AHO`{B@Ld}}}B@Ld}\",[]]Ak[\"{{{AHO`{BCLn}}}BCLn}\",[]]Ak[\"{{{AHO`{AHE`}}}AHE`}\",[]]Ak[\"{{{AHO`{BBLd}}}BBLd}\",[]]Ak[\"{{{AHO`{BCOl}}}BCOl}\",[]]Ak[\"{{{AHO`{BFGh}}}BFGh}\",[]]Ak[\"{{{AHO`{BFIf}}}BFIf}\",[]]Ak[\"{{{AHO`{AOL`}}}AOL`}\",[]]Ak[\"{{{AHO`{BBMh}}}BBMh}\",[]]Ak[\"{{{AHO`{BABd}}}BABd}\",[]]Ak[\"{{{AHO`{BH@l}}}BH@l}\",[]]Ak[\"{{{AHO`{B@Kh}}}B@Kh}\",[]]Ak[\"{{{AHO`{AOJd}}}AOJd}\",[]]Ak[\"{{{AHO`{AHCf}}}AHCf}\",[]]Ak[\"{{{AHO`{BCLh}}}BCLh}\",[]]Ak[\"{{{AHO`{BEFf}}}BEFf}\",[]]Ak[\"{{{AHO`{B@M`}}}B@M`}\",[]]Ak[\"{{{AHO`{B@Mf}}}B@Mf}\",[]]Ak[\"{{{AHO`{B@N`}}}B@N`}\",[]]Ak[\"{{{AHO`{BFKn}}}BFKn}\",[]]Ak[\"{{{AHO`{AIMd}}}AIMd}\",[]]Ai[\"{{{AHO`{DAl}}}DAl}\",[]]Ai[\"{{{AHO`{A@j}}}A@j}\",[]]Ak[\"{{{AHO`{ABCd}}}ABCd}\",[]]Ak[\"{{{AHO`{AHCb}}}AHCb}\",[]]Ai[\"{{{AHO`{CNj}}}CNj}\",[]]Ak[\"{{{AHO`{AIJl}}}AIJl}\",[]]Ai[\"{{{AHO`{IDh}}}IDh}\",[]]Ak[\"{{{AHO`{AOJn}}}AOJn}\",[]]Ai[\"{{{AHO`{NKl}}}NKl}\",[]]Ak[\"{{{AHO`{BBAl}}}BBAl}\",[]]Ai[\"{{{AHO`{IFb}}}IFb}\",[]]Ak[\"{{{AHO`{BEJb}}}BEJb}\",[]]Ak[\"{{{AHO`{BGHn}}}BGHn}\",[]]Ak[\"{{{AHO`{BEJf}}}BEJf}\",[]]Ai[\"{{{AHO`{KIb}}}KIb}\",[]]Ak[\"{{{AHO`{BGIl}}}BGIl}\",[]]Ak[\"{{{AHO`{BFDf}}}BFDf}\",[]]Ai[\"{{{AHO`{KG`}}}KG`}\",[]]Ak[\"{{{AHO`{BAAl}}}BAAl}\",[]]Ak[\"{{{AHO`{AINl}}}AINl}\",[]]Ak[\"{{{AHO`{AHEj}}}AHEj}\",[]]Ak[\"{{{AHO`{BFDb}}}BFDb}\",[]]Ak[\"{{{AHO`{BFKf}}}BFKf}\",[]]Ak[\"{{{AHO`{AIKj}}}AIKj}\",[]]Ak[\"{{{AHO`{ABE`}}}ABE`}\",[]]Ak[\"{{{AHO`{AIM`}}}AIM`}\",[]]Ak[\"{{{AHO`{AHEn}}}AHEn}\",[]]Ak[\"{{{AHO`{BCMh}}}BCMh}\",[]]Ak[\"{{{AHO`{AHFd}}}AHFd}\",[]]Ak[\"{{{AHO`{BBBl}}}BBBl}\",[]]Ak[\"{{{AHO`{AJAn}}}AJAn}\",[]]Ak[\"{{{AHO`{AOKn}}}AOKn}\",[]]Ak[\"{{{AHO`{BC@j}}}BC@j}\",[]]Ak[\"{{{AHO`{B@Ll}}}B@Ll}\",[]]Ak[\"{{{AHO`{BCM`}}}BCM`}\",[]]Ak[\"{{{AHO`{AHEb}}}AHEb}\",[]]Ak[\"{{{AHO`{BBLf}}}BBLf}\",[]]Ak[\"{{{AHO`{BHDj}}}BHDj}\",[]]Ak[\"{{{AHO`{BCOn}}}BCOn}\",[]]Ak[\"{{{AHO`{BFGj}}}BFGj}\",[]]Ak[\"{{{AHO`{BFIh}}}BFIh}\",[]]Ak[\"{{{AHO`{AOLb}}}AOLb}\",[]]Ak[\"{{{AHO`{BBMj}}}BBMj}\",[]]Ak[\"{{{AHO`{BABh}}}BABh}\",[]]Ak[\"{{{AHO`{BH@n}}}BH@n}\",[]]Ak[\"{{{AHO`{B@Kl}}}B@Kl}\",[]]Ak[\"{{{AHO`{AOJf}}}AOJf}\",[]]Ak[\"{{{AHO`{AHCh}}}AHCh}\",[]]Ak[\"{{{AHO`{AIMl}}}AIMl}\",[]]Ak[\"{{{AHO`{AJ@h}}}AJ@h}\",[]]Ak[\"{{{AHO`{B@Mj}}}B@Mj}\",[]]Ak[\"{{{AHO`{BCLl}}}BCLl}\",[]]Ak[\"{{{AHO`{BEFj}}}BEFj}\",[]]Ak[\"{{{AHO`{AAOl}}}AAOl}\",[]]Ak[\"{{{AHO`{BEGb}}}BEGb}\",[]]Ak[\"{{{AHO`{B@Mb}}}B@Mb}\",[]]Ak[\"{{{AHO`{BCNh}}}BCNh}\",[]]Ak[\"{{{AHO`{BHE`}}}BHE`}\",[]]Ak[\"{{{AHO`{ABAh}}}ABAh}\",[]]Ak[\"{{{AHO`{BFCl}}}BFCl}\",[]]Ak[\"{{{AHO`{B@Mh}}}B@Mh}\",[]]Ak[\"{{{AHO`{B@Nb}}}B@Nb}\",[]]Ak[\"{{{AHO`{BCAb}}}BCAb}\",[]]Ak[\"{{{AHO`{BFL`}}}BFL`}\",[]]Ak[\"{{{AHO`{AIMf}}}AIMf}\",[]]Ak[\"{{{AHO`{BIAl}}}BIAl}\",[]]Ai[\"{{{AHO`{DAn}}}DAn}\",[]]Ai[\"{{{AHO`{A@l}}}A@l}\",[]]Ak[\"{{{AHO`{ABCf}}}ABCf}\",[]]Ak[\"{{{AHO`{AHCd}}}AHCd}\",[]]Ak[\"{{{AHO`{BBCh}}}BBCh}\",[]]Ak[\"{{{AHO`{BGAn}}}BGAn}\",[]]Ai[\"{{{AHO`{IFf}}}IFf}\",[]]Ai[\"{{{AHO`{IFd}}}IFd}\",[]]Ak[\"{{{AHO`{BEJd}}}BEJd}\",[]]Ak[\"{{{AHO`{BGI`}}}BGI`}\",[]]Ak[\"{{{AHO`{BEJh}}}BEJh}\",[]]Ai[\"{{{AHO`{CNl}}}CNl}\",[]]Ak[\"{{{AHO`{AIJn}}}AIJn}\",[]]Ai[\"{{{AHO`{IDj}}}IDj}\",[]]Ak[\"{{{AHO`{AOK`}}}AOK`}\",[]]Ai[\"{{{AHO`{NKn}}}NKn}\",[]]Ak[\"{{{AHO`{BBAn}}}BBAn}\",[]]Ai[\"{{{AHO`{IFn}}}IFn}\",[]]Ak[\"{{{AHO`{ABC`}}}ABC`}\",[]]Ak[\"{{{AHO`{ABDl}}}ABDl}\",[]]Ak[\"{{{AHO`{B@Nd}}}B@Nd}\",[]]Ak[\"{{{AHO`{BG@n}}}BG@n}\",[]]Ak[\"{{{AHO`{BCN`}}}BCN`}\",[]]Ak[\"{{{AHO`{BHKb}}}BHKb}\",[]]Ak[\"{{{AHO`{BHKd}}}BHKd}\",[]]Bn[\"{{{AHO`{AILb}}KI`{AHO`{{K@j{Oh}}}}}ICj}\",[]]Bn[\"{{{AHO`{AB@h}}KI`{AHO`{{K@j{Oh}}}}}ICj}\",[]]Bf[\"{{{AHO`{DA`}}}{{KGd{ICjBBLd}}}}\",[]]Bf[\"{{{AHO`{CGbAILd}}NK`KIbICn}ICj}\",[]]Bj[\"{{{AHO`{B@Mf}}}{{AHO`{{K@j{Oh}}}}}}\",[]]Bj[\"{{{AHO`{B@Mh}}}{{AHO`{{K@j{Oh}}}}}}\",[]]Aa[\"{BCAbAIMl}\",[]]A`[\"{ABCdCNb}\",[]]A`[\"{ABCfCNb}\",[]]A`[\"{B@N`DC`}\",[]]A`[\"{B@NbDC`}\",[]]l[\"{NKb}\",[]]l[\"{NKd}\",[]]Cf[\"{{{AHO`{BFHd}}{AHO`{CGbA@f}}}{{KGd{B@MhBFCl}}}}\",[]]Cf[\"{{{AHO`{BIE`}}{AHO`{CGbA@f}}}{{KGd{B@MhBFCl}}}}\",[]]Bc[\"{{{AHO`{AILd}}}{{ABh{KG`}}}}\",[]]Bd[\"{{{AHO`{IHj}}{AHO`{CMl}}}ICj}\",[]]Am[\"{{{AHO`{AOJ`}}KCb}ICj}\",[]]Ai[\"{{{AHO`{IHl}}}ICj}\",[]]Bg[\"{{{ABb{{AHO`{CGbAIJd}}}}NK`}ICj}\",[]]Bm[\"{{{AHO`{CGbAJ@`}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAJ@b}}KIb}{{KGd{ICjB@Ll}}}}\",[]]Am[\"{ABA`{{KGd{ICjAIOj}}}}\",[]]Dc[\"{{{AHO`{CGbAB@j}}ABAb{AHO`{CGb{ABh{Oh}}}}}{{KGd{ABDjAIOl}}}}\",[]]Bj[\"{{{AHO`{NMd}}{ABb{{A@d{KEn}}}}}ICj}\",[]]Bk[\"{{{AHO`{BACb}}{ABb{{A@d{KEn}}}}}ICj}\",[]]Bk[\"{{{AHO`{AOMl}}{ABb{{A@d{KEn}}}}}ICj}\",[]]o[\"{AAjDC`}\",[]]Ak[\"{{{AHO`{AILb}}}BCMf}\",[]]Ak[\"{{{AHO`{AB@h}}}BAOf}\",[]]Aj[\"{{{AHO`{DA`}}}AHEl}\",[]]A`[\"{KEdBCMf}\",[]]An[\"{{{AHO`{CGbAILd}}}BCMh}\",[]]Ce[\"{{{AHO`{CGbAINn}}{KFl{KHl}}}{{AHO`{CGbAINn}}}}\",[]]Ce[\"{{{AHO`{CGbAIO`}}{KFl{KHl}}}{{AHO`{CGbAIO`}}}}\",[]]Ck[\"{{{AHO`{CGbAJ@`}}{AHO`{{K@j{Oh}}}}}{{KGd{KCbAJAl}}}}\",[]]Ck[\"{{{AHO`{CGbAJ@b}}{AHO`{{K@j{Oh}}}}}{{KGd{KCbAJAn}}}}\",[]]Bl[\"{{{AHO`{BGAn}}{AHO`{CGbc}}}ICjKDj}\",[\"W\"]]Aj[\"{{{AHO`{AB@h}}}KCj}\",[]]An[\"{ABA`{{KGd{AIKnBCLn}}}}\",[]]Bi[\"{{{AHO`{CGbNNf}}A@l}{{KFl{ABCf}}}}\",[]]Fj[\"{{{AHO`{CGbAB@j}}ABAbNK`{AHO`{CGb{ABh{Oh}}}}{KFl{{A@b{BABh}}}}}{{KGd{{KC`{BEGbAILd}}{A@d{AOIj}}}}}}\",[]]Am[\"{AHO`{{AHO`{c}}}{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A`[\"{AAjAOIn}\",[]]Bc[\"{{AJ@fBBLbAAj}{{KGh{AOJ`}}}}\",[]]Aj[\"{AJ@f{{KGf{AB@h}}}}\",[]]Ba[\"{{}{{KGd{ICj{A@d{IEd}}}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BCLn}\",[]]Be[\"{{{AHO`{AB@j}}}{{AHO`{BBMj}}}}\",[]]o[\"{OhBFKn}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{BABdA@b}\",[]]o[\"{OhBFL`}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{BABhA@b}\",[]]A`[\"{BCAbKFl}\",[]]Bm[\"{{{AHO`{CGbc}}}{{KGd{KI`BBCh}}}A@f}\",[\"B\"]]Bm[\"{{{AHO`{CGbc}}}{{KGd{KFnBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{AHCfBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{BFKnBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{ABCdBBCh}}}A@f}\",[\"B\"]]Bi[\"{{{AHO`{CGbc}}}{{KGl{KIb}}}A@f}\",[\"B\"]]Bi[\"{{{AHO`{CGbc}}}{{KGl{KG`}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AHCh}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AIMl}}}A@f}\",[\"B\"]]Ek[\"{{{AHO`{CGb{KEl{AAOb}}}}{AHO`{c}}{AHO`{{K@j{CN`}}}}DC`}{{KGd{BCNhBFCl}}}{BFHdIHh}}\",[\"\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{BFL`}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{ABCf}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AHBd}}}A@f}\",[\"B\"]]A`[\"{ABC`KFl}\",[]]Bk[\"{{{AHO`{KI`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KFn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHCf}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{BFKn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{ABCd}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KIb}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KG`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHCh}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AIMl}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AAOl}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{BFL`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{ABCf}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHBn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bj[\"{{{AHO`{CGbAJ@`}}}{{KGd{ICjB@Ld}}}}\",[]]Bj[\"{{{AHO`{CGbAJ@b}}}{{KGd{ICjAOKn}}}}\",[]]An[\"{{{AHO`{AONh}}AB@d}ICj}\",[]]Ea[\"{{{AHO`{CGbAB@j}}NK`AHCd{KFl{B@Nb}}AAOb{AHO`{CGb{ABh{Oh}}}}}{{KFl{BAOb}}}}\",[]]o[\"{D@dNKb}\",[]]o[\"{D@fNKd}\",[]]A`[\"{ABA`ICj}\",[]]Ba[\"{{{AHO`{CGbAB@j}}ABAb}ICj}\",[]]Bh[\"{{{AHO`{AJAf}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BBOd}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BEJj}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{AJAh}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BBOf}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BEJl}}{AHO`{CMl}}ICn}ICj}\",[]]A`[\"{AHAlDC`}\",[]]o[\"{ID`CNb}\",[]]o[\"{IDbCNb}\",[]]Ch[\"{{{AHO`{CGbAILf}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbCNj}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbIDh}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbNKl}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Ch[\"{{{AHO`{CGbAILh}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbCNl}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbIDj}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbNKn}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]o[\"{D@dNKb}\",[]]o[\"{D@fNKd}\",[]]o[\"{BEKfOh}\",[]]A`[\"{KEdBCLn}\",[]]A`[\"{BCLhICn}\",[]]A`[\"{BEFfICn}\",[]]Aa[\"{AH@`BFD`}\",[]]A`[\"{BCLlICn}\",[]]A`[\"{BEFjICn}\",[]]A`[\"{BCAbKHl}\",[]]Aa[\"{BBLjBCM`}\",[]]Aa[\"{AH@bBFDb}\",[]]Bg[\"{{{AHO`{AB@h}}AHFl}{{KGf{ICj}}}}\",[]]A`[\"{ABA`ICj}\",[]]Cf[\"{{{AHO`{CGbAB@j}}ABAb{AHO`{CGb{ABh{Oh}}}}}ABDj}\",[]]Ak[\"{{{AHO`{AHCb}}}AJ@f}\",[]]l[\"{NKb}\",[]]Ak[\"{{{AHO`{AHCd}}}AJ@f}\",[]]l[\"{NKd}\",[]]An[\"{{AB@fAAj}{{KGh{ICj}}}}\",[]]B`[\"{{BABdAJ@f}{{KGf{AB@h}}}}\",[]]Bc[\"{BABb{{KGd{ICj{A@d{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BFDd}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BC@h}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AHFb}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AIOh}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BC@f}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AJAl}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BAC`}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BCLn}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BCM`}}}{{KFl{{AHO`{IEd}}}}}}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABDlKFl}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AINjAIKd}}}}\",[]]Aa[\"{BAAbAINj}\",[]]Aa[\"{BAAdAINl}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{ABC`KCb}\",[]]Aa[\"{AHElABDn}\",[]]Aa[\"{BCMfABDn}\",[]]Aa[\"{AHEnABE`}\",[]]Aa[\"{BCMhABE`}\",[]]3210Dh[\"{{{AHO`{NJj}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAOJj}}}}\",[]]Dh[\"{{{AHO`{NJl}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAOJl}}}}\",[]]Aj[\"{{{AHO`{AILf}}}CNb}\",[]]Ai[\"{{{AHO`{CNj}}}CNb}\",[]]Ai[\"{{{AHO`{IDh}}}CNb}\",[]]Ai[\"{{{AHO`{NKl}}}CNb}\",[]]Aj[\"{{{AHO`{AILh}}}CNb}\",[]]Ai[\"{{{AHO`{CNl}}}CNb}\",[]]Ai[\"{{{AHO`{IDj}}}CNb}\",[]]Ai[\"{{{AHO`{NKn}}}CNb}\",[]]Aj[\"{{{AHO`{BGOj}}}KCb}\",[]]Aj[\"{{{AHO`{BGOl}}}KCb}\",[]]Aj[\"{{{AHO`{BIAb}}}KCb}\",[]]Aj[\"{{{AHO`{BIAl}}}KCb}\",[]]o[\"{AAjKCb}\",[]]n[\"{{}NIl}\",[]]0A`[\"{A@hAAOf}\",[]]111Ba[\"{{AHO`{AHO`{c}}}ABBj{}}\",[\"K\"]]0000000000000000000Cg[\"{{{AHO`{AB@h}}AJ@f{AHO`{CMl}}}{{KGd{AIKnB@M`}}}}\",[]]Dl[\"{{{AHO`{CGbAB@j}}NK`B@KlAJ@f{AHO`{CMl}}}{{KGd{{KC`{BEGbAILd}}B@Mb}}}}\",[]]Bd[\"{{{AHO`{ABA`}}}{{KFl{BEGf}}}}\",[]]Dm[\"{{{AHO`{AHDj}}KFnCNb{AHO`{{K@j{Oh}}}}{AHO`{CGbAAOb}}}{{KGd{ICjAOJj}}}}\",[]]Ca[\"{{{AHO`{AHCl}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Bd[\"{{{AHO`{ABAb}}}{{KFl{BEGh}}}}\",[]]Dm[\"{{{AHO`{AHDl}}KG`CNb{AHO`{{K@j{Oh}}}}{AHO`{CGbAAOb}}}{{KGd{ICjAOJl}}}}\",[]]Ca[\"{{{AHO`{AHCn}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]o[\"{{}AONf}\",[]]n[\"{{}IHj}\",[]]o[\"{{}AOJ`}\",[]]o[\"{{}BANd}\",[]]o[\"{{}BAOf}\",[]]n[\"{{}KI`}\",[]]n[\"{{}KFn}\",[]]o[\"{{}AINj}\",[]]o[\"{{}AIKd}\",[]]o[\"{{}ABDn}\",[]]o[\"{{}AILn}\",[]]o[\"{{}AHEl}\",[]]o[\"{{}BCMf}\",[]]o[\"{{}B@Ld}\",[]]o[\"{{}BCOl}\",[]]o[\"{{}BFGh}\",[]]o[\"{{}BFIf}\",[]]o[\"{{}AOL`}\",[]]o[\"{{}BBMh}\",[]]o[\"{{}BH@l}\",[]]o[\"{{}BEJj}\",[]]o[\"{{}AIJl}\",[]]o[\"{{}AOJn}\",[]]o[\"{{}BBAl}\",[]]o[\"{{}BFBj}\",[]]o[\"{{}BANf}\",[]]o[\"{{}BIAb}\",[]]n[\"{{}KIb}\",[]]n[\"{{}KG`}\",[]]o[\"{{}AINl}\",[]]o[\"{{}AIKj}\",[]]o[\"{{}ABE`}\",[]]o[\"{{}AIM`}\",[]]o[\"{{}AHEn}\",[]]o[\"{{}BCMh}\",[]]o[\"{{}BC@j}\",[]]o[\"{{}B@Ll}\",[]]o[\"{{}BCOn}\",[]]o[\"{{}BFGj}\",[]]o[\"{{}BFIh}\",[]]o[\"{{}AOLb}\",[]]o[\"{{}BBMj}\",[]]o[\"{{}BH@n}\",[]]o[\"{{}BIAl}\",[]]o[\"{{}BEJl}\",[]]o[\"{{}AIJn}\",[]]o[\"{{}AOK`}\",[]]o[\"{{}BBAn}\",[]]o[\"{{}BFBl}\",[]]o[\"{{}ABC`}\",[]]n[\"{{}IHl}\",[]]o[\"{{}BCN`}\",[]]o[\"{{}BAOd}\",[]]Ak[\"{{{AHO`{BBBb}}}B@Mh}\",[]]Ak[\"{{{AHO`{BCNh}}}B@Mh}\",[]]Aa[\"{BHE`B@Mh}\",[]]Aa[\"{BFLbB@Mh}\",[]]A`[\"{D@hB@Mh}\",[]]A`[\"{IH`B@Mh}\",[]]A`[\"{IHdB@Mh}\",[]]Aa[\"{BEKfB@Mh}\",[]]Cg[\"{{{AHO`{AHDj}}KFnCNb{AHO`{CGb{K@j{Oh}}}}KCb}ICj}\",[]]Ca[\"{{{AHO`{AHCl}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Cg[\"{{{AHO`{AHDl}}KG`CNb{AHO`{CGb{K@j{Oh}}}}KCb}ICj}\",[]]Ca[\"{{{AHO`{AHCn}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Aj[\"{{{AHO`{AIOd}}}DC`}\",[]]Aj[\"{{{AHO`{BGB`}}}DC`}\",[]]Ak[\"{{{AHO`{AILf}}}BFBj}\",[]]Aj[\"{{{AHO`{CNj}}}BFBj}\",[]]Aj[\"{{{AHO`{IDh}}}BFBj}\",[]]Aj[\"{{{AHO`{NKl}}}BFBj}\",[]]Ak[\"{{{AHO`{AILh}}}BFBl}\",[]]Aj[\"{{{AHO`{CNl}}}BFBl}\",[]]Aj[\"{{{AHO`{IDj}}}BFBl}\",[]]Aj[\"{{{AHO`{NKn}}}BFBl}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CMn}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CMn}{{AHO`{CGbBCOn}}}}\",[]]Bf[\"{{{AHO`{CGbAILf}}NK`CNbCNb}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}NK`CNbCNb}ICj}\",[]]Aj[\"{{{AHO`{AILb}}}KFf}\",[]]Bc[\"{{{AHO`{ABBh}}}{{KFl{KFn}}}}\",[]]Aa[\"{BHE`B@Mh}\",[]]Aa[\"{BFLbB@Mh}\",[]]A`[\"{D@hB@Mh}\",[]]A`[\"{IH`B@Mh}\",[]]Aa[\"{BEKfB@Mh}\",[]]Aj[\"{{{AHO`{AJ@`}}}NMn}\",[]]Bn[\"{{{AHO`{AJ@b}}}{{KGd{{KFl{KIb}}B@Ll}}}}\",[]]o[\"{AAjKCb}\",[]]o[\"{IHjKCb}\",[]]Am[\"{{{AHO`{CGbAILd}}}NNf}\",[]]Aj[\"{{{AHO`{AHDj}}}KCb}\",[]]Aj[\"{{{AHO`{AHDl}}}KCb}\",[]]A`[\"{AHO`KHn}\",[]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bd[\"{{{AHO`{BGJ`}}}{{KFl{AILb}}}}\",[]]Bc[\"{{{AHO`{BCAf}}}{{KFl{DA`}}}}\",[]]Bn[\"{{{AHO`{CGbB@Kh}}CN`}{{AHO`{CGbB@Kh}}}}\",[]]Bn[\"{{{AHO`{CGbB@Kl}}CN`}{{AHO`{CGbB@Kl}}}}\",[]]A`[\"{BHE`CN`}\",[]]A`[\"{BFLbCN`}\",[]]o[\"{D@hCN`}\",[]]o[\"{IH`CN`}\",[]]A`[\"{AHAlKFl}\",[]]Aa[\"{ABDlAHO`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aa[\"{BC@lAB@d}\",[]]A`[\"{KDlBC@j}\",[]]Aa[\"{AHElAILn}\",[]]Aa[\"{BCMfAILn}\",[]]Aa[\"{AHEnAIM`}\",[]]Aa[\"{BCMhAIM`}\",[]]3210Bh[\"{{{AHO`{CGbc}}KCb}B@Mf{A@fIHh}}\",[\"\"]]Bh[\"{{{AHO`{CGbc}}KCb}B@Mh{A@fIHh}}\",[\"\"]]o[\"{{}BCNj}\",[]]o[\"{{}BCNl}\",[]]A`[\"{CNbBIAb}\",[]]Cd[\"{{{AHO`{CMl}}}{{KGh{AOMfc}}}{}}\",[\"FromStr::Err\"]]Cd[\"{{{AHO`{CMl}}}{{KGh{AOInc}}}{}}\",[\"FromStr::Err\"]]o[\"{CN`KI`}\",[]]o[\"{CN`KIb}\",[]]Al[\"{CNb{{KGd{KI`BGIj}}}}\",[]]Al[\"{CNb{{KGd{KIbBGIl}}}}\",[]]Aa[\"{BGGnAOJh}\",[]]Aa[\"{BIEbBB@b}\",[]]Aa[\"{BGH`AOJh}\",[]]Aa[\"{BIEdBB@b}\",[]]Af[\"{{}{{KFl{Ab}}}}\",[]]0000Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBFIf}}AB@d}{{AHO`{CGbBFIf}}}}\",[]]Bo[\"{{{AHO`{CGbBFIh}}AB@d}{{AHO`{CGbBFIh}}}}\",[]]Bb[\"{{{A@d{AILf}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{CNj}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{IDh}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{NKl}}}{{A@d{A@`}}}}\",[]]Bb[\"{{{A@d{AILh}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{CNl}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{IDj}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{NKn}}}{{A@d{A@`}}}}\",[]]Aj[\"{{{AHO`{BGJ`}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBH@l}}AB@d}{{AHO`{CGbBH@l}}}}\",[]]Bo[\"{{{AHO`{CGbBH@n}}AB@d}{{AHO`{CGbBH@n}}}}\",[]]Bc[\"{{{AHO`{AIKn}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{ABA`}}}{{KFl{KFb}}}}\",[]]Bm[\"{{{AHO`{DA`}}}{{KGd{{KFl{KFb}}AIKd}}}}\",[]]Bc[\"{{{AHO`{AHCb}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{ABAb}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{AHCd}}}{{KFl{KFb}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bc[\"{{{AHO`{AHBb}}}{{KFl{KCb}}}}\",[]]Am[\"{{{AHO`{AONh}}KCb}ICj}\",[]]Aj[\"{{{AHO`{AILb}}}NLb}\",[]]Bg[\"{{{AHO`{AJ@`}}}{{KGd{CElB@Ld}}}}\",[]]Bg[\"{{{AHO`{AJ@b}}}{{KGd{CElB@Ll}}}}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]]A`[\"{AHAlKFl}\",[]]A`[\"{AOIjKFl}\",[]]Ck[\"{{{AHO`{CGbBBMh}}{KFl{{IIh{Oh}}}}}{{AHO`{CGbBBMh}}}}\",[]]Ck[\"{{{AHO`{CGbBBMj}}{KFl{{IIh{Oh}}}}}{{AHO`{CGbBBMj}}}}\",[]]A`[\"{BFBjKFl}\",[]]A`[\"{BFBlKFl}\",[]]Ac[\"{AHO`c{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Ao[\"{c{{KGd{e}}}{}{}}\",[\"U\",\"T\"]]000000000000000000000000000000000000000000000000000000Al[\"{CNb{{KGd{KI`BGIj}}}}\",[]]Al[\"{ICh{{KGd{KI`BGIj}}}}\",[]]Al[\"{KCb{{KGd{KI`BGIj}}}}\",[]]3333333333333333333Aj[\"{AB@d{{KGd{AOL`}}}}\",[]]444444Ai[\"{CNb{{KGd{AHCf}}}}\",[]]55555555555555555555555555555Bc[\"{{{A@b{B@Kd}}}{{KGd{BEJb}}}}\",[]]Aj[\"{B@Kd{{KGd{BEJb}}}}\",[]]77Bc[\"{{{A@b{BAB`}}}{{KGd{BEJf}}}}\",[]]Aj[\"{BAB`{{KGd{BEJf}}}}\",[]]999999999999999999999Al[\"{ICh{{KGd{KIbBGIl}}}}\",[]]Al[\"{KCb{{KGd{KIbBGIl}}}}\",[]];Al[\"{CNb{{KGd{KIbBGIl}}}}\",[]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Bm[\"{B@Kd{{KGd{BEJdc}}}{}}\",[\"TryFrom::Error\"]]Cf[\"{{{A@b{B@Kd}}}{{KGd{BEJdc}}}{}}\",[\"TryFrom::Error\"]]Ao[\"{c{{KGd{e}}}{}{}}\",[\"U\",\"T\"]]00Cf[\"{{{A@b{BAB`}}}{{KGd{BEJhc}}}{}}\",[\"TryFrom::Error\"]]Bm[\"{BAB`{{KGd{BEJhc}}}{}}\",[\"TryFrom::Error\"]]22222222222222222222222Aj[\"{{}{{KGd{c}}}{}}\",[\"U\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cd[\"{{{ABb{{AHO`{CGbc}}}}{AHO`{CGbNIn}}}DAh{}}\",[\"F\"]]000000000Cc[\"{{{AHO`{BCAd}}AJAj{AHO`{ABDl}}}{{KGf{ICj}}}}\",[]]Bk[\"{{{AHO`{BGOj}}B@Mf}{{KGd{ICjAIMd}}}}\",[]]Bk[\"{{{AHO`{BGOl}}B@Mh}{{KGd{ICjAIMf}}}}\",[]]0Bk[\"{{{AHO`{BIAb}}B@Mh}{{KGd{ICjAIMf}}}}\",[]]Ak[\"{{{AHO`{AILb}}}AAO`}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{KI`IF`}}}}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{DAlIF`}}}}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{A@jIF`}}}}\",[]]Bj[\"{{{AHO`{CGbBACd}}}{{KGd{ABCdIF`}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{KIb}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{DAn}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{A@l}}}}\",[]]Bg[\"{{{AHO`{CGbBACd}}}{{KGj{ABCf}}}}\",[]]Aa[\"{AOInBGIh}\",[]]Bd[\"{{{AHO`{AILf}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{CNj}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{IDh}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{NKl}}}{{A@d{AILf}}}}\",[]]Bd[\"{{{AHO`{AILh}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{CNl}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{IDj}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{NKn}}}{{A@d{AILh}}}}\",[]]A`[\"{ABDnCNb}\",[]]An[\"{{{AHO`{CGbAILd}}}AHBb}\",[]]A`[\"{ABE`CNb}\",[]]C`[\"{{{AHO`{CGbB@Mf}}}{{AHO`{CGb{K@j{Oh}}}}}}\",[]]C`[\"{{{AHO`{CGbB@Mh}}}{{AHO`{CGb{K@j{Oh}}}}}}\",[]]Ah[\"{Oh{{KFl{B@N`}}}}\",[]]Ah[\"{Oh{{KFl{B@Nb}}}}\",[]]Ah[\"{Oh{{KFl{B@Nd}}}}\",[]]A`[\"{ABCdDAl}\",[]]A`[\"{ABCfDAn}\",[]]Bi[\"{AIKn{{KGd{{KC`{AILbBD@f}}AIKn}}}}\",[]]Aa[\"{{}c{}}\",[\"I\"]]o[\"{DAlDC`}\",[]]o[\"{DAnDC`}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]21Aj[\"{{{AHO`{ABA`}}}DC`}\",[]]Aj[\"{{{AHO`{ABAb}}}DC`}\",[]]Bn[\"{{{AHO`{CGbBABd}}DC`}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}DC`}{{AHO`{CGbBABh}}}}\",[]]Bm[\"{{{AHO`{NMd}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]Bn[\"{{{AHO`{BACb}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]Bn[\"{{{AHO`{AOMl}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Ak[\"{{{AHO`{AILb}}}ABBf}\",[]]Bo[\"{{{AHO`{AILb}}cAINj}ABBh{{D@b{AHCb}}}}\",[\"\"]]Ce[\"{{{AHO`{CGbAILd}}AHCdAINlNK`}{{KGd{KG`AHEb}}}}\",[]]43Bm[\"{{{AHO`{CGbAILd}}KG`}{{KGd{ICjAIKj}}}}\",[]]E`[\"{{{ABb{{AHO`{CGbBGIb}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbBEFb}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbAINh}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbBGA`}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbAIOd}}}}{AHO`{CGbNIn}}{AHO`{CGbNLn}}}{{DAh{{KGf{ICj}}}}}}\",[]]Ec[\"{{{AHO`{CGbAIOd}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{Oh}}}}}{{DAh{{KGd{KCbAHFb}}}}}}\",[]]Ef[\"{{{ABb{{AHO`{CGbAIOd}}}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{Oh}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]Fg[\"{{{AHO`{CGbBBL`}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{AIMh}}}}{AHO`{CGb{K@j{ABC`}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]Dn[\"{{{ABb{{AHO`{CGbAHFj}}}}{AHO`{ABDl}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]>=Ce[\"{{{AHO`{CGbBBMh}}{A@b{NJj}}}{{AHO`{CGbBBMh}}}}\",[]]Ce[\"{{{AHO`{CGbBBMj}}{A@b{NJl}}}{{AHO`{CGbBBMj}}}}\",[]]Cj[\"{{{AHO`{BABf}}CN`B@Mf{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BEJf}}CN`B@Mf{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BABj}}CN`B@Mh{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BEJh}}CN`B@Mh{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BHKd}}CN`B@Md{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Bb[\"{KCb{{KC`{KCb{KFl{KCb}}}}}}\",[]]000Aj[\"{{{AHO`{AILb}}}KCb}\",[]]A`[\"{AHO`KHl}\",[]]0000000000000000000000000000000000000000000000000000000000000000000Cf[\"{{{AHO`{CGbBABd}}{A@b{BFBn}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{BFC`}}}{{AHO`{CGbBABh}}}}\",[]]A`[\"{BHE`IGf}\",[]]A`[\"{BABdA@b}\",[]]A`[\"{BABhA@b}\",[]]Aj[\"{{{AHO`{AB@h}}}ICj}\",[]]Ck[\"{{{AHO`{CGbAJ@`}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAJAl}}}}\",[]]n[\"{{}KCb}\",[]]Ak[\"{{{AHO`{AILb}}}AH@h}\",[]]Ba[\"{{{AHO`{CGbABDn}}ABDn}ICj}\",[]]Ba[\"{{{AHO`{CGbAILn}}AILn}ICj}\",[]]Ba[\"{{{AHO`{CGbBCMf}}AHEl}ICj}\",[]]Ba[\"{{{AHO`{CGbABE`}}ABE`}ICj}\",[]]Ba[\"{{{AHO`{CGbAIM`}}AIM`}ICj}\",[]]Ba[\"{{{AHO`{CGbBCMh}}AHEn}ICj}\",[]]Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bi[\"{{{AHO`{CGb}}}{{AHO`{CGbc}}}{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bg[\"{{{AHO`{AIOd}}}{{KGd{CNbB@Ld}}}}\",[]]Bg[\"{{{AHO`{AIOf}}}{{KGd{CNbB@Ll}}}}\",[]]Bc[\"{{AHO`{AHO`{CGbc}}}ICj{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cc[\"{{{AHO`{CGbAILd}}NK`KG`KIb}{{KGd{ICjBBLf}}}}\",[]]A`[\"{AHAlDC`}\",[]]B`[\"{{AHO`{AHO`{c}}}DC`{}}\",[\"K\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Aa[\"{BCLhBFKn}\",[]]A`[\"{BEFfKI`}\",[]]Aa[\"{BCLlBFL`}\",[]]A`[\"{BEFjKIb}\",[]]A`[\"{BFAnKIb}\",[]]A`[\"{BCNnKIb}\",[]]o[\"{NMjKIb}\",[]]Aa[\"{BCLhAIMj}\",[]]Aa[\"{BCLlAIMl}\",[]]o[\"{KI`CNb}\",[]]o[\"{KIbCNb}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Aj[\"{{{AHO`{BAOd}}}DC`}\",[]]Bd[\"{{{AHO`{BBL`}}}{{KGf{AJ@f}}}}\",[]]Bd[\"{{{AHO`{AB@h}}}{{KGf{AJ@f}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{BCMfCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BCMhCNb}\",[]]Cc[\"{{{AHO`{BCN`}}{AHO`{AIOn}}CNb}{{A@b{AONh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bg[\"{{{AHO`{AILb}}KFn}{{KFl{AHEl}}}}\",[]]o[\"{KEdABh}\",[]]A`[\"{AHBfA@d}\",[]]Bj[\"{{{AHO`{CGbAILd}}KG`}{{KFl{AHEn}}}}\",[]]A`[\"{AHBhA@d}\",[]]Db[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]00Eg[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}{AHO`{{K@j{Oh}}}}}{{DAh{{KGd{KCbAJAl}}}}}}\",[]]Ec[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}{AHO`{{K@j{Oh}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]0Bm[\"{{{AHO`{IHl}}{AHO`{D@n}}}{{KGf{ICj}}}}\",[]]Cd[\"{{{AHO`{CGbAIOd}}KCb}{{KGd{{KFl{ICn}}AHFb}}}}\",[]]Cd[\"{{{AHO`{CGbBGB`}}KCb}{{KGd{{KFl{ID`}}AHFb}}}}\",[]]Cn[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{Oh}}}}}{{KGd{ICjBC@f}}}}\",[]]Bk[\"{{{AHO`{DA`}}AINj}{{KGd{AINjBFKd}}}}\",[]]Bn[\"{{{AHO`{CGbAINn}}NK`}{{AHO`{CGbAINn}}}}\",[]]Bn[\"{{{AHO`{CGbAIO`}}NK`}{{AHO`{CGbAIO`}}}}\",[]]A`[\"{BC@lAG`}\",[]]o[\"{IHjCNb}\",[]]o[\"{{}AJ@f}\",[]]0o[\"{{}AHO`}\",[]]Bk[\"{{ABA`{A@b{BABd}}}{{KGd{AIKnBCLn}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bh[\"{{{AHO`{AHAl}}AJ@f}{{KGh{AHFl}}}}\",[]]A`[\"{AHElCMn}\",[]]Aj[\"{{{AHO`{AILd}}}CMn}\",[]]A`[\"{AHEnCMn}\",[]]Ce[\"{{{AHO`{CGbAINn}}{KFl{KHl}}}{{AHO`{CGbAINn}}}}\",[]]Ce[\"{{{AHO`{CGbAIO`}}{KFl{KHl}}}{{AHO`{CGbAIO`}}}}\",[]]Aa[\"{ABDhAJ@f}\",[]]Aa[\"{ABDjAJ@f}\",[]]Aa[\"{ABDlAJ@f}\",[]]Aa[\"{AJ@fAHCb}\",[]]Aa[\"{AJ@fAHCd}\",[]]o[\"{AAjCMn}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CMn}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CMn}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlCMn}\",[]]Bo[\"{{{AHO`{CGbBCOl}}AB@d}{{AHO`{CGbBCOl}}}}\",[]]Bo[\"{{{AHO`{CGbBCOn}}AB@d}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]k[\"{{}}\",[]]0000000000Bh[\"{ABA`c{}}\",[\"IntoFuture::IntoFuture\"]]11Aj[\"{{{AHO`{BAOd}}}DC`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]o[\"{AAjKCb}\",[]]Ao[\"{{AHO`c}{{NKf{c}}}{}}\",[\"S\"]]0C`[\"{{{AHO`{CGbAILf}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bo[\"{{{AHO`{CGbCNj}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]C`[\"{{{AHO`{CGbAILh}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bo[\"{{{AHO`{CGbCNl}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bk[\"{{{AHO`{CGbIHl}}NK`{AHO`{BCN`}}}ICj}\",[]]A`[\"{BFBjKFl}\",[]]A`[\"{BFBlKFl}\",[]]Bn[\"{{{AHO`{KI`}}{AHO`{KI`}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KFn}}{AHO`{KFn}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AOL`}}{AHO`{AOL`}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{B@Mf}}{AHO`{B@Mf}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{DAl}}{AHO`{DAl}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{A@j}}{AHO`{A@j}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{ABCd}}{AHO`{ABCd}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KIb}}{AHO`{KIb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BFDf}}{AHO`{BFDf}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KG`}}{AHO`{KG`}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AHFd}}{AHO`{AHFd}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BBBl}}{AHO`{BBBl}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AJAn}}{AHO`{AJAn}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AOLb}}{AHO`{AOLb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BEGb}}{AHO`{BEGb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BFCl}}{AHO`{BFCl}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{B@Mh}}{AHO`{B@Mh}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{DAn}}{AHO`{DAn}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{A@l}}{AHO`{A@l}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{ABCf}}{AHO`{ABCf}}}{{KFl{ABBj}}}}\",[]]Ak[\"{{{AHO`{AILb}}}AINh}\",[]]Bk[\"{{{AHO`{AILd}}KG`}{{KGd{AINlAIKj}}}}\",[]]Cc[\"{{{AHO`{CGbAIOd}}KCb}{{KGd{{ABh{Oh}}BC@h}}}}\",[]]Bb[\"{{{AHO`{CGbAILd}}ABCf}AIOf}\",[]]Aj[\"{{{AHO`{AHCl}}}KCb}\",[]]Aj[\"{{{AHO`{AHCn}}}KCb}\",[]]Bb[\"{{{AHO`{CGbAILd}}ABCf}AJ@b}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CNb}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CNb}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]]Cf[\"{{{AHO`{CGbBABd}}{A@b{AJ@n}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{AJA`}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kh}}{A@b{AJAf}}}{{AHO`{CGbB@Kh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kl}}{A@b{AJAh}}}{{AHO`{CGbB@Kl}}}}\",[]]o[\"{AAjCNb}\",[]]Bn[\"{{{AHO`{CGbBFIf}}CMn}{{AHO`{CGbBFIf}}}}\",[]]Bn[\"{{{AHO`{CGbBFIh}}CMn}{{AHO`{CGbBFIh}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BGJ`}\",[]]Aj[\"{{{AHO`{DA`}}}BCAf}\",[]]Aj[\"{{{A@b{BABf}}}BABd}\",[]]Aj[\"{{{A@b{BABj}}}BABh}\",[]]Aj[\"{{BCNjc}BCNjABCn}\",[\"\"]]Aj[\"{{BCNlc}BCNlABCn}\",[\"\"]]Bm[\"{{{AHO`{CGbAJ@`}}ICn}{{KGd{ICjAJAl}}}}\",[]]n[\"{{}KFb}\",[]]o[\"{NIlNIl}\",[]]0000Bd[\"{{{AHO`{BGOj}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BGOl}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BIAb}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BIAl}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{AILb}}}{{KFl{BCLn}}}}\",[]]Ck[\"{{{AHO`{AB@h}}B@KhAJ@f{AHO`{CMl}}}{{KGd{AIKnB@M`}}}}\",[]]Ak[\"{{{AHO`{BAAl}}}AB@d}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]An[\"{{AIObDC`}{{KGh{KCb}}}}\",[]]Cl[\"{{{AHO`{NMf}}}{{KFl{{KC`{{A@d{AHCl}}{A@d{AHDj}}}}}}}}\",[]]Cm[\"{{{AHO`{AJAb}}}{{KFl{{KC`{{A@d{AHCl}}{A@d{AHDj}}}}}}}}\",[]]Cl[\"{{{AHO`{NMh}}}{{KFl{{KC`{{A@d{AHCn}}{A@d{AHDl}}}}}}}}\",[]]Cm[\"{{{AHO`{AJAd}}}{{KFl{{KC`{{A@d{AHCn}}{A@d{AHDl}}}}}}}}\",[]]A`[\"{BGGnABh}\",[]]A`[\"{BIEbABh}\",[]]A`[\"{BGH`ABh}\",[]]A`[\"{BIEdABh}\",[]]An[\"{{{AHO`{CGbBGOj}}}B@Mf}\",[]]An[\"{{{AHO`{CGbBGOl}}}B@Mh}\",[]]An[\"{{{AHO`{CGbBIAb}}}B@Mh}\",[]]An[\"{{{AHO`{CGbBIAl}}}B@Mh}\",[]]Ak[\"{{{AHO`{BCAd}}}B@Oj}\",[]]Ba[\"{{{AHO`{CGbAILd}}BCMd}ICj}\",[]]Bo[\"{{{AHO`{CGbAB@j}}BEGbBAOd}{{KFl{BCMd}}}}\",[]]B`[\"{{{AHO`{NMf}}B@MfDAl}D@d}\",[]]Bn[\"{{{AHO`{BABf}}CN`B@Mf}{{KGd{D@dBFLf}}}}\",[]]Ba[\"{{{AHO`{AJAb}}B@MfDAl}D@d}\",[]]Bn[\"{{{AHO`{BEJf}}CN`B@Mf}{{KGd{D@dBFLf}}}}\",[]]B`[\"{{{AHO`{NMh}}B@MhDAn}D@f}\",[]]Bn[\"{{{AHO`{BABj}}CN`B@Mh}{{KGd{D@fBFLl}}}}\",[]]Ba[\"{{{AHO`{AJAd}}B@MhDAn}D@f}\",[]]Bn[\"{{{AHO`{BEJh}}CN`B@Mh}{{KGd{D@fBFLl}}}}\",[]]Bn[\"{{{AHO`{BHKd}}CN`B@Md}{{KGd{D@fBFLl}}}}\",[]]Aj[\"{{}{{NM`{c}}}{}}\",[\"T\"]]0A`[\"{AHElCNb}\",[]]A`[\"{BCMfCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BCMhCNb}\",[]]Bn[\"{{{AHO`{CGbBABd}}KCb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}KCb}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{BBL`}}}DC`}\",[]]0Aj[\"{{{AHO`{BCAd}}}DC`}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AHCbAIKd}}}}\",[]]Bk[\"{{{AHO`{AILd}}KG`}{{KGd{AHCdAIKj}}}}\",[]]Cc[\"{{{AHO`{BCN`}}{AHO`{AIOb}}CNb}{{A@b{AONh}}}}\",[]]Ak[\"{{{AHO`{ABA`}}}B@Mf}\",[]]Ak[\"{{{AHO`{ABAb}}}B@Mh}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bf[\"{{{AHO`{CGbAILd}}}{{KFl{NK`}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{A@b{AOLn}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{A@b{AOM`}}}{{AHO`{CGbBCOn}}}}\",[]]43A`[\"{AAjAOMf}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABDlKFl}\",[]]A`[\"{BFBjKFl}\",[]]A`[\"{BFBlKFl}\",[]]Ai[\"{{{AHO`{NNf}}}KCb}\",[]]Bo[\"{{{AHO`{CGbBIAb}}AB@d}{{AHO`{CGbBIAb}}}}\",[]]Bo[\"{{{AHO`{CGbBIAl}}AB@d}{{AHO`{CGbBIAl}}}}\",[]]Bj[\"{{{AHO`{AJ@`}}CEl}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAJ@b}}CEl}{{KGd{ICjB@Ll}}}}\",[]]?>A`[\"{IHjAONf}\",[]]A`[\"{AOJ`IHj}\",[]]Bj[\"{{{A@b{B@Kd}}IHn}{{KGd{BEJbBGHn}}}}\",[]]Bj[\"{{{A@b{BAB`}}IHn}{{KGd{BEJfBGHn}}}}\",[]]Bj[\"{{{A@b{B@Kd}}IHn}{{KGd{BEJdBGI`}}}}\",[]]Bj[\"{{{A@b{BAB`}}IHn}{{KGd{BEJhBGI`}}}}\",[]]Dj[\"{{{AHO`{CGbAJ@b}}{AHO`{CGb{AHO`{CGb{K@j{ICn}}}}}}}{{KGd{KCbAJAn}}}}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{AHAlDC`}\",[]]Cd[\"{{{AHO`{CGbBBMh}}{A@b{A`}}}{{AHO`{CGbBBMh}}}}\",[]]Cd[\"{{{AHO`{CGbBBMj}}{A@b{A`}}}{{AHO`{CGbBBMj}}}}\",[]]Bk[\"{{{AHO`{BBL`}}}{{ABb{{A@d{AHFj}}}}}}\",[]]o[\"{AAjCNb}\",[]]Aa[\"{AONfAHD`}\",[]]76Aa[\"{AIOjABA`}\",[]]Aa[\"{AIOlABAb}\",[]]Cf[\"{{{AHO`{CGbBFGh}}{KFl{AB@d}}}{{AHO`{CGbBFGh}}}}\",[]]Cf[\"{{{AHO`{CGbBFGj}}{KFl{AB@d}}}{{AHO`{CGbBFGj}}}}\",[]]9;:An[\"{{{AHO`{AONh}}AB@d}ICj}\",[]]B`[\"{{{AHO`{CGbAILf}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbCNj}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbIDh}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbNKl}}CMn}ICj}\",[]]B`[\"{{{AHO`{CGbAILh}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbCNl}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbIDj}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbNKn}}CMn}ICj}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Bj[\"{{{AHO`{AILb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMf}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMh}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAd}}}{{KFl{{A@d{A@`}}}}}}\",[]]Db[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]Db[\"{{{AHO`{CGbAILd}}NK`B@Oj{AHO`{CGb{ABh{Oh}}}}}{{KFl{ABDj}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{AHO`{CMl}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{AHO`{CMl}}}{{AHO`{CGbBCOn}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BAA`}\",[]]Bj[\"{{{AHO`{AILb}}ICn}{{KGd{ICjBFDd}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Ai[\"{{{AHO`{NJj}}}KCb}\",[]]Ai[\"{{{AHO`{NJl}}}KCb}\",[]]Dh[\"{{{AHO`{B@Kj}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMf}}B@M`}}}}\",[]]Cb[\"{{{AHO`{BABf}}CN`{AHO`{BGAn}}}{{A@d{NMf}}}}\",[]]Dh[\"{{{AHO`{BEJb}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMf}}B@M`}}}}\",[]]Cb[\"{{{AHO`{BEJf}}CN`{AHO`{BGAn}}}{{A@d{NMf}}}}\",[]]Dh[\"{{{AHO`{B@Kn}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMh}}B@Mb}}}}\",[]]Cb[\"{{{AHO`{BABj}}CN`{AHO`{BGAn}}}{{A@d{NMh}}}}\",[]]Dh[\"{{{AHO`{BEJd}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMh}}B@Mb}}}}\",[]]Cb[\"{{{AHO`{BEJh}}CN`{AHO`{BGAn}}}{{A@d{NMh}}}}\",[]]Dh[\"{{{AHO`{BHKb}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMh}}B@Ln}}}}\",[]]Cb[\"{{{AHO`{BHKd}}CN`{AHO`{BGAn}}}{{A@d{NMh}}}}\",[]]Dd[\"{{{ABb{{AHO`{CGbc}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{KGd}}}}}{}}\",[\"S\"]]0Bn[\"{{AJ@fBBLbAAj}{{KGh{{KC`{AB@fAIL`}}}}}}\",[]]Bd[\"{{{AHO`{AILd}}}{{AHO`{NMh}}}}\",[]]A`[\"{AOJ`IHj}\",[]]Cb[\"{{{AHO`{AOLn}}DAlAJ@fB@MfNK`}{{KFl{AINn}}}}\",[]]Cb[\"{{{AHO`{BCNj}}DAlAJ@fB@MfNK`}{{KFl{AINn}}}}\",[]]Cb[\"{{{AHO`{AOM`}}DAnAJ@fB@MhNK`}{{KFl{AIO`}}}}\",[]]Cb[\"{{{AHO`{BCNl}}DAnAJ@fB@MhNK`}{{KFl{AIO`}}}}\",[]]B`[\"{{{AHO`{CGbAILd}}NK`}ICj}\",[]]Ca[\"{{{AHO`{CGbAIKn}}}{{KGd{{A@d{A@`}}BCLn}}}}\",[]]Bj[\"{{{AHO`{AILb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMf}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMh}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAd}}}{{KFl{{A@d{A@`}}}}}}\",[]]o[\"{AILnOh}\",[]]o[\"{AIM`Oh}\",[]]Ai[\"{{{AHO`{CMl}}}DC`}\",[]]Aj[\"{{{AHO`{AILf}}}CNb}\",[]]Ai[\"{{{AHO`{CNj}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAIJl}}CNb}{{AHO`{CGbAIJl}}}}\",[]]Ai[\"{{{AHO`{IDh}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAOJn}}CNb}{{AHO`{CGbAOJn}}}}\",[]]Ai[\"{{{AHO`{NKl}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAl}}CNb}{{AHO`{CGbBBAl}}}}\",[]]Aj[\"{{{AHO`{AILh}}}CNb}\",[]]Ai[\"{{{AHO`{CNl}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAIJn}}CNb}{{AHO`{CGbAIJn}}}}\",[]]Ai[\"{{{AHO`{IDj}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAOK`}}CNb}{{AHO`{CGbAOK`}}}}\",[]]Ai[\"{{{AHO`{NKn}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAn}}CNb}{{AHO`{CGbBBAn}}}}\",[]]Aa[\"{AIOdBGB`}\",[]]Ai[\"{{{AHO`{NMf}}}DC`}\",[]]Aj[\"{{{AHO`{AJAb}}}DC`}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Ai[\"{{{AHO`{NMh}}}DC`}\",[]]Aj[\"{{{AHO`{AJAd}}}DC`}\",[]]Co[\"{{{AHO`{NMf}}B@Mf{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]D`[\"{{{AHO`{AJAb}}B@Mf{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]Co[\"{{{AHO`{NMh}}B@Mh{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]D`[\"{{{AHO`{AJAd}}B@Mh{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]Bn[\"{{{AHO`{CGbBFIf}}CMn}{{AHO`{CGbBFIf}}}}\",[]]Bn[\"{{{AHO`{CGbBFIh}}CMn}{{AHO`{CGbBFIh}}}}\",[]]Cd[\"{{{AHO`{CGbNMf}}}{{KFl{{NKb{{A@d{AHDj}}}}}}}}\",[]]Ce[\"{{{AHO`{CGbAJAb}}}{{KFl{{NKb{{A@d{AHDj}}}}}}}}\",[]]Cd[\"{{{AHO`{CGbNMh}}}{{KFl{{NKd{{A@d{AHDl}}}}}}}}\",[]]Ce[\"{{{AHO`{CGbAJAd}}}{{KFl{{NKd{{A@d{AHDl}}}}}}}}\",[]]Bf[\"{{{AHO`{CGbAILf}}CMnCNbNK`}ICj}\",[]]Be[\"{{{AHO`{CGbCNj}}CMnCNbNK`}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}CMnCNbNK`}ICj}\",[]]Be[\"{{{AHO`{CGbCNl}}CMnCNbNK`}ICj}\",[]]Bf[\"{{{AHO`{CGbAILf}}NK`CMnCNb}ICj}\",[]]Be[\"{{{AHO`{CGbCNj}}NK`CMnCNb}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}NK`CMnCNb}ICj}\",[]]Be[\"{{{AHO`{CGbCNl}}NK`CMnCNb}ICj}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]De[\"{{{AHO`{CGbBCOl}}c{AHO`{CMl}}}{{AHO`{CGbBCOl}}}{{ICl{D@n}}}}\",[\"\"]]De[\"{{{AHO`{CGbBCOn}}c{AHO`{CMl}}}{{AHO`{CGbBCOn}}}{{ICl{D@n}}}}\",[\"\"]]Ci[\"{{{AHO`{CGbNMf}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`IEl}}}}\",[]]Cj[\"{{{AHO`{CGbAJAb}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`IEl}}}}\",[]]Cj[\"{{{AHO`{CGbNMh}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`BCAb}}}}\",[]]Ck[\"{{{AHO`{CGbAJAd}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`BCAb}}}}\",[]]o[\"{AAjDC`}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KI`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KIb}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]Ca[\"{{{AHO`{CGbAIOd}}}{{KGd{{KFl{KI`}}AIOh}}}}\",[]]Ca[\"{{{AHO`{CGbBGB`}}}{{KGd{{KFl{KI`}}AIOh}}}}\",[]]Ca[\"{{{AHO`{CGbAIOf}}}{{KGd{{KFl{KIb}}B@Ll}}}}\",[]]Ak[\"{{{AHO`{AIKn}}}AJ@f}\",[]]Ak[\"{{{AHO`{ABA`}}}AJ@f}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AJ@fAIKd}}}}\",[]]Ak[\"{{{AHO`{ABAb}}}AJ@f}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]B`[\"{{KI`c}KI`{{D@b{KI`}}}}\",[\"\"]]B`[\"{{KFnc}KFn{{D@b{KFn}}}}\",[\"\"]]B`[\"{{KIbc}KIb{{D@b{KIb}}}}\",[\"\"]]B`[\"{{KG`c}KG`{{D@b{KG`}}}}\",[\"\"]]20Ae[\"{{AB@dCNb}AG`}\",[]]Bn[\"{{{AHO`{CGbBCOl}}AFn}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}AFn}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{IHjAB@d}\",[]]B`[\"{{}{{AHO`{{K@j{BG@n}}}}}}\",[]]An[\"{{AHO`{ONf{CGbOh}}}ICj}\",[]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000An[\"{{}{{KFl{{A@b{NMd}}}}}}\",[]]Bn[\"{{{AHO`{CGbBBMh}}DC`}{{AHO`{CGbBBMh}}}}\",[]]Bn[\"{{{AHO`{CGbBBMj}}DC`}{{AHO`{CGbBBMj}}}}\",[]]Aj[\"{{{AHO`{AHDj}}}CNb}\",[]]Aj[\"{{{AHO`{AHDl}}}CNb}\",[]]A`[\"{ABC`KFl}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Bf[\"{{{AHO`{CMl}}}{{KGh{CNbBBB`}}}}\",[]]Bn[\"{{{AHO`{AB@h}}{A@d{BBL`}}}{{KGf{ICj}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Cj[\"{{{AHO`{NMb}}BBLbBBBj{AHO`{AAj}}}{{KC`{AJ@fAB@f}}}}\",[]]Cb[\"{{{AHO`{CGbAILd}}KG`AINl}{{KGd{AINlBFKf}}}}\",[]]Am[\"{{{AHO`{AILb}}CNb}ICj}\",[]]B`[\"{{{AHO`{CGbAILd}}CNb}ICj}\",[]]A`[\"{BC@jDC`}\",[]]B`[\"{{{AHO`{CGbIHj}}BC@l}ICj}\",[]]Aa[\"{AONfAHD`}\",[]]Bn[\"{{{AHO`{NMd}}AHFl}{{KGf{{A@d{BBL`}}}}}}\",[]]Bo[\"{{{AHO`{BACb}}AHFl}{{KGf{{A@d{BBL`}}}}}}\",[]]Bo[\"{{{AHO`{AOMl}}AHFl}{{KGf{{A@d{BBL`}}}}}}\",[]]Ci[\"{{{AHO`{CGbNMf}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@d}}}}\",[]]Cj[\"{{{AHO`{CGbAJAb}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@d}}}}\",[]]Ci[\"{{{AHO`{CGbNMh}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@f}}}}\",[]]Cj[\"{{{AHO`{CGbAJAd}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@f}}}}\",[]]Cb[\"{{{AHO`{ABD`}}IChAJ@lAB@d}{{KGd{ICjBCOf}}}}\",[]]Cb[\"{{{AHO`{BANd}}IChAJ@lAB@d}{{KGd{ICjBCOf}}}}\",[]]Cb[\"{{{AHO`{B@Ol}}IChAJ@lAB@d}{{KGd{ICjBCOf}}}}\",[]]Cb[\"{{{AHO`{ABDb}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Cb[\"{{{AHO`{BANf}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Cb[\"{{{AHO`{B@On}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Al[\"{{}{{KGd{B@KfBGI`}}}}\",[]]Bn[\"{{{AHO`{AILb}}KFn}{{KFl{{A@d{AILf}}}}}}\",[]]Bo[\"{{{AHO`{AILd}}KG`}{{KFl{{AHO`{AILh}}}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aj[\"{{{AHO`{AILb}}}ICj}\",[]]Am[\"{{{AHO`{CGbAILd}}}ICj}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAjIEn}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{A@hIEn}}}}\",[]]Bg[\"{{{AHO`{AIJb}}}{{KGd{AAOfIEn}}}}\",[]]Bg[\"{{{AHO`{AIJb}}}{{KGd{AHAlIEn}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAlIEn}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAnIEn}}}}\",[]]Ak[\"{{{AHO`{BCAd}}}B@Oj}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{AOL`}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AOLb}}}{{AHO`{CGbBCOn}}}}\",[]]<;Aj[\"{{{AHO`{AB@h}}}KCb}\",[]]Aj[\"{{{AHO`{AB@j}}}KCb}\",[]]Bo[\"{{{AHO`{AILb}}cAINj}ABBh{{D@b{AHCb}}}}\",[\"\"]]Co[\"{{{AHO`{CGbAILd}}AHCdAINlNK`}{{KGd{{KC`{KG`DC`}}AHEb}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CN`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CN`}{{AHO`{CGbBCOn}}}}\",[]]Df[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{ICn}}}}}{{KGd{{KFl{KCb}}AHFb}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Bg[\"{{{AHO`{BCAd}}AJAj}{{KGf{KCb}}}}\",[]]A`[\"{AHAlCNb}\",[]]10Aj[\"{{{AHO`{AAj}}}BCOj}\",[]]Cf[\"{{{AHO`{CGbBABd}}{A@b{BCOl}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kh}}{A@b{BCOl}}}{{AHO`{CGbB@Kh}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{BCOn}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kl}}{A@b{BCOn}}}{{AHO`{CGbB@Kl}}}}\",[]]Aa[\"{BABdBH@l}\",[]]Aa[\"{BABhBH@n}\",[]]Bj[\"{{{ABh{BBLb}}BBBj}{{KGd{BABdIFb}}}}\",[]]Bj[\"{{{ABh{BBLb}}BBBj}{{KGd{BABhIFd}}}}\",[]]Co[\"{{{AHO`{CGbAJ@`}}{AHO`{CGb{K@j{ICn}}}}}{{KGd{ICjAJAl}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BFBjCNb}\",[]]A`[\"{BFBlCNb}\",[]]Bc[\"{{{AHO`{AILb}}}{{KFl{KCb}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Aj[\"{{{AHO`{AHBb}}}KCb}\",[]]Be[\"{{{AHO`{AB@h}}{KFl{BABd}}}ICj}\",[]]Bo[\"{{{AHO`{CGbAB@j}}{KFl{{A@b{BABh}}}}}ICj}\",[]]Bd[\"{{{AHO`{BG@n}}}{{KFl{BBBh}}}}\",[]]Aj[\"{{{AHO`{AB@h}}}ICj}\",[]]Dj[\"{{{AHO`{CGbAJ@`}}{AHO`{CGb{AHO`{CGb{K@j{ICn}}}}}}}{{KGd{KCbAJAl}}}}\",[]]o[\"{{}AHO`}\",[]]n[\"{{}NIl}\",[]]0000Bn[\"{{{AHO`{CGbBCOl}}KCb}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KCb}{{AHO`{CGbBCOn}}}}\",[]]o[\"{CNbKI`}\",[]]o[\"{CNbKIb}\",[]]A`[\"{BAOfCNb}\",[]]Bf[\"{{{AHO`{BGJ`}}{AHO`{BGJ`}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBBMh}}AB@d}{{AHO`{CGbBBMh}}}}\",[]]Bo[\"{{{AHO`{CGbBBMj}}AB@d}{{AHO`{CGbBBMj}}}}\",[]]Ae[\"{{KCbCNb}BANd}\",[]]Ae[\"{{KCbCNb}BANf}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]7Bg[\"{{{AHO`{AILd}}KG`}{{KFl{AINl}}}}\",[]]An[\"{{{AHO`{AILb}}ICn}BAAn}\",[]]Bm[\"{{{AHO`{CGbBEJb}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJf}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJd}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJh}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Am[\"{{{AHO`{AILb}}KI`}ICj}\",[]]B`[\"{{{AHO`{CGbAILd}}KIb}ICj}\",[]]Ce[\"{{{AHO`{CGbBBMh}}{ABh{CN`}}}{{AHO`{CGbBBMh}}}}\",[]]Ce[\"{{{AHO`{CGbBBMj}}{ABh{CN`}}}{{AHO`{CGbBBMj}}}}\",[]]Fg[\"{{{AHO`{BHEb}}{AHO`{BBLb}}{AHO`{{K@j{BBLb}}}}{AHO`{AJ@d}}{AHO`{{K@j{Oh}}}}ABEb}{{KGd{BFK`IEh}}}}\",[]]Af[\"{{BCNjNK`}BCNj}\",[]]Af[\"{{BCNlNK`}BCNl}\",[]]A`[\"{BAOfCNb}\",[]]Al[\"{BACd{{KGd{DAlIF`}}}}\",[]]Al[\"{BACd{{KGd{A@jIF`}}}}\",[]]Ai[\"{BACd{{KGj{DAn}}}}\",[]]Ai[\"{BACd{{KGj{A@l}}}}\",[]]o[\"{NIlNIl}\",[]]Bo[\"{{{AHO`{CGbBFIf}}AB@d}{{AHO`{CGbBFIf}}}}\",[]]Bo[\"{{{AHO`{CGbBFIh}}AB@d}{{AHO`{CGbBFIh}}}}\",[]]Bb[\"{{{AHO`{NMf}}}{{KFl{DC`}}}}\",[]]Bc[\"{{{AHO`{AJAb}}}{{KFl{DC`}}}}\",[]]Bb[\"{{{AHO`{NMh}}}{{KFl{DC`}}}}\",[]]Bc[\"{{{AHO`{AJAd}}}{{KFl{DC`}}}}\",[]]Bg[\"{{{AHO`{AILb}}}{{KGd{ICjBCLn}}}}\",[]]Ba[\"{{{AHO`{BFCf}}KFnAHCb}DC`}\",[]]Ba[\"{{{AHO`{BFCh}}KG`AHCd}DC`}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{AB@d}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AB@d}}}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Bo[\"{{{AHO`{CGbAILf}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbCNj}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbIDh}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbNKl}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bo[\"{{{AHO`{CGbAILh}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbCNl}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbIDj}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbNKn}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]A`[\"{BAOfCNb}\",[]]Al[\"{{{AHO`{NNf}}A@l}CNb}\",[]]Bi[\"{{{AHO`{CGbAIOn}}CNb}{{KGh{ICj}}}}\",[]]<;A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Cf[\"{{{AHO`{CGbBCOl}}{KFl{BFGh}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{BFGj}}}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAjIEn}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{A@hIEn}}}}\",[]]Bj[\"{{{AHO`{CGbAIJb}}}{{KGd{AAOfIEn}}}}\",[]]Bj[\"{{{AHO`{CGbAIJb}}}{{KGd{AHAlIEn}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAlIEn}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAnIEn}}}}\",[]]Cd[\"{{{A@b{AIL`}}CNbDC`}{{KGh{{KC`{BC@lBC@l}}}}}}\",[]]Bn[\"{{{AHO`{CGbBABd}}CNb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}CNb}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{AILb}}}DC`}\",[]]Ak[\"{{{AHO`{BBL`}}}B@Oj}\",[]]0Ci[\"{{{AHO`{CGbBBMh}}CMn}{{KGd{{AHO`{CGbBBMh}}AOJd}}}}\",[]]Ci[\"{{{AHO`{CGbBBMj}}CMn}{{KGd{{AHO`{CGbBBMj}}AOJf}}}}\",[]]A`[\"{AHAlCMn}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{BFIf}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{BFIh}}}{{AHO`{CGbBCOn}}}}\",[]]Bg[\"{{{AHO`{CGbAILd}}}{{KFl{BAOd}}}}\",[]]Cf[\"{{{AHO`{CGbBABd}}{KFl{BABl}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{KFl{BABl}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbBABd}}{KFl{BABn}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{KFl{BABn}}}{{AHO`{CGbBABh}}}}\",[]]Cd[\"{{}{{KGd{{KC`{{ABh{BBLb}}BBBj}}{A@d{IEd}}}}}}\",[]]Bn[\"{{{AHO`{CGbBFGh}}KI`}{{AHO`{CGbBFGh}}}}\",[]]Bn[\"{{{AHO`{CGbBFGj}}KIb}{{AHO`{CGbBFGj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bo[\"{{{AHO`{CGbBABd}}AB@d}{{AHO`{CGbBABd}}}}\",[]]Bo[\"{{{AHO`{CGbBABh}}AB@d}{{AHO`{CGbBABh}}}}\",[]]Ci[\"{{{AHO`{DA`}}{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKd}}}}\",[]]Bj[\"{{{AHO`{BCAd}}AJAjKCb}{{KGf{ICj}}}}\",[]]054Bm[\"{{{AHO`{NMf}}}{{KGd{{KFl{BGAn}}IEl}}}}\",[]]Bn[\"{{{AHO`{AJAb}}}{{KGd{{KFl{BGAn}}IEl}}}}\",[]]Bn[\"{{{AHO`{NMh}}}{{KGd{{KFl{BGAn}}BCAb}}}}\",[]]Bo[\"{{{AHO`{AJAd}}}{{KGd{{KFl{BGAn}}BCAb}}}}\",[]]Aj[\"{{{AHO`{AHDj}}}CNb}\",[]]Aj[\"{{{AHO`{AHDl}}}CNb}\",[]]Bl[\"{{{AHO`{AB@h}}{KFl{{A@b{BFCf}}}}}ICj}\",[]]Cc[\"{{{AHO`{CGbAILd}}{KFl{{AHO`{BFCh}}}}NK`}ICj}\",[]]Aj[\"{{{AHO`{AB@j}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAl}}AFn}{{AHO`{CGbBBAl}}}}\",[]]Bn[\"{{{AHO`{CGbBBAn}}AFn}{{AHO`{CGbBBAn}}}}\",[]]Ak[\"{{{AHO`{AHFj}}}B@Oj}\",[]]0Ak[\"{{{AHO`{AILb}}}BGA`}\",[]]Cb[\"{{{AHO`{AILd}}KG`}{{KGd{{KFl{AJ@f}}AIKj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KI`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KIb}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]Bo[\"{{{AHO`{AHAl}}{AHO`{CMl}}}{{KGf{BCOj}}}}\",[]]Em[\"{{{AHO`{AILb}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHLn}}}}\",[]]El[\"{{{AHO`{NMf}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHLn}}}}\",[]]Em[\"{{{AHO`{AJAb}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHLn}}}}\",[]]El[\"{{{AHO`{NMh}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHM`}}}}\",[]]Em[\"{{{AHO`{AJAd}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHM`}}}}\",[]]Am[\"{{{AHO`{CGbAHB`}}}ICj}\",[]]0Am[\"{{{AHO`{AILd}}A@l}CNb}\",[]]Ak[\"{{{AHO`{AILb}}}BGIb}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{BEFbAIKd}}}}\",[]]>=E`[\"{{{AHO`{BHEb}}{AHO`{{K@j{Oh}}}}{AHO`{BBLb}}{AHO`{BGOn}}}{{KGd{BHGhIEh}}}}\",[]]0Bg[\"{{{A@b{BBCb}}}{{KGd{B@KhBGIn}}}}\",[]]Bg[\"{{{A@b{BBCb}}}{{KGd{B@KlBGIn}}}}\",[]]Bn[\"{{{AHO`{CGbBFGh}}KI`}{{AHO`{CGbBFGh}}}}\",[]]Bn[\"{{{AHO`{CGbBFGj}}KIb}{{AHO`{CGbBFGj}}}}\",[]]o[\"{NIlNIl}\",[]]0000Aj[\"{{{AHO`{AILd}}}DC`}\",[]]0Bd[\"{{{AHO`{CGbAILf}}CNbAB@d}ICj}\",[]]Bc[\"{{{AHO`{CGbCNj}}CNbAB@d}ICj}\",[]]Bd[\"{{{AHO`{CGbAILh}}CNbAB@d}ICj}\",[]]Bc[\"{{{AHO`{CGbCNl}}CNbAB@d}ICj}\",[]]Ci[\"{{{AHO`{DA`}}{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKd}}}}\",[]]Cd[\"{{{AHO`{CGbAAj}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Cd[\"{{{AHO`{CGbA@h}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Ce[\"{{{AHO`{CGbAAOf}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Ce[\"{{{AHO`{CGbAHAl}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Cd[\"{{{AHO`{CGbAAl}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Cd[\"{{{AHO`{CGbAAn}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Bo[\"{{{AHO`{CGbBABd}}BH@l}{{AHO`{CGbBABd}}}}\",[]]Bo[\"{{{AHO`{CGbBABh}}BH@n}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{BBMh}}}CNb}\",[]]Aj[\"{{{AHO`{BBMj}}}CNb}\",[]]Cd[\"{{{AHO`{CGbB@Kh}}{A@b{A`}}}{{AHO`{CGbB@Kh}}}}\",[]]Cd[\"{{{AHO`{CGbB@Kl}}{A@b{A`}}}{{AHO`{CGbB@Kl}}}}\",[]]Cl[\"{{BBMh{KFl{BABd}}{A@d{BBL`}}{A@b{NMd}}}{{KGf{AB@h}}}}\",[]]Aj[\"{{{AHO`{ABA`}}}DC`}\",[]]Aj[\"{{{AHO`{ABAb}}}DC`}\",[]]Ca[\"{{{AHO`{CGbAILd}}NK`AIMn}{{KGd{ICjBHDj}}}}\",[]]Bd[\"{{{AHO`{BHEb}}}{{ABh{BCOb}}}}\",[]]Bj[\"{{{AHO`{AILb}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bm[\"{{{AHO`{CGbAILd}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KCb}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KCb}{{AHO`{CGbBCOn}}}}\",[]]Bm[\"{{}{{KGd{{KC`{BBLbBFJb}}{A@d{IEd}}}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]An[\"{{{AHO`{AB@h}}B@Kh}ICj}\",[]]Dc[\"{{{AHO`{CGbAILd}}NK`KG`{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKj}}}}\",[]]o[\"{{}AHO`}\",[]]Aj[\"{{{AHO`{AILb}}}KCb}\",[]]Bn[\"{{{AHO`{CGbBABd}}CNb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}CNb}{{AHO`{CGbBABh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KI`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KIb}{{AHO`{CGbBCOn}}}}\",[]]:Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bc[\"{{{AHO`{CGbAILd}}A@lKIb}ICj}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Ak[\"{{}{{KGd{B@KhIFb}}}}\",[]]Ak[\"{{}{{KGd{B@KlIFd}}}}\",[]]6587Cg[\"{{{AHO`{CGbAAj}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Cg[\"{{{AHO`{CGbA@h}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Ch[\"{{{AHO`{CGbAAOf}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Ch[\"{{{AHO`{CGbAHAl}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Cg[\"{{{AHO`{CGbAAl}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Cg[\"{{{AHO`{CGbAAn}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]n[\"{{}ICj}\",[]]Ce[\"{{{AHO`{CGbBCOl}}{KFl{KCb}}}{{AHO`{CGbBCOl}}}}\",[]]Ce[\"{{{AHO`{CGbBCOn}}{KFl{KCb}}}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{AILb}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Cd[\"{{{AHO`{CGbAILd}}NK`}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Am[\"{{{AHO`{CGbAILf}}}ICj}\",[]]Al[\"{{{AHO`{CGbCNj}}}ICj}\",[]]Al[\"{{{AHO`{CGbIDh}}}ICj}\",[]]Am[\"{{{AHO`{CGbAILh}}}ICj}\",[]]Al[\"{{{AHO`{CGbCNl}}}ICj}\",[]]Al[\"{{{AHO`{CGbIDj}}}ICj}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Bj[\"{{{AHO`{AILb}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bm[\"{{{AHO`{CGbAILd}}AJ@f}{{KGd{ICjIFh}}}}\",[]]D`[\"{{{AHO`{CGbAILd}}KG`{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKj}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{A@b{BFBf}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{A@b{BFBh}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{AB@d}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AB@d}}}{{AHO`{CGbBCOn}}}}\",[]]Ce[\"{{{AHO`{CGbBCOl}}{KFl{CNb}}}{{AHO`{CGbBCOl}}}}\",[]]Ce[\"{{{AHO`{CGbBCOn}}{KFl{CNb}}}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]];Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Am[\"{{{AHO`{AILb}}KI`}ICj}\",[]]o[\"{NIlNIl}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CN`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CN`}{{AHO`{CGbBCOn}}}}\",[]]310;:54Bn[\"{{{AHO`{AILb}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Bn[\"{{{AHO`{AILd}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]10Bm[\"{{{AHO`{CGbBCOl}}Oh}{{AHO`{CGbBCOl}}}}\",[]]Bm[\"{{{AHO`{CGbBCOn}}Oh}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{BGAnKFl}\",[]]")
\ No newline at end of file
diff --git a/pr/721/docs/search.index/path/30a74cfcf7d5.js b/pr/721/docs/search.index/path/a96c5934a8c0.js
similarity index 98%
rename from pr/721/docs/search.index/path/30a74cfcf7d5.js
rename to pr/721/docs/search.index/path/a96c5934a8c0.js
index 2fd47262f..6ef62d487 100644
--- a/pr/721/docs/search.index/path/30a74cfcf7d5.js
+++ b/pr/721/docs/search.index/path/a96c5934a8c0.js
@@ -1 +1 @@
-rd_("f[1,\"\"]0Al[10,\"core::ops\",\"core::ops\"]Ce[5,\"clap_builder::util::id\",\"clap_builder::util::id\"]22Ag[10,\"core::ops::arith\"]A`[10,\"core::any\"]Ao[5,\"alloc::sync\",\"alloc::sync\"]Ba[5,\"alloc::boxed\",\"alloc::boxed\"]Cb[10,\"bytes::buf::buf_impl\",\"bytes::buf::buf_impl\"]Ai[5,\"noq_perf\",\"noq_perf\"]i[6,\"noq\"]Ak[6,\"noq_proto\",\"noq_proto\"]Ae[10,\"core::ops::bit\"]Ac[5,\"bench\",\"bench\"]Ba[5,\"perf::client\",\"perf::client\"]Ba[5,\"perf::server\",\"perf::server\"]A`[10,\"core::cmp\"]Ak[5,\"core::pin\",\"core::pin\"]Am[5,\"alloc::vec\",\"alloc::vec\"]f[1,\"\"]00m[2,\"noq_udp\"]f[0,\"\"]f[3,\"\"]3333Ak[10,\"clap_builder::derive\"]Bn[10,\"std::os::fd::owned\",\"std::os::fd::owned\"]Ae[5,\"noq::congestion\"]Ci[5,\"noq_proto::congestion\",\"noq_proto::congestion::bbr3\"]Af[10,\"core::ops::drop\"]Ad[10,\"core::convert\"]Aa[10,\"core::hash\"]1Aa[5,\"noq::crypto\"]Bk[5,\"noq_proto::crypto\",\"noq_proto::crypto\"]Ba[15,\"noq_proto::ProtectedHeader\"]Ak[5,\"std::path\",\"std::path\"]Ae[5,\"noq\",\"noq::path\"]Bi[6,\"core::task::poll\",\"core::task::poll\"]i[6,\"noq\"]Ak[6,\"noq_proto\",\"noq_proto\"]Ak[2,\"noq_proto::congestion\"]f[1,\"\"]f[3,\"\"]i[2,\"noq\"]1Ag[2,\"noq_proto::config\"]Bd[2,\"noq_proto::connection::streams\"]0Ab[2,\"noq::runtime\"]55Bd[10,\"core::convert\",\"core::convert\"]Ba[5,\"bytes::bytes\",\"bytes::bytes\"]i[5,\"noq\"]Cb[5,\"noq_proto\",\"noq_proto::connection::assembler\"]Ab[10,\"core::clone\"]Bi[6,\"noq_proto::frame\",\"noq_proto::frame\"]Ae[5,\"noq::congestion\"]Cj[5,\"noq_proto::congestion\",\"noq_proto::congestion::cubic\"]A`[10,\"core::fmt\"]Ag[10,\"core::ops::deref\"]Ak[5,\"core::fmt\",\"core::fmt\"]Ab[10,\"core::error\"]Bc[6,\"rustls::error\",\"rustls::error\"]Ai[2,\"noq::crypto::rustls\"]Ba[8,\"clap_builder\",\"clap_builder\"]Ao[2,\"noq_proto::crypto::rustls\"]Cm[5,\"noq_proto::transport_error\",\"noq_proto::transport_error\"]Bi[6,\"arbitrary::error\",\"arbitrary::error\"]Ai[6,\"noq::crypto::rustls\"]Ao[6,\"noq_proto::crypto::rustls\"]Dg[6,\"noq_proto::transport_parameters\",\"noq_proto::transport_parameters\"]Co[6,\"noq_proto::n0_nat_traversal\",\"noq_proto::n0_nat_traversal\"]o[2,\"noq_proto\"]Bg[6,\"noq_proto\",\"noq_proto::connection\"]2Bi[5,\"core::ops::range\",\"core::ops::range\"]Ba[15,\"noq_proto::ProtectedHeader\"]0Bb[10,\"core::marker\",\"core::marker\"]Ba[5,\"bench::stats\",\"bench::stats\"]Ao[5,\"perf::stats\",\"perf::stats\"]Ba[5,\"rustls::quic\",\"rustls::quic\"]Ah[10,\"std::io\",\"std::io\"]f[1,\"\"]f[3,\"\"]Ak[2,\"noq_proto::congestion\"]l[2,\"rustls\"]Bi[5,\"bytes::bytes_mut\",\"bytes::bytes_mut\"]Ai[6,\"noq_perf\",\"noq_perf\"]Bb[5,\"noq_proto\",\"noq_proto::frame\"]Ag[10,\"core::ops::deref\"]Am[5,\"core::time\",\"core::time\"]Bc[5,\"noq::endpoint\",\"noq::endpoint\"]Ai[5,\"noq\",\"noq::endpoint\"]Be[5,\"noq_proto\",\"noq_proto::endpoint\"]Am[15,\"noq_proto::StreamEvent\"]Ai[5,\"noq\",\"noq::incoming\"]2Bc[10,\"core::iter::traits::iterator\"]An[10,\"tonic::service::layered\"]Bc[6,\"noq_proto\",\"noq_proto::packet\"]Ak[5,\"noq\",\"noq::connection\"]Ae[5,\"noq\",\"noq::path\"]Ak[6,\"core::cmp\",\"core::cmp\"]7Ag[5,\"noq_udp\",\"noq_udp\"]i[5,\"noq\"]Ak[5,\"noq_proto\",\"noq_proto\"]Ad[10,\"alloc::string\"]j[10,\"noq\"]Bc[10,\"noq_proto\",\"noq_proto::token\"]4354Bn[5,\"noq_proto\",\"noq_proto::connection::stats\"]Bi[5,\"rustls_pki_types\",\"rustls_pki_types\"]?i[2,\"noq\"]o[2,\"noq_proto\"]1Ak[2,\"noq_proto::congestion\"]f[3,\"\"]Ae[15,\"noq::PathEvent\"]Ak[15,\"noq_proto::PathEvent\"]Ak[5,\"noq\",\"noq::connection\"]Ag[10,\"core::ops::arith\"]A`[10,\"arbitrary\"]Al[10,\"tokio::io::async_read\"]Ai[10,\"futures_io::if_std\"]Am[15,\"noq_proto::StreamEvent\"]Ac[10,\"core::borrow\"]Aa[5,\"perf\",\"perf\"]Ak[5,\"criterion\",\"criterion\"]Cb[5,\"noq_proto\",\"noq_proto::connection::datagrams\"]Bl[10,\"noq_proto::coding\",\"noq_proto::coding\"]<;0Ak[5,\"core::fmt\",\"core::fmt\"]i[5,\"noq\"]Ak[5,\"noq_proto\",\"noq_proto\"]i[6,\"noq\"]Bb[6,\"noq_proto\",\"noq_proto::frame\"]Ab[10,\"noq::crypto\"]Bl[10,\"noq_proto::crypto\",\"noq_proto::crypto\"]Ba[5,\"hdrhistogram\",\"hdrhistogram\"]21A`[10,\"core::cmp\"]5Bg[6,\"noq_proto\",\"noq_proto::connection\"]i[2,\"noq\"]o[2,\"noq_proto\"]8Bn[6,\"noq_proto\",\"noq_proto::connection::paths\"];Bn[5,\"noq_proto\",\"noq_proto::connection::stats\"]Al[6,\"noq\",\"noq::recv_stream\"]Cf[6,\"noq_proto\",\"noq_proto::connection::streams::recv\"]Ak[10,\"futures_core::future\"]Ak[10,\"futures_core::stream\"]Ai[10,\"noq\",\"noq::runtime\"]Bc[5,\"std::net::udp\",\"std::net::udp\"]Ak[10,\"clap_builder::derive\"]Ak[2,\"noq_proto::connection\"]0f[3,\"\"]f[1,\"\"]Ag[2,\"noq_proto::config\"]Em[5,\"clap_builder::parser::matches::arg_matches\",\"clap_builder::parser::matches::arg_matches\"]7Am[10,\"tokio::io::async_write\"]Ai[10,\"futures_io::if_std\"]Ae[5,\"noq::congestion\"]Ci[5,\"noq_proto::congestion\",\"noq_proto::congestion::bbr3\"]i[5,\"noq\"]Bn[5,\"noq_proto\",\"noq_proto::connection::paths\"]Aa[10,\"equivalent\"]Ak[5,\"noq\",\"noq::connection\"]Bg[5,\"noq::connection\",\"noq::connection\"]1Bg[5,\"noq_proto\",\"noq_proto::connection\"]Af[10,\"noq::congestion\"]Cd[10,\"noq_proto::congestion\",\"noq_proto::congestion\"]A`[10,\"hashbrown\"]68Bn[5,\"noq_proto\",\"noq_proto::connection::stats\"]B`[10,\"core::future::into_future\"]:Bj[5,\"noq_proto\",\"noq_proto::cid_generator\"]Ag[5,\"std::io\",\"std::io\"]Bi[6,\"noq_proto::frame\",\"noq_proto::frame\"]Bb[6,\"noq_proto\",\"noq_proto::frame\"]Bm[8,\"core::num::nonzero\",\"core::num::nonzero\"]Cm[5,\"rustls::error::other_error\",\"rustls::error::other_error\"]A`[10,\"core::cmp\"]Am[5,\"noq\",\"noq::event_stream\"]i[6,\"noq\"]Bn[6,\"noq_proto\",\"noq_proto::connection::paths\"]i[5,\"noq\"]Bi[5,\"noq_proto\",\"noq_proto::config::qlog\"]Bi[5,\"noq::recv_stream\",\"noq::recv_stream\"]Al[5,\"noq\",\"noq::recv_stream\"]C`[5,\"noq_proto\",\"noq_proto::connection::streams\"]Al[6,\"noq\",\"noq::recv_stream\"]Ai[5,\"noq\",\"noq::incoming\"]Be[5,\"noq_proto\",\"noq_proto::endpoint\"]Bi[5,\"noq::send_stream\",\"noq::send_stream\"]Al[5,\"noq\",\"noq::send_stream\"]5Dc[6,\"rustls_pki_types::server_name\",\"rustls_pki_types::server_name\"]Ce[6,\"core::net::socket_addr\",\"core::net::socket_addr\"]Bb[5,\"noq_proto\",\"noq_proto::frame\"]Ak[10,\"clap_builder::derive\"]Ak[5,\"std::time\",\"std::time\"]j[10,\"noq\"]Bd[10,\"noq_proto\",\"noq_proto::config\"]Ai[5,\"noq::crypto::rustls\"]Ck[5,\"noq_proto::crypto::rustls\",\"noq_proto::crypto::rustls\"]3Bc[10,\"noq_proto\",\"noq_proto::token\"]Ag[5,\"noq_udp\",\"noq_udp\"]Al[6,\"noq\",\"noq::send_stream\"]Cf[6,\"noq_proto\",\"noq_proto::connection::streams::send\"]i[2,\"noq\"]o[2,\"noq_proto\"]10Be[5,\"noq_proto\",\"noq_proto::endpoint\"]Ac[6,\"bench\",\"bench\"]Aa[5,\"bulk\",\"bulk\"]Da[6,\"noq_proto::connection::state\",\"noq_proto::connection::state\"]i[6,\"noq\"]Bc[6,\"noq_proto\",\"noq_proto::config\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Aa[5,\"noq::crypto\"]Bk[5,\"noq_proto::crypto\",\"noq_proto::crypto\"]Ae[5,\"noq::congestion\"]Cj[5,\"noq_proto::congestion\",\"noq_proto::congestion::cubic\"]Ae[15,\"noq::PathEvent\"]Ak[15,\"noq_proto::PathEvent\"]?i[5,\"noq\"]Bn[5,\"noq_proto\",\"noq_proto::config::transport\"]Ae[10,\"tonic::request\"]j[10,\"noq\"]Bj[10,\"noq_proto\",\"noq_proto::config::qlog\"]Ac[6,\"bench\",\"bench\"]An[5,\"noq\",\"noq::runtime::smol\"]o[2,\"noq_proto\"]C`[6,\"noq_proto\",\"noq_proto::connection::streams\"]Ba[5,\"bench::stats\",\"bench::stats\"]Ao[5,\"perf::stats\",\"perf::stats\"]f[3,\"\"]i[2,\"noq\"]Ak[2,\"noq_proto::connection\"]1Co[5,\"rustls::client::client_conn\",\"rustls::client::client_conn\"]Bk[5,\"noq_proto::config\",\"noq_proto::config\"]?Ab[10,\"noq::crypto\"]Bc[5,\"noq_proto\",\"noq_proto::config\"]Bl[10,\"noq_proto::crypto\",\"noq_proto::crypto\"]i[5,\"noq\"]C`[5,\"noq_proto\",\"noq_proto::connection::streams\"]Bo[6,\"noq_proto::endpoint\",\"noq_proto::endpoint\"]i[6,\"noq\"]Be[6,\"noq_proto\",\"noq_proto::endpoint\"]Bk[5,\"noq_proto::shared\",\"noq_proto::shared\"]5Bc[5,\"noq_proto\",\"noq_proto::shared\"]Bb[5,\"noq_proto\",\"noq_proto::frame\"]4Bc[6,\"noq_proto\",\"noq_proto::shared\"]Ag[6,\"noq_udp\",\"noq_udp\"]Bb[10,\"core::iter::traits::collect\"]Bm[8,\"core::num::nonzero\",\"core::num::nonzero\"];Bb[5,\"noq_proto\",\"noq_proto::token\"]Ae[15,\"noq::PathEvent\"]Ak[15,\"noq_proto::PathEvent\"]Ak[5,\"noq\",\"noq::connection\"]21Da[5,\"noq_proto::connection::paths\",\"noq_proto::connection::paths\"]Bn[5,\"noq_proto\",\"noq_proto::connection::paths\"]2Co[5,\"rustls::server::server_conn\",\"rustls::server::server_conn\"]Bk[5,\"noq_proto::config\",\"noq_proto::config\"]i[5,\"noq\"]Ab[10,\"noq::crypto\"]Bc[5,\"noq_proto\",\"noq_proto::config\"]Bl[10,\"noq_proto::crypto\",\"noq_proto::crypto\"]Ce[5,\"core::net::socket_addr\",\"core::net::socket_addr\"]0Al[6,\"noq\",\"noq::send_stream\"]Ao[5,\"noq\",\"noq::runtime::tokio\"]Cg[5,\"arbitrary::unstructured\",\"arbitrary::unstructured\"]i[2,\"noq\"]j[2,\"perf\"]9Bl[5,\"noq_proto\",\"noq_proto::bloom_token_log\"]Ab[10,\"core::clone\"]Be[6,\"noq_proto\",\"noq_proto::endpoint\"]Bc[5,\"noq_proto\",\"noq_proto::shared\"]Ai[5,\"noq\",\"noq::endpoint\"]Ai[5,\"noq::crypto::rustls\"]Ck[5,\"noq_proto::crypto::rustls\",\"noq_proto::crypto::rustls\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Bo[5,\"noq_proto::endpoint\",\"noq_proto::endpoint\"]Be[5,\"noq_proto\",\"noq_proto::endpoint\"]Ae[5,\"noq::congestion\"]Cm[5,\"noq_proto::congestion\",\"noq_proto::congestion::new_reno\"]Bi[5,\"core::num::error\",\"core::num::error\"]Bc[5,\"noq_proto\",\"noq_proto::packet\"]Ec[5,\"clap_builder::builder::possible_value\",\"clap_builder::builder::possible_value\"]Bi[6,\"rustls_pki_types\",\"rustls_pki_types\"]Cf[6,\"noq_proto\",\"noq_proto::connection::streams::recv\"]Cg[5,\"rustls::webpki::anchors\",\"rustls::webpki::anchors\"]i[5,\"noq\"]Bc[5,\"noq_proto\",\"noq_proto::config\"]Bk[5,\"noq_proto::coding\",\"noq_proto::coding\"]o[2,\"noq_proto\"]0f[3,\"\"]Ai[10,\"noq\",\"noq::runtime\"]Bi[5,\"rustls_pki_types\",\"rustls_pki_types\"]i[6,\"noq\"]Bg[6,\"noq_proto\",\"noq_proto::connection\"]Ak[10,\"clap_builder::derive\"]Ag[15,\"noq_proto::Event\"]:91Ai[5,\"noq\",\"noq::incoming\"]Bb[5,\"noq_proto\",\"noq_proto::frame\"]Bc[6,\"rustls::error\",\"rustls::error\"]=Bb[5,\"noq_proto\",\"noq_proto::token\"]1Al[6,\"noq\",\"noq::recv_stream\"]0C`[5,\"noq_proto\",\"noq_proto::connection::streams\"]Ba[5,\"bench::stats\",\"bench::stats\"]o[5,\"noq_proto\"]Al[5,\"noq_udp\",\"noq_udp::imp\"]Ae[5,\"noq\",\"noq::path\"]i[5,\"noq\"]9>=Bc[5,\"noq_proto\",\"noq_proto::shared\"]1Bn[5,\"noq_proto\",\"noq_proto::connection::stats\"]Ba[5,\"rustls::rand\",\"rustls::rand\"]Ao[5,\"perf::stats\",\"perf::stats\"]o[2,\"noq_proto\"]Bc[6,\"noq_proto\",\"noq_proto::packet\"]6Bi[5,\"noq_proto\",\"noq_proto::config::qlog\"]Bc[15,\"noq_proto::PathAbandonReason\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Ak[5,\"std::time\",\"std::time\"]:Bb[5,\"noq_proto\",\"noq_proto::token\"]Da[5,\"noq_proto::config::transport\",\"noq_proto::config::transport\"]Bi[5,\"bytes::bytes_mut\",\"bytes::bytes_mut\"]Ai[6,\"noq_perf\",\"noq_perf\"]Bb[5,\"noq_proto\",\"noq_proto::frame\"]Ag[10,\"core::ops::deref\"]Am[5,\"core::time\",\"core::time\"]Bc[5,\"noq::endpoint\",\"noq::endpoint\"]Ai[5,\"noq\",\"noq::endpoint\"]Be[5,\"noq_proto\",\"noq_proto::endpoint\"]Am[15,\"noq_proto::StreamEvent\"]Ai[5,\"noq\",\"noq::incoming\"]2Bc[10,\"core::iter::traits::iterator\"]An[10,\"tonic::service::layered\"]Bc[6,\"noq_proto\",\"noq_proto::packet\"]Ak[5,\"noq\",\"noq::connection\"]Ae[5,\"noq\",\"noq::path\"]Ak[6,\"core::cmp\",\"core::cmp\"]7Ag[5,\"noq_udp\",\"noq_udp\"]i[5,\"noq\"]Ak[5,\"noq_proto\",\"noq_proto\"]Ad[10,\"alloc::string\"]j[10,\"noq\"]Bc[10,\"noq_proto\",\"noq_proto::token\"]4354Bn[5,\"noq_proto\",\"noq_proto::connection::stats\"]Bi[5,\"rustls_pki_types\",\"rustls_pki_types\"]?i[2,\"noq\"]o[2,\"noq_proto\"]1Ak[2,\"noq_proto::congestion\"]f[3,\"\"]Ae[15,\"noq::PathEvent\"]Ak[15,\"noq_proto::PathEvent\"]Ak[5,\"noq\",\"noq::connection\"]Ag[10,\"core::ops::arith\"]A`[10,\"arbitrary\"]Al[10,\"tokio::io::async_read\"]Ai[10,\"futures_io::if_std\"]Am[15,\"noq_proto::StreamEvent\"]Ac[10,\"core::borrow\"]Aa[5,\"perf\",\"perf\"]Ak[5,\"criterion\",\"criterion\"]Cb[5,\"noq_proto\",\"noq_proto::connection::datagrams\"]Bl[10,\"noq_proto::coding\",\"noq_proto::coding\"]<;0Ak[5,\"core::fmt\",\"core::fmt\"]i[5,\"noq\"]Ak[5,\"noq_proto\",\"noq_proto\"]i[6,\"noq\"]Bb[6,\"noq_proto\",\"noq_proto::frame\"]Ab[10,\"noq::crypto\"]Bl[10,\"noq_proto::crypto\",\"noq_proto::crypto\"]Ba[5,\"hdrhistogram\",\"hdrhistogram\"]21A`[10,\"core::cmp\"]5Bg[6,\"noq_proto\",\"noq_proto::connection\"]i[2,\"noq\"]o[2,\"noq_proto\"]8Bn[6,\"noq_proto\",\"noq_proto::connection::paths\"];Bn[5,\"noq_proto\",\"noq_proto::connection::stats\"]Al[6,\"noq\",\"noq::recv_stream\"]Cf[6,\"noq_proto\",\"noq_proto::connection::streams::recv\"]Ak[10,\"futures_core::future\"]Ak[10,\"futures_core::stream\"]Ai[10,\"noq\",\"noq::runtime\"]Bc[5,\"std::net::udp\",\"std::net::udp\"]Ak[10,\"clap_builder::derive\"]Ak[2,\"noq_proto::connection\"]0f[3,\"\"]f[1,\"\"]Ag[2,\"noq_proto::config\"]Em[5,\"clap_builder::parser::matches::arg_matches\",\"clap_builder::parser::matches::arg_matches\"]7Am[10,\"tokio::io::async_write\"]Ai[10,\"futures_io::if_std\"]Ae[5,\"noq::congestion\"]Ci[5,\"noq_proto::congestion\",\"noq_proto::congestion::bbr3\"]i[5,\"noq\"]Bn[5,\"noq_proto\",\"noq_proto::connection::paths\"]Aa[10,\"equivalent\"]Ak[5,\"noq\",\"noq::connection\"]Bg[5,\"noq::connection\",\"noq::connection\"]1Bg[5,\"noq_proto\",\"noq_proto::connection\"]Af[10,\"noq::congestion\"]Cd[10,\"noq_proto::congestion\",\"noq_proto::congestion\"]A`[10,\"hashbrown\"]68Bn[5,\"noq_proto\",\"noq_proto::connection::stats\"]B`[10,\"core::future::into_future\"]:Bj[5,\"noq_proto\",\"noq_proto::cid_generator\"]Ag[5,\"std::io\",\"std::io\"]Bi[6,\"noq_proto::frame\",\"noq_proto::frame\"]Bb[6,\"noq_proto\",\"noq_proto::frame\"]Bm[8,\"core::num::nonzero\",\"core::num::nonzero\"]Cm[5,\"rustls::error::other_error\",\"rustls::error::other_error\"]A`[10,\"core::cmp\"]Am[5,\"noq\",\"noq::event_stream\"]i[6,\"noq\"]Bn[6,\"noq_proto\",\"noq_proto::connection::paths\"]i[5,\"noq\"]Bi[5,\"noq_proto\",\"noq_proto::config::qlog\"]Bi[5,\"noq::recv_stream\",\"noq::recv_stream\"]Al[5,\"noq\",\"noq::recv_stream\"]C`[5,\"noq_proto\",\"noq_proto::connection::streams\"]Al[6,\"noq\",\"noq::recv_stream\"]Ai[5,\"noq\",\"noq::incoming\"]Be[5,\"noq_proto\",\"noq_proto::endpoint\"]Bi[5,\"noq::send_stream\",\"noq::send_stream\"]Al[5,\"noq\",\"noq::send_stream\"]5Dc[6,\"rustls_pki_types::server_name\",\"rustls_pki_types::server_name\"]Ce[6,\"core::net::socket_addr\",\"core::net::socket_addr\"]Bb[5,\"noq_proto\",\"noq_proto::frame\"]Ak[10,\"clap_builder::derive\"]Ak[5,\"std::time\",\"std::time\"]j[10,\"noq\"]Bd[10,\"noq_proto\",\"noq_proto::config\"]Ai[5,\"noq::crypto::rustls\"]Ck[5,\"noq_proto::crypto::rustls\",\"noq_proto::crypto::rustls\"]3Bc[10,\"noq_proto\",\"noq_proto::token\"]Ag[5,\"noq_udp\",\"noq_udp\"]Al[6,\"noq\",\"noq::send_stream\"]Cf[6,\"noq_proto\",\"noq_proto::connection::streams::send\"]i[2,\"noq\"]o[2,\"noq_proto\"]10Be[5,\"noq_proto\",\"noq_proto::endpoint\"]Ac[6,\"bench\",\"bench\"]Aa[5,\"bulk\",\"bulk\"]Da[6,\"noq_proto::connection::state\",\"noq_proto::connection::state\"]i[6,\"noq\"]Bc[6,\"noq_proto\",\"noq_proto::config\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Aa[5,\"noq::crypto\"]Bk[5,\"noq_proto::crypto\",\"noq_proto::crypto\"]Ae[5,\"noq::congestion\"]Cj[5,\"noq_proto::congestion\",\"noq_proto::congestion::cubic\"]Ae[15,\"noq::PathEvent\"]Ak[15,\"noq_proto::PathEvent\"]?i[5,\"noq\"]Bn[5,\"noq_proto\",\"noq_proto::config::transport\"]Ae[10,\"tonic::request\"]j[10,\"noq\"]Bj[10,\"noq_proto\",\"noq_proto::config::qlog\"]Ac[6,\"bench\",\"bench\"]An[5,\"noq\",\"noq::runtime::smol\"]o[2,\"noq_proto\"]C`[6,\"noq_proto\",\"noq_proto::connection::streams\"]Ba[5,\"bench::stats\",\"bench::stats\"]Ao[5,\"perf::stats\",\"perf::stats\"]f[3,\"\"]i[2,\"noq\"]Ak[2,\"noq_proto::connection\"]1Co[5,\"rustls::client::client_conn\",\"rustls::client::client_conn\"]Bk[5,\"noq_proto::config\",\"noq_proto::config\"]?Ab[10,\"noq::crypto\"]Bc[5,\"noq_proto\",\"noq_proto::config\"]Bl[10,\"noq_proto::crypto\",\"noq_proto::crypto\"]i[5,\"noq\"]C`[5,\"noq_proto\",\"noq_proto::connection::streams\"]Bo[6,\"noq_proto::endpoint\",\"noq_proto::endpoint\"]i[6,\"noq\"]Be[6,\"noq_proto\",\"noq_proto::endpoint\"]Bk[5,\"noq_proto::shared\",\"noq_proto::shared\"]5Bc[5,\"noq_proto\",\"noq_proto::shared\"]Bb[5,\"noq_proto\",\"noq_proto::frame\"]4Bc[6,\"noq_proto\",\"noq_proto::shared\"]Ag[6,\"noq_udp\",\"noq_udp\"]Bb[10,\"core::iter::traits::collect\"]Bm[8,\"core::num::nonzero\",\"core::num::nonzero\"];Bb[5,\"noq_proto\",\"noq_proto::token\"]Ae[15,\"noq::PathEvent\"]Ak[15,\"noq_proto::PathEvent\"]Ak[5,\"noq\",\"noq::connection\"]21Da[5,\"noq_proto::connection::paths\",\"noq_proto::connection::paths\"]Bn[5,\"noq_proto\",\"noq_proto::connection::paths\"]2Co[5,\"rustls::server::server_conn\",\"rustls::server::server_conn\"]Bk[5,\"noq_proto::config\",\"noq_proto::config\"]i[5,\"noq\"]Ab[10,\"noq::crypto\"]Bc[5,\"noq_proto\",\"noq_proto::config\"]Bl[10,\"noq_proto::crypto\",\"noq_proto::crypto\"]Ce[5,\"core::net::socket_addr\",\"core::net::socket_addr\"]0Al[6,\"noq\",\"noq::send_stream\"]Ao[5,\"noq\",\"noq::runtime::tokio\"]Cg[5,\"arbitrary::unstructured\",\"arbitrary::unstructured\"]i[2,\"noq\"]j[2,\"perf\"]9Bl[5,\"noq_proto\",\"noq_proto::bloom_token_log\"]Ab[10,\"core::clone\"]Be[6,\"noq_proto\",\"noq_proto::endpoint\"]Bc[5,\"noq_proto\",\"noq_proto::shared\"]Ai[5,\"noq\",\"noq::endpoint\"]Ai[5,\"noq::crypto::rustls\"]Ck[5,\"noq_proto::crypto::rustls\",\"noq_proto::crypto::rustls\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Bo[5,\"noq_proto::endpoint\",\"noq_proto::endpoint\"]Be[5,\"noq_proto\",\"noq_proto::endpoint\"]Ae[5,\"noq::congestion\"]Cm[5,\"noq_proto::congestion\",\"noq_proto::congestion::new_reno\"]Bi[5,\"core::num::error\",\"core::num::error\"]Bc[5,\"noq_proto\",\"noq_proto::packet\"]Ec[5,\"clap_builder::builder::possible_value\",\"clap_builder::builder::possible_value\"]Bi[6,\"rustls_pki_types\",\"rustls_pki_types\"]Cf[6,\"noq_proto\",\"noq_proto::connection::streams::recv\"]Cg[5,\"rustls::webpki::anchors\",\"rustls::webpki::anchors\"]i[5,\"noq\"]Bc[5,\"noq_proto\",\"noq_proto::config\"]Bk[5,\"noq_proto::coding\",\"noq_proto::coding\"]o[2,\"noq_proto\"]0f[3,\"\"]Ai[10,\"noq\",\"noq::runtime\"]Bi[5,\"rustls_pki_types\",\"rustls_pki_types\"]i[6,\"noq\"]Bg[6,\"noq_proto\",\"noq_proto::connection\"]Ak[10,\"clap_builder::derive\"]Ag[15,\"noq_proto::Event\"]:91Ai[5,\"noq\",\"noq::incoming\"]Bb[5,\"noq_proto\",\"noq_proto::frame\"]Bc[6,\"rustls::error\",\"rustls::error\"]=Bb[5,\"noq_proto\",\"noq_proto::token\"]1Al[6,\"noq\",\"noq::recv_stream\"]0C`[5,\"noq_proto\",\"noq_proto::connection::streams\"]Ba[5,\"bench::stats\",\"bench::stats\"]o[5,\"noq_proto\"]Al[5,\"noq_udp\",\"noq_udp::imp\"]Ae[5,\"noq\",\"noq::path\"]i[5,\"noq\"]9>=Bc[5,\"noq_proto\",\"noq_proto::shared\"]1Bn[5,\"noq_proto\",\"noq_proto::connection::stats\"]Ba[5,\"rustls::rand\",\"rustls::rand\"]Ao[5,\"perf::stats\",\"perf::stats\"]o[2,\"noq_proto\"]Bc[6,\"noq_proto\",\"noq_proto::packet\"]6Bi[5,\"noq_proto\",\"noq_proto::config::qlog\"]Bc[15,\"noq_proto::PathAbandonReason\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Ak[5,\"std::time\",\"std::time\"]:Bb[5,\"noq_proto\",\"noq_proto::token\"]Da[5,\"noq_proto::config::transport\",\"noq_proto::config::transport\"]Settings All
Rustdoc settings
Back
\ No newline at end of file
+Settings All
Rustdoc settings
Back
\ No newline at end of file
diff --git a/pr/721/docs/src/noq_proto/connection/mod.rs.html b/pr/721/docs/src/noq_proto/connection/mod.rs.html
index e5b3c93ef..1c24a3baf 100644
--- a/pr/721/docs/src/noq_proto/connection/mod.rs.html
+++ b/pr/721/docs/src/noq_proto/connection/mod.rs.html
@@ -1002,6837 +1002,6836 @@
1002 let path = vacant_entry.insert(PathState { data, prev: None });
1003
1004 let mut pn_space = spaces::PacketNumberSpace::new(now, SpaceId::Data, &mut self.rng);
-1005 pn_space.open_status = OpenStatus::Sent;
-1006 if let Some(pn) = pn {
-1007 pn_space.dedup.insert(pn);
-1008 }
-1009 self.spaces[SpaceId::Data]
-1010 .number_spaces
-1011 .insert(path_id, pn_space);
-1012 self.qlog.emit_tuple_assigned(path_id, network_path, now);
-1013
-1014 // If the remote opened this path we may not have CIDs for it. For locally opened
-1015 // paths the caller should have already made sure we have CIDs and refused to open
-1016 // it if there were none.
-1017 if !self.remote_cids.contains_key(&path_id) {
-1018 debug!(%path_id, "Remote opened path without issuing CIDs");
-1019 self.spaces[SpaceId::Data]
-1020 .pending
-1021 .path_cids_blocked
-1022 .insert(path_id, VarInt(0));
-1023 // Do not abandon this path right away. CIDs might be in-flight still and arrive
-1024 // soon. It is up to the remote to handle this situation.
-1025 }
-1026
-1027 &mut path.data
-1028 }
-1029
-1030 /// Returns packets to transmit
-1031 ///
-1032 /// Connections should be polled for transmit after:
-1033 /// - the application performed some I/O on the connection
-1034 /// - a call was made to `handle_event`
-1035 /// - a call was made to `handle_timeout`
-1036 ///
-1037 /// `max_datagrams` specifies how many datagrams can be returned inside a
-1038 /// single Transmit using GSO. This must be at least 1.
-1039 #[must_use]
-1040 pub fn poll_transmit(
-1041 &mut self,
-1042 now: Instant,
-1043 max_datagrams: NonZeroUsize,
-1044 buf: &mut Vec<u8>,
-1045 ) -> Option<Transmit> {
-1046 let max_datagrams = match self.config.enable_segmentation_offload {
-1047 false => NonZeroUsize::MIN,
-1048 true => max_datagrams,
-1049 };
-1050
-1051 // Each call to poll_transmit can only send datagrams to one destination, because
-1052 // all datagrams in a GSO batch are for the same destination. Therefore only
-1053 // datagrams for one destination address are produced for each poll_transmit call.
-1054
-1055 // Check whether we need to send a close message
-1056 let connection_close_pending = match self.state.as_type() {
-1057 StateType::Drained => {
-1058 for path in self.paths.values_mut() {
-1059 path.data.app_limited = true;
-1060 }
-1061 return None;
-1062 }
-1063 StateType::Draining | StateType::Closed => {
-1064 // self.connection_close_pending is only reset once the associated packet
-1065 // had been encoded successfully
-1066 if !self.connection_close_pending {
-1067 for path in self.paths.values_mut() {
-1068 path.data.app_limited = true;
-1069 }
-1070 return None;
-1071 }
-1072 true
-1073 }
-1074 _ => false,
-1075 };
-1076
-1077 // Schedule an ACK_FREQUENCY frame if a new one needs to be sent.
-1078 if let Some(config) = &self.config.ack_frequency_config {
-1079 let rtt = self
-1080 .paths
-1081 .values()
-1082 .map(|p| p.data.rtt.get())
-1083 .min()
-1084 .expect("one path exists");
-1085 self.spaces[SpaceId::Data].pending.ack_frequency = self
-1086 .ack_frequency
-1087 .should_send_ack_frequency(rtt, config, &self.peer_params)
-1088 && self.highest_space == SpaceKind::Data
-1089 && self.peer_supports_ack_frequency();
-1090 }
-1091
-1092 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
-1093 while let Some(path_id) = next_path_id {
-1094 if !connection_close_pending
-1095 && let Some(transmit) = self.poll_transmit_off_path(now, buf, path_id)
-1096 {
-1097 return Some(transmit);
-1098 }
-1099
-1100 let info = self.scheduling_info(path_id);
-1101 if let Some(transmit) = self.poll_transmit_on_path(
-1102 now,
-1103 buf,
-1104 path_id,
-1105 max_datagrams,
-1106 &info,
-1107 connection_close_pending,
-1108 ) {
-1109 return Some(transmit);
-1110 }
-1111
-1112 // Continue checking other paths, tail-loss probes may need to be sent
-1113 // in all spaces.
-1114 debug_assert!(
-1115 buf.is_empty(),
-1116 "nothing to send on path but buffer not empty"
-1117 );
-1118
-1119 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
-1120 }
-1121
-1122 // We didn't produce any application data packet
-1123 debug_assert!(
-1124 buf.is_empty(),
-1125 "there was data in the buffer, but it was not sent"
-1126 );
-1127
-1128 if self.state.is_established() {
-1129 // Try MTU probing now
-1130 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
-1131 while let Some(path_id) = next_path_id {
-1132 if let Some(transmit) = self.poll_transmit_mtu_probe(now, buf, path_id) {
-1133 return Some(transmit);
-1134 }
-1135 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
-1136 }
-1137 }
-1138
-1139 None
-1140 }
-1141
-1142 /// Computes the packet scheduling information for this path.
-1143 ///
-1144 /// While this information is only returned for a single path, it is important to know
-1145 /// that this information remains static for the entire span of a single
-1146 /// [`Connection::poll_transmit`] call. In other words, the return value is purely
-1147 /// functional and only depends on the [`PathId`] **during a single** `poll_transmit`
-1148 /// call. It can be computed up-front for all paths but we don't do that because it
-1149 /// involves an allocation.
-1150 ///
-1151 /// See the inline comments for how the packet scheduling works.
-1152 ///
-1153 /// # Panics
-1154 ///
-1155 /// This will panic if called for a path for which we do not have any [`PathData`], like
-1156 /// so many other functions we have. But this is the only one to document this in its
-1157 /// doc comment. Maybe that should change. Eventually we'll refactor things for this
-1158 /// panic to go away.
-1159 fn scheduling_info(&self, path_id: PathId) -> PathSchedulingInfo {
-1160 // Such a space is preferred for SpaceKind::Data frames.
-1161 let have_validated_status_available_space = self.paths.iter().any(|(path_id, path)| {
-1162 self.remote_cids.contains_key(path_id)
-1163 && !self.abandoned_paths.contains(path_id)
-1164 && path.data.validated
-1165 && path.data.local_status() == PathStatus::Available
-1166 });
-1167
-1168 // Such a space is able to send SpaceKind::Data frames.
-1169 let have_validated_space = self.paths.iter().any(|(path_id, path)| {
-1170 self.remote_cids.contains_key(path_id)
-1171 && !self.abandoned_paths.contains(path_id)
-1172 && path.data.validated
-1173 });
-1174
-1175 let is_handshaking = self.is_handshaking();
-1176 let has_cids = self.remote_cids.contains_key(&path_id);
-1177 let is_abandoned = self.abandoned_paths.contains(&path_id);
-1178 let path_data = self.path_data(path_id);
-1179 let validated = path_data.validated;
-1180 let status = path_data.local_status();
-1181
-1182 // This is the core packet scheduling, whether this space ID may send
-1183 // SpaceKind::Data frames.
-1184 let may_send_data = has_cids
-1185 && !is_abandoned
-1186 && if is_handshaking {
-1187 // There is only one path during the handshake. We want to
-1188 // already send 0-RTT and 0.5-RTT (permitting anti-amplification
-1189 // limit) data.
-1190 true
-1191 } else if !validated {
-1192 // TODO(flub): When we have a network change we might end up
-1193 // having to abandon all paths and re-open new ones to the
-1194 // same remotes. This leaves us without any validated
-1195 // path. Perhaps we should have a way to figure out if the
-1196 // path is to a previously-validated remote address and allow
-1197 // sending data to such remotes immediately.
-1198 false
-1199 } else {
-1200 match status {
-1201 PathStatus::Available => {
-1202 // Best possible space to send data on.
-1203 true
-1204 }
-1205 PathStatus::Backup => {
-1206 // If there is a status-available path we prefer that.
-1207 !have_validated_status_available_space
-1208 }
-1209 }
-1210 };
-1211
-1212 // CONNECTION_CLOSE is allowed to be sent on a non-validated
-1213 // path. Particularly during the handshake we want to send it before the
-1214 // path is validated. Later if there is no validated path available we
-1215 // will also accept sending it on an un-validated path.
-1216 let may_send_close = has_cids
-1217 && !is_abandoned
-1218 && if !validated && have_validated_status_available_space {
-1219 // We have a better space to send on.
-1220 false
-1221 } else {
-1222 // No other validated space, this is as good as it gets.
-1223 true
-1224 };
-1225
-1226 // PATH_ABANDON is normally sent together with other SpaceKind::Data frames. But if
-1227 // there is no other validated space to send it on, it can be sent on the path to be
-1228 // abandoned itself if that was validated.
-1229 let may_self_abandon = has_cids && validated && !have_validated_space;
-1230
-1231 PathSchedulingInfo {
-1232 is_abandoned,
-1233 may_send_data,
-1234 may_send_close,
-1235 may_self_abandon,
-1236 }
-1237 }
-1238
-1239 fn build_transmit(&mut self, path_id: PathId, transmit: TransmitBuf<'_>) -> Transmit {
-1240 debug_assert!(
-1241 !transmit.is_empty(),
-1242 "must not be called with an empty transmit buffer"
-1243 );
-1244
-1245 let network_path = self.path_data(path_id).network_path;
-1246 trace!(
-1247 segment_size = transmit.segment_size(),
-1248 last_datagram_len = transmit.len() % transmit.segment_size(),
-1249 %network_path,
-1250 "sending {} bytes in {} datagrams",
-1251 transmit.len(),
-1252 transmit.num_datagrams()
-1253 );
-1254 self.path_data_mut(path_id)
-1255 .inc_total_sent(transmit.len() as u64);
-1256
-1257 self.path_stats
-1258 .for_path(path_id)
-1259 .udp_tx
-1260 .on_sent(transmit.num_datagrams() as u64, transmit.len());
-1261
-1262 Transmit {
-1263 destination: network_path.remote,
-1264 size: transmit.len(),
-1265 ecn: if self.path_data(path_id).sending_ecn {
-1266 Some(EcnCodepoint::Ect0)
-1267 } else {
-1268 None
-1269 },
-1270 segment_size: match transmit.num_datagrams() {
-1271 1 => None,
-1272 _ => Some(transmit.segment_size()),
-1273 },
-1274 src_ip: network_path.local_ip,
-1275 }
-1276 }
-1277
-1278 /// poll_transmit logic for off-path data.
-1279 fn poll_transmit_off_path(
-1280 &mut self,
-1281 now: Instant,
-1282 buf: &mut Vec<u8>,
-1283 path_id: PathId,
-1284 ) -> Option<Transmit> {
-1285 if let Some(challenge) = self.send_prev_path_challenge(now, buf, path_id) {
-1286 return Some(challenge);
-1287 }
-1288 if let Some(response) = self.send_off_path_path_response(now, buf, path_id) {
-1289 return Some(response);
-1290 }
-1291 if let Some(challenge) = self.send_nat_traversal_path_challenge(now, buf, path_id) {
-1292 return Some(challenge);
-1293 }
-1294 None
-1295 }
-1296
-1297 /// poll_transmit logic for on-path data.
-1298 ///
-1299 /// This is not quite the same as for a multipath packet space, since [`PathId::ZERO`]
-1300 /// has 3 packet spaces, which this handles.
-1301 ///
-1302 /// See [`Self::poll_transmit_off_path`] for off-path data.
-1303 #[must_use]
-1304 fn poll_transmit_on_path(
-1305 &mut self,
-1306 now: Instant,
-1307 buf: &mut Vec<u8>,
-1308 path_id: PathId,
-1309 max_datagrams: NonZeroUsize,
-1310 scheduling_info: &PathSchedulingInfo,
-1311 connection_close_pending: bool,
-1312 ) -> Option<Transmit> {
-1313 // Check if there is at least one active CID to use for sending
-1314 let Some(remote_cid) = self.remote_cids.get(&path_id).map(CidQueue::active) else {
-1315 if !self.abandoned_paths.contains(&path_id) {
-1316 debug!(%path_id, "no remote CIDs for path");
-1317 }
-1318 return None;
-1319 };
-1320
-1321 // Whether the last packet in the datagram must be padded so the datagram takes up
-1322 // an exact size. An earlier space can decide to not fill an entire datagram and
-1323 // require the next space to fill it further. But may need a specific size of the
-1324 // datagram containing the packet. The final packet built in the datagram must pad
-1325 // to this size.
-1326 let mut pad_datagram = PadDatagram::No;
-1327
-1328 // The packet number of the last built packet. This is kept kept across spaces.
-1329 // QUIC is supposed to have a single congestion controller for the Initial,
-1330 // Handshake and Data(PathId::ZERO) spaces.
-1331 let mut last_packet_number = None;
-1332
-1333 // If we end up not sending anything, we need to know if that was because there was
-1334 // nothing to send or because we were congestion blocked.
-1335 let mut congestion_blocked = false;
-1336
-1337 // Set the segment size to this path's MTU for on-path data.
-1338 let pmtu = self.path_data(path_id).current_mtu().into();
-1339 let mut transmit = TransmitBuf::new(buf, max_datagrams, pmtu);
-1340
-1341 // Iterate over the available spaces.
-1342 for space_id in SpaceId::iter() {
-1343 // Only PathId::ZERO uses non Data space ids.
-1344 if path_id != PathId::ZERO && space_id != SpaceId::Data {
-1345 continue;
-1346 }
-1347 match self.poll_transmit_path_space(
-1348 now,
-1349 &mut transmit,
-1350 path_id,
-1351 space_id,
-1352 remote_cid,
-1353 scheduling_info,
-1354 connection_close_pending,
-1355 pad_datagram,
-1356 ) {
-1357 PollPathSpaceStatus::NothingToSend {
-1358 congestion_blocked: cb,
-1359 } => {
-1360 congestion_blocked |= cb;
-1361 // Continue checking other spaces, tail-loss probes may need to be sent
-1362 // in all spaces.
-1363 }
-1364 PollPathSpaceStatus::WrotePacket {
-1365 last_packet_number: pn,
-1366 pad_datagram: pad,
-1367 } => {
-1368 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
-1369 last_packet_number = Some(pn);
-1370 pad_datagram = pad;
-1371 // Always check higher spaces. If the transmit is full or they have
-1372 // nothing to send they will not write packets. But if they can, they
-1373 // must always be allowed to add to this transmit because coalescing may
-1374 // be required.
-1375 continue;
-1376 }
-1377 PollPathSpaceStatus::Send {
-1378 last_packet_number: pn,
-1379 } => {
-1380 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
-1381 last_packet_number = Some(pn);
-1382 break;
-1383 }
-1384 }
-1385 }
-1386
-1387 if last_packet_number.is_some() || congestion_blocked {
-1388 self.qlog.emit_recovery_metrics(
-1389 path_id,
-1390 &mut self
-1391 .paths
-1392 .get_mut(&path_id)
-1393 .expect("path_id was iterated from self.paths above")
-1394 .data,
-1395 now,
-1396 );
-1397 }
-1398
-1399 self.path_data_mut(path_id).app_limited =
-1400 last_packet_number.is_none() && !congestion_blocked;
-1401
-1402 match last_packet_number {
-1403 Some(last_packet_number) => {
-1404 // Note that when sending in multiple spaces the last packet number will be
-1405 // the one from the highest space.
-1406 self.path_data_mut(path_id).congestion.on_sent(
-1407 now,
-1408 transmit.len() as u64,
-1409 last_packet_number,
-1410 );
-1411 Some(self.build_transmit(path_id, transmit))
-1412 }
-1413 None => None,
-1414 }
-1415 }
-1416
-1417 /// poll_transmit logic for a QUIC-MULTIPATH packet number space (PathID + SpaceId).
-1418 #[must_use]
-1419 fn poll_transmit_path_space(
-1420 &mut self,
-1421 now: Instant,
-1422 transmit: &mut TransmitBuf<'_>,
-1423 path_id: PathId,
-1424 space_id: SpaceId,
-1425 remote_cid: ConnectionId,
-1426 scheduling_info: &PathSchedulingInfo,
-1427 // If we need to send a CONNECTION_CLOSE frame.
-1428 connection_close_pending: bool,
-1429 // Whether the current datagram needs to be padded to a certain size.
-1430 mut pad_datagram: PadDatagram,
-1431 ) -> PollPathSpaceStatus {
-1432 // Keep track of the last packet number we wrote. If None we did not write any
-1433 // packets.
-1434 let mut last_packet_number = None;
-1435
-1436 // Each loop of this may build one packet. It works logically as follows:
-1437 //
-1438 // - Check if something *needs* to be sent in this space and *can* be sent.
-1439 // - If not, return to the caller who will call us again for the next space.
-1440 // - Start a new datagram.
-1441 // - Unless coalescing the packet into an existing datagram.
-1442 // - Write the packet header and payload.
-1443 // - Check if coalescing a next packet into the datagram is possible.
-1444 // - If coalescing, finish packet without padding to leave space in the datagram.
-1445 // - If not coalescing, complete the datagram:
-1446 // - Finish packet with padding.
-1447 // - Set the transmit segment size if this is the first datagram.
-1448 // - Loop: next iteration will exit the loop if nothing more to send in this
-1449 // space. The TransmitBuf will contain a started datagram with space if
-1450 // coalescing, or completely filled datagram if not coalescing.
-1451 loop {
-1452 // Determine if anything can be sent in this packet number space.
-1453 let max_packet_size = if transmit.datagram_remaining_mut() > 0 {
-1454 // A datagram is started already, we are coalescing another packet into it.
-1455 transmit.datagram_remaining_mut()
-1456 } else {
-1457 // A new datagram needs to be started.
-1458 transmit.segment_size()
-1459 };
-1460 let can_send =
-1461 self.space_can_send(space_id, path_id, max_packet_size, connection_close_pending);
-1462 let needs_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
-1463 let space_will_send = {
-1464 if scheduling_info.is_abandoned {
-1465 // If this path is abandoned then we might still have to send
-1466 // PATH_ABANDON itself on it if there was no better space
-1467 // available. Otherwise we want to send the PATH_ABANDON as permitted by
-1468 // may_send_data however.
-1469 scheduling_info.may_self_abandon
-1470 && self.spaces[space_id]
-1471 .pending
-1472 .path_abandon
-1473 .contains_key(&path_id)
-1474 } else if can_send.close && scheduling_info.may_send_close {
-1475 // This is the best path to send a CONNECTION_CLOSE on.
-1476 true
-1477 } else if needs_loss_probe || can_send.space_specific {
-1478 // We always send a loss probe or space-specific frames if the path is
-1479 // not abandoned.
-1480 true
-1481 } else {
-1482 // Anything else we only send if we're the best path for SpaceKind::Data
-1483 // frames.
-1484 !can_send.is_empty() && scheduling_info.may_send_data
-1485 }
-1486 };
-1487
-1488 if !space_will_send {
-1489 // Nothing more to send. Previous iterations of this loop may have built
-1490 // packets already.
-1491 return match last_packet_number {
-1492 Some(pn) => PollPathSpaceStatus::WrotePacket {
-1493 last_packet_number: pn,
-1494 pad_datagram,
-1495 },
-1496 None => {
-1497 // Only log for spaces which have crypto.
-1498 if self.crypto_state.has_keys(space_id.encryption_level())
-1499 || (space_id == SpaceId::Data
-1500 && self.crypto_state.has_keys(EncryptionLevel::ZeroRtt))
-1501 {
-1502 trace!(?space_id, %path_id, "nothing to send in space");
-1503 }
-1504 PollPathSpaceStatus::NothingToSend {
-1505 congestion_blocked: false,
-1506 }
-1507 }
-1508 };
-1509 }
-1510
-1511 // We want to send on this space, check congestion control if we can. But only
-1512 // if we will need to start a new datagram. If we are coalescing into an already
-1513 // started datagram we do not need to check congestion control again.
-1514 if transmit.datagram_remaining_mut() == 0 {
-1515 let congestion_blocked =
-1516 self.path_congestion_check(space_id, path_id, transmit, &can_send, now);
-1517 if congestion_blocked != PathBlocked::No {
-1518 // Previous iterations of this loop may have built packets already.
-1519 return match last_packet_number {
-1520 Some(pn) => PollPathSpaceStatus::WrotePacket {
-1521 last_packet_number: pn,
-1522 pad_datagram,
-1523 },
-1524 None => {
-1525 return PollPathSpaceStatus::NothingToSend {
-1526 congestion_blocked: true,
-1527 };
-1528 }
-1529 };
-1530 }
-1531
-1532 // If the datagram is full (or there never was one started), we need to start a
-1533 // new one.
-1534 if transmit.num_datagrams() >= transmit.max_datagrams().get() {
-1535 // No more datagrams allowed.
-1536 // Previous iterations of this loop may have built packets already.
-1537 return match last_packet_number {
-1538 Some(pn) => PollPathSpaceStatus::WrotePacket {
-1539 last_packet_number: pn,
-1540 pad_datagram,
-1541 },
-1542 None => {
-1543 return PollPathSpaceStatus::NothingToSend {
-1544 congestion_blocked: false,
-1545 };
-1546 }
-1547 };
-1548 }
-1549
-1550 if needs_loss_probe {
-1551 // Ensure we have something to send for a tail-loss probe.
-1552 let request_immediate_ack =
-1553 space_id == SpaceId::Data && self.peer_supports_ack_frequency();
-1554 self.spaces[space_id].queue_tail_loss_probe(
-1555 path_id,
-1556 request_immediate_ack,
-1557 &self.streams,
-1558 );
-1559
-1560 self.spaces[space_id].for_path(path_id).loss_probes -= 1; // needs_loss_probe ensures loss_probes > 0
-1561
-1562 // Clamp the datagram to at most the minimum MTU to ensure that loss
-1563 // probes can get through and enable recovery even if the path MTU
-1564 // has shrank unexpectedly.
-1565 transmit.start_new_datagram_with_size(std::cmp::min(
-1566 usize::from(INITIAL_MTU),
-1567 transmit.segment_size(),
-1568 ));
-1569 } else {
-1570 transmit.start_new_datagram();
-1571 }
-1572 trace!(count = transmit.num_datagrams(), "new datagram started");
-1573
-1574 // We started a new datagram, we decide later if it needs padding.
-1575 pad_datagram = PadDatagram::No;
-1576 }
-1577
-1578 // If coalescing another packet into the existing datagram, there should
-1579 // still be enough space for a whole packet.
-1580 if transmit.datagram_start_offset() < transmit.len() {
-1581 debug_assert!(transmit.datagram_remaining_mut() >= MIN_PACKET_SPACE);
-1582 }
-1583
-1584 //
-1585 // From here on, we've determined that a packet will definitely be sent.
-1586 //
-1587
-1588 if self.crypto_state.has_keys(EncryptionLevel::Initial)
-1589 && space_id == SpaceId::Handshake
-1590 && self.side.is_client()
-1591 {
-1592 // A client stops both sending and processing Initial packets when it
-1593 // sends its first Handshake packet.
-1594 self.discard_space(now, SpaceKind::Initial);
-1595 }
-1596 if let Some(ref mut prev) = self.crypto_state.prev_crypto {
-1597 prev.update_unacked = false;
-1598 }
-1599
-1600 let Some(mut builder) =
-1601 PacketBuilder::new(now, space_id, path_id, remote_cid, transmit, self)
-1602 else {
-1603 // Confidentiality limit is exceeded and the connection has been killed. We
-1604 // should not send any other packets. This works in a roundabout way: We
-1605 // have started a datagram but not written anything into it. So even if we
-1606 // get called again for another space we will see an already started
-1607 // datagram and try and start another packet here. Then be stopped by the
-1608 // same confidentiality limit.
-1609 return PollPathSpaceStatus::NothingToSend {
-1610 congestion_blocked: false,
-1611 };
-1612 };
-1613 last_packet_number = Some(builder.packet_number);
-1614
-1615 if space_id == SpaceId::Initial
-1616 && (self.side.is_client() || can_send.is_ack_eliciting() || needs_loss_probe)
-1617 {
-1618 // https://www.rfc-editor.org/rfc/rfc9000.html#section-14.1
-1619 pad_datagram |= PadDatagram::ToMinMtu;
-1620 }
-1621 if space_id == SpaceId::Data && self.config.pad_to_mtu {
-1622 pad_datagram |= PadDatagram::ToSegmentSize;
-1623 }
-1624
-1625 if scheduling_info.may_send_close && can_send.close {
-1626 trace!("sending CONNECTION_CLOSE");
-1627 // Encode ACKs before the ConnectionClose message, to give the receiver
-1628 // a better approximate on what data has been processed. This is
-1629 // especially important with ack delay, since the peer might not
-1630 // have gotten any other ACK for the data earlier on.
-1631 let is_multipath_negotiated = self.is_multipath_negotiated();
-1632 for path_id in self.spaces[space_id]
-1633 .number_spaces
-1634 .iter()
-1635 .filter(|(_, pns)| !pns.pending_acks.ranges().is_empty())
-1636 .map(|(&path_id, _)| path_id)
-1637 .collect::<Vec<_>>()
-1638 {
-1639 Self::populate_acks(
-1640 now,
-1641 self.receiving_ecn,
-1642 path_id,
-1643 space_id,
-1644 &mut self.spaces[space_id],
-1645 is_multipath_negotiated,
-1646 &mut builder,
-1647 &mut self.path_stats.for_path(path_id).frame_tx,
-1648 self.crypto_state.has_keys(space_id.encryption_level()),
-1649 );
-1650 }
-1651
-1652 // Since there only 64 ACK frames there will always be enough space
-1653 // to encode the ConnectionClose frame too. However we still have the
-1654 // check here to prevent crashes if something changes.
-1655
-1656 // TODO(flub): This needs fixing for multipath, to ensure we can always
-1657 // write the CONNECTION_CLOSE even if we have many PATH_ACKs to send:
-1658 // https://github.com/n0-computer/noq/issues/367.
-1659 debug_assert!(
-1660 builder.frame_space_remaining() > frame::ConnectionClose::SIZE_BOUND,
-1661 "ACKs should leave space for ConnectionClose"
-1662 );
-1663 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
-1664 if frame::ConnectionClose::SIZE_BOUND < builder.frame_space_remaining() {
-1665 let max_frame_size = builder.frame_space_remaining();
-1666 let close: Close = match self.state.as_type() {
-1667 StateType::Closed => {
-1668 let reason: Close =
-1669 self.state.as_closed().expect("checked").clone().into();
-1670 if space_id == SpaceId::Data || reason.is_transport_layer() {
-1671 reason
-1672 } else {
-1673 TransportError::APPLICATION_ERROR("").into()
-1674 }
-1675 }
-1676 StateType::Draining => TransportError::NO_ERROR("").into(),
-1677 _ => unreachable!(
-1678 "tried to make a close packet when the connection wasn't closed"
-1679 ),
-1680 };
-1681 builder.write_frame(close.encoder(max_frame_size), stats);
-1682 }
-1683 let last_pn = builder.packet_number;
-1684 builder.finish_and_track(now, self, path_id, pad_datagram);
-1685 if space_id.kind() == self.highest_space {
-1686 // Don't send another close packet. Even with multipath we only send
-1687 // CONNECTION_CLOSE on a single path since we expect our paths to work.
-1688 self.connection_close_pending = false;
-1689 }
-1690 // Send a close frame in every possible space for robustness, per
-1691 // RFC9000 "Immediate Close during the Handshake". Don't bother trying
-1692 // to send anything else.
-1693 // TODO(flub): This breaks during the handshake if we can not coalesce
-1694 // packets due to space reasons: the next space would either fail a
-1695 // debug_assert checking for enough packet space or produce an invalid
-1696 // packet. We need to keep track of per-space pending CONNECTION_CLOSE to
-1697 // be able to send these across multiple calls to poll_transmit. Then
-1698 // check for coalescing space here because initial packets need to be in
-1699 // padded datagrams. And also add space checks for CONNECTION_CLOSE in
-1700 // space_can_send so it would stop a GSO batch if the datagram is too
-1701 // small for another CONNECTION_CLOSE packet.
-1702 return PollPathSpaceStatus::WrotePacket {
-1703 last_packet_number: last_pn,
-1704 pad_datagram,
-1705 };
-1706 }
-1707
-1708 self.populate_packet(now, space_id, path_id, scheduling_info, &mut builder);
-1709
-1710 // ACK-only packets should only be sent when explicitly allowed. If we write them due to
-1711 // any other reason, there is a bug which leads to one component announcing write
-1712 // readiness while not writing any data. This degrades performance. The condition is
-1713 // only checked if the full MTU is available and when potentially large fixed-size
-1714 // frames aren't queued, so that lack of space in the datagram isn't the reason for just
-1715 // writing ACKs.
-1716 debug_assert!(
-1717 !(builder.sent_frames().is_ack_only(&self.streams)
-1718 && !can_send.acks
-1719 && (can_send.other || can_send.space_specific)
-1720 && builder.buf.segment_size()
-1721 == self.path_data(path_id).current_mtu() as usize
-1722 && self.datagrams.outgoing.is_empty()),
-1723 "SendableFrames was {can_send:?}, but only ACKs have been written"
-1724 );
-1725 if builder.sent_frames().requires_padding {
-1726 pad_datagram |= PadDatagram::ToMinMtu;
-1727 }
-1728
-1729 for (path_id, _pn) in builder.sent_frames().largest_acked.iter() {
-1730 self.spaces[space_id]
-1731 .for_path(*path_id)
-1732 .pending_acks
-1733 .acks_sent();
-1734 self.timers.stop(
-1735 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
-1736 self.qlog.with_time(now),
-1737 );
-1738 }
-1739
-1740 // Now we need to finish the packet. Before we do so we need to know if we will
-1741 // be coalescing the next packet into this one, or will be ending the datagram
-1742 // as well. Because if this is the last packet in the datagram more padding
-1743 // might be needed because of the packet type, or to fill the GSO segment size.
-1744
-1745 // Are we allowed to coalesce AND is there enough space for another *packet* in
-1746 // this datagram AND will we definitely send another packet?
-1747 if builder.can_coalesce && path_id == PathId::ZERO && {
-1748 let max_packet_size = builder
-1749 .buf
-1750 .datagram_remaining_mut()
-1751 .saturating_sub(builder.predict_packet_end());
-1752 max_packet_size > MIN_PACKET_SPACE
-1753 && self.has_pending_packet(space_id, max_packet_size, connection_close_pending)
-1754 } {
-1755 // We can append/coalesce the next packet into the current
-1756 // datagram. Finish the current packet without adding extra padding.
-1757 trace!("will coalesce with next packet");
-1758 builder.finish_and_track(now, self, path_id, PadDatagram::No);
-1759 } else {
-1760 // We need a new datagram for the next packet. Finish the current
-1761 // packet with padding.
-1762 // TODO(flub): if there isn't any more data to be sent, this will still pad
-1763 // to the segment size and only discover there is nothing to send before
-1764 // starting the next packet. That is wasting up to 32 bytes.
-1765 if builder.buf.num_datagrams() > 1 && matches!(pad_datagram, PadDatagram::No) {
-1766 // If too many padding bytes would be required to continue the
-1767 // GSO batch after this packet, end the GSO batch here. Ensures
-1768 // that fixed-size frames with heterogeneous sizes
-1769 // (e.g. application datagrams) won't inadvertently waste large
-1770 // amounts of bandwidth. The exact threshold is a bit arbitrary
-1771 // and might benefit from further tuning, though there's no
-1772 // universally optimal value.
-1773 const MAX_PADDING: usize = 32;
-1774 if builder.buf.datagram_remaining_mut()
-1775 > builder.predict_packet_end() + MAX_PADDING
-1776 {
-1777 trace!(
-1778 "GSO truncated by demand for {} padding bytes",
-1779 builder.buf.datagram_remaining_mut() - builder.predict_packet_end()
-1780 );
-1781 let last_pn = builder.packet_number;
-1782 builder.finish_and_track(now, self, path_id, PadDatagram::No);
-1783 return PollPathSpaceStatus::Send {
-1784 last_packet_number: last_pn,
-1785 };
-1786 }
-1787
-1788 // Pad the current datagram to GSO segment size so it can be
-1789 // included in the GSO batch.
-1790 builder.finish_and_track(now, self, path_id, PadDatagram::ToSegmentSize);
-1791 } else {
-1792 builder.finish_and_track(now, self, path_id, pad_datagram);
-1793 }
-1794
-1795 // If this is the first datagram we set the segment size to the size of the
-1796 // first datagram.
-1797 if transmit.num_datagrams() == 1 {
-1798 transmit.clip_segment_size();
-1799 }
-1800 }
-1801 }
-1802 }
-1803
-1804 fn poll_transmit_mtu_probe(
-1805 &mut self,
-1806 now: Instant,
-1807 buf: &mut Vec<u8>,
-1808 path_id: PathId,
-1809 ) -> Option<Transmit> {
-1810 let (active_cid, probe_size) = self.get_mtu_probe_data(now, path_id)?;
-1811
-1812 // We are definitely sending a DPLPMTUD probe.
-1813 let mut transmit = TransmitBuf::new(buf, NonZeroUsize::MIN, probe_size as usize);
-1814 transmit.start_new_datagram_with_size(probe_size as usize);
-1815
-1816 let mut builder =
-1817 PacketBuilder::new(now, SpaceId::Data, path_id, active_cid, &mut transmit, self)?;
-1818
-1819 // We implement MTU probes as ping packets padded up to the probe size
-1820 trace!(?probe_size, "writing MTUD probe");
-1821 builder.write_frame(frame::Ping, &mut self.path_stats.for_path(path_id).frame_tx);
-1822
-1823 // If supported by the peer, we want no delays to the probe's ACK
-1824 if self.peer_supports_ack_frequency() {
-1825 builder.write_frame(
-1826 frame::ImmediateAck,
-1827 &mut self.path_stats.for_path(path_id).frame_tx,
-1828 );
-1829 }
-1830
-1831 builder.finish_and_track(now, self, path_id, PadDatagram::ToSize(probe_size));
-1832
-1833 self.path_stats.for_path(path_id).sent_plpmtud_probes += 1;
-1834
-1835 Some(self.build_transmit(path_id, transmit))
-1836 }
-1837
-1838 /// Returns the CID and probe size if a DPLPMTUD probe is needed.
-1839 ///
-1840 /// We MTU probe all paths for which all of the following is true:
-1841 /// - We have an active destination CID for the path.
-1842 /// - The remote address *and* path are validated.
-1843 /// - The path is not abandoned.
-1844 /// - The MTU Discovery subsystem wants to probe the path.
-1845 fn get_mtu_probe_data(&mut self, now: Instant, path_id: PathId) -> Option<(ConnectionId, u16)> {
-1846 let active_cid = self.remote_cids.get(&path_id).map(CidQueue::active)?;
-1847 let is_eligible = self.path_data(path_id).validated
-1848 && !self.path_data(path_id).is_validating_path()
-1849 && !self.abandoned_paths.contains(&path_id);
-1850
-1851 if !is_eligible {
-1852 return None;
-1853 }
-1854 let next_pn = self.spaces[SpaceId::Data]
-1855 .for_path(path_id)
-1856 .peek_tx_number();
-1857 let probe_size = self
-1858 .path_data_mut(path_id)
-1859 .mtud
-1860 .poll_transmit(now, next_pn)?;
-1861
-1862 Some((active_cid, probe_size))
-1863 }
-1864
-1865 /// Returns true if there is a further packet to send on [`PathId::ZERO`].
-1866 ///
-1867 /// In other words this is predicting whether the next call to
-1868 /// [`Connection::space_can_send`] issued will return some frames to be sent. Including
-1869 /// having to predict which packet number space it will be invoked with. This depends on
-1870 /// how both [`Connection::poll_transmit_on_path`] and
-1871 /// [`Connection::poll_transmit_path_space`] behave.
-1872 ///
-1873 /// This is needed to determine if packet coalescing can happen. Because the last packet
-1874 /// in a datagram may need to be padded and thus we must know if another packet will
-1875 /// follow or not.
-1876 ///
-1877 /// The next packet can be either in the same space, or in one of the following spaces
-1878 /// on the same path. Because a 0-RTT packet can be coalesced with a 1-RTT packet and
-1879 /// both are in the Data(PathId::ZERO) space. Previous spaces are not checked, because
-1880 /// packets are built from Initial to Handshake to Data spaces.
-1881 fn has_pending_packet(
-1882 &mut self,
-1883 current_space_id: SpaceId,
-1884 max_packet_size: usize,
-1885 connection_close_pending: bool,
-1886 ) -> bool {
-1887 let mut space_id = current_space_id;
-1888 loop {
-1889 let can_send = self.space_can_send(
-1890 space_id,
-1891 PathId::ZERO,
-1892 max_packet_size,
-1893 connection_close_pending,
-1894 );
-1895 if !can_send.is_empty() {
-1896 return true;
-1897 }
-1898 match space_id.next() {
-1899 Some(next_space_id) => space_id = next_space_id,
-1900 None => break,
-1901 }
-1902 }
-1903 false
-1904 }
-1905
-1906 /// Checks if creating a new datagram would be blocked by congestion control
-1907 fn path_congestion_check(
-1908 &mut self,
-1909 space_id: SpaceId,
-1910 path_id: PathId,
-1911 transmit: &TransmitBuf<'_>,
-1912 can_send: &SendableFrames,
-1913 now: Instant,
-1914 ) -> PathBlocked {
-1915 // Anti-amplification is only based on `total_sent`, which gets updated after
-1916 // the transmit is sent. Therefore we pass the amount of bytes for datagrams
-1917 // that are already created, as well as 1 byte for starting another datagram. If
-1918 // there is any anti-amplification budget left, we always allow a full MTU to be
-1919 // sent (see https://github.com/quinn-rs/quinn/issues/1082).
-1920 if self.side().is_server()
-1921 && self
-1922 .path_data(path_id)
-1923 .anti_amplification_blocked(transmit.len() as u64 + 1)
-1924 {
-1925 trace!(?space_id, %path_id, "blocked by anti-amplification");
-1926 return PathBlocked::AntiAmplification;
-1927 }
-1928
-1929 // Congestion control check.
-1930 // Tail loss probes must not be blocked by congestion, or a deadlock could arise.
-1931 let bytes_to_send = transmit.segment_size() as u64;
-1932 let need_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
-1933
-1934 if can_send.other && !need_loss_probe && !can_send.close {
-1935 let path = self.path_data(path_id);
-1936 if path.in_flight.bytes + bytes_to_send >= path.congestion.window() {
-1937 trace!(
-1938 ?space_id,
-1939 %path_id,
-1940 in_flight=%path.in_flight.bytes,
-1941 congestion_window=%path.congestion.window(),
-1942 "blocked by congestion control",
-1943 );
-1944 return PathBlocked::Congestion;
-1945 }
-1946 }
-1947
-1948 // Pacing check.
-1949 if let Some(delay) = self.path_data_mut(path_id).pacing_delay(bytes_to_send, now) {
-1950 let resume_time = now + delay;
-1951 self.timers.set(
-1952 Timer::PerPath(path_id, PathTimer::Pacing),
-1953 resume_time,
-1954 self.qlog.with_time(now),
-1955 );
-1956 // Loss probes and CONNECTION_CLOSE should be subject to pacing, even though
-1957 // they are not congestion controlled.
-1958 trace!(?space_id, %path_id, ?delay, "blocked by pacing");
-1959 return PathBlocked::Pacing;
-1960 }
-1961
-1962 PathBlocked::No
-1963 }
-1964
-1965 /// Send PATH_CHALLENGE for a previous path if necessary
-1966 ///
-1967 /// QUIC-TRANSPORT section 9.3.3
-1968 /// <https://www.rfc-editor.org/rfc/rfc9000.html#name-off-path-packet-forwarding>
-1969 fn send_prev_path_challenge(
-1970 &mut self,
-1971 now: Instant,
-1972 buf: &mut Vec<u8>,
-1973 path_id: PathId,
-1974 ) -> Option<Transmit> {
-1975 let (prev_cid, prev_path) = self.paths.get_mut(&path_id)?.prev.as_mut()?;
-1976 if !prev_path.pending_challenge {
-1977 return None;
-1978 };
-1979 prev_path.pending_challenge = false;
-1980 let token = self.rng.random();
-1981 let network_path = prev_path.network_path;
-1982 prev_path.record_path_challenge_sent(now, token, network_path);
-1983
-1984 debug_assert_eq!(
-1985 self.highest_space,
-1986 SpaceKind::Data,
-1987 "PATH_CHALLENGE queued without 1-RTT keys"
-1988 );
-1989 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
-1990 buf.start_new_datagram();
-1991
-1992 // Use the previous CID to avoid linking the new path with the previous path. We
-1993 // don't bother accounting for possible retirement of that prev_cid because this is
-1994 // sent once, immediately after migration, when the CID is known to be valid. Even
-1995 // if a post-migration packet caused the CID to be retired, it's fair to pretend
-1996 // this is sent first.
-1997 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, *prev_cid, buf, self)?;
-1998 let challenge = frame::PathChallenge(token);
-1999 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
-2000 builder.write_frame_with_log_msg(challenge, stats, Some("validating previous path"));
-2001
-2002 // An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame
-2003 // to at least the smallest allowed maximum datagram size of 1200 bytes,
-2004 // unless the anti-amplification limit for the path does not permit
-2005 // sending a datagram of this size
-2006 builder.pad_to(MIN_INITIAL_SIZE);
-2007
-2008 builder.finish(self, now);
-2009 self.path_stats
-2010 .for_path(path_id)
-2011 .udp_tx
-2012 .on_sent(1, buf.len());
-2013
-2014 trace!(
-2015 dst = ?network_path.remote,
-2016 src = ?network_path.local_ip,
-2017 len = buf.len(),
-2018 "sending prev_path off-path challenge",
-2019 );
-2020 Some(Transmit {
-2021 destination: network_path.remote,
-2022 size: buf.len(),
-2023 ecn: None,
-2024 segment_size: None,
-2025 src_ip: network_path.local_ip,
-2026 })
-2027 }
-2028
-2029 fn send_off_path_path_response(
-2030 &mut self,
-2031 now: Instant,
-2032 buf: &mut Vec<u8>,
-2033 path_id: PathId,
-2034 ) -> Option<Transmit> {
-2035 let network_path = self
-2036 .paths
-2037 .get_mut(&path_id)
-2038 .map(|state| state.data.network_path)?;
-2039 let cid_queue = self.remote_cids.get_mut(&path_id)?;
-2040 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
-2041 let (token, network_path) = pns.pending_path_responses.pop_off_path(network_path)?;
-2042
-2043 // TODO: make off-path probes unlinkable.
-2044 let cid = cid_queue.active();
-2045
-2046 // PATH_RESPONSE (off-path)
-2047 let frame = frame::PathResponse(token);
-2048
-2049 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
-2050 buf.start_new_datagram();
-2051
-2052 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, buf, self)?;
-2053 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
-2054 builder.write_frame_with_log_msg(frame, stats, Some("(off-path)"));
-2055
-2056 // PATH_CHALLENGE (off-path)
-2057 //
-2058 // If we are a client doing NAT traversal, always include a PATH_CHALLENGE with any
-2059 // off-path PATH_RESPONSE. No need to schedule any retries for this, if NAT
-2060 // traversal is taking place then this remote already is being probed with
-2061 // retries, this only speeds up a successful traversal.
-2062 if self
-2063 .find_validated_path_on_network_path(network_path)
-2064 .is_none()
-2065 && self.n0_nat_traversal.client_side().is_ok()
-2066 {
-2067 let token = self.rng.random();
-2068 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
-2069 builder.write_frame(frame::PathChallenge(token), stats);
-2070 let ip_port = (network_path.remote.ip(), network_path.remote.port());
-2071 self.n0_nat_traversal.mark_probe_sent(ip_port, token);
-2072 }
-2073
-2074 // Off-path: not tracked in congestion control. The packet is sent to a
-2075 // different destination than path_id's network path.
-2076 builder.pad_to(MIN_INITIAL_SIZE);
-2077 builder.finish(self, now);
-2078
-2079 let size = buf.len();
-2080 self.path_stats.for_path(path_id).udp_tx.on_sent(1, size);
-2081
-2082 trace!(
-2083 dst = ?network_path.remote,
-2084 src = ?network_path.local_ip,
-2085 len = buf.len(),
-2086 "sending off-path PATH_RESPONSE",
-2087 );
-2088 Some(Transmit {
-2089 destination: network_path.remote,
-2090 size,
-2091 ecn: None,
-2092 segment_size: None,
-2093 src_ip: network_path.local_ip,
-2094 })
-2095 }
-2096
-2097 /// Send a nat traversal challenge (off-path) on this path if possible.
-2098 fn send_nat_traversal_path_challenge(
-2099 &mut self,
-2100 now: Instant,
-2101 buf: &mut Vec<u8>,
-2102 path_id: PathId,
-2103 ) -> Option<Transmit> {
-2104 let remote = self.n0_nat_traversal.next_probe_addr()?;
-2105
-2106 if !self.paths.get(&path_id)?.data.validated {
-2107 // Path is not usable for probing
-2108 return None;
-2109 }
-2110
-2111 // TODO: Using the active CID here makes the paths linkable. This is a violation of
-2112 // RFC9000 but something we want to accept in the short term. Eventually we aim
-2113 // to fix up the supply of CIDs sufficiently so that we can keep paths unlinkable
-2114 // again.
-2115 let Some(cid) = self
-2116 .remote_cids
-2117 .get(&path_id)
-2118 .map(|cid_queue| cid_queue.active())
-2119 else {
-2120 trace!(%path_id, "Not sending NAT traversal probe for path with no CIDs");
-2121 return None;
-2122 };
-2123 let token = self.rng.random();
-2124
-2125 // PATH_CHALLENGE (NAT probe)
-2126 let frame = frame::PathChallenge(token);
-2127
-2128 let mut buf = TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
-2129 buf.start_new_datagram();
-2130
-2131 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, &mut buf, self)?;
-2132 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
-2133 builder.write_frame_with_log_msg(frame, stats, Some("(nat-traversal)"));
-2134 // Off-path: not tracked in congestion control. The packet is sent to a
-2135 // different destination than path_id's network path.
-2136 builder.finish(self, now);
-2137
-2138 // Mark as sent after packet build succeeds.
-2139 self.n0_nat_traversal.mark_probe_sent(remote, token);
-2140
-2141 let size = buf.len();
-2142 self.path_stats.for_path(path_id).udp_tx.on_sent(1, size);
-2143
-2144 trace!(dst = ?remote, len = buf.len(), "sending off-path NAT probe");
-2145 Some(Transmit {
-2146 destination: remote.into(),
-2147 size,
-2148 ecn: None,
-2149 segment_size: None,
-2150 src_ip: None,
-2151 })
-2152 }
-2153
-2154 /// Indicate what types of frames are ready to send for the given packet number space.
-2155 ///
-2156 /// Only for on-path data.
-2157 ///
-2158 /// *packet_size* is the number of bytes available to build the next packet.
-2159 /// *connection_close_pending* indicates whether a CONNECTION_CLOSE frame needs to be
-2160 /// sent.
-2161 fn space_can_send(
-2162 &mut self,
-2163 space_id: SpaceId,
-2164 path_id: PathId,
-2165 packet_size: usize,
-2166 connection_close_pending: bool,
-2167 ) -> SendableFrames {
-2168 let space = &mut self.spaces[space_id];
-2169 let space_has_crypto = self.crypto_state.has_keys(space_id.encryption_level());
-2170
-2171 if !space_has_crypto
-2172 && (space_id != SpaceId::Data
-2173 || !self.crypto_state.has_keys(EncryptionLevel::ZeroRtt)
-2174 || self.side.is_server())
-2175 {
-2176 // Nothing to send in this space
-2177 return SendableFrames::empty();
-2178 }
-2179
-2180 let mut can_send = space.can_send(path_id, &self.streams);
-2181
-2182 // Check for 1RTT space.
-2183 if space_id == SpaceId::Data {
-2184 let pn = space.for_path(path_id).peek_tx_number();
-2185 // Number of bytes available for frames if this is a 1-RTT packet. We're
-2186 // guaranteed to be able to send an individual frame at least this large in the
-2187 // next 1-RTT packet. This could be generalized to support every space, but it's
-2188 // only needed to handle large fixed-size frames, which only exist in 1-RTT
-2189 // (application datagrams).
-2190 let frame_space_1rtt =
-2191 packet_size.saturating_sub(self.predict_1rtt_overhead(pn, path_id));
-2192 can_send |= self.can_send_1rtt(path_id, frame_space_1rtt);
-2193 }
-2194
-2195 can_send.close = connection_close_pending && space_has_crypto;
-2196
-2197 can_send
-2198 }
-2199
-2200 /// Process `ConnectionEvent`s generated by the associated `Endpoint`
-2201 ///
-2202 /// Will execute protocol logic upon receipt of a connection event, in turn preparing signals
-2203 /// (including application `Event`s, `EndpointEvent`s and outgoing datagrams) that should be
-2204 /// extracted through the relevant methods.
-2205 pub fn handle_event(&mut self, event: ConnectionEvent) {
-2206 use ConnectionEventInner::*;
-2207 match event.0 {
-2208 Datagram(DatagramConnectionEvent {
-2209 now,
-2210 network_path,
-2211 path_id,
-2212 ecn,
-2213 first_decode,
-2214 remaining,
-2215 }) => {
-2216 let span = trace_span!("pkt", %path_id);
-2217 let _guard = span.enter();
-2218
-2219 if self.early_discard_packet(network_path, path_id) {
-2220 // A return value of true indicates we should discard this packet.
-2221 return;
-2222 }
-2223
-2224 let was_anti_amplification_blocked = self
-2225 .path(path_id)
-2226 .map(|path| path.anti_amplification_blocked(1))
-2227 // We never tried to send on an non-existing (new) path so have not been
-2228 // anti-amplification blocked for it previously.
-2229 .unwrap_or(false);
-2230
-2231 let rx = &mut self.path_stats.for_path(path_id).udp_rx;
-2232 rx.datagrams += 1;
-2233 rx.bytes += first_decode.len() as u64;
-2234 let data_len = first_decode.len();
-2235
-2236 self.handle_decode(now, network_path, path_id, ecn, first_decode);
-2237 // The current `path` might have changed inside `handle_decode` since the packet
-2238 // could have triggered a migration. The packet might also belong to an unknown
-2239 // path and have been rejected. Make sure the data received is accounted for the
-2240 // most recent path by accessing `path` after `handle_decode`.
-2241 if let Some(path) = self.path_mut(path_id) {
-2242 path.inc_total_recvd(data_len as u64);
-2243 }
-2244
-2245 if let Some(data) = remaining {
-2246 self.path_stats.for_path(path_id).udp_rx.bytes += data.len() as u64;
-2247 self.handle_coalesced(now, network_path, path_id, ecn, data);
-2248 }
-2249
-2250 if let Some(path) = self.paths.get_mut(&path_id) {
-2251 self.qlog
-2252 .emit_recovery_metrics(path_id, &mut path.data, now);
-2253 }
-2254
-2255 if was_anti_amplification_blocked {
-2256 // A prior attempt to set the loss detection timer may have failed due to
-2257 // anti-amplification, so ensure it's set now. Prevents a handshake deadlock if
-2258 // the server's first flight is lost.
-2259 self.set_loss_detection_timer(now, path_id);
-2260 }
-2261 }
-2262 NewIdentifiers(ids, now, cid_len, cid_lifetime) => {
-2263 let path_id = ids.first().map(|issued| issued.path_id).unwrap_or_default();
-2264 debug_assert!(ids.iter().all(|issued| issued.path_id == path_id));
-2265
-2266 // Path may have been abandoned while this reply was in flight,
-2267 // retire the CIDs instead of queuing them.
-2268 if self.abandoned_paths.contains(&path_id) {
-2269 if !self.state.is_drained() {
-2270 for issued in &ids {
-2271 self.endpoint_events
-2272 .push_back(EndpointEventInner::RetireConnectionId(
-2273 now,
-2274 path_id,
-2275 issued.sequence,
-2276 false,
-2277 ));
-2278 }
-2279 }
-2280 return;
-2281 }
-2282
-2283 let cid_state = self
-2284 .local_cid_state
-2285 .entry(path_id)
-2286 .or_insert_with(|| CidState::new(cid_len, cid_lifetime, now, 0));
-2287 cid_state.new_cids(&ids, now);
-2288
-2289 ids.into_iter().rev().for_each(|frame| {
-2290 self.spaces[SpaceId::Data].pending.new_cids.push(frame);
-2291 });
-2292 // Always update Timer::PushNewCid
-2293 self.reset_cid_retirement(now);
-2294 }
-2295 }
-2296 }
-2297
-2298 /// Returns whether a packet can be discarded early.
-2299 ///
-2300 /// Packets sent on the wrong network path can be entirely ignored, saving further
-2301 /// processing.
-2302 ///
-2303 /// Returns true if a packet coming in for this `path_id` over given `network_path`
-2304 /// should be discarded.
-2305 fn early_discard_packet(&mut self, network_path: FourTuple, path_id: PathId) -> bool {
-2306 if self.is_handshaking() && path_id != PathId::ZERO {
-2307 debug!(%network_path, %path_id, "discarding multipath packet during handshake");
-2308 return true;
-2309 }
-2310
-2311 let peer_may_probe = self.peer_may_probe();
-2312 let local_ip_may_migrate = self.local_ip_may_migrate();
-2313
-2314 // If this packet could initiate a migration and we're a client or a server that
-2315 // forbids migration, drop the datagram. This could be relaxed to heuristically
-2316 // permit NAT-rebinding-like migration.
-2317 if let Some(known_path) = self.path_mut(path_id) {
-2318 if network_path.remote != known_path.network_path.remote && !peer_may_probe {
-2319 trace!(
-2320 %path_id,
-2321 %network_path,
-2322 %known_path.network_path,
-2323 "discarding packet from unrecognized peer"
-2324 );
-2325 return true;
-2326 }
-2327
-2328 if known_path.network_path.local_ip.is_some()
-2329 && network_path.local_ip.is_some()
-2330 && known_path.network_path.local_ip != network_path.local_ip
-2331 && !local_ip_may_migrate
-2332 {
-2333 trace!(
-2334 %path_id,
-2335 %network_path,
-2336 %known_path.network_path,
-2337 "discarding packet sent to incorrect interface"
-2338 );
-2339 return true;
-2340 }
-2341 }
-2342 false
-2343 }
-2344
-2345 /// Whether the peer may probe new paths.
-2346 ///
-2347 /// RFC9000 §9 and QNT both have probing packets which may arrive from new paths. This
-2348 /// indicates whether these are allowed or not. This is a strict superset from
-2349 /// [`Self::peer_may_migrate`]: every network path that may be migrated to, may also
-2350 /// be probed. But e.g. servers may not migrate, but can be allowed to probe.
-2351 // TODO(flub): In RFC9000 the server is allowed to send off-path probing packets
-2352 // once the client has been probing such a 4-tuple. These probes are currently
-2353 // not yet recognised and will end up being discarded because of this.
-2354 // See https://github.com/n0-computer/noq/issues/607.
-2355 fn peer_may_probe(&self) -> bool {
-2356 match &self.side {
-2357 ConnectionSide::Client { .. } => {
-2358 if let Some(hs) = self.state.as_handshake() {
-2359 hs.allow_server_migration
-2360 } else {
-2361 self.n0_nat_traversal.is_negotiated() && self.is_handshake_confirmed()
-2362 }
-2363 }
-2364 ConnectionSide::Server { server_config } => {
-2365 self.is_handshake_confirmed()
-2366 && (server_config.migration || self.n0_nat_traversal.is_negotiated())
-2367 }
-2368 }
-2369 }
-2370
-2371 /// Whether the peer's remote address may migrate.
-2372 ///
-2373 /// In RFC9000 only the client may migrate.
-2374 ///
-2375 /// QUIC relies on stable endpoints during the handshake. So other than the server's
-2376 /// preferred_address transport parameter no side may migrate before the handshake is
-2377 /// completed.
-2378 ///
-2379 /// It is noteworthy that for iroh we allow server migrations during the handshake when
-2380 /// [`state::Handshake::allow_server_migration`] is enabled, but that is handled earlier
-2381 /// in [`Self::handle_packet`] and without probing the current and previous paths.
-2382 fn peer_may_migrate(&self) -> bool {
-2383 match &self.side {
-2384 ConnectionSide::Server { server_config } => {
-2385 server_config.migration && self.is_handshake_confirmed()
-2386 }
-2387 ConnectionSide::Client { .. } => false,
-2388 }
-2389 }
-2390
-2391 /// Whether our local IP address is allowed to change with new incoming packets.
-2392 ///
-2393 /// Incoming packets show us the local IP address we received a packet on, which could
-2394 /// be different from what we thought due to e.g. NAT rebinding or moving from mobile
-2395 /// data to WiFi without being notified of the network change.
-2396 ///
-2397 /// This is only allowed to happen after the handshake is confirmed and when we are the
-2398 /// client. Unless QNT is negotiated in which case the server is also allowed to
-2399 /// migrate.
-2400 ///
-2401 /// Be aware that probing packets, which do not exist in Multipath without QNT, are
-2402 /// exempt from this.
-2403 fn local_ip_may_migrate(&self) -> bool {
-2404 (self.side.is_client() || self.n0_nat_traversal.is_negotiated())
-2405 && self.is_handshake_confirmed()
-2406 }
-2407 /// Process timer expirations
-2408 ///
-2409 /// Executes protocol logic, potentially preparing signals (including application `Event`s,
-2410 /// `EndpointEvent`s and outgoing datagrams) that should be extracted through the relevant
-2411 /// methods.
-2412 ///
-2413 /// It is most efficient to call this immediately after the system clock reaches the latest
-2414 /// `Instant` that was output by `poll_timeout`; however spurious extra calls will simply
-2415 /// no-op and therefore are safe.
-2416 pub fn handle_timeout(&mut self, now: Instant) {
-2417 while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) {
-2418 let span = match timer {
-2419 Timer::Conn(timer) => trace_span!("timeout", scope = "conn", ?timer),
-2420 Timer::PerPath(path_id, timer) => {
-2421 trace_span!("timer_fired", scope="path", %path_id, ?timer)
-2422 }
-2423 };
-2424 let _guard = span.enter();
-2425 trace!("timeout");
-2426 match timer {
-2427 Timer::Conn(timer) => match timer {
-2428 ConnTimer::Close => {
-2429 let was_draining = self.state.move_to_drained(None);
-2430 if !was_draining {
-2431 self.endpoint_events.push_back(EndpointEventInner::Draining);
-2432 }
-2433 // move_to_drained checks that we weren't in drained before.
-2434 // Adding events to endpoint_events is only legal if `Drained` was never queued before.
-2435 self.endpoint_events.push_back(EndpointEventInner::Drained);
-2436 }
-2437 ConnTimer::Idle => {
-2438 self.kill(ConnectionError::TimedOut);
-2439 }
-2440 ConnTimer::KeepAlive => {
-2441 self.ping();
-2442 }
-2443 ConnTimer::KeyDiscard => {
-2444 self.crypto_state.discard_temporary_keys();
-2445 }
-2446 ConnTimer::PushNewCid => {
-2447 while let Some((path_id, when)) = self.next_cid_retirement() {
-2448 if when > now {
-2449 break;
-2450 }
-2451 match self.local_cid_state.get_mut(&path_id) {
-2452 None => error!(%path_id, "No local CID state for path"),
-2453 Some(cid_state) => {
-2454 // Update `retire_prior_to` field in NEW_CONNECTION_ID frame
-2455 let num_new_cid = cid_state.on_cid_timeout().into();
-2456 if !self.state.is_closed() {
-2457 trace!(
-2458 "push a new CID to peer RETIRE_PRIOR_TO field {}",
-2459 cid_state.retire_prior_to()
-2460 );
-2461 self.endpoint_events.push_back(
-2462 EndpointEventInner::NeedIdentifiers(
-2463 path_id,
-2464 now,
-2465 num_new_cid,
-2466 ),
-2467 );
-2468 }
-2469 }
-2470 }
-2471 }
-2472 }
-2473 ConnTimer::NoAvailablePath => {
-2474 // Grace period expired: all paths were abandoned and no new path
-2475 // was opened. Close the connection. There are no paths left to
-2476 // send CONNECTION_CLOSE on, so this is a silent close.
-2477 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4-8
-2478 if self.state.is_closed() || self.state.is_drained() {
-2479 // Connection already closing/drained (e.g. application called
-2480 // close() before the grace timer fired). Nothing to do.
-2481 error!("no viable path timer fired, but connection already closing");
-2482 } else {
-2483 trace!("no viable path grace period expired, closing connection");
-2484 let err = TransportError::NO_VIABLE_PATH(
-2485 "last path abandoned, no new path opened",
-2486 );
-2487 self.close_common();
-2488 self.set_close_timer(now);
-2489 self.connection_close_pending = true;
-2490 self.state.move_to_closed(err);
-2491 }
-2492 }
-2493 ConnTimer::NatTraversalProbeRetry => {
-2494 self.n0_nat_traversal.queue_retries(self.is_ipv6());
-2495 if let Some(delay) =
-2496 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
-2497 {
-2498 self.timers.set(
-2499 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
-2500 now + delay,
-2501 self.qlog.with_time(now),
-2502 );
-2503 trace!("re-queued NAT probes");
-2504 } else {
-2505 trace!("no more NAT probes remaining");
-2506 }
-2507 }
-2508 },
-2509 Timer::PerPath(path_id, timer) => {
-2510 match timer {
-2511 PathTimer::PathIdle => {
-2512 if let Err(err) =
-2513 self.close_path_inner(now, path_id, PathAbandonReason::TimedOut)
-2514 {
-2515 warn!(?err, "failed closing path");
-2516 }
-2517 }
-2518
-2519 PathTimer::PathKeepAlive => {
-2520 self.ping_path(path_id).ok();
-2521 }
-2522 PathTimer::LossDetection => {
-2523 self.on_loss_detection_timeout(now, path_id);
-2524 if let Some(path) = self.paths.get_mut(&path_id) {
-2525 self.qlog
-2526 .emit_recovery_metrics(path_id, &mut path.data, now);
-2527 } else {
-2528 error!("LossDetection fired for unknown path");
-2529 }
-2530 }
-2531 PathTimer::PathValidationFailed => {
-2532 let Some(path) = self.paths.get_mut(&path_id) else {
-2533 continue;
-2534 };
-2535 self.timers.stop(
-2536 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
-2537 self.qlog.with_time(now),
-2538 );
-2539 debug!("path migration validation failed");
-2540 if let Some((_, prev)) = path.prev.take() {
-2541 path.data = prev;
-2542 }
-2543 path.data.reset_on_path_challenges();
-2544 }
-2545 PathTimer::PathChallengeLost => {
-2546 let Some(path) = self.paths.get_mut(&path_id) else {
-2547 continue;
-2548 };
-2549 trace!(?path.data.lost_challenge_count, "path challenge deemed lost");
-2550 path.data.pending_challenge = true;
-2551 path.data.lost_challenge_count += 1;
-2552 self.timers.set(
-2553 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
-2554 now + path.data.on_path_challenge_expiry(),
-2555 self.qlog.with_time(now),
-2556 );
-2557 }
-2558 PathTimer::AbandonFromValidation => {
-2559 let Some(path) = self.paths.get_mut(&path_id) else {
-2560 continue;
-2561 };
-2562 path.data.reset_on_path_challenges();
-2563 self.timers.stop(
-2564 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
-2565 self.qlog.with_time(now),
-2566 );
-2567 debug!("new path validation failed");
-2568 if let Err(err) = self.close_path_inner(
-2569 now,
-2570 path_id,
-2571 PathAbandonReason::ValidationFailed,
-2572 ) {
-2573 warn!(?err, "failed closing path");
-2574 }
-2575 }
-2576 PathTimer::Pacing => {}
-2577 PathTimer::MaxAckDelay => {
-2578 // This timer is only armed in the Data space
-2579 self.spaces[SpaceId::Data]
-2580 .for_path(path_id)
-2581 .pending_acks
-2582 .on_max_ack_delay_timeout()
-2583 }
-2584 PathTimer::PathDrained => {
-2585 // The path was abandoned and 3*PTO has expired since. Clean up all
-2586 // remaining state and install stateless reset token.
-2587 self.timers.stop_per_path(path_id, self.qlog.with_time(now));
-2588 if let Some(local_cid_state) = self.local_cid_state.remove(&path_id) {
-2589 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events. All timers should be cleared in drained connections.
-2590 let (min_seq, max_seq) = local_cid_state.active_seq();
-2591 for seq in min_seq..=max_seq {
-2592 self.endpoint_events.push_back(
-2593 EndpointEventInner::RetireConnectionId(
-2594 now, path_id, seq, false,
-2595 ),
-2596 );
-2597 }
-2598 }
-2599 self.discard_path(path_id, now);
-2600 }
-2601 }
-2602 }
-2603 }
-2604 }
-2605 }
-2606
-2607 /// Close a connection immediately
-2608 ///
-2609 /// This does not ensure delivery of outstanding data. It is the application's responsibility to
-2610 /// call this only when all important communications have been completed, e.g. by calling
-2611 /// [`SendStream::finish`] on outstanding streams and waiting for the corresponding
-2612 /// [`StreamEvent::Finished`] event.
-2613 ///
-2614 /// If [`Streams::send_streams`] returns 0, all outstanding stream data has been
-2615 /// delivered. There may still be data from the peer that has not been received.
-2616 ///
-2617 /// [`StreamEvent::Finished`]: crate::StreamEvent::Finished
-2618 pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) {
-2619 self.close_inner(
-2620 now,
-2621 Close::Application(frame::ApplicationClose { error_code, reason }),
-2622 )
-2623 }
-2624
-2625 /// Close the connection immediately, initiated by an API call.
-2626 ///
-2627 /// This will not produce a [`ConnectionLost`] event propagated by the
-2628 /// [`Connection::poll`] call, because the API call already propagated the error to the
-2629 /// user.
-2630 ///
-2631 /// Not to be used when entering immediate close due to an internal state change based
-2632 /// on an event. See [`State::move_to_closed_local`] for details.
-2633 ///
-2634 /// This initiates immediate close from
-2635 /// <https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2>, moving to the closed
-2636 /// state.
-2637 ///
-2638 /// [`ConnectionLost`]: crate::Event::ConnectionLost
-2639 /// [`Connection::poll`]: super::Connection::poll
-2640 fn close_inner(&mut self, now: Instant, reason: Close) {
-2641 let was_closed = self.state.is_closed();
-2642 if !was_closed {
-2643 self.close_common();
-2644 self.set_close_timer(now);
-2645 self.connection_close_pending = true;
-2646 self.state.move_to_closed_local(reason);
-2647 }
-2648 }
-2649
-2650 /// Control datagrams
-2651 pub fn datagrams(&mut self) -> Datagrams<'_> {
-2652 Datagrams { conn: self }
-2653 }
-2654
-2655 /// Returns connection statistics
-2656 pub fn stats(&mut self) -> ConnectionStats {
-2657 let mut stats = self.partial_stats.clone();
-2658
-2659 for path_stats in self.path_stats.iter_stats() {
-2660 // Self::path_stats() computes the path rtt, cwnd and current_mtu on access
-2661 // because they are not simple counters. When computing the connection stats we
-2662 // can skip that effort since those fields are not used in the `impl
-2663 // Add<PathStats> for ConnectionStats`.
-2664 stats += *path_stats;
-2665 }
-2666
-2667 stats
-2668 }
-2669
-2670 /// Returns path statistics
-2671 pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> {
-2672 let path = self.paths.get(&path_id)?;
-2673 let stats = self.path_stats.for_path(path_id);
-2674 stats.rtt = path.data.rtt.get();
-2675 stats.cwnd = path.data.congestion.window();
-2676 stats.current_mtu = path.data.mtud.current_mtu();
-2677 Some(*stats)
-2678 }
-2679
-2680 /// Ping the remote endpoint
-2681 ///
-2682 /// Causes an ACK-eliciting packet to be transmitted on the connection.
-2683 pub fn ping(&mut self) {
-2684 // TODO(flub): This is very brute-force: it pings *all* the paths. Instead it would
-2685 // be nice if we could only send a single packet for this.
-2686 for path_data in self.spaces[self.highest_space].number_spaces.values_mut() {
-2687 path_data.pending_ping = true;
-2688 }
-2689 }
-2690
-2691 /// Ping the remote endpoint over a specific path
-2692 ///
-2693 /// Causes an ACK-eliciting packet to be transmitted on the path.
-2694 pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> {
-2695 let path_data = self.spaces[self.highest_space]
-2696 .number_spaces
-2697 .get_mut(&path)
-2698 .ok_or(ClosedPath { _private: () })?;
-2699 path_data.pending_ping = true;
-2700 Ok(())
-2701 }
-2702
-2703 /// Update traffic keys spontaneously
-2704 ///
-2705 /// This can be useful for testing key updates, as they otherwise only happen infrequently.
-2706 pub fn force_key_update(&mut self) {
-2707 if !self.state.is_established() {
-2708 debug!("ignoring forced key update in illegal state");
-2709 return;
-2710 }
-2711 if self.crypto_state.prev_crypto.is_some() {
-2712 // We already just updated, or are currently updating, the keys. Concurrent key updates
-2713 // are illegal.
-2714 debug!("ignoring redundant forced key update");
-2715 return;
-2716 }
-2717 self.crypto_state.update_keys(None, false);
-2718 }
-2719
-2720 /// Get a session reference
-2721 pub fn crypto_session(&self) -> &dyn crypto::Session {
-2722 self.crypto_state.session.as_ref()
-2723 }
-2724
-2725 /// Whether the connection is in the process of being established
-2726 ///
-2727 /// If this returns `false`, the connection may be either established or closed, signaled by the
-2728 /// emission of a [`Connected`](Event::Connected) or [`ConnectionLost`](Event::ConnectionLost)
-2729 /// event respectively. Note that locally-initiated closes via [`close()`](Self::close) do not
-2730 /// emit a `ConnectionLost` event.
-2731 ///
-2732 /// For an established connection this essentially means the handshake is **completed**,
-2733 /// but not necessarily yet confirmed.
-2734 pub fn is_handshaking(&self) -> bool {
-2735 self.state.is_handshake()
-2736 }
-2737
-2738 /// Whether the connection is closed
-2739 ///
-2740 /// Closed connections cannot transport any further data. A connection becomes closed when
-2741 /// either peer application intentionally closes it, or when either transport layer detects an
-2742 /// error such as a time-out or certificate validation failure.
-2743 ///
-2744 /// A [`ConnectionLost`](Event::ConnectionLost) event is emitted with details when the
-2745 /// connection is closed by the peer or due to an error. When the local application closes
-2746 /// the connection via [`close()`](Self::close), no `ConnectionLost` event is emitted;
-2747 /// instead, pending operations fail with [`ConnectionError::LocallyClosed`].
-2748 pub fn is_closed(&self) -> bool {
-2749 self.state.is_closed()
-2750 }
-2751
-2752 /// Whether there is no longer any need to keep the connection around
-2753 ///
-2754 /// Closed connections become drained after a brief timeout to absorb any remaining in-flight
-2755 /// packets from the peer. All drained connections have been closed.
-2756 pub fn is_drained(&self) -> bool {
-2757 self.state.is_drained()
-2758 }
-2759
-2760 /// For clients, if the peer accepted the 0-RTT data packets
-2761 ///
-2762 /// The value is meaningless until after the handshake completes.
-2763 pub fn accepted_0rtt(&self) -> bool {
-2764 self.crypto_state.accepted_0rtt
-2765 }
-2766
-2767 /// Whether 0-RTT is/was possible during the handshake
-2768 pub fn has_0rtt(&self) -> bool {
-2769 self.crypto_state.zero_rtt_enabled
-2770 }
-2771
-2772 /// Whether there are any pending retransmits
-2773 pub fn has_pending_retransmits(&self) -> bool {
-2774 !self.spaces[SpaceId::Data].pending.is_empty(&self.streams)
-2775 }
-2776
-2777 /// Look up whether we're the client or server of this Connection
-2778 pub fn side(&self) -> Side {
-2779 self.side.side()
-2780 }
-2781
-2782 /// Get the address observed by the remote over the given path
-2783 pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> {
-2784 self.path(path_id)
-2785 .map(|path_data| {
-2786 path_data
-2787 .last_observed_addr_report
-2788 .as_ref()
-2789 .map(|observed| observed.socket_addr())
-2790 })
-2791 .ok_or(ClosedPath { _private: () })
-2792 }
-2793
-2794 /// Current best estimate of this connection's latency (round-trip-time)
-2795 pub fn rtt(&self, path_id: PathId) -> Option<Duration> {
-2796 self.path(path_id).map(|d| d.rtt.get())
-2797 }
-2798
-2799 /// Current state of this connection's congestion controller, for debugging purposes
-2800 pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> {
-2801 self.path(path_id).map(|d| d.congestion.as_ref())
-2802 }
-2803
-2804 /// Modify the number of remotely initiated streams that may be concurrently open
-2805 ///
-2806 /// No streams may be opened by the peer unless fewer than `count` are already open. Large
-2807 /// `count`s increase both minimum and worst-case memory consumption.
-2808 pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) {
-2809 self.streams.set_max_concurrent(dir, count);
-2810 // If the limit was reduced, then a flow control update previously deemed insignificant may
-2811 // now be significant.
-2812 let pending = &mut self.spaces[SpaceId::Data].pending;
-2813 self.streams.queue_max_stream_id(pending);
-2814 }
-2815
-2816 /// Modify the number of open paths allowed when multipath is enabled
-2817 ///
-2818 /// When reducing the number of concurrent paths this will only affect delaying sending
-2819 /// new MAX_PATH_ID frames until fewer than this number of paths are possible. To
-2820 /// actively reduce paths they must be closed using [`Connection::close_path`], which
-2821 /// can also be used to close not-yet-opened paths.
-2822 ///
-2823 /// If multipath is not negotiated (see the [`TransportConfig`]) this can not enable
-2824 /// multipath and will fail.
-2825 pub fn set_max_concurrent_paths(
-2826 &mut self,
-2827 now: Instant,
-2828 count: NonZeroU32,
-2829 ) -> Result<(), MultipathNotNegotiated> {
-2830 if !self.is_multipath_negotiated() {
-2831 return Err(MultipathNotNegotiated { _private: () });
-2832 }
-2833 self.max_concurrent_paths = count;
-2834
-2835 let in_use_count = self
-2836 .local_max_path_id
-2837 .next()
-2838 .saturating_sub(self.abandoned_paths.len())
-2839 .as_u32();
-2840 let extra_needed = count.get().saturating_sub(in_use_count);
-2841 let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed);
-2842
-2843 self.set_max_path_id(now, new_max_path_id);
-2844
-2845 Ok(())
-2846 }
-2847
-2848 /// If needed, issues a new MAX_PATH_ID frame and new CIDs for any newly allowed paths
-2849 fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) {
-2850 if max_path_id <= self.local_max_path_id {
-2851 return;
-2852 }
-2853
-2854 self.local_max_path_id = max_path_id;
-2855 self.spaces[SpaceId::Data].pending.max_path_id = true;
-2856
-2857 self.issue_first_path_cids(now);
-2858 }
-2859
-2860 /// Current number of remotely initiated streams that may be concurrently open
-2861 ///
-2862 /// If the target for this limit is reduced using [`set_max_concurrent_streams`](Self::set_max_concurrent_streams),
-2863 /// it will not change immediately, even if fewer streams are open. Instead, it will
-2864 /// decrement by one for each time a remotely initiated stream of matching directionality is closed.
-2865 pub fn max_concurrent_streams(&self, dir: Dir) -> u64 {
-2866 self.streams.max_concurrent(dir)
-2867 }
-2868
-2869 /// See [`TransportConfig::send_window()`]
-2870 pub fn set_send_window(&mut self, send_window: u64) {
-2871 self.streams.set_send_window(send_window);
-2872 }
-2873
-2874 /// See [`TransportConfig::receive_window()`]
-2875 pub fn set_receive_window(&mut self, receive_window: VarInt) {
-2876 if self.streams.set_receive_window(receive_window) {
-2877 self.spaces[SpaceId::Data].pending.max_data = true;
-2878 }
-2879 }
-2880
-2881 /// Whether the Multipath for QUIC extension is enabled.
-2882 ///
-2883 /// Multipath is only enabled after the handshake is completed and if it was enabled by both
-2884 /// peers.
-2885 pub fn is_multipath_negotiated(&self) -> bool {
-2886 !self.is_handshaking()
-2887 && self.config.max_concurrent_multipath_paths.is_some()
-2888 && self.peer_params.initial_max_path_id.is_some()
-2889 }
-2890
-2891 fn on_ack_received(
-2892 &mut self,
-2893 now: Instant,
-2894 space: SpaceId,
-2895 ack: frame::Ack,
-2896 ) -> Result<(), TransportError> {
-2897 // All ACKs are referencing path 0
-2898 let path = PathId::ZERO;
-2899 self.inner_on_ack_received(now, space, path, ack)
-2900 }
-2901
-2902 fn on_path_ack_received(
-2903 &mut self,
-2904 now: Instant,
-2905 space: SpaceId,
-2906 path_ack: frame::PathAck,
-2907 ) -> Result<(), TransportError> {
-2908 let (ack, path) = path_ack.into_ack();
-2909 self.inner_on_ack_received(now, space, path, ack)
-2910 }
-2911
-2912 /// Handles an ACK frame acknowledging packets sent on *path*.
-2913 fn inner_on_ack_received(
-2914 &mut self,
-2915 now: Instant,
-2916 space: SpaceId,
-2917 path: PathId,
-2918 ack: frame::Ack,
-2919 ) -> Result<(), TransportError> {
-2920 if !self.spaces[space].number_spaces.contains_key(&path) {
-2921 if self.abandoned_paths.contains(&path) {
-2922 // See also
-2923 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4.3-3
-2924 // > When an endpoint finally deletes all state associated with the path [...]
-2925 // > PATH_ACK frames received with an abandoned path ID are silently ignored,
-2926 // > as specified in Section 4.
-2927 trace!("silently ignoring PATH_ACK on discarded path");
-2928 return Ok(());
-2929 } else {
-2930 return Err(TransportError::PROTOCOL_VIOLATION(
-2931 "received PATH_ACK with path ID never used",
-2932 ));
-2933 }
-2934 }
-2935 if ack.largest >= self.spaces[space].for_path(path).next_packet_number {
-2936 return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked"));
-2937 }
-2938 // `Some(pn)` if this ACK raised `largest_acked_packet_pn`.
-2939 let new_largest_pn = {
-2940 let space = &mut self.spaces[space].for_path(path);
-2941 if space
-2942 .largest_acked_packet_pn
-2943 .is_none_or(|pn| ack.largest > pn)
-2944 {
-2945 space.largest_acked_packet_pn = Some(ack.largest);
-2946 if let Some(info) = space.sent_packets.get(ack.largest) {
-2947 // This should always succeed, but a misbehaving peer might ACK a packet we
-2948 // haven't sent. At worst, that will result in us spuriously reducing the
-2949 // congestion window.
-2950 space.largest_acked_packet_send_time = info.time_sent;
-2951 }
-2952 Some(ack.largest)
-2953 } else {
-2954 None
-2955 }
-2956 };
-2957
-2958 if self.detect_spurious_loss(&ack, space, path) {
-2959 self.path_stats.for_path(path).spurious_congestion_events += 1;
-2960 self.path_data_mut(path)
-2961 .congestion
-2962 .on_spurious_congestion_event();
-2963 }
-2964
-2965 // Avoid DoS from unreasonably huge ack ranges by filtering out just the new acks.
-2966 let mut newly_acked: ArrayRangeSet = ArrayRangeSet::new();
-2967 for range in ack.iter() {
-2968 self.spaces[space].for_path(path).check_ack(range.clone())?;
-2969 for (pn, _) in self.spaces[space]
-2970 .for_path(path)
-2971 .sent_packets
-2972 .iter_range(range)
-2973 {
-2974 newly_acked.insert_one(pn);
-2975 }
-2976 }
-2977
-2978 if newly_acked.is_empty() {
-2979 return Ok(());
-2980 }
-2981
-2982 let mut ack_eliciting_acked = false;
-2983 for packet in newly_acked.elts() {
-2984 if let Some(info) = self.spaces[space].for_path(path).take(packet) {
-2985 for (acked_path_id, acked_pn) in info.largest_acked.iter() {
-2986 // Assume ACKs for all packets below the largest acknowledged in
-2987 // `packet` have been received. This can cause the peer to spuriously
-2988 // retransmit if some of our earlier ACKs were lost, but allows for
-2989 // simpler state tracking. See discussion at
-2990 // https://www.rfc-editor.org/rfc/rfc9000.html#name-limiting-ranges-by-tracking
-2991 if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) {
-2992 pns.pending_acks.subtract_below(*acked_pn);
-2993 }
-2994 }
-2995 ack_eliciting_acked |= info.ack_eliciting;
-2996
-2997 // Notify MTU discovery that a packet was acked, because it might be an MTU probe
-2998 let path_data = self.path_data_mut(path);
-2999 let mtu_updated = path_data.mtud.on_acked(space.kind(), packet, info.size);
-3000 if mtu_updated {
-3001 path_data
-3002 .congestion
-3003 .on_mtu_update(path_data.mtud.current_mtu());
-3004 }
-3005
-3006 // Notify ack frequency that a packet was acked, because it might contain an ACK_FREQUENCY frame
-3007 self.ack_frequency.on_acked(path, packet);
-3008
-3009 self.on_packet_acked(now, path, packet, info);
-3010 }
-3011 }
-3012
-3013 let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet_pn;
-3014 let path_data = self.path_data_mut(path);
-3015 let app_limited = path_data.app_limited;
-3016 let in_flight = path_data.in_flight.bytes;
-3017
-3018 path_data
-3019 .congestion
-3020 .on_end_acks(now, in_flight, app_limited, largest_ackd);
-3021
-3022 if new_largest_pn.is_some() && ack_eliciting_acked {
-3023 let ack_delay = if space != SpaceId::Data {
-3024 Duration::from_micros(0)
-3025 } else {
-3026 cmp::min(
-3027 self.ack_frequency.peer_max_ack_delay,
-3028 Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0),
-3029 )
-3030 };
-3031 let rtt = now.saturating_duration_since(
-3032 self.spaces[space]
-3033 .for_path(path)
-3034 .largest_acked_packet_send_time,
-3035 );
-3036
-3037 let next_pn = self.spaces[space].for_path(path).next_packet_number;
-3038 let path_data = self.path_data_mut(path);
-3039 // TODO(@divma): should be a method of path, should be contained in a single place
-3040 path_data.rtt.update(ack_delay, rtt);
-3041 if path_data.first_packet_after_rtt_sample.is_none() {
-3042 path_data.first_packet_after_rtt_sample = Some((space.kind(), next_pn));
-3043 }
-3044 }
-3045
-3046 // Must be called before crypto/pto_count are clobbered
-3047 self.detect_lost_packets(now, space, path, true);
-3048
-3049 // If the peer did not complete the handshake address validation the ACK could be
-3050 // spoofed, e.g. in the Initial space. Setting the pto_count back to 0 removes the
-3051 // exponential backoff from the PTO timer and would result in too many tail-loss
-3052 // probes being sent.
-3053 if self.peer_completed_handshake_address_validation() {
-3054 self.path_data_mut(path).pto_count = 0;
-3055 }
-3056
-3057 // Explicit congestion notification
-3058 // TODO(@divma): this code is a good example of logic that should be contained in a single
-3059 // place but it's split between the path data and the packet number space data, we should
-3060 // find a way to make this work without two lookups
-3061 if self.path_data(path).sending_ecn {
-3062 if let Some(ecn) = ack.ecn {
-3063 // We only examine ECN counters from ACKs that we are certain we received in transmit
-3064 // order, allowing us to compute an increase in ECN counts to compare against the number
-3065 // of newly acked packets that remains well-defined in the presence of arbitrary packet
-3066 // reordering.
-3067 if let Some(largest_sent_pn) = new_largest_pn {
-3068 let sent = self.spaces[space]
-3069 .for_path(path)
-3070 .largest_acked_packet_send_time;
-3071 self.process_ecn(
-3072 now,
-3073 space,
-3074 path,
-3075 newly_acked.range_count() as u64,
-3076 ecn,
-3077 sent,
-3078 largest_sent_pn,
-3079 );
-3080 }
-3081 } else {
-3082 // We always start out sending ECN, so any ack that doesn't acknowledge it disables it.
-3083 debug!("ECN not acknowledged by peer");
-3084 self.path_data_mut(path).sending_ecn = false;
-3085 }
-3086 }
-3087
-3088 self.set_loss_detection_timer(now, path);
-3089 Ok(())
-3090 }
-3091
-3092 fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool {
-3093 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
-3094
-3095 if lost_packets.is_empty() {
-3096 return false;
-3097 }
-3098
-3099 for range in ack.iter() {
-3100 let spurious_losses: Vec<u64> = lost_packets
-3101 .iter_range(range.clone())
-3102 .map(|(pn, _info)| pn)
-3103 .collect();
-3104
-3105 for pn in spurious_losses {
-3106 lost_packets.remove(pn);
-3107 }
-3108 }
-3109
-3110 // If this ACK frame acknowledged all deemed lost packets,
-3111 // then we have raised a spurious congestion event in the past.
-3112 // We cannot conclude when there are remaining packets,
-3113 // but future ACK frames might indicate a spurious loss detection.
-3114 lost_packets.is_empty()
-3115 }
-3116
-3117 /// Drain lost packets that we reasonably think will never arrive
-3118 ///
-3119 /// The current criterion is copied from `msquic`:
-3120 /// discard packets that were sent earlier than 2 probe timeouts ago.
-3121 fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) {
-3122 let two_pto = 2 * self.path_data(path).rtt.pto_base();
-3123
-3124 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
-3125 lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto);
-3126 }
-3127
-3128 /// Process a new ECN block from an in-order ACK
-3129 fn process_ecn(
-3130 &mut self,
-3131 now: Instant,
-3132 space: SpaceId,
-3133 path: PathId,
-3134 newly_acked_pn: u64,
-3135 ecn: frame::EcnCounts,
-3136 largest_sent_time: Instant,
-3137 largest_sent_pn: u64,
-3138 ) {
-3139 match self.spaces[space]
-3140 .for_path(path)
-3141 .detect_ecn(newly_acked_pn, ecn)
-3142 {
-3143 Err(e) => {
-3144 debug!("halting ECN due to verification failure: {}", e);
-3145
-3146 self.path_data_mut(path).sending_ecn = false;
-3147 // Wipe out the existing value because it might be garbage and could interfere with
-3148 // future attempts to use ECN on new paths.
-3149 self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO;
-3150 }
-3151 Ok(false) => {}
-3152 Ok(true) => {
-3153 self.path_stats.for_path(path).congestion_events += 1;
-3154 self.path_data_mut(path).congestion.on_congestion_event(
-3155 now,
-3156 largest_sent_time,
-3157 false,
-3158 true,
-3159 0,
-3160 largest_sent_pn,
-3161 );
-3162 }
-3163 }
-3164 }
-3165
-3166 // Not timing-aware, so it's safe to call this for inferred acks, such as arise from
-3167 // high-latency handshakes
-3168 fn on_packet_acked(&mut self, now: Instant, path_id: PathId, pn: u64, info: SentPacket) {
-3169 let path = self.path_data_mut(path_id);
-3170 let app_limited = path.app_limited;
-3171 path.remove_in_flight(&info);
-3172 if info.ack_eliciting && info.path_generation == path.generation() {
-3173 // Only pass ACKs to the congestion controller if it belongs to this exact
-3174 // generation of the path. Otherwise we might be feeding ACKs from the previous
-3175 // 4-tuple into our congestion controller.
-3176 let rtt = path.rtt;
-3177 path.congestion
-3178 .on_ack(now, info.time_sent, info.size.into(), pn, app_limited, &rtt);
-3179 }
-3180
-3181 // Update state for confirmed delivery of frames
-3182 if let Some(retransmits) = info.retransmits.get() {
-3183 for (id, _) in retransmits.reset_stream.iter() {
-3184 self.streams.reset_acked(*id);
-3185 }
-3186 }
-3187
-3188 for frame in info.stream_frames {
-3189 self.streams.received_ack_of(frame);
-3190 }
-3191 }
-3192
-3193 fn set_key_discard_timer(&mut self, now: Instant, space: SpaceKind) {
-3194 let start = if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) {
-3195 now
-3196 } else {
-3197 self.crypto_state
-3198 .prev_crypto
-3199 .as_ref()
-3200 .expect("no previous keys")
-3201 .end_packet
-3202 .as_ref()
-3203 .expect("update not acknowledged yet")
-3204 .1
-3205 };
-3206
-3207 // QUIC-MULTIPATH § 2.5 Key Phase Update Process: use largest PTO of all paths.
-3208 self.timers.set(
-3209 Timer::Conn(ConnTimer::KeyDiscard),
-3210 start + self.max_pto_for_space(space) * 3,
-3211 self.qlog.with_time(now),
-3212 );
-3213 }
-3214
-3215 /// Handle a [`PathTimer::LossDetection`] timeout.
-3216 ///
-3217 /// This timer expires for two reasons:
-3218 /// - An ACK-eliciting packet we sent should be considered lost.
-3219 /// - The PTO may have expired and a tail-loss probe needs to be scheduled.
-3220 ///
-3221 /// The former needs us to schedule re-transmission of the lost data.
-3222 ///
-3223 /// The latter means we have not received an ACK for an ack-eliciting packet we sent
-3224 /// within the PTO time-window. We need to schedule a tail-loss probe, an ack-eliciting
-3225 /// packet, to try and elicit new acknowledgements. These new acknowledgements will
-3226 /// indicate whether the previously sent packets were lost or not.
-3227 fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) {
-3228 if let Some((_, pn_space)) = self.loss_time_and_space(path_id) {
-3229 // Time threshold loss Detection
-3230 self.detect_lost_packets(now, pn_space, path_id, false);
-3231 self.set_loss_detection_timer(now, path_id);
-3232 return;
-3233 }
-3234
-3235 let Some((_, space)) = self.pto_time_and_space(now, path_id) else {
-3236 error!(%path_id, "PTO expired while unset");
-3237 return;
-3238 };
-3239 trace!(
-3240 in_flight = self.path_data(path_id).in_flight.bytes,
-3241 count = self.path_data(path_id).pto_count,
-3242 ?space,
-3243 %path_id,
-3244 "PTO fired"
-3245 );
-3246
-3247 let count = match self.path_data(path_id).in_flight.ack_eliciting {
-3248 // A PTO when we're not expecting any ACKs must be due to handshake
-3249 // anti-amplification deadlock prevention.
-3250 0 => {
-3251 debug_assert!(!self.peer_completed_handshake_address_validation());
-3252 1
-3253 }
-3254 // Conventional loss probe
-3255 _ => 2,
-3256 };
-3257 let pns = self.spaces[space].for_path(path_id);
-3258 pns.loss_probes = pns.loss_probes.saturating_add(count);
-3259 let path_data = self.path_data_mut(path_id);
-3260 path_data.pto_count = path_data.pto_count.saturating_add(1);
-3261 self.set_loss_detection_timer(now, path_id);
-3262 }
-3263
-3264 /// Detect any lost packets
-3265 ///
-3266 /// There are two cases in which we detects lost packets:
-3267 ///
-3268 /// - We received an ACK packet.
-3269 /// - The [`PathTimer::LossDetection`] timer expired. So there is an un-acknowledged packet
-3270 /// that was followed by an acknowledged packet. The loss timer for this
-3271 /// un-acknowledged packet expired and we need to detect that packet as lost.
-3272 ///
-3273 /// Packets are lost if they are both (See RFC9002 §6.1):
-3274 ///
-3275 /// - Unacknowledged, in flight and sent prior to an acknowledged packet.
-3276 /// - Old enough by either:
-3277 /// - Having a packet number [`TransportConfig::packet_threshold`] lower then the last
-3278 /// acknowledged packet.
-3279 /// - Being sent [`TransportConfig::time_threshold`] * RTT in the past.
-3280 fn detect_lost_packets(
-3281 &mut self,
-3282 now: Instant,
-3283 pn_space: SpaceId,
-3284 path_id: PathId,
-3285 due_to_ack: bool,
-3286 ) {
-3287 let mut lost_packets = Vec::<u64>::new();
-3288 let mut lost_mtu_probe = None;
-3289 let mut in_persistent_congestion = false;
-3290 let mut size_of_lost_packets = 0u64;
-3291 self.spaces[pn_space].for_path(path_id).loss_time = None;
-3292
-3293 // Find all the lost packets, populating all variables initialised above.
-3294
-3295 let path = self.path_data(path_id);
-3296 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
-3297 let loss_delay = path
-3298 .rtt
-3299 .conservative()
-3300 .mul_f32(self.config.time_threshold)
-3301 .max(TIMER_GRANULARITY);
-3302 let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample;
-3303
-3304 let largest_acked_packet_pn = self.spaces[pn_space]
-3305 .for_path(path_id)
-3306 .largest_acked_packet_pn
-3307 .expect("detect_lost_packets only to be called if path received at least one ACK");
-3308 let packet_threshold = self.config.packet_threshold as u64;
-3309
-3310 // InPersistentCongestion: Determine if all packets in the time period before the newest
-3311 // lost packet, including the edges, are marked lost. PTO computation must always
-3312 // include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1).
-3313 let congestion_period = self
-3314 .pto(SpaceKind::Data, path_id)
-3315 .saturating_mul(self.config.persistent_congestion_threshold);
-3316 let mut persistent_congestion_start: Option<Instant> = None;
-3317 let mut prev_packet = None;
-3318 let space = self.spaces[pn_space].for_path(path_id);
-3319
-3320 for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet_pn) {
-3321 if prev_packet != Some(packet.wrapping_sub(1)) {
-3322 // An intervening packet was acknowledged
-3323 persistent_congestion_start = None;
-3324 }
-3325
-3326 // Packets sent before now - loss_delay are deemed lost.
-3327 // However, we avoid subtraction as it can panic and there's no
-3328 // saturating equivalent of this subtraction operation with a Duration.
-3329 let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay;
-3330 if packet_too_old || largest_acked_packet_pn >= packet + packet_threshold {
-3331 // The packet should be declared lost.
-3332 if Some(packet) == in_flight_mtu_probe {
-3333 // Lost MTU probes are not included in `lost_packets`, because they
-3334 // should not trigger a congestion control response
-3335 lost_mtu_probe = in_flight_mtu_probe;
-3336 } else {
-3337 lost_packets.push(packet);
-3338 size_of_lost_packets += info.size as u64;
-3339 if info.ack_eliciting && due_to_ack {
-3340 match persistent_congestion_start {
-3341 // Two ACK-eliciting packets lost more than
-3342 // congestion_period apart, with no ACKed packets in between
-3343 Some(start) if info.time_sent - start > congestion_period => {
-3344 in_persistent_congestion = true;
-3345 }
-3346 // Persistent congestion must start after the first RTT sample
-3347 None if first_packet_after_rtt_sample
-3348 .is_some_and(|x| x < (pn_space.kind(), packet)) =>
-3349 {
-3350 persistent_congestion_start = Some(info.time_sent);
-3351 }
-3352 _ => {}
-3353 }
-3354 }
-3355 }
-3356 } else {
-3357 // The packet should not yet be declared lost.
-3358 if space.loss_time.is_none() {
-3359 // Since we iterate in order the lowest packet number's loss time will
-3360 // always be the earliest.
-3361 space.loss_time = Some(info.time_sent + loss_delay);
-3362 }
-3363 persistent_congestion_start = None;
-3364 }
-3365
-3366 prev_packet = Some(packet);
-3367 }
-3368
-3369 self.handle_lost_packets(
-3370 pn_space,
-3371 path_id,
-3372 now,
-3373 lost_packets,
-3374 lost_mtu_probe,
-3375 loss_delay,
-3376 in_persistent_congestion,
-3377 size_of_lost_packets,
-3378 );
-3379 }
-3380
-3381 /// Drops the path state, declaring any remaining in-flight packets as lost
-3382 fn discard_path(&mut self, path_id: PathId, now: Instant) {
-3383 trace!(%path_id, "dropping path state");
-3384 let path = self.path_data(path_id);
-3385 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
-3386
-3387 let mut size_of_lost_packets = 0u64; // add to path_stats.lost_bytes;
-3388 let lost_pns: Vec<_> = self.spaces[SpaceId::Data]
-3389 .for_path(path_id)
-3390 .sent_packets
-3391 .iter()
-3392 .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe)
-3393 .map(|(pn, info)| {
-3394 size_of_lost_packets += info.size as u64;
-3395 pn
-3396 })
-3397 .collect();
-3398
-3399 if !lost_pns.is_empty() {
-3400 trace!(
-3401 %path_id,
-3402 count = lost_pns.len(),
-3403 lost_bytes = size_of_lost_packets,
-3404 "packets lost on path abandon"
-3405 );
-3406 self.handle_lost_packets(
-3407 SpaceId::Data,
-3408 path_id,
-3409 now,
-3410 lost_pns,
-3411 in_flight_mtu_probe,
-3412 Duration::ZERO,
-3413 false,
-3414 size_of_lost_packets,
-3415 );
-3416 }
-3417 // Before removing the path, we fetch the final path stats via `Self::path_stats`.
-3418 // This updates some values for the last time.
-3419 let path_stats = self.path_stats.discard(&path_id);
-3420 self.partial_stats += path_stats;
-3421 self.paths.remove(&path_id);
-3422 self.spaces[SpaceId::Data].number_spaces.remove(&path_id);
-3423
-3424 self.events.push_back(
-3425 PathEvent::Discarded {
-3426 id: path_id,
-3427 path_stats: Box::new(path_stats),
-3428 }
-3429 .into(),
-3430 );
-3431 }
-3432
-3433 fn handle_lost_packets(
-3434 &mut self,
-3435 pn_space: SpaceId,
-3436 path_id: PathId,
-3437 now: Instant,
-3438 lost_packets: Vec<u64>,
-3439 lost_mtu_probe: Option<u64>,
-3440 loss_delay: Duration,
-3441 in_persistent_congestion: bool,
-3442 size_of_lost_packets: u64,
-3443 ) {
-3444 debug_assert!(lost_packets.is_sorted(), "lost_packets must be sorted");
-3445
-3446 self.drain_lost_packets(now, pn_space, path_id);
-3447
-3448 // OnPacketsLost
-3449 if let Some(largest_lost) = lost_packets.last().cloned() {
-3450 let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes;
-3451 let largest_lost_sent = self.spaces[pn_space]
-3452 .for_path(path_id)
-3453 .sent_packets
-3454 .get(largest_lost)
-3455 .unwrap()
-3456 .time_sent;
-3457 let path_stats = self.path_stats.for_path(path_id);
-3458 path_stats.lost_packets += lost_packets.len() as u64;
-3459 path_stats.lost_bytes += size_of_lost_packets;
-3460 trace!(
-3461 %path_id,
-3462 count = lost_packets.len(),
-3463 lost_bytes = size_of_lost_packets,
-3464 "packets lost",
-3465 );
-3466
-3467 for &packet in &lost_packets {
-3468 let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else {
-3469 continue;
-3470 };
-3471 self.qlog
-3472 .emit_packet_lost(packet, &info, loss_delay, pn_space.kind(), now);
-3473 self.paths
-3474 .get_mut(&path_id)
-3475 .unwrap()
-3476 .remove_in_flight(&info);
-3477
-3478 for frame in info.stream_frames {
-3479 self.streams.retransmit(frame);
-3480 }
-3481 self.spaces[pn_space].pending |= info.retransmits;
-3482 let path = self.path_data_mut(path_id);
-3483 path.pending |= info.path_retransmits;
-3484 path.mtud.on_non_probe_lost(packet, info.size);
-3485 path.congestion.on_packet_lost(info.size, packet, now);
-3486
-3487 self.spaces[pn_space].for_path(path_id).lost_packets.insert(
-3488 packet,
-3489 LostPacket {
-3490 time_sent: info.time_sent,
-3491 },
-3492 );
-3493 }
-3494
-3495 let path = self.path_data_mut(path_id);
-3496 if path.mtud.black_hole_detected(now) {
-3497 path.congestion.on_mtu_update(path.mtud.current_mtu());
-3498 if let Some(max_datagram_size) = self.datagrams().max_size()
-3499 && self.datagrams.drop_oversized(max_datagram_size)
-3500 && self.datagrams.send_blocked
-3501 {
-3502 self.datagrams.send_blocked = false;
-3503 self.events.push_back(Event::DatagramsUnblocked);
-3504 }
-3505 self.path_stats.for_path(path_id).black_holes_detected += 1;
-3506 }
-3507
-3508 // Don't apply congestion penalty for lost ack-only packets
-3509 let lost_ack_eliciting =
-3510 old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes;
-3511
-3512 if lost_ack_eliciting {
-3513 self.path_stats.for_path(path_id).congestion_events += 1;
-3514 self.path_data_mut(path_id).congestion.on_congestion_event(
-3515 now,
-3516 largest_lost_sent,
-3517 in_persistent_congestion,
-3518 false,
-3519 size_of_lost_packets,
-3520 largest_lost,
-3521 );
-3522 }
-3523 }
-3524
-3525 // Handle a lost MTU probe
-3526 if let Some(packet) = lost_mtu_probe {
-3527 let info = self.spaces[SpaceId::Data]
-3528 .for_path(path_id)
-3529 .take(packet)
-3530 .unwrap(); // safe: lost_mtu_probe is omitted from lost_packets, and
-3531 // therefore must not have been removed yet
-3532 self.paths
-3533 .get_mut(&path_id)
-3534 .unwrap()
-3535 .remove_in_flight(&info);
-3536 self.path_data_mut(path_id).mtud.on_probe_lost();
-3537 self.path_stats.for_path(path_id).lost_plpmtud_probes += 1;
-3538 }
-3539 }
-3540
-3541 /// Returns the earliest time packets should be declared lost for all spaces on a path.
-3542 ///
-3543 /// If a path has an acknowledged packet with any prior un-acknowledged packets, the
-3544 /// earliest un-acknowledged packet can be declared lost after a timeout has elapsed.
-3545 /// The time returned is when this packet should be declared lost.
-3546 fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> {
-3547 SpaceId::iter()
-3548 .filter_map(|id| {
-3549 self.spaces[id]
-3550 .number_spaces
-3551 .get(&path_id)
-3552 .and_then(|pns| pns.loss_time)
-3553 .map(|time| (time, id))
-3554 })
-3555 .min_by_key(|&(time, _)| time)
-3556 }
-3557
-3558 /// Returns the earliest next PTO should fire for all spaces on a path.
-3559 ///
-3560 /// This needs to be fully deterministic because it is also used to determine the PTO
-3561 /// that fired, not just to set the next timer. So if it fired in the past it needs to
-3562 /// return the time from the past at which it fired.
-3563 ///
-3564 /// This is the next time a tail-loss probe should be sent.
-3565 fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> {
-3566 let path = self.path(path_id)?;
-3567 let pto_count = path.pto_count;
-3568
-3569 // Cap the maximum interval between two tail-loss probes.
-3570 let max_interval = if path.rtt.get() > SLOW_RTT_THRESHOLD {
-3571 // For slow links we want to increase the interval beyond 2s.
-3572 (path.rtt.get() * 3) / 2
-3573 } else if let Some(idle) = path.idle_timeout.or(self.idle_timeout)
-3574 && idle <= MIN_IDLE_FOR_FAST_PTO
-3575 {
-3576 // If the idle timeout is relatively low, cap at 1s so we get plenty of retries
-3577 // before the idle timeout fires.
-3578 MAX_PTO_FAST_INTERVAL
-3579 } else {
-3580 // Otherwise cap to 2s.
-3581 MAX_PTO_INTERVAL
-3582 };
-3583
-3584 if path_id == PathId::ZERO
-3585 && path.in_flight.ack_eliciting == 0
-3586 && !self.peer_completed_handshake_address_validation()
-3587 {
-3588 // Address Validation during Connection Establishment:
-3589 // https://www.rfc-editor.org/rfc/rfc9000.html#section-8.1. To prevent a
-3590 // deadlock if an Initial or Handshake packet from the server is lost and the
-3591 // server can not send more due to its anti-amplification limit the client must
-3592 // send another packet on PTO.
-3593 let space = match self.highest_space {
-3594 SpaceKind::Handshake => SpaceId::Handshake,
-3595 _ => SpaceId::Initial,
-3596 };
-3597
-3598 let backoff = 2u32.pow(path.pto_count.min(MAX_BACKOFF_EXPONENT));
-3599 let duration = path.rtt.pto_base() * backoff;
-3600 let duration = duration.min(max_interval);
-3601 return Some((now + duration, space));
-3602 }
-3603
-3604 let mut result = None;
-3605 for space in SpaceId::iter() {
-3606 let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else {
-3607 continue;
-3608 };
-3609
-3610 if space == SpaceId::Data && !self.is_handshake_confirmed() {
-3611 // https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-7:
-3612 // An endpoint MUST NOT set its PTO timer for the Application Data packet
-3613 // number space until the handshake is confirmed.
-3614 continue;
-3615 }
-3616
-3617 if !pns.has_in_flight() {
-3618 continue;
-3619 }
-3620
-3621 // Compute the PTO duration for this space, we want to cap the maximum interval
-3622 // between two tail-loss probes so to not do a simple exponential backoff but
-3623 // rather iterate through the probes to compute the capped increment for an
-3624 // exponential backoff at each step.
-3625 let duration = {
-3626 let max_ack_delay = if space == SpaceId::Data {
-3627 self.ack_frequency.max_ack_delay_for_pto()
-3628 } else {
-3629 Duration::ZERO
-3630 };
-3631 let pto_base = path.rtt.pto_base() + max_ack_delay;
-3632 let mut duration = pto_base;
-3633 for i in 1..=pto_count {
-3634 let exponential_duration = pto_base * 2u32.pow(i.min(MAX_BACKOFF_EXPONENT));
-3635 let max_duration = duration + max_interval;
-3636 duration = exponential_duration.min(max_duration);
-3637 }
-3638 duration
-3639 };
-3640
-3641 let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else {
-3642 continue;
-3643 };
-3644 // Base the deadline on when the last probe was sent, so the PTO
-3645 // doesn't fire before the response has had time to arrive.
-3646 let pto = last_ack_eliciting + duration;
-3647 if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) {
-3648 if path.anti_amplification_blocked(1) {
-3649 // Nothing would be able to be sent.
-3650 continue;
-3651 }
-3652 if path.in_flight.ack_eliciting == 0 {
-3653 // Nothing ack-eliciting, no PTO to arm/fire.
-3654 continue;
-3655 }
-3656 result = Some((pto, space));
-3657 }
-3658 }
-3659 result
-3660 }
-3661
-3662 /// Whether the peer validated our address in the connection handshake.
-3663 fn peer_completed_handshake_address_validation(&self) -> bool {
-3664 if self.side.is_server() || self.state.is_closed() {
-3665 return true;
-3666 }
-3667 // The server is guaranteed to have validated our address if any of our handshake or
-3668 // 1-RTT packets are acknowledged or we've seen HANDSHAKE_DONE and discarded
-3669 // handshake keys.
-3670 self.spaces[SpaceId::Handshake]
-3671 .path_space(PathId::ZERO)
-3672 .and_then(|pns| pns.largest_acked_packet_pn)
-3673 .is_some()
-3674 || self.spaces[SpaceId::Data]
-3675 .path_space(PathId::ZERO)
-3676 .and_then(|pns| pns.largest_acked_packet_pn)
-3677 .is_some()
-3678 || (self.crypto_state.has_keys(EncryptionLevel::OneRtt)
-3679 && !self.crypto_state.has_keys(EncryptionLevel::Handshake))
-3680 }
-3681
-3682 /// Resets the the [`PathTimer::LossDetection`] timer to the next instant it may be needed
-3683 ///
-3684 /// The timer must fire if either:
-3685 /// - An ack-eliciting packet we sent needs to be declared lost.
-3686 /// - A tail-loss probe needs to be sent.
-3687 ///
-3688 /// See [`Connection::on_loss_detection_timeout`] for details.
-3689 fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) {
-3690 if self.state.is_closed() {
-3691 // No loss detection takes place on closed connections, and `close_common` already
-3692 // stopped time timer. Ensure we don't restart it inadvertently, e.g. in response to a
-3693 // reordered packet being handled by state-insensitive code.
-3694 return;
-3695 }
-3696
-3697 if let Some((loss_time, _)) = self.loss_time_and_space(path_id) {
-3698 // Time threshold loss detection.
-3699 self.timers.set(
-3700 Timer::PerPath(path_id, PathTimer::LossDetection),
-3701 loss_time,
-3702 self.qlog.with_time(now),
-3703 );
-3704 return;
-3705 }
-3706
-3707 // Determine which PN space to arm PTO for.
-3708 // We can only send tail-loss probes on paths that aren't abandoned yet.
-3709 if !self.abandoned_paths.contains(&path_id)
-3710 && let Some((timeout, _)) = self.pto_time_and_space(now, path_id)
-3711 {
-3712 self.timers.set(
-3713 Timer::PerPath(path_id, PathTimer::LossDetection),
-3714 timeout,
-3715 self.qlog.with_time(now),
-3716 );
-3717 } else {
-3718 self.timers.stop(
-3719 Timer::PerPath(path_id, PathTimer::LossDetection),
-3720 self.qlog.with_time(now),
-3721 );
-3722 }
-3723 }
-3724
-3725 /// The maximum probe timeout across all paths
-3726 ///
-3727 /// See [`Connection::pto`]
-3728 fn max_pto_for_space(&self, space: SpaceKind) -> Duration {
-3729 self.paths
-3730 .keys()
-3731 .map(|path_id| self.pto(space, *path_id))
-3732 .max()
-3733 .unwrap_or_else(|| {
-3734 // No paths remain (e.g. last path was abandoned and the NoAvailablePath grace timer
-3735 // fired before any new path was opened). Fall back to a PTO derived from the
-3736 // configured initial RTT, matching RFC 9002 §6.2.2 initial values.
-3737 let rtt = self.config.initial_rtt;
-3738 let max_ack_delay = match space {
-3739 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
-3740 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
-3741 };
-3742 rtt + cmp::max(4 * (rtt / 2), TIMER_GRANULARITY) + max_ack_delay
-3743 })
-3744 }
-3745
-3746 /// Probe Timeout
-3747 ///
-3748 /// The PTO is logically the time in which you'd expect to receive an acknowledgement
-3749 /// for a packet. So approximately RTT + max_ack_delay.
-3750 fn pto(&self, space: SpaceKind, path_id: PathId) -> Duration {
-3751 let max_ack_delay = match space {
-3752 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
-3753 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
-3754 };
-3755 self.path_data(path_id).rtt.pto_base() + max_ack_delay
-3756 }
-3757
-3758 fn on_packet_authenticated(
-3759 &mut self,
-3760 now: Instant,
-3761 space_id: SpaceKind,
-3762 path_id: PathId,
-3763 ecn: Option<EcnCodepoint>,
-3764 packet_number: Option<u64>,
-3765 spin: bool,
-3766 is_1rtt: bool,
-3767 remote: &FourTuple,
-3768 ) {
-3769 // During the handshake we already have discarded packets that do not match the path
-3770 // remote. So any off-path packet here is either a probing packet or a
-3771 // migration. Handling probing packets here means that the path's idle timeout will
-3772 // be reset and will delay detecting the path as idle. However tail-loss probes
-3773 // would still not get acknowledged if the path was broken so eventually the path
-3774 // would still become idle.
-3775 let is_on_path = self
-3776 .path_data(path_id)
-3777 .network_path
-3778 .is_probably_same_path(remote);
-3779
-3780 self.total_authed_packets += 1;
-3781 self.reset_keep_alive(path_id, now);
-3782 self.reset_idle_timeout(now, space_id, path_id);
-3783 self.path_data_mut(path_id).permit_idle_reset = true;
-3784
-3785 // Do not process ECN for off-path packets. If this is a migration we'll get ECN
-3786 // back once we've migrated.
-3787 if is_on_path {
-3788 self.receiving_ecn |= ecn.is_some();
-3789 if let Some(x) = ecn {
-3790 let space = &mut self.spaces[space_id];
-3791 space.for_path(path_id).ecn_counters += x;
-3792
-3793 if x.is_ce() {
-3794 space
-3795 .for_path(path_id)
-3796 .pending_acks
-3797 .set_immediate_ack_required();
-3798 }
-3799 }
-3800 }
-3801
-3802 let Some(packet_number) = packet_number else {
-3803 return;
-3804 };
-3805 match &self.side {
-3806 ConnectionSide::Client { .. } => {
-3807 // If we received a handshake packet that authenticated, then we're talking to
-3808 // the real server. From now on we should no longer allow the server to migrate
-3809 // its address.
-3810 if space_id == SpaceKind::Handshake
-3811 && let Some(hs) = self.state.as_handshake_mut()
-3812 {
-3813 hs.allow_server_migration = false;
-3814 }
-3815 }
-3816 ConnectionSide::Server { .. } => {
-3817 if self.crypto_state.has_keys(EncryptionLevel::Initial)
-3818 && space_id == SpaceKind::Handshake
-3819 {
-3820 // A server stops sending and processing Initial packets when it receives its first Handshake packet.
-3821 self.discard_space(now, SpaceKind::Initial);
-3822 }
-3823 if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) && is_1rtt {
-3824 // Discard 0-RTT keys soon after receiving a 1-RTT packet
-3825 self.set_key_discard_timer(now, space_id)
-3826 }
-3827 }
-3828 }
-3829 let space = self.spaces[space_id].for_path(path_id);
-3830
-3831 space.pending_acks.insert_one(packet_number, now);
-3832 if packet_number >= space.largest_received_packet_number.unwrap_or_default() {
-3833 space.largest_received_packet_number = Some(packet_number);
-3834
-3835 // Update outgoing spin bit for on-path packets, inverting iff we're the client
-3836 if is_on_path {
-3837 self.spin = self.side.is_client() ^ spin;
-3838 }
-3839 }
-3840 }
-3841
-3842 /// Resets the idle timeout timers
-3843 ///
-3844 /// Without multipath there is only the connection-wide idle timeout. When multipath is
-3845 /// enabled there is an additional per-path idle timeout.
-3846 fn reset_idle_timeout(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
-3847 // First reset the global idle timeout.
-3848 if let Some(timeout) = self.idle_timeout {
-3849 if self.state.is_closed() {
-3850 self.timers
-3851 .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now));
-3852 } else {
-3853 let dt = cmp::max(timeout, 3 * self.max_pto_for_space(space));
-3854 self.timers.set(
-3855 Timer::Conn(ConnTimer::Idle),
-3856 now + dt,
-3857 self.qlog.with_time(now),
-3858 );
-3859 }
-3860 }
-3861
-3862 // Now handle the per-path state
-3863 if let Some(timeout) = self.path_data(path_id).idle_timeout {
-3864 if self.state.is_closed() {
-3865 self.timers.stop(
-3866 Timer::PerPath(path_id, PathTimer::PathIdle),
-3867 self.qlog.with_time(now),
-3868 );
-3869 } else {
-3870 let dt = cmp::max(timeout, 3 * self.pto(space, path_id));
-3871 self.timers.set(
-3872 Timer::PerPath(path_id, PathTimer::PathIdle),
-3873 now + dt,
-3874 self.qlog.with_time(now),
-3875 );
-3876 }
-3877 }
-3878 }
-3879
-3880 /// Resets both the [`ConnTimer::KeepAlive`] and [`PathTimer::PathKeepAlive`] timers
-3881 fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) {
-3882 if !self.state.is_established() {
-3883 return;
-3884 }
-3885
-3886 if let Some(interval) = self.config.keep_alive_interval {
-3887 self.timers.set(
-3888 Timer::Conn(ConnTimer::KeepAlive),
-3889 now + interval,
-3890 self.qlog.with_time(now),
-3891 );
-3892 }
-3893
-3894 if let Some(interval) = self.path_data(path_id).keep_alive {
-3895 self.timers.set(
-3896 Timer::PerPath(path_id, PathTimer::PathKeepAlive),
-3897 now + interval,
-3898 self.qlog.with_time(now),
-3899 );
-3900 }
-3901 }
-3902
-3903 /// Sets the timer for when a previously issued CID should be retired next
-3904 fn reset_cid_retirement(&mut self, now: Instant) {
-3905 if let Some((_path, t)) = self.next_cid_retirement() {
-3906 self.timers.set(
-3907 Timer::Conn(ConnTimer::PushNewCid),
-3908 t,
-3909 self.qlog.with_time(now),
-3910 );
-3911 }
-3912 }
-3913
-3914 /// The next time when a previously issued CID should be retired
-3915 fn next_cid_retirement(&self) -> Option<(PathId, Instant)> {
-3916 self.local_cid_state
-3917 .iter()
-3918 .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t)))
-3919 .min_by_key(|(_path_id, timeout)| *timeout)
-3920 }
-3921
-3922 /// Handle the already-decrypted first packet from the client
-3923 ///
-3924 /// Decrypting the first packet in the `Endpoint` allows stateless packet handling to be more
-3925 /// efficient.
-3926 pub(crate) fn handle_first_packet(
-3927 &mut self,
-3928 now: Instant,
-3929 network_path: FourTuple,
-3930 ecn: Option<EcnCodepoint>,
-3931 packet_number: u64,
-3932 packet: InitialPacket,
-3933 remaining: Option<BytesMut>,
-3934 ) -> Result<(), ConnectionError> {
-3935 let span = trace_span!("first recv");
-3936 let _guard = span.enter();
-3937 debug_assert!(self.side.is_server());
-3938 let len = packet.header_data.len() + packet.payload.len();
-3939 let path_id = PathId::ZERO;
-3940 self.path_data_mut(path_id).total_recvd = len as u64;
-3941
-3942 if let Some(hs) = self.state.as_handshake_mut() {
-3943 hs.expected_token = packet.header.token.clone();
-3944 } else {
-3945 unreachable!("first packet must be delivered in Handshake state");
-3946 }
-3947
-3948 // The first packet is always on PathId::ZERO
-3949 self.on_packet_authenticated(
-3950 now,
-3951 SpaceKind::Initial,
-3952 path_id,
-3953 ecn,
-3954 Some(packet_number),
+1005 if let Some(pn) = pn {
+1006 pn_space.dedup.insert(pn);
+1007 }
+1008 self.spaces[SpaceId::Data]
+1009 .number_spaces
+1010 .insert(path_id, pn_space);
+1011 self.qlog.emit_tuple_assigned(path_id, network_path, now);
+1012
+1013 // If the remote opened this path we may not have CIDs for it. For locally opened
+1014 // paths the caller should have already made sure we have CIDs and refused to open
+1015 // it if there were none.
+1016 if !self.remote_cids.contains_key(&path_id) {
+1017 debug!(%path_id, "Remote opened path without issuing CIDs");
+1018 self.spaces[SpaceId::Data]
+1019 .pending
+1020 .path_cids_blocked
+1021 .insert(path_id, VarInt(0));
+1022 // Do not abandon this path right away. CIDs might be in-flight still and arrive
+1023 // soon. It is up to the remote to handle this situation.
+1024 }
+1025
+1026 &mut path.data
+1027 }
+1028
+1029 /// Returns packets to transmit
+1030 ///
+1031 /// Connections should be polled for transmit after:
+1032 /// - the application performed some I/O on the connection
+1033 /// - a call was made to `handle_event`
+1034 /// - a call was made to `handle_timeout`
+1035 ///
+1036 /// `max_datagrams` specifies how many datagrams can be returned inside a
+1037 /// single Transmit using GSO. This must be at least 1.
+1038 #[must_use]
+1039 pub fn poll_transmit(
+1040 &mut self,
+1041 now: Instant,
+1042 max_datagrams: NonZeroUsize,
+1043 buf: &mut Vec<u8>,
+1044 ) -> Option<Transmit> {
+1045 let max_datagrams = match self.config.enable_segmentation_offload {
+1046 false => NonZeroUsize::MIN,
+1047 true => max_datagrams,
+1048 };
+1049
+1050 // Each call to poll_transmit can only send datagrams to one destination, because
+1051 // all datagrams in a GSO batch are for the same destination. Therefore only
+1052 // datagrams for one destination address are produced for each poll_transmit call.
+1053
+1054 // Check whether we need to send a close message
+1055 let connection_close_pending = match self.state.as_type() {
+1056 StateType::Drained => {
+1057 for path in self.paths.values_mut() {
+1058 path.data.app_limited = true;
+1059 }
+1060 return None;
+1061 }
+1062 StateType::Draining | StateType::Closed => {
+1063 // self.connection_close_pending is only reset once the associated packet
+1064 // had been encoded successfully
+1065 if !self.connection_close_pending {
+1066 for path in self.paths.values_mut() {
+1067 path.data.app_limited = true;
+1068 }
+1069 return None;
+1070 }
+1071 true
+1072 }
+1073 _ => false,
+1074 };
+1075
+1076 // Schedule an ACK_FREQUENCY frame if a new one needs to be sent.
+1077 if let Some(config) = &self.config.ack_frequency_config {
+1078 let rtt = self
+1079 .paths
+1080 .values()
+1081 .map(|p| p.data.rtt.get())
+1082 .min()
+1083 .expect("one path exists");
+1084 self.spaces[SpaceId::Data].pending.ack_frequency = self
+1085 .ack_frequency
+1086 .should_send_ack_frequency(rtt, config, &self.peer_params)
+1087 && self.highest_space == SpaceKind::Data
+1088 && self.peer_supports_ack_frequency();
+1089 }
+1090
+1091 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
+1092 while let Some(path_id) = next_path_id {
+1093 if !connection_close_pending
+1094 && let Some(transmit) = self.poll_transmit_off_path(now, buf, path_id)
+1095 {
+1096 return Some(transmit);
+1097 }
+1098
+1099 let info = self.scheduling_info(path_id);
+1100 if let Some(transmit) = self.poll_transmit_on_path(
+1101 now,
+1102 buf,
+1103 path_id,
+1104 max_datagrams,
+1105 &info,
+1106 connection_close_pending,
+1107 ) {
+1108 return Some(transmit);
+1109 }
+1110
+1111 // Continue checking other paths, tail-loss probes may need to be sent
+1112 // in all spaces.
+1113 debug_assert!(
+1114 buf.is_empty(),
+1115 "nothing to send on path but buffer not empty"
+1116 );
+1117
+1118 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
+1119 }
+1120
+1121 // We didn't produce any application data packet
+1122 debug_assert!(
+1123 buf.is_empty(),
+1124 "there was data in the buffer, but it was not sent"
+1125 );
+1126
+1127 if self.state.is_established() {
+1128 // Try MTU probing now
+1129 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
+1130 while let Some(path_id) = next_path_id {
+1131 if let Some(transmit) = self.poll_transmit_mtu_probe(now, buf, path_id) {
+1132 return Some(transmit);
+1133 }
+1134 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
+1135 }
+1136 }
+1137
+1138 None
+1139 }
+1140
+1141 /// Computes the packet scheduling information for this path.
+1142 ///
+1143 /// While this information is only returned for a single path, it is important to know
+1144 /// that this information remains static for the entire span of a single
+1145 /// [`Connection::poll_transmit`] call. In other words, the return value is purely
+1146 /// functional and only depends on the [`PathId`] **during a single** `poll_transmit`
+1147 /// call. It can be computed up-front for all paths but we don't do that because it
+1148 /// involves an allocation.
+1149 ///
+1150 /// See the inline comments for how the packet scheduling works.
+1151 ///
+1152 /// # Panics
+1153 ///
+1154 /// This will panic if called for a path for which we do not have any [`PathData`], like
+1155 /// so many other functions we have. But this is the only one to document this in its
+1156 /// doc comment. Maybe that should change. Eventually we'll refactor things for this
+1157 /// panic to go away.
+1158 fn scheduling_info(&self, path_id: PathId) -> PathSchedulingInfo {
+1159 // Such a space is preferred for SpaceKind::Data frames.
+1160 let have_validated_status_available_space = self.paths.iter().any(|(path_id, path)| {
+1161 self.remote_cids.contains_key(path_id)
+1162 && !self.abandoned_paths.contains(path_id)
+1163 && path.data.validated
+1164 && path.data.local_status() == PathStatus::Available
+1165 });
+1166
+1167 // Such a space is able to send SpaceKind::Data frames.
+1168 let have_validated_space = self.paths.iter().any(|(path_id, path)| {
+1169 self.remote_cids.contains_key(path_id)
+1170 && !self.abandoned_paths.contains(path_id)
+1171 && path.data.validated
+1172 });
+1173
+1174 let is_handshaking = self.is_handshaking();
+1175 let has_cids = self.remote_cids.contains_key(&path_id);
+1176 let is_abandoned = self.abandoned_paths.contains(&path_id);
+1177 let path_data = self.path_data(path_id);
+1178 let validated = path_data.validated;
+1179 let status = path_data.local_status();
+1180
+1181 // This is the core packet scheduling, whether this space ID may send
+1182 // SpaceKind::Data frames.
+1183 let may_send_data = has_cids
+1184 && !is_abandoned
+1185 && if is_handshaking {
+1186 // There is only one path during the handshake. We want to
+1187 // already send 0-RTT and 0.5-RTT (permitting anti-amplification
+1188 // limit) data.
+1189 true
+1190 } else if !validated {
+1191 // TODO(flub): When we have a network change we might end up
+1192 // having to abandon all paths and re-open new ones to the
+1193 // same remotes. This leaves us without any validated
+1194 // path. Perhaps we should have a way to figure out if the
+1195 // path is to a previously-validated remote address and allow
+1196 // sending data to such remotes immediately.
+1197 false
+1198 } else {
+1199 match status {
+1200 PathStatus::Available => {
+1201 // Best possible space to send data on.
+1202 true
+1203 }
+1204 PathStatus::Backup => {
+1205 // If there is a status-available path we prefer that.
+1206 !have_validated_status_available_space
+1207 }
+1208 }
+1209 };
+1210
+1211 // CONNECTION_CLOSE is allowed to be sent on a non-validated
+1212 // path. Particularly during the handshake we want to send it before the
+1213 // path is validated. Later if there is no validated path available we
+1214 // will also accept sending it on an un-validated path.
+1215 let may_send_close = has_cids
+1216 && !is_abandoned
+1217 && if !validated && have_validated_status_available_space {
+1218 // We have a better space to send on.
+1219 false
+1220 } else {
+1221 // No other validated space, this is as good as it gets.
+1222 true
+1223 };
+1224
+1225 // PATH_ABANDON is normally sent together with other SpaceKind::Data frames. But if
+1226 // there is no other validated space to send it on, it can be sent on the path to be
+1227 // abandoned itself if that was validated.
+1228 let may_self_abandon = has_cids && validated && !have_validated_space;
+1229
+1230 PathSchedulingInfo {
+1231 is_abandoned,
+1232 may_send_data,
+1233 may_send_close,
+1234 may_self_abandon,
+1235 }
+1236 }
+1237
+1238 fn build_transmit(&mut self, path_id: PathId, transmit: TransmitBuf<'_>) -> Transmit {
+1239 debug_assert!(
+1240 !transmit.is_empty(),
+1241 "must not be called with an empty transmit buffer"
+1242 );
+1243
+1244 let network_path = self.path_data(path_id).network_path;
+1245 trace!(
+1246 segment_size = transmit.segment_size(),
+1247 last_datagram_len = transmit.len() % transmit.segment_size(),
+1248 %network_path,
+1249 "sending {} bytes in {} datagrams",
+1250 transmit.len(),
+1251 transmit.num_datagrams()
+1252 );
+1253 self.path_data_mut(path_id)
+1254 .inc_total_sent(transmit.len() as u64);
+1255
+1256 self.path_stats
+1257 .for_path(path_id)
+1258 .udp_tx
+1259 .on_sent(transmit.num_datagrams() as u64, transmit.len());
+1260
+1261 Transmit {
+1262 destination: network_path.remote,
+1263 size: transmit.len(),
+1264 ecn: if self.path_data(path_id).sending_ecn {
+1265 Some(EcnCodepoint::Ect0)
+1266 } else {
+1267 None
+1268 },
+1269 segment_size: match transmit.num_datagrams() {
+1270 1 => None,
+1271 _ => Some(transmit.segment_size()),
+1272 },
+1273 src_ip: network_path.local_ip,
+1274 }
+1275 }
+1276
+1277 /// poll_transmit logic for off-path data.
+1278 fn poll_transmit_off_path(
+1279 &mut self,
+1280 now: Instant,
+1281 buf: &mut Vec<u8>,
+1282 path_id: PathId,
+1283 ) -> Option<Transmit> {
+1284 if let Some(challenge) = self.send_prev_path_challenge(now, buf, path_id) {
+1285 return Some(challenge);
+1286 }
+1287 if let Some(response) = self.send_off_path_path_response(now, buf, path_id) {
+1288 return Some(response);
+1289 }
+1290 if let Some(challenge) = self.send_nat_traversal_path_challenge(now, buf, path_id) {
+1291 return Some(challenge);
+1292 }
+1293 None
+1294 }
+1295
+1296 /// poll_transmit logic for on-path data.
+1297 ///
+1298 /// This is not quite the same as for a multipath packet space, since [`PathId::ZERO`]
+1299 /// has 3 packet spaces, which this handles.
+1300 ///
+1301 /// See [`Self::poll_transmit_off_path`] for off-path data.
+1302 #[must_use]
+1303 fn poll_transmit_on_path(
+1304 &mut self,
+1305 now: Instant,
+1306 buf: &mut Vec<u8>,
+1307 path_id: PathId,
+1308 max_datagrams: NonZeroUsize,
+1309 scheduling_info: &PathSchedulingInfo,
+1310 connection_close_pending: bool,
+1311 ) -> Option<Transmit> {
+1312 // Check if there is at least one active CID to use for sending
+1313 let Some(remote_cid) = self.remote_cids.get(&path_id).map(CidQueue::active) else {
+1314 if !self.abandoned_paths.contains(&path_id) {
+1315 debug!(%path_id, "no remote CIDs for path");
+1316 }
+1317 return None;
+1318 };
+1319
+1320 // Whether the last packet in the datagram must be padded so the datagram takes up
+1321 // an exact size. An earlier space can decide to not fill an entire datagram and
+1322 // require the next space to fill it further. But may need a specific size of the
+1323 // datagram containing the packet. The final packet built in the datagram must pad
+1324 // to this size.
+1325 let mut pad_datagram = PadDatagram::No;
+1326
+1327 // The packet number of the last built packet. This is kept kept across spaces.
+1328 // QUIC is supposed to have a single congestion controller for the Initial,
+1329 // Handshake and Data(PathId::ZERO) spaces.
+1330 let mut last_packet_number = None;
+1331
+1332 // If we end up not sending anything, we need to know if that was because there was
+1333 // nothing to send or because we were congestion blocked.
+1334 let mut congestion_blocked = false;
+1335
+1336 // Set the segment size to this path's MTU for on-path data.
+1337 let pmtu = self.path_data(path_id).current_mtu().into();
+1338 let mut transmit = TransmitBuf::new(buf, max_datagrams, pmtu);
+1339
+1340 // Iterate over the available spaces.
+1341 for space_id in SpaceId::iter() {
+1342 // Only PathId::ZERO uses non Data space ids.
+1343 if path_id != PathId::ZERO && space_id != SpaceId::Data {
+1344 continue;
+1345 }
+1346 match self.poll_transmit_path_space(
+1347 now,
+1348 &mut transmit,
+1349 path_id,
+1350 space_id,
+1351 remote_cid,
+1352 scheduling_info,
+1353 connection_close_pending,
+1354 pad_datagram,
+1355 ) {
+1356 PollPathSpaceStatus::NothingToSend {
+1357 congestion_blocked: cb,
+1358 } => {
+1359 congestion_blocked |= cb;
+1360 // Continue checking other spaces, tail-loss probes may need to be sent
+1361 // in all spaces.
+1362 }
+1363 PollPathSpaceStatus::WrotePacket {
+1364 last_packet_number: pn,
+1365 pad_datagram: pad,
+1366 } => {
+1367 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
+1368 last_packet_number = Some(pn);
+1369 pad_datagram = pad;
+1370 // Always check higher spaces. If the transmit is full or they have
+1371 // nothing to send they will not write packets. But if they can, they
+1372 // must always be allowed to add to this transmit because coalescing may
+1373 // be required.
+1374 continue;
+1375 }
+1376 PollPathSpaceStatus::Send {
+1377 last_packet_number: pn,
+1378 } => {
+1379 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
+1380 last_packet_number = Some(pn);
+1381 break;
+1382 }
+1383 }
+1384 }
+1385
+1386 if last_packet_number.is_some() || congestion_blocked {
+1387 self.qlog.emit_recovery_metrics(
+1388 path_id,
+1389 &mut self
+1390 .paths
+1391 .get_mut(&path_id)
+1392 .expect("path_id was iterated from self.paths above")
+1393 .data,
+1394 now,
+1395 );
+1396 }
+1397
+1398 self.path_data_mut(path_id).app_limited =
+1399 last_packet_number.is_none() && !congestion_blocked;
+1400
+1401 match last_packet_number {
+1402 Some(last_packet_number) => {
+1403 // Note that when sending in multiple spaces the last packet number will be
+1404 // the one from the highest space.
+1405 self.path_data_mut(path_id).congestion.on_sent(
+1406 now,
+1407 transmit.len() as u64,
+1408 last_packet_number,
+1409 );
+1410 Some(self.build_transmit(path_id, transmit))
+1411 }
+1412 None => None,
+1413 }
+1414 }
+1415
+1416 /// poll_transmit logic for a QUIC-MULTIPATH packet number space (PathID + SpaceId).
+1417 #[must_use]
+1418 fn poll_transmit_path_space(
+1419 &mut self,
+1420 now: Instant,
+1421 transmit: &mut TransmitBuf<'_>,
+1422 path_id: PathId,
+1423 space_id: SpaceId,
+1424 remote_cid: ConnectionId,
+1425 scheduling_info: &PathSchedulingInfo,
+1426 // If we need to send a CONNECTION_CLOSE frame.
+1427 connection_close_pending: bool,
+1428 // Whether the current datagram needs to be padded to a certain size.
+1429 mut pad_datagram: PadDatagram,
+1430 ) -> PollPathSpaceStatus {
+1431 // Keep track of the last packet number we wrote. If None we did not write any
+1432 // packets.
+1433 let mut last_packet_number = None;
+1434
+1435 // Each loop of this may build one packet. It works logically as follows:
+1436 //
+1437 // - Check if something *needs* to be sent in this space and *can* be sent.
+1438 // - If not, return to the caller who will call us again for the next space.
+1439 // - Start a new datagram.
+1440 // - Unless coalescing the packet into an existing datagram.
+1441 // - Write the packet header and payload.
+1442 // - Check if coalescing a next packet into the datagram is possible.
+1443 // - If coalescing, finish packet without padding to leave space in the datagram.
+1444 // - If not coalescing, complete the datagram:
+1445 // - Finish packet with padding.
+1446 // - Set the transmit segment size if this is the first datagram.
+1447 // - Loop: next iteration will exit the loop if nothing more to send in this
+1448 // space. The TransmitBuf will contain a started datagram with space if
+1449 // coalescing, or completely filled datagram if not coalescing.
+1450 loop {
+1451 // Determine if anything can be sent in this packet number space.
+1452 let max_packet_size = if transmit.datagram_remaining_mut() > 0 {
+1453 // A datagram is started already, we are coalescing another packet into it.
+1454 transmit.datagram_remaining_mut()
+1455 } else {
+1456 // A new datagram needs to be started.
+1457 transmit.segment_size()
+1458 };
+1459 let can_send =
+1460 self.space_can_send(space_id, path_id, max_packet_size, connection_close_pending);
+1461 let needs_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
+1462 let space_will_send = {
+1463 if scheduling_info.is_abandoned {
+1464 // If this path is abandoned then we might still have to send
+1465 // PATH_ABANDON itself on it if there was no better space
+1466 // available. Otherwise we want to send the PATH_ABANDON as permitted by
+1467 // may_send_data however.
+1468 scheduling_info.may_self_abandon
+1469 && self.spaces[space_id]
+1470 .pending
+1471 .path_abandon
+1472 .contains_key(&path_id)
+1473 } else if can_send.close && scheduling_info.may_send_close {
+1474 // This is the best path to send a CONNECTION_CLOSE on.
+1475 true
+1476 } else if needs_loss_probe || can_send.space_specific {
+1477 // We always send a loss probe or space-specific frames if the path is
+1478 // not abandoned.
+1479 true
+1480 } else {
+1481 // Anything else we only send if we're the best path for SpaceKind::Data
+1482 // frames.
+1483 !can_send.is_empty() && scheduling_info.may_send_data
+1484 }
+1485 };
+1486
+1487 if !space_will_send {
+1488 // Nothing more to send. Previous iterations of this loop may have built
+1489 // packets already.
+1490 return match last_packet_number {
+1491 Some(pn) => PollPathSpaceStatus::WrotePacket {
+1492 last_packet_number: pn,
+1493 pad_datagram,
+1494 },
+1495 None => {
+1496 // Only log for spaces which have crypto.
+1497 if self.crypto_state.has_keys(space_id.encryption_level())
+1498 || (space_id == SpaceId::Data
+1499 && self.crypto_state.has_keys(EncryptionLevel::ZeroRtt))
+1500 {
+1501 trace!(?space_id, %path_id, "nothing to send in space");
+1502 }
+1503 PollPathSpaceStatus::NothingToSend {
+1504 congestion_blocked: false,
+1505 }
+1506 }
+1507 };
+1508 }
+1509
+1510 // We want to send on this space, check congestion control if we can. But only
+1511 // if we will need to start a new datagram. If we are coalescing into an already
+1512 // started datagram we do not need to check congestion control again.
+1513 if transmit.datagram_remaining_mut() == 0 {
+1514 let congestion_blocked =
+1515 self.path_congestion_check(space_id, path_id, transmit, &can_send, now);
+1516 if congestion_blocked != PathBlocked::No {
+1517 // Previous iterations of this loop may have built packets already.
+1518 return match last_packet_number {
+1519 Some(pn) => PollPathSpaceStatus::WrotePacket {
+1520 last_packet_number: pn,
+1521 pad_datagram,
+1522 },
+1523 None => {
+1524 return PollPathSpaceStatus::NothingToSend {
+1525 congestion_blocked: true,
+1526 };
+1527 }
+1528 };
+1529 }
+1530
+1531 // If the datagram is full (or there never was one started), we need to start a
+1532 // new one.
+1533 if transmit.num_datagrams() >= transmit.max_datagrams().get() {
+1534 // No more datagrams allowed.
+1535 // Previous iterations of this loop may have built packets already.
+1536 return match last_packet_number {
+1537 Some(pn) => PollPathSpaceStatus::WrotePacket {
+1538 last_packet_number: pn,
+1539 pad_datagram,
+1540 },
+1541 None => {
+1542 return PollPathSpaceStatus::NothingToSend {
+1543 congestion_blocked: false,
+1544 };
+1545 }
+1546 };
+1547 }
+1548
+1549 if needs_loss_probe {
+1550 // Ensure we have something to send for a tail-loss probe.
+1551 let request_immediate_ack =
+1552 space_id == SpaceId::Data && self.peer_supports_ack_frequency();
+1553 self.spaces[space_id].queue_tail_loss_probe(
+1554 path_id,
+1555 request_immediate_ack,
+1556 &self.streams,
+1557 );
+1558
+1559 self.spaces[space_id].for_path(path_id).loss_probes -= 1; // needs_loss_probe ensures loss_probes > 0
+1560
+1561 // Clamp the datagram to at most the minimum MTU to ensure that loss
+1562 // probes can get through and enable recovery even if the path MTU
+1563 // has shrank unexpectedly.
+1564 transmit.start_new_datagram_with_size(std::cmp::min(
+1565 usize::from(INITIAL_MTU),
+1566 transmit.segment_size(),
+1567 ));
+1568 } else {
+1569 transmit.start_new_datagram();
+1570 }
+1571 trace!(count = transmit.num_datagrams(), "new datagram started");
+1572
+1573 // We started a new datagram, we decide later if it needs padding.
+1574 pad_datagram = PadDatagram::No;
+1575 }
+1576
+1577 // If coalescing another packet into the existing datagram, there should
+1578 // still be enough space for a whole packet.
+1579 if transmit.datagram_start_offset() < transmit.len() {
+1580 debug_assert!(transmit.datagram_remaining_mut() >= MIN_PACKET_SPACE);
+1581 }
+1582
+1583 //
+1584 // From here on, we've determined that a packet will definitely be sent.
+1585 //
+1586
+1587 if self.crypto_state.has_keys(EncryptionLevel::Initial)
+1588 && space_id == SpaceId::Handshake
+1589 && self.side.is_client()
+1590 {
+1591 // A client stops both sending and processing Initial packets when it
+1592 // sends its first Handshake packet.
+1593 self.discard_space(now, SpaceKind::Initial);
+1594 }
+1595 if let Some(ref mut prev) = self.crypto_state.prev_crypto {
+1596 prev.update_unacked = false;
+1597 }
+1598
+1599 let Some(mut builder) =
+1600 PacketBuilder::new(now, space_id, path_id, remote_cid, transmit, self)
+1601 else {
+1602 // Confidentiality limit is exceeded and the connection has been killed. We
+1603 // should not send any other packets. This works in a roundabout way: We
+1604 // have started a datagram but not written anything into it. So even if we
+1605 // get called again for another space we will see an already started
+1606 // datagram and try and start another packet here. Then be stopped by the
+1607 // same confidentiality limit.
+1608 return PollPathSpaceStatus::NothingToSend {
+1609 congestion_blocked: false,
+1610 };
+1611 };
+1612 last_packet_number = Some(builder.packet_number);
+1613
+1614 if space_id == SpaceId::Initial
+1615 && (self.side.is_client() || can_send.is_ack_eliciting() || needs_loss_probe)
+1616 {
+1617 // https://www.rfc-editor.org/rfc/rfc9000.html#section-14.1
+1618 pad_datagram |= PadDatagram::ToMinMtu;
+1619 }
+1620 if space_id == SpaceId::Data && self.config.pad_to_mtu {
+1621 pad_datagram |= PadDatagram::ToSegmentSize;
+1622 }
+1623
+1624 if scheduling_info.may_send_close && can_send.close {
+1625 trace!("sending CONNECTION_CLOSE");
+1626 // Encode ACKs before the ConnectionClose message, to give the receiver
+1627 // a better approximate on what data has been processed. This is
+1628 // especially important with ack delay, since the peer might not
+1629 // have gotten any other ACK for the data earlier on.
+1630 let is_multipath_negotiated = self.is_multipath_negotiated();
+1631 for path_id in self.spaces[space_id]
+1632 .number_spaces
+1633 .iter()
+1634 .filter(|(_, pns)| !pns.pending_acks.ranges().is_empty())
+1635 .map(|(&path_id, _)| path_id)
+1636 .collect::<Vec<_>>()
+1637 {
+1638 Self::populate_acks(
+1639 now,
+1640 self.receiving_ecn,
+1641 path_id,
+1642 space_id,
+1643 &mut self.spaces[space_id],
+1644 is_multipath_negotiated,
+1645 &mut builder,
+1646 &mut self.path_stats.for_path(path_id).frame_tx,
+1647 self.crypto_state.has_keys(space_id.encryption_level()),
+1648 );
+1649 }
+1650
+1651 // Since there only 64 ACK frames there will always be enough space
+1652 // to encode the ConnectionClose frame too. However we still have the
+1653 // check here to prevent crashes if something changes.
+1654
+1655 // TODO(flub): This needs fixing for multipath, to ensure we can always
+1656 // write the CONNECTION_CLOSE even if we have many PATH_ACKs to send:
+1657 // https://github.com/n0-computer/noq/issues/367.
+1658 debug_assert!(
+1659 builder.frame_space_remaining() > frame::ConnectionClose::SIZE_BOUND,
+1660 "ACKs should leave space for ConnectionClose"
+1661 );
+1662 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
+1663 if frame::ConnectionClose::SIZE_BOUND < builder.frame_space_remaining() {
+1664 let max_frame_size = builder.frame_space_remaining();
+1665 let close: Close = match self.state.as_type() {
+1666 StateType::Closed => {
+1667 let reason: Close =
+1668 self.state.as_closed().expect("checked").clone().into();
+1669 if space_id == SpaceId::Data || reason.is_transport_layer() {
+1670 reason
+1671 } else {
+1672 TransportError::APPLICATION_ERROR("").into()
+1673 }
+1674 }
+1675 StateType::Draining => TransportError::NO_ERROR("").into(),
+1676 _ => unreachable!(
+1677 "tried to make a close packet when the connection wasn't closed"
+1678 ),
+1679 };
+1680 builder.write_frame(close.encoder(max_frame_size), stats);
+1681 }
+1682 let last_pn = builder.packet_number;
+1683 builder.finish_and_track(now, self, path_id, pad_datagram);
+1684 if space_id.kind() == self.highest_space {
+1685 // Don't send another close packet. Even with multipath we only send
+1686 // CONNECTION_CLOSE on a single path since we expect our paths to work.
+1687 self.connection_close_pending = false;
+1688 }
+1689 // Send a close frame in every possible space for robustness, per
+1690 // RFC9000 "Immediate Close during the Handshake". Don't bother trying
+1691 // to send anything else.
+1692 // TODO(flub): This breaks during the handshake if we can not coalesce
+1693 // packets due to space reasons: the next space would either fail a
+1694 // debug_assert checking for enough packet space or produce an invalid
+1695 // packet. We need to keep track of per-space pending CONNECTION_CLOSE to
+1696 // be able to send these across multiple calls to poll_transmit. Then
+1697 // check for coalescing space here because initial packets need to be in
+1698 // padded datagrams. And also add space checks for CONNECTION_CLOSE in
+1699 // space_can_send so it would stop a GSO batch if the datagram is too
+1700 // small for another CONNECTION_CLOSE packet.
+1701 return PollPathSpaceStatus::WrotePacket {
+1702 last_packet_number: last_pn,
+1703 pad_datagram,
+1704 };
+1705 }
+1706
+1707 self.populate_packet(now, space_id, path_id, scheduling_info, &mut builder);
+1708
+1709 // ACK-only packets should only be sent when explicitly allowed. If we write them due to
+1710 // any other reason, there is a bug which leads to one component announcing write
+1711 // readiness while not writing any data. This degrades performance. The condition is
+1712 // only checked if the full MTU is available and when potentially large fixed-size
+1713 // frames aren't queued, so that lack of space in the datagram isn't the reason for just
+1714 // writing ACKs.
+1715 debug_assert!(
+1716 !(builder.sent_frames().is_ack_only(&self.streams)
+1717 && !can_send.acks
+1718 && (can_send.other || can_send.space_specific)
+1719 && builder.buf.segment_size()
+1720 == self.path_data(path_id).current_mtu() as usize
+1721 && self.datagrams.outgoing.is_empty()),
+1722 "SendableFrames was {can_send:?}, but only ACKs have been written"
+1723 );
+1724 if builder.sent_frames().requires_padding {
+1725 pad_datagram |= PadDatagram::ToMinMtu;
+1726 }
+1727
+1728 for (path_id, _pn) in builder.sent_frames().largest_acked.iter() {
+1729 self.spaces[space_id]
+1730 .for_path(*path_id)
+1731 .pending_acks
+1732 .acks_sent();
+1733 self.timers.stop(
+1734 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
+1735 self.qlog.with_time(now),
+1736 );
+1737 }
+1738
+1739 // Now we need to finish the packet. Before we do so we need to know if we will
+1740 // be coalescing the next packet into this one, or will be ending the datagram
+1741 // as well. Because if this is the last packet in the datagram more padding
+1742 // might be needed because of the packet type, or to fill the GSO segment size.
+1743
+1744 // Are we allowed to coalesce AND is there enough space for another *packet* in
+1745 // this datagram AND will we definitely send another packet?
+1746 if builder.can_coalesce && path_id == PathId::ZERO && {
+1747 let max_packet_size = builder
+1748 .buf
+1749 .datagram_remaining_mut()
+1750 .saturating_sub(builder.predict_packet_end());
+1751 max_packet_size > MIN_PACKET_SPACE
+1752 && self.has_pending_packet(space_id, max_packet_size, connection_close_pending)
+1753 } {
+1754 // We can append/coalesce the next packet into the current
+1755 // datagram. Finish the current packet without adding extra padding.
+1756 trace!("will coalesce with next packet");
+1757 builder.finish_and_track(now, self, path_id, PadDatagram::No);
+1758 } else {
+1759 // We need a new datagram for the next packet. Finish the current
+1760 // packet with padding.
+1761 // TODO(flub): if there isn't any more data to be sent, this will still pad
+1762 // to the segment size and only discover there is nothing to send before
+1763 // starting the next packet. That is wasting up to 32 bytes.
+1764 if builder.buf.num_datagrams() > 1 && matches!(pad_datagram, PadDatagram::No) {
+1765 // If too many padding bytes would be required to continue the
+1766 // GSO batch after this packet, end the GSO batch here. Ensures
+1767 // that fixed-size frames with heterogeneous sizes
+1768 // (e.g. application datagrams) won't inadvertently waste large
+1769 // amounts of bandwidth. The exact threshold is a bit arbitrary
+1770 // and might benefit from further tuning, though there's no
+1771 // universally optimal value.
+1772 const MAX_PADDING: usize = 32;
+1773 if builder.buf.datagram_remaining_mut()
+1774 > builder.predict_packet_end() + MAX_PADDING
+1775 {
+1776 trace!(
+1777 "GSO truncated by demand for {} padding bytes",
+1778 builder.buf.datagram_remaining_mut() - builder.predict_packet_end()
+1779 );
+1780 let last_pn = builder.packet_number;
+1781 builder.finish_and_track(now, self, path_id, PadDatagram::No);
+1782 return PollPathSpaceStatus::Send {
+1783 last_packet_number: last_pn,
+1784 };
+1785 }
+1786
+1787 // Pad the current datagram to GSO segment size so it can be
+1788 // included in the GSO batch.
+1789 builder.finish_and_track(now, self, path_id, PadDatagram::ToSegmentSize);
+1790 } else {
+1791 builder.finish_and_track(now, self, path_id, pad_datagram);
+1792 }
+1793
+1794 // If this is the first datagram we set the segment size to the size of the
+1795 // first datagram.
+1796 if transmit.num_datagrams() == 1 {
+1797 transmit.clip_segment_size();
+1798 }
+1799 }
+1800 }
+1801 }
+1802
+1803 fn poll_transmit_mtu_probe(
+1804 &mut self,
+1805 now: Instant,
+1806 buf: &mut Vec<u8>,
+1807 path_id: PathId,
+1808 ) -> Option<Transmit> {
+1809 let (active_cid, probe_size) = self.get_mtu_probe_data(now, path_id)?;
+1810
+1811 // We are definitely sending a DPLPMTUD probe.
+1812 let mut transmit = TransmitBuf::new(buf, NonZeroUsize::MIN, probe_size as usize);
+1813 transmit.start_new_datagram_with_size(probe_size as usize);
+1814
+1815 let mut builder =
+1816 PacketBuilder::new(now, SpaceId::Data, path_id, active_cid, &mut transmit, self)?;
+1817
+1818 // We implement MTU probes as ping packets padded up to the probe size
+1819 trace!(?probe_size, "writing MTUD probe");
+1820 builder.write_frame(frame::Ping, &mut self.path_stats.for_path(path_id).frame_tx);
+1821
+1822 // If supported by the peer, we want no delays to the probe's ACK
+1823 if self.peer_supports_ack_frequency() {
+1824 builder.write_frame(
+1825 frame::ImmediateAck,
+1826 &mut self.path_stats.for_path(path_id).frame_tx,
+1827 );
+1828 }
+1829
+1830 builder.finish_and_track(now, self, path_id, PadDatagram::ToSize(probe_size));
+1831
+1832 self.path_stats.for_path(path_id).sent_plpmtud_probes += 1;
+1833
+1834 Some(self.build_transmit(path_id, transmit))
+1835 }
+1836
+1837 /// Returns the CID and probe size if a DPLPMTUD probe is needed.
+1838 ///
+1839 /// We MTU probe all paths for which all of the following is true:
+1840 /// - We have an active destination CID for the path.
+1841 /// - The remote address *and* path are validated.
+1842 /// - The path is not abandoned.
+1843 /// - The MTU Discovery subsystem wants to probe the path.
+1844 fn get_mtu_probe_data(&mut self, now: Instant, path_id: PathId) -> Option<(ConnectionId, u16)> {
+1845 let active_cid = self.remote_cids.get(&path_id).map(CidQueue::active)?;
+1846 let is_eligible = self.path_data(path_id).validated
+1847 && !self.path_data(path_id).is_validating_path()
+1848 && !self.abandoned_paths.contains(&path_id);
+1849
+1850 if !is_eligible {
+1851 return None;
+1852 }
+1853 let next_pn = self.spaces[SpaceId::Data]
+1854 .for_path(path_id)
+1855 .peek_tx_number();
+1856 let probe_size = self
+1857 .path_data_mut(path_id)
+1858 .mtud
+1859 .poll_transmit(now, next_pn)?;
+1860
+1861 Some((active_cid, probe_size))
+1862 }
+1863
+1864 /// Returns true if there is a further packet to send on [`PathId::ZERO`].
+1865 ///
+1866 /// In other words this is predicting whether the next call to
+1867 /// [`Connection::space_can_send`] issued will return some frames to be sent. Including
+1868 /// having to predict which packet number space it will be invoked with. This depends on
+1869 /// how both [`Connection::poll_transmit_on_path`] and
+1870 /// [`Connection::poll_transmit_path_space`] behave.
+1871 ///
+1872 /// This is needed to determine if packet coalescing can happen. Because the last packet
+1873 /// in a datagram may need to be padded and thus we must know if another packet will
+1874 /// follow or not.
+1875 ///
+1876 /// The next packet can be either in the same space, or in one of the following spaces
+1877 /// on the same path. Because a 0-RTT packet can be coalesced with a 1-RTT packet and
+1878 /// both are in the Data(PathId::ZERO) space. Previous spaces are not checked, because
+1879 /// packets are built from Initial to Handshake to Data spaces.
+1880 fn has_pending_packet(
+1881 &mut self,
+1882 current_space_id: SpaceId,
+1883 max_packet_size: usize,
+1884 connection_close_pending: bool,
+1885 ) -> bool {
+1886 let mut space_id = current_space_id;
+1887 loop {
+1888 let can_send = self.space_can_send(
+1889 space_id,
+1890 PathId::ZERO,
+1891 max_packet_size,
+1892 connection_close_pending,
+1893 );
+1894 if !can_send.is_empty() {
+1895 return true;
+1896 }
+1897 match space_id.next() {
+1898 Some(next_space_id) => space_id = next_space_id,
+1899 None => break,
+1900 }
+1901 }
+1902 false
+1903 }
+1904
+1905 /// Checks if creating a new datagram would be blocked by congestion control
+1906 fn path_congestion_check(
+1907 &mut self,
+1908 space_id: SpaceId,
+1909 path_id: PathId,
+1910 transmit: &TransmitBuf<'_>,
+1911 can_send: &SendableFrames,
+1912 now: Instant,
+1913 ) -> PathBlocked {
+1914 // Anti-amplification is only based on `total_sent`, which gets updated after
+1915 // the transmit is sent. Therefore we pass the amount of bytes for datagrams
+1916 // that are already created, as well as 1 byte for starting another datagram. If
+1917 // there is any anti-amplification budget left, we always allow a full MTU to be
+1918 // sent (see https://github.com/quinn-rs/quinn/issues/1082).
+1919 if self.side().is_server()
+1920 && self
+1921 .path_data(path_id)
+1922 .anti_amplification_blocked(transmit.len() as u64 + 1)
+1923 {
+1924 trace!(?space_id, %path_id, "blocked by anti-amplification");
+1925 return PathBlocked::AntiAmplification;
+1926 }
+1927
+1928 // Congestion control check.
+1929 // Tail loss probes must not be blocked by congestion, or a deadlock could arise.
+1930 let bytes_to_send = transmit.segment_size() as u64;
+1931 let need_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
+1932
+1933 if can_send.other && !need_loss_probe && !can_send.close {
+1934 let path = self.path_data(path_id);
+1935 if path.in_flight.bytes + bytes_to_send >= path.congestion.window() {
+1936 trace!(
+1937 ?space_id,
+1938 %path_id,
+1939 in_flight=%path.in_flight.bytes,
+1940 congestion_window=%path.congestion.window(),
+1941 "blocked by congestion control",
+1942 );
+1943 return PathBlocked::Congestion;
+1944 }
+1945 }
+1946
+1947 // Pacing check.
+1948 if let Some(delay) = self.path_data_mut(path_id).pacing_delay(bytes_to_send, now) {
+1949 let resume_time = now + delay;
+1950 self.timers.set(
+1951 Timer::PerPath(path_id, PathTimer::Pacing),
+1952 resume_time,
+1953 self.qlog.with_time(now),
+1954 );
+1955 // Loss probes and CONNECTION_CLOSE should be subject to pacing, even though
+1956 // they are not congestion controlled.
+1957 trace!(?space_id, %path_id, ?delay, "blocked by pacing");
+1958 return PathBlocked::Pacing;
+1959 }
+1960
+1961 PathBlocked::No
+1962 }
+1963
+1964 /// Send PATH_CHALLENGE for a previous path if necessary
+1965 ///
+1966 /// QUIC-TRANSPORT section 9.3.3
+1967 /// <https://www.rfc-editor.org/rfc/rfc9000.html#name-off-path-packet-forwarding>
+1968 fn send_prev_path_challenge(
+1969 &mut self,
+1970 now: Instant,
+1971 buf: &mut Vec<u8>,
+1972 path_id: PathId,
+1973 ) -> Option<Transmit> {
+1974 let (prev_cid, prev_path) = self.paths.get_mut(&path_id)?.prev.as_mut()?;
+1975 if !prev_path.pending_challenge {
+1976 return None;
+1977 };
+1978 prev_path.pending_challenge = false;
+1979 let token = self.rng.random();
+1980 let network_path = prev_path.network_path;
+1981 prev_path.record_path_challenge_sent(now, token, network_path);
+1982
+1983 debug_assert_eq!(
+1984 self.highest_space,
+1985 SpaceKind::Data,
+1986 "PATH_CHALLENGE queued without 1-RTT keys"
+1987 );
+1988 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
+1989 buf.start_new_datagram();
+1990
+1991 // Use the previous CID to avoid linking the new path with the previous path. We
+1992 // don't bother accounting for possible retirement of that prev_cid because this is
+1993 // sent once, immediately after migration, when the CID is known to be valid. Even
+1994 // if a post-migration packet caused the CID to be retired, it's fair to pretend
+1995 // this is sent first.
+1996 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, *prev_cid, buf, self)?;
+1997 let challenge = frame::PathChallenge(token);
+1998 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
+1999 builder.write_frame_with_log_msg(challenge, stats, Some("validating previous path"));
+2000
+2001 // An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame
+2002 // to at least the smallest allowed maximum datagram size of 1200 bytes,
+2003 // unless the anti-amplification limit for the path does not permit
+2004 // sending a datagram of this size
+2005 builder.pad_to(MIN_INITIAL_SIZE);
+2006
+2007 builder.finish(self, now);
+2008 self.path_stats
+2009 .for_path(path_id)
+2010 .udp_tx
+2011 .on_sent(1, buf.len());
+2012
+2013 trace!(
+2014 dst = ?network_path.remote,
+2015 src = ?network_path.local_ip,
+2016 len = buf.len(),
+2017 "sending prev_path off-path challenge",
+2018 );
+2019 Some(Transmit {
+2020 destination: network_path.remote,
+2021 size: buf.len(),
+2022 ecn: None,
+2023 segment_size: None,
+2024 src_ip: network_path.local_ip,
+2025 })
+2026 }
+2027
+2028 fn send_off_path_path_response(
+2029 &mut self,
+2030 now: Instant,
+2031 buf: &mut Vec<u8>,
+2032 path_id: PathId,
+2033 ) -> Option<Transmit> {
+2034 let network_path = self
+2035 .paths
+2036 .get_mut(&path_id)
+2037 .map(|state| state.data.network_path)?;
+2038 let cid_queue = self.remote_cids.get_mut(&path_id)?;
+2039 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
+2040 let (token, network_path) = pns.pending_path_responses.pop_off_path(network_path)?;
+2041
+2042 // TODO: make off-path probes unlinkable.
+2043 let cid = cid_queue.active();
+2044
+2045 // PATH_RESPONSE (off-path)
+2046 let frame = frame::PathResponse(token);
+2047
+2048 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
+2049 buf.start_new_datagram();
+2050
+2051 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, buf, self)?;
+2052 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
+2053 builder.write_frame_with_log_msg(frame, stats, Some("(off-path)"));
+2054
+2055 // PATH_CHALLENGE (off-path)
+2056 //
+2057 // If we are a client doing NAT traversal, always include a PATH_CHALLENGE with any
+2058 // off-path PATH_RESPONSE. No need to schedule any retries for this, if NAT
+2059 // traversal is taking place then this remote already is being probed with
+2060 // retries, this only speeds up a successful traversal.
+2061 if self
+2062 .find_validated_path_on_network_path(network_path)
+2063 .is_none()
+2064 && self.n0_nat_traversal.client_side().is_ok()
+2065 {
+2066 let token = self.rng.random();
+2067 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
+2068 builder.write_frame(frame::PathChallenge(token), stats);
+2069 let ip_port = (network_path.remote.ip(), network_path.remote.port());
+2070 self.n0_nat_traversal.mark_probe_sent(ip_port, token);
+2071 }
+2072
+2073 // Off-path: not tracked in congestion control. The packet is sent to a
+2074 // different destination than path_id's network path.
+2075 builder.pad_to(MIN_INITIAL_SIZE);
+2076 builder.finish(self, now);
+2077
+2078 let size = buf.len();
+2079 self.path_stats.for_path(path_id).udp_tx.on_sent(1, size);
+2080
+2081 trace!(
+2082 dst = ?network_path.remote,
+2083 src = ?network_path.local_ip,
+2084 len = buf.len(),
+2085 "sending off-path PATH_RESPONSE",
+2086 );
+2087 Some(Transmit {
+2088 destination: network_path.remote,
+2089 size,
+2090 ecn: None,
+2091 segment_size: None,
+2092 src_ip: network_path.local_ip,
+2093 })
+2094 }
+2095
+2096 /// Send a nat traversal challenge (off-path) on this path if possible.
+2097 fn send_nat_traversal_path_challenge(
+2098 &mut self,
+2099 now: Instant,
+2100 buf: &mut Vec<u8>,
+2101 path_id: PathId,
+2102 ) -> Option<Transmit> {
+2103 let remote = self.n0_nat_traversal.next_probe_addr()?;
+2104
+2105 if !self.paths.get(&path_id)?.data.validated {
+2106 // Path is not usable for probing
+2107 return None;
+2108 }
+2109
+2110 // TODO: Using the active CID here makes the paths linkable. This is a violation of
+2111 // RFC9000 but something we want to accept in the short term. Eventually we aim
+2112 // to fix up the supply of CIDs sufficiently so that we can keep paths unlinkable
+2113 // again.
+2114 let Some(cid) = self
+2115 .remote_cids
+2116 .get(&path_id)
+2117 .map(|cid_queue| cid_queue.active())
+2118 else {
+2119 trace!(%path_id, "Not sending NAT traversal probe for path with no CIDs");
+2120 return None;
+2121 };
+2122 let token = self.rng.random();
+2123
+2124 // PATH_CHALLENGE (NAT probe)
+2125 let frame = frame::PathChallenge(token);
+2126
+2127 let mut buf = TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
+2128 buf.start_new_datagram();
+2129
+2130 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, &mut buf, self)?;
+2131 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
+2132 builder.write_frame_with_log_msg(frame, stats, Some("(nat-traversal)"));
+2133 // Off-path: not tracked in congestion control. The packet is sent to a
+2134 // different destination than path_id's network path.
+2135 builder.finish(self, now);
+2136
+2137 // Mark as sent after packet build succeeds.
+2138 self.n0_nat_traversal.mark_probe_sent(remote, token);
+2139
+2140 let size = buf.len();
+2141 self.path_stats.for_path(path_id).udp_tx.on_sent(1, size);
+2142
+2143 trace!(dst = ?remote, len = buf.len(), "sending off-path NAT probe");
+2144 Some(Transmit {
+2145 destination: remote.into(),
+2146 size,
+2147 ecn: None,
+2148 segment_size: None,
+2149 src_ip: None,
+2150 })
+2151 }
+2152
+2153 /// Indicate what types of frames are ready to send for the given packet number space.
+2154 ///
+2155 /// Only for on-path data.
+2156 ///
+2157 /// *packet_size* is the number of bytes available to build the next packet.
+2158 /// *connection_close_pending* indicates whether a CONNECTION_CLOSE frame needs to be
+2159 /// sent.
+2160 fn space_can_send(
+2161 &mut self,
+2162 space_id: SpaceId,
+2163 path_id: PathId,
+2164 packet_size: usize,
+2165 connection_close_pending: bool,
+2166 ) -> SendableFrames {
+2167 let space = &mut self.spaces[space_id];
+2168 let space_has_crypto = self.crypto_state.has_keys(space_id.encryption_level());
+2169
+2170 if !space_has_crypto
+2171 && (space_id != SpaceId::Data
+2172 || !self.crypto_state.has_keys(EncryptionLevel::ZeroRtt)
+2173 || self.side.is_server())
+2174 {
+2175 // Nothing to send in this space
+2176 return SendableFrames::empty();
+2177 }
+2178
+2179 let mut can_send = space.can_send(path_id, &self.streams);
+2180
+2181 // Check for 1RTT space.
+2182 if space_id == SpaceId::Data {
+2183 let pn = space.for_path(path_id).peek_tx_number();
+2184 // Number of bytes available for frames if this is a 1-RTT packet. We're
+2185 // guaranteed to be able to send an individual frame at least this large in the
+2186 // next 1-RTT packet. This could be generalized to support every space, but it's
+2187 // only needed to handle large fixed-size frames, which only exist in 1-RTT
+2188 // (application datagrams).
+2189 let frame_space_1rtt =
+2190 packet_size.saturating_sub(self.predict_1rtt_overhead(pn, path_id));
+2191 can_send |= self.can_send_1rtt(path_id, frame_space_1rtt);
+2192 }
+2193
+2194 can_send.close = connection_close_pending && space_has_crypto;
+2195
+2196 can_send
+2197 }
+2198
+2199 /// Process `ConnectionEvent`s generated by the associated `Endpoint`
+2200 ///
+2201 /// Will execute protocol logic upon receipt of a connection event, in turn preparing signals
+2202 /// (including application `Event`s, `EndpointEvent`s and outgoing datagrams) that should be
+2203 /// extracted through the relevant methods.
+2204 pub fn handle_event(&mut self, event: ConnectionEvent) {
+2205 use ConnectionEventInner::*;
+2206 match event.0 {
+2207 Datagram(DatagramConnectionEvent {
+2208 now,
+2209 network_path,
+2210 path_id,
+2211 ecn,
+2212 first_decode,
+2213 remaining,
+2214 }) => {
+2215 let span = trace_span!("pkt", %path_id);
+2216 let _guard = span.enter();
+2217
+2218 if self.early_discard_packet(network_path, path_id) {
+2219 // A return value of true indicates we should discard this packet.
+2220 return;
+2221 }
+2222
+2223 let was_anti_amplification_blocked = self
+2224 .path(path_id)
+2225 .map(|path| path.anti_amplification_blocked(1))
+2226 // We never tried to send on an non-existing (new) path so have not been
+2227 // anti-amplification blocked for it previously.
+2228 .unwrap_or(false);
+2229
+2230 let rx = &mut self.path_stats.for_path(path_id).udp_rx;
+2231 rx.datagrams += 1;
+2232 rx.bytes += first_decode.len() as u64;
+2233 let data_len = first_decode.len();
+2234
+2235 self.handle_decode(now, network_path, path_id, ecn, first_decode);
+2236 // The current `path` might have changed inside `handle_decode` since the packet
+2237 // could have triggered a migration. The packet might also belong to an unknown
+2238 // path and have been rejected. Make sure the data received is accounted for the
+2239 // most recent path by accessing `path` after `handle_decode`.
+2240 if let Some(path) = self.path_mut(path_id) {
+2241 path.inc_total_recvd(data_len as u64);
+2242 }
+2243
+2244 if let Some(data) = remaining {
+2245 self.path_stats.for_path(path_id).udp_rx.bytes += data.len() as u64;
+2246 self.handle_coalesced(now, network_path, path_id, ecn, data);
+2247 }
+2248
+2249 if let Some(path) = self.paths.get_mut(&path_id) {
+2250 self.qlog
+2251 .emit_recovery_metrics(path_id, &mut path.data, now);
+2252 }
+2253
+2254 if was_anti_amplification_blocked {
+2255 // A prior attempt to set the loss detection timer may have failed due to
+2256 // anti-amplification, so ensure it's set now. Prevents a handshake deadlock if
+2257 // the server's first flight is lost.
+2258 self.set_loss_detection_timer(now, path_id);
+2259 }
+2260 }
+2261 NewIdentifiers(ids, now, cid_len, cid_lifetime) => {
+2262 let path_id = ids.first().map(|issued| issued.path_id).unwrap_or_default();
+2263 debug_assert!(ids.iter().all(|issued| issued.path_id == path_id));
+2264
+2265 // Path may have been abandoned while this reply was in flight,
+2266 // retire the CIDs instead of queuing them.
+2267 if self.abandoned_paths.contains(&path_id) {
+2268 if !self.state.is_drained() {
+2269 for issued in &ids {
+2270 self.endpoint_events
+2271 .push_back(EndpointEventInner::RetireConnectionId(
+2272 now,
+2273 path_id,
+2274 issued.sequence,
+2275 false,
+2276 ));
+2277 }
+2278 }
+2279 return;
+2280 }
+2281
+2282 let cid_state = self
+2283 .local_cid_state
+2284 .entry(path_id)
+2285 .or_insert_with(|| CidState::new(cid_len, cid_lifetime, now, 0));
+2286 cid_state.new_cids(&ids, now);
+2287
+2288 ids.into_iter().rev().for_each(|frame| {
+2289 self.spaces[SpaceId::Data].pending.new_cids.push(frame);
+2290 });
+2291 // Always update Timer::PushNewCid
+2292 self.reset_cid_retirement(now);
+2293 }
+2294 }
+2295 }
+2296
+2297 /// Returns whether a packet can be discarded early.
+2298 ///
+2299 /// Packets sent on the wrong network path can be entirely ignored, saving further
+2300 /// processing.
+2301 ///
+2302 /// Returns true if a packet coming in for this `path_id` over given `network_path`
+2303 /// should be discarded.
+2304 fn early_discard_packet(&mut self, network_path: FourTuple, path_id: PathId) -> bool {
+2305 if self.is_handshaking() && path_id != PathId::ZERO {
+2306 debug!(%network_path, %path_id, "discarding multipath packet during handshake");
+2307 return true;
+2308 }
+2309
+2310 let peer_may_probe = self.peer_may_probe();
+2311 let local_ip_may_migrate = self.local_ip_may_migrate();
+2312
+2313 // If this packet could initiate a migration and we're a client or a server that
+2314 // forbids migration, drop the datagram. This could be relaxed to heuristically
+2315 // permit NAT-rebinding-like migration.
+2316 if let Some(known_path) = self.path_mut(path_id) {
+2317 if network_path.remote != known_path.network_path.remote && !peer_may_probe {
+2318 trace!(
+2319 %path_id,
+2320 %network_path,
+2321 %known_path.network_path,
+2322 "discarding packet from unrecognized peer"
+2323 );
+2324 return true;
+2325 }
+2326
+2327 if known_path.network_path.local_ip.is_some()
+2328 && network_path.local_ip.is_some()
+2329 && known_path.network_path.local_ip != network_path.local_ip
+2330 && !local_ip_may_migrate
+2331 {
+2332 trace!(
+2333 %path_id,
+2334 %network_path,
+2335 %known_path.network_path,
+2336 "discarding packet sent to incorrect interface"
+2337 );
+2338 return true;
+2339 }
+2340 }
+2341 false
+2342 }
+2343
+2344 /// Whether the peer may probe new paths.
+2345 ///
+2346 /// RFC9000 §9 and QNT both have probing packets which may arrive from new paths. This
+2347 /// indicates whether these are allowed or not. This is a strict superset from
+2348 /// [`Self::peer_may_migrate`]: every network path that may be migrated to, may also
+2349 /// be probed. But e.g. servers may not migrate, but can be allowed to probe.
+2350 // TODO(flub): In RFC9000 the server is allowed to send off-path probing packets
+2351 // once the client has been probing such a 4-tuple. These probes are currently
+2352 // not yet recognised and will end up being discarded because of this.
+2353 // See https://github.com/n0-computer/noq/issues/607.
+2354 fn peer_may_probe(&self) -> bool {
+2355 match &self.side {
+2356 ConnectionSide::Client { .. } => {
+2357 if let Some(hs) = self.state.as_handshake() {
+2358 hs.allow_server_migration
+2359 } else {
+2360 self.n0_nat_traversal.is_negotiated() && self.is_handshake_confirmed()
+2361 }
+2362 }
+2363 ConnectionSide::Server { server_config } => {
+2364 self.is_handshake_confirmed()
+2365 && (server_config.migration || self.n0_nat_traversal.is_negotiated())
+2366 }
+2367 }
+2368 }
+2369
+2370 /// Whether the peer's remote address may migrate.
+2371 ///
+2372 /// In RFC9000 only the client may migrate.
+2373 ///
+2374 /// QUIC relies on stable endpoints during the handshake. So other than the server's
+2375 /// preferred_address transport parameter no side may migrate before the handshake is
+2376 /// completed.
+2377 ///
+2378 /// It is noteworthy that for iroh we allow server migrations during the handshake when
+2379 /// [`state::Handshake::allow_server_migration`] is enabled, but that is handled earlier
+2380 /// in [`Self::handle_packet`] and without probing the current and previous paths.
+2381 fn peer_may_migrate(&self) -> bool {
+2382 match &self.side {
+2383 ConnectionSide::Server { server_config } => {
+2384 server_config.migration && self.is_handshake_confirmed()
+2385 }
+2386 ConnectionSide::Client { .. } => false,
+2387 }
+2388 }
+2389
+2390 /// Whether our local IP address is allowed to change with new incoming packets.
+2391 ///
+2392 /// Incoming packets show us the local IP address we received a packet on, which could
+2393 /// be different from what we thought due to e.g. NAT rebinding or moving from mobile
+2394 /// data to WiFi without being notified of the network change.
+2395 ///
+2396 /// This is only allowed to happen after the handshake is confirmed and when we are the
+2397 /// client. Unless QNT is negotiated in which case the server is also allowed to
+2398 /// migrate.
+2399 ///
+2400 /// Be aware that probing packets, which do not exist in Multipath without QNT, are
+2401 /// exempt from this.
+2402 fn local_ip_may_migrate(&self) -> bool {
+2403 (self.side.is_client() || self.n0_nat_traversal.is_negotiated())
+2404 && self.is_handshake_confirmed()
+2405 }
+2406 /// Process timer expirations
+2407 ///
+2408 /// Executes protocol logic, potentially preparing signals (including application `Event`s,
+2409 /// `EndpointEvent`s and outgoing datagrams) that should be extracted through the relevant
+2410 /// methods.
+2411 ///
+2412 /// It is most efficient to call this immediately after the system clock reaches the latest
+2413 /// `Instant` that was output by `poll_timeout`; however spurious extra calls will simply
+2414 /// no-op and therefore are safe.
+2415 pub fn handle_timeout(&mut self, now: Instant) {
+2416 while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) {
+2417 let span = match timer {
+2418 Timer::Conn(timer) => trace_span!("timeout", scope = "conn", ?timer),
+2419 Timer::PerPath(path_id, timer) => {
+2420 trace_span!("timer_fired", scope="path", %path_id, ?timer)
+2421 }
+2422 };
+2423 let _guard = span.enter();
+2424 trace!("timeout");
+2425 match timer {
+2426 Timer::Conn(timer) => match timer {
+2427 ConnTimer::Close => {
+2428 let was_draining = self.state.move_to_drained(None);
+2429 if !was_draining {
+2430 self.endpoint_events.push_back(EndpointEventInner::Draining);
+2431 }
+2432 // move_to_drained checks that we weren't in drained before.
+2433 // Adding events to endpoint_events is only legal if `Drained` was never queued before.
+2434 self.endpoint_events.push_back(EndpointEventInner::Drained);
+2435 }
+2436 ConnTimer::Idle => {
+2437 self.kill(ConnectionError::TimedOut);
+2438 }
+2439 ConnTimer::KeepAlive => {
+2440 self.ping();
+2441 }
+2442 ConnTimer::KeyDiscard => {
+2443 self.crypto_state.discard_temporary_keys();
+2444 }
+2445 ConnTimer::PushNewCid => {
+2446 while let Some((path_id, when)) = self.next_cid_retirement() {
+2447 if when > now {
+2448 break;
+2449 }
+2450 match self.local_cid_state.get_mut(&path_id) {
+2451 None => error!(%path_id, "No local CID state for path"),
+2452 Some(cid_state) => {
+2453 // Update `retire_prior_to` field in NEW_CONNECTION_ID frame
+2454 let num_new_cid = cid_state.on_cid_timeout().into();
+2455 if !self.state.is_closed() {
+2456 trace!(
+2457 "push a new CID to peer RETIRE_PRIOR_TO field {}",
+2458 cid_state.retire_prior_to()
+2459 );
+2460 self.endpoint_events.push_back(
+2461 EndpointEventInner::NeedIdentifiers(
+2462 path_id,
+2463 now,
+2464 num_new_cid,
+2465 ),
+2466 );
+2467 }
+2468 }
+2469 }
+2470 }
+2471 }
+2472 ConnTimer::NoAvailablePath => {
+2473 // Grace period expired: all paths were abandoned and no new path
+2474 // was opened. Close the connection. There are no paths left to
+2475 // send CONNECTION_CLOSE on, so this is a silent close.
+2476 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4-8
+2477 if self.state.is_closed() || self.state.is_drained() {
+2478 // Connection already closing/drained (e.g. application called
+2479 // close() before the grace timer fired). Nothing to do.
+2480 error!("no viable path timer fired, but connection already closing");
+2481 } else {
+2482 trace!("no viable path grace period expired, closing connection");
+2483 let err = TransportError::NO_VIABLE_PATH(
+2484 "last path abandoned, no new path opened",
+2485 );
+2486 self.close_common();
+2487 self.set_close_timer(now);
+2488 self.connection_close_pending = true;
+2489 self.state.move_to_closed(err);
+2490 }
+2491 }
+2492 ConnTimer::NatTraversalProbeRetry => {
+2493 self.n0_nat_traversal.queue_retries(self.is_ipv6());
+2494 if let Some(delay) =
+2495 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
+2496 {
+2497 self.timers.set(
+2498 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
+2499 now + delay,
+2500 self.qlog.with_time(now),
+2501 );
+2502 trace!("re-queued NAT probes");
+2503 } else {
+2504 trace!("no more NAT probes remaining");
+2505 }
+2506 }
+2507 },
+2508 Timer::PerPath(path_id, timer) => {
+2509 match timer {
+2510 PathTimer::PathIdle => {
+2511 if let Err(err) =
+2512 self.close_path_inner(now, path_id, PathAbandonReason::TimedOut)
+2513 {
+2514 warn!(?err, "failed closing path");
+2515 }
+2516 }
+2517
+2518 PathTimer::PathKeepAlive => {
+2519 self.ping_path(path_id).ok();
+2520 }
+2521 PathTimer::LossDetection => {
+2522 self.on_loss_detection_timeout(now, path_id);
+2523 if let Some(path) = self.paths.get_mut(&path_id) {
+2524 self.qlog
+2525 .emit_recovery_metrics(path_id, &mut path.data, now);
+2526 } else {
+2527 error!("LossDetection fired for unknown path");
+2528 }
+2529 }
+2530 PathTimer::PathValidationFailed => {
+2531 let Some(path) = self.paths.get_mut(&path_id) else {
+2532 continue;
+2533 };
+2534 self.timers.stop(
+2535 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
+2536 self.qlog.with_time(now),
+2537 );
+2538 debug!("path migration validation failed");
+2539 if let Some((_, prev)) = path.prev.take() {
+2540 path.data = prev;
+2541 }
+2542 path.data.reset_on_path_challenges();
+2543 }
+2544 PathTimer::PathChallengeLost => {
+2545 let Some(path) = self.paths.get_mut(&path_id) else {
+2546 continue;
+2547 };
+2548 trace!(?path.data.lost_challenge_count, "path challenge deemed lost");
+2549 path.data.pending_challenge = true;
+2550 path.data.lost_challenge_count += 1;
+2551 self.timers.set(
+2552 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
+2553 now + path.data.on_path_challenge_expiry(),
+2554 self.qlog.with_time(now),
+2555 );
+2556 }
+2557 PathTimer::AbandonFromValidation => {
+2558 let Some(path) = self.paths.get_mut(&path_id) else {
+2559 continue;
+2560 };
+2561 path.data.reset_on_path_challenges();
+2562 self.timers.stop(
+2563 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
+2564 self.qlog.with_time(now),
+2565 );
+2566 debug!("new path validation failed");
+2567 if let Err(err) = self.close_path_inner(
+2568 now,
+2569 path_id,
+2570 PathAbandonReason::ValidationFailed,
+2571 ) {
+2572 warn!(?err, "failed closing path");
+2573 }
+2574 }
+2575 PathTimer::Pacing => {}
+2576 PathTimer::MaxAckDelay => {
+2577 // This timer is only armed in the Data space
+2578 self.spaces[SpaceId::Data]
+2579 .for_path(path_id)
+2580 .pending_acks
+2581 .on_max_ack_delay_timeout()
+2582 }
+2583 PathTimer::PathDrained => {
+2584 // The path was abandoned and 3*PTO has expired since. Clean up all
+2585 // remaining state and install stateless reset token.
+2586 self.timers.stop_per_path(path_id, self.qlog.with_time(now));
+2587 if let Some(local_cid_state) = self.local_cid_state.remove(&path_id) {
+2588 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events. All timers should be cleared in drained connections.
+2589 let (min_seq, max_seq) = local_cid_state.active_seq();
+2590 for seq in min_seq..=max_seq {
+2591 self.endpoint_events.push_back(
+2592 EndpointEventInner::RetireConnectionId(
+2593 now, path_id, seq, false,
+2594 ),
+2595 );
+2596 }
+2597 }
+2598 self.discard_path(path_id, now);
+2599 }
+2600 }
+2601 }
+2602 }
+2603 }
+2604 }
+2605
+2606 /// Close a connection immediately
+2607 ///
+2608 /// This does not ensure delivery of outstanding data. It is the application's responsibility to
+2609 /// call this only when all important communications have been completed, e.g. by calling
+2610 /// [`SendStream::finish`] on outstanding streams and waiting for the corresponding
+2611 /// [`StreamEvent::Finished`] event.
+2612 ///
+2613 /// If [`Streams::send_streams`] returns 0, all outstanding stream data has been
+2614 /// delivered. There may still be data from the peer that has not been received.
+2615 ///
+2616 /// [`StreamEvent::Finished`]: crate::StreamEvent::Finished
+2617 pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) {
+2618 self.close_inner(
+2619 now,
+2620 Close::Application(frame::ApplicationClose { error_code, reason }),
+2621 )
+2622 }
+2623
+2624 /// Close the connection immediately, initiated by an API call.
+2625 ///
+2626 /// This will not produce a [`ConnectionLost`] event propagated by the
+2627 /// [`Connection::poll`] call, because the API call already propagated the error to the
+2628 /// user.
+2629 ///
+2630 /// Not to be used when entering immediate close due to an internal state change based
+2631 /// on an event. See [`State::move_to_closed_local`] for details.
+2632 ///
+2633 /// This initiates immediate close from
+2634 /// <https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2>, moving to the closed
+2635 /// state.
+2636 ///
+2637 /// [`ConnectionLost`]: crate::Event::ConnectionLost
+2638 /// [`Connection::poll`]: super::Connection::poll
+2639 fn close_inner(&mut self, now: Instant, reason: Close) {
+2640 let was_closed = self.state.is_closed();
+2641 if !was_closed {
+2642 self.close_common();
+2643 self.set_close_timer(now);
+2644 self.connection_close_pending = true;
+2645 self.state.move_to_closed_local(reason);
+2646 }
+2647 }
+2648
+2649 /// Control datagrams
+2650 pub fn datagrams(&mut self) -> Datagrams<'_> {
+2651 Datagrams { conn: self }
+2652 }
+2653
+2654 /// Returns connection statistics
+2655 pub fn stats(&mut self) -> ConnectionStats {
+2656 let mut stats = self.partial_stats.clone();
+2657
+2658 for path_stats in self.path_stats.iter_stats() {
+2659 // Self::path_stats() computes the path rtt, cwnd and current_mtu on access
+2660 // because they are not simple counters. When computing the connection stats we
+2661 // can skip that effort since those fields are not used in the `impl
+2662 // Add<PathStats> for ConnectionStats`.
+2663 stats += *path_stats;
+2664 }
+2665
+2666 stats
+2667 }
+2668
+2669 /// Returns path statistics
+2670 pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> {
+2671 let path = self.paths.get(&path_id)?;
+2672 let stats = self.path_stats.for_path(path_id);
+2673 stats.rtt = path.data.rtt.get();
+2674 stats.cwnd = path.data.congestion.window();
+2675 stats.current_mtu = path.data.mtud.current_mtu();
+2676 Some(*stats)
+2677 }
+2678
+2679 /// Ping the remote endpoint
+2680 ///
+2681 /// Causes an ACK-eliciting packet to be transmitted on the connection.
+2682 pub fn ping(&mut self) {
+2683 // TODO(flub): This is very brute-force: it pings *all* the paths. Instead it would
+2684 // be nice if we could only send a single packet for this.
+2685 for path_data in self.spaces[self.highest_space].number_spaces.values_mut() {
+2686 path_data.pending_ping = true;
+2687 }
+2688 }
+2689
+2690 /// Ping the remote endpoint over a specific path
+2691 ///
+2692 /// Causes an ACK-eliciting packet to be transmitted on the path.
+2693 pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> {
+2694 let path_data = self.spaces[self.highest_space]
+2695 .number_spaces
+2696 .get_mut(&path)
+2697 .ok_or(ClosedPath { _private: () })?;
+2698 path_data.pending_ping = true;
+2699 Ok(())
+2700 }
+2701
+2702 /// Update traffic keys spontaneously
+2703 ///
+2704 /// This can be useful for testing key updates, as they otherwise only happen infrequently.
+2705 pub fn force_key_update(&mut self) {
+2706 if !self.state.is_established() {
+2707 debug!("ignoring forced key update in illegal state");
+2708 return;
+2709 }
+2710 if self.crypto_state.prev_crypto.is_some() {
+2711 // We already just updated, or are currently updating, the keys. Concurrent key updates
+2712 // are illegal.
+2713 debug!("ignoring redundant forced key update");
+2714 return;
+2715 }
+2716 self.crypto_state.update_keys(None, false);
+2717 }
+2718
+2719 /// Get a session reference
+2720 pub fn crypto_session(&self) -> &dyn crypto::Session {
+2721 self.crypto_state.session.as_ref()
+2722 }
+2723
+2724 /// Whether the connection is in the process of being established
+2725 ///
+2726 /// If this returns `false`, the connection may be either established or closed, signaled by the
+2727 /// emission of a [`Connected`](Event::Connected) or [`ConnectionLost`](Event::ConnectionLost)
+2728 /// event respectively. Note that locally-initiated closes via [`close()`](Self::close) do not
+2729 /// emit a `ConnectionLost` event.
+2730 ///
+2731 /// For an established connection this essentially means the handshake is **completed**,
+2732 /// but not necessarily yet confirmed.
+2733 pub fn is_handshaking(&self) -> bool {
+2734 self.state.is_handshake()
+2735 }
+2736
+2737 /// Whether the connection is closed
+2738 ///
+2739 /// Closed connections cannot transport any further data. A connection becomes closed when
+2740 /// either peer application intentionally closes it, or when either transport layer detects an
+2741 /// error such as a time-out or certificate validation failure.
+2742 ///
+2743 /// A [`ConnectionLost`](Event::ConnectionLost) event is emitted with details when the
+2744 /// connection is closed by the peer or due to an error. When the local application closes
+2745 /// the connection via [`close()`](Self::close), no `ConnectionLost` event is emitted;
+2746 /// instead, pending operations fail with [`ConnectionError::LocallyClosed`].
+2747 pub fn is_closed(&self) -> bool {
+2748 self.state.is_closed()
+2749 }
+2750
+2751 /// Whether there is no longer any need to keep the connection around
+2752 ///
+2753 /// Closed connections become drained after a brief timeout to absorb any remaining in-flight
+2754 /// packets from the peer. All drained connections have been closed.
+2755 pub fn is_drained(&self) -> bool {
+2756 self.state.is_drained()
+2757 }
+2758
+2759 /// For clients, if the peer accepted the 0-RTT data packets
+2760 ///
+2761 /// The value is meaningless until after the handshake completes.
+2762 pub fn accepted_0rtt(&self) -> bool {
+2763 self.crypto_state.accepted_0rtt
+2764 }
+2765
+2766 /// Whether 0-RTT is/was possible during the handshake
+2767 pub fn has_0rtt(&self) -> bool {
+2768 self.crypto_state.zero_rtt_enabled
+2769 }
+2770
+2771 /// Whether there are any pending retransmits
+2772 pub fn has_pending_retransmits(&self) -> bool {
+2773 !self.spaces[SpaceId::Data].pending.is_empty(&self.streams)
+2774 }
+2775
+2776 /// Look up whether we're the client or server of this Connection
+2777 pub fn side(&self) -> Side {
+2778 self.side.side()
+2779 }
+2780
+2781 /// Get the address observed by the remote over the given path
+2782 pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> {
+2783 self.path(path_id)
+2784 .map(|path_data| {
+2785 path_data
+2786 .last_observed_addr_report
+2787 .as_ref()
+2788 .map(|observed| observed.socket_addr())
+2789 })
+2790 .ok_or(ClosedPath { _private: () })
+2791 }
+2792
+2793 /// Current best estimate of this connection's latency (round-trip-time)
+2794 pub fn rtt(&self, path_id: PathId) -> Option<Duration> {
+2795 self.path(path_id).map(|d| d.rtt.get())
+2796 }
+2797
+2798 /// Current state of this connection's congestion controller, for debugging purposes
+2799 pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> {
+2800 self.path(path_id).map(|d| d.congestion.as_ref())
+2801 }
+2802
+2803 /// Modify the number of remotely initiated streams that may be concurrently open
+2804 ///
+2805 /// No streams may be opened by the peer unless fewer than `count` are already open. Large
+2806 /// `count`s increase both minimum and worst-case memory consumption.
+2807 pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) {
+2808 self.streams.set_max_concurrent(dir, count);
+2809 // If the limit was reduced, then a flow control update previously deemed insignificant may
+2810 // now be significant.
+2811 let pending = &mut self.spaces[SpaceId::Data].pending;
+2812 self.streams.queue_max_stream_id(pending);
+2813 }
+2814
+2815 /// Modify the number of open paths allowed when multipath is enabled
+2816 ///
+2817 /// When reducing the number of concurrent paths this will only affect delaying sending
+2818 /// new MAX_PATH_ID frames until fewer than this number of paths are possible. To
+2819 /// actively reduce paths they must be closed using [`Connection::close_path`], which
+2820 /// can also be used to close not-yet-opened paths.
+2821 ///
+2822 /// If multipath is not negotiated (see the [`TransportConfig`]) this can not enable
+2823 /// multipath and will fail.
+2824 pub fn set_max_concurrent_paths(
+2825 &mut self,
+2826 now: Instant,
+2827 count: NonZeroU32,
+2828 ) -> Result<(), MultipathNotNegotiated> {
+2829 if !self.is_multipath_negotiated() {
+2830 return Err(MultipathNotNegotiated { _private: () });
+2831 }
+2832 self.max_concurrent_paths = count;
+2833
+2834 let in_use_count = self
+2835 .local_max_path_id
+2836 .next()
+2837 .saturating_sub(self.abandoned_paths.len())
+2838 .as_u32();
+2839 let extra_needed = count.get().saturating_sub(in_use_count);
+2840 let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed);
+2841
+2842 self.set_max_path_id(now, new_max_path_id);
+2843
+2844 Ok(())
+2845 }
+2846
+2847 /// If needed, issues a new MAX_PATH_ID frame and new CIDs for any newly allowed paths
+2848 fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) {
+2849 if max_path_id <= self.local_max_path_id {
+2850 return;
+2851 }
+2852
+2853 self.local_max_path_id = max_path_id;
+2854 self.spaces[SpaceId::Data].pending.max_path_id = true;
+2855
+2856 self.issue_first_path_cids(now);
+2857 }
+2858
+2859 /// Current number of remotely initiated streams that may be concurrently open
+2860 ///
+2861 /// If the target for this limit is reduced using [`set_max_concurrent_streams`](Self::set_max_concurrent_streams),
+2862 /// it will not change immediately, even if fewer streams are open. Instead, it will
+2863 /// decrement by one for each time a remotely initiated stream of matching directionality is closed.
+2864 pub fn max_concurrent_streams(&self, dir: Dir) -> u64 {
+2865 self.streams.max_concurrent(dir)
+2866 }
+2867
+2868 /// See [`TransportConfig::send_window()`]
+2869 pub fn set_send_window(&mut self, send_window: u64) {
+2870 self.streams.set_send_window(send_window);
+2871 }
+2872
+2873 /// See [`TransportConfig::receive_window()`]
+2874 pub fn set_receive_window(&mut self, receive_window: VarInt) {
+2875 if self.streams.set_receive_window(receive_window) {
+2876 self.spaces[SpaceId::Data].pending.max_data = true;
+2877 }
+2878 }
+2879
+2880 /// Whether the Multipath for QUIC extension is enabled.
+2881 ///
+2882 /// Multipath is only enabled after the handshake is completed and if it was enabled by both
+2883 /// peers.
+2884 pub fn is_multipath_negotiated(&self) -> bool {
+2885 !self.is_handshaking()
+2886 && self.config.max_concurrent_multipath_paths.is_some()
+2887 && self.peer_params.initial_max_path_id.is_some()
+2888 }
+2889
+2890 fn on_ack_received(
+2891 &mut self,
+2892 now: Instant,
+2893 space: SpaceId,
+2894 ack: frame::Ack,
+2895 ) -> Result<(), TransportError> {
+2896 // All ACKs are referencing path 0
+2897 let path = PathId::ZERO;
+2898 self.inner_on_ack_received(now, space, path, ack)
+2899 }
+2900
+2901 fn on_path_ack_received(
+2902 &mut self,
+2903 now: Instant,
+2904 space: SpaceId,
+2905 path_ack: frame::PathAck,
+2906 ) -> Result<(), TransportError> {
+2907 let (ack, path) = path_ack.into_ack();
+2908 self.inner_on_ack_received(now, space, path, ack)
+2909 }
+2910
+2911 /// Handles an ACK frame acknowledging packets sent on *path*.
+2912 fn inner_on_ack_received(
+2913 &mut self,
+2914 now: Instant,
+2915 space: SpaceId,
+2916 path: PathId,
+2917 ack: frame::Ack,
+2918 ) -> Result<(), TransportError> {
+2919 if !self.spaces[space].number_spaces.contains_key(&path) {
+2920 if self.abandoned_paths.contains(&path) {
+2921 // See also
+2922 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4.3-3
+2923 // > When an endpoint finally deletes all state associated with the path [...]
+2924 // > PATH_ACK frames received with an abandoned path ID are silently ignored,
+2925 // > as specified in Section 4.
+2926 trace!("silently ignoring PATH_ACK on discarded path");
+2927 return Ok(());
+2928 } else {
+2929 return Err(TransportError::PROTOCOL_VIOLATION(
+2930 "received PATH_ACK with path ID never used",
+2931 ));
+2932 }
+2933 }
+2934 if ack.largest >= self.spaces[space].for_path(path).next_packet_number {
+2935 return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked"));
+2936 }
+2937 // `Some(pn)` if this ACK raised `largest_acked_packet_pn`.
+2938 let new_largest_pn = {
+2939 let space = &mut self.spaces[space].for_path(path);
+2940 if space
+2941 .largest_acked_packet_pn
+2942 .is_none_or(|pn| ack.largest > pn)
+2943 {
+2944 space.largest_acked_packet_pn = Some(ack.largest);
+2945 if let Some(info) = space.sent_packets.get(ack.largest) {
+2946 // This should always succeed, but a misbehaving peer might ACK a packet we
+2947 // haven't sent. At worst, that will result in us spuriously reducing the
+2948 // congestion window.
+2949 space.largest_acked_packet_send_time = info.time_sent;
+2950 }
+2951 Some(ack.largest)
+2952 } else {
+2953 None
+2954 }
+2955 };
+2956
+2957 if self.detect_spurious_loss(&ack, space, path) {
+2958 self.path_stats.for_path(path).spurious_congestion_events += 1;
+2959 self.path_data_mut(path)
+2960 .congestion
+2961 .on_spurious_congestion_event();
+2962 }
+2963
+2964 // Avoid DoS from unreasonably huge ack ranges by filtering out just the new acks.
+2965 let mut newly_acked: ArrayRangeSet = ArrayRangeSet::new();
+2966 for range in ack.iter() {
+2967 self.spaces[space].for_path(path).check_ack(range.clone())?;
+2968 for (pn, _) in self.spaces[space]
+2969 .for_path(path)
+2970 .sent_packets
+2971 .iter_range(range)
+2972 {
+2973 newly_acked.insert_one(pn);
+2974 }
+2975 }
+2976
+2977 if newly_acked.is_empty() {
+2978 return Ok(());
+2979 }
+2980
+2981 let mut ack_eliciting_acked = false;
+2982 for packet in newly_acked.elts() {
+2983 if let Some(info) = self.spaces[space].for_path(path).take(packet) {
+2984 for (acked_path_id, acked_pn) in info.largest_acked.iter() {
+2985 // Assume ACKs for all packets below the largest acknowledged in
+2986 // `packet` have been received. This can cause the peer to spuriously
+2987 // retransmit if some of our earlier ACKs were lost, but allows for
+2988 // simpler state tracking. See discussion at
+2989 // https://www.rfc-editor.org/rfc/rfc9000.html#name-limiting-ranges-by-tracking
+2990 if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) {
+2991 pns.pending_acks.subtract_below(*acked_pn);
+2992 }
+2993 }
+2994 ack_eliciting_acked |= info.ack_eliciting;
+2995
+2996 // Notify MTU discovery that a packet was acked, because it might be an MTU probe
+2997 let path_data = self.path_data_mut(path);
+2998 let mtu_updated = path_data.mtud.on_acked(space.kind(), packet, info.size);
+2999 if mtu_updated {
+3000 path_data
+3001 .congestion
+3002 .on_mtu_update(path_data.mtud.current_mtu());
+3003 }
+3004
+3005 // Notify ack frequency that a packet was acked, because it might contain an ACK_FREQUENCY frame
+3006 self.ack_frequency.on_acked(path, packet);
+3007
+3008 self.on_packet_acked(now, path, packet, info);
+3009 }
+3010 }
+3011
+3012 let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet_pn;
+3013 let path_data = self.path_data_mut(path);
+3014 let app_limited = path_data.app_limited;
+3015 let in_flight = path_data.in_flight.bytes;
+3016
+3017 path_data
+3018 .congestion
+3019 .on_end_acks(now, in_flight, app_limited, largest_ackd);
+3020
+3021 if new_largest_pn.is_some() && ack_eliciting_acked {
+3022 let ack_delay = if space != SpaceId::Data {
+3023 Duration::from_micros(0)
+3024 } else {
+3025 cmp::min(
+3026 self.ack_frequency.peer_max_ack_delay,
+3027 Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0),
+3028 )
+3029 };
+3030 let rtt = now.saturating_duration_since(
+3031 self.spaces[space]
+3032 .for_path(path)
+3033 .largest_acked_packet_send_time,
+3034 );
+3035
+3036 let next_pn = self.spaces[space].for_path(path).next_packet_number;
+3037 let path_data = self.path_data_mut(path);
+3038 // TODO(@divma): should be a method of path, should be contained in a single place
+3039 path_data.rtt.update(ack_delay, rtt);
+3040 if path_data.first_packet_after_rtt_sample.is_none() {
+3041 path_data.first_packet_after_rtt_sample = Some((space.kind(), next_pn));
+3042 }
+3043 }
+3044
+3045 // Must be called before crypto/pto_count are clobbered
+3046 self.detect_lost_packets(now, space, path, true);
+3047
+3048 // If the peer did not complete the handshake address validation the ACK could be
+3049 // spoofed, e.g. in the Initial space. Setting the pto_count back to 0 removes the
+3050 // exponential backoff from the PTO timer and would result in too many tail-loss
+3051 // probes being sent.
+3052 if self.peer_completed_handshake_address_validation() {
+3053 self.path_data_mut(path).pto_count = 0;
+3054 }
+3055
+3056 // Explicit congestion notification
+3057 // TODO(@divma): this code is a good example of logic that should be contained in a single
+3058 // place but it's split between the path data and the packet number space data, we should
+3059 // find a way to make this work without two lookups
+3060 if self.path_data(path).sending_ecn {
+3061 if let Some(ecn) = ack.ecn {
+3062 // We only examine ECN counters from ACKs that we are certain we received in transmit
+3063 // order, allowing us to compute an increase in ECN counts to compare against the number
+3064 // of newly acked packets that remains well-defined in the presence of arbitrary packet
+3065 // reordering.
+3066 if let Some(largest_sent_pn) = new_largest_pn {
+3067 let sent = self.spaces[space]
+3068 .for_path(path)
+3069 .largest_acked_packet_send_time;
+3070 self.process_ecn(
+3071 now,
+3072 space,
+3073 path,
+3074 newly_acked.range_count() as u64,
+3075 ecn,
+3076 sent,
+3077 largest_sent_pn,
+3078 );
+3079 }
+3080 } else {
+3081 // We always start out sending ECN, so any ack that doesn't acknowledge it disables it.
+3082 debug!("ECN not acknowledged by peer");
+3083 self.path_data_mut(path).sending_ecn = false;
+3084 }
+3085 }
+3086
+3087 self.set_loss_detection_timer(now, path);
+3088 Ok(())
+3089 }
+3090
+3091 fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool {
+3092 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
+3093
+3094 if lost_packets.is_empty() {
+3095 return false;
+3096 }
+3097
+3098 for range in ack.iter() {
+3099 let spurious_losses: Vec<u64> = lost_packets
+3100 .iter_range(range.clone())
+3101 .map(|(pn, _info)| pn)
+3102 .collect();
+3103
+3104 for pn in spurious_losses {
+3105 lost_packets.remove(pn);
+3106 }
+3107 }
+3108
+3109 // If this ACK frame acknowledged all deemed lost packets,
+3110 // then we have raised a spurious congestion event in the past.
+3111 // We cannot conclude when there are remaining packets,
+3112 // but future ACK frames might indicate a spurious loss detection.
+3113 lost_packets.is_empty()
+3114 }
+3115
+3116 /// Drain lost packets that we reasonably think will never arrive
+3117 ///
+3118 /// The current criterion is copied from `msquic`:
+3119 /// discard packets that were sent earlier than 2 probe timeouts ago.
+3120 fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) {
+3121 let two_pto = 2 * self.path_data(path).rtt.pto_base();
+3122
+3123 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
+3124 lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto);
+3125 }
+3126
+3127 /// Process a new ECN block from an in-order ACK
+3128 fn process_ecn(
+3129 &mut self,
+3130 now: Instant,
+3131 space: SpaceId,
+3132 path: PathId,
+3133 newly_acked_pn: u64,
+3134 ecn: frame::EcnCounts,
+3135 largest_sent_time: Instant,
+3136 largest_sent_pn: u64,
+3137 ) {
+3138 match self.spaces[space]
+3139 .for_path(path)
+3140 .detect_ecn(newly_acked_pn, ecn)
+3141 {
+3142 Err(e) => {
+3143 debug!("halting ECN due to verification failure: {}", e);
+3144
+3145 self.path_data_mut(path).sending_ecn = false;
+3146 // Wipe out the existing value because it might be garbage and could interfere with
+3147 // future attempts to use ECN on new paths.
+3148 self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO;
+3149 }
+3150 Ok(false) => {}
+3151 Ok(true) => {
+3152 self.path_stats.for_path(path).congestion_events += 1;
+3153 self.path_data_mut(path).congestion.on_congestion_event(
+3154 now,
+3155 largest_sent_time,
+3156 false,
+3157 true,
+3158 0,
+3159 largest_sent_pn,
+3160 );
+3161 }
+3162 }
+3163 }
+3164
+3165 // Not timing-aware, so it's safe to call this for inferred acks, such as arise from
+3166 // high-latency handshakes
+3167 fn on_packet_acked(&mut self, now: Instant, path_id: PathId, pn: u64, info: SentPacket) {
+3168 let path = self.path_data_mut(path_id);
+3169 let app_limited = path.app_limited;
+3170 path.remove_in_flight(&info);
+3171 if info.ack_eliciting && info.path_generation == path.generation() {
+3172 // Only pass ACKs to the congestion controller if it belongs to this exact
+3173 // generation of the path. Otherwise we might be feeding ACKs from the previous
+3174 // 4-tuple into our congestion controller.
+3175 let rtt = path.rtt;
+3176 path.congestion
+3177 .on_ack(now, info.time_sent, info.size.into(), pn, app_limited, &rtt);
+3178 }
+3179
+3180 // Update state for confirmed delivery of frames
+3181 if let Some(retransmits) = info.retransmits.get() {
+3182 for (id, _) in retransmits.reset_stream.iter() {
+3183 self.streams.reset_acked(*id);
+3184 }
+3185 }
+3186
+3187 for frame in info.stream_frames {
+3188 self.streams.received_ack_of(frame);
+3189 }
+3190 }
+3191
+3192 fn set_key_discard_timer(&mut self, now: Instant, space: SpaceKind) {
+3193 let start = if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) {
+3194 now
+3195 } else {
+3196 self.crypto_state
+3197 .prev_crypto
+3198 .as_ref()
+3199 .expect("no previous keys")
+3200 .end_packet
+3201 .as_ref()
+3202 .expect("update not acknowledged yet")
+3203 .1
+3204 };
+3205
+3206 // QUIC-MULTIPATH § 2.5 Key Phase Update Process: use largest PTO of all paths.
+3207 self.timers.set(
+3208 Timer::Conn(ConnTimer::KeyDiscard),
+3209 start + self.max_pto_for_space(space) * 3,
+3210 self.qlog.with_time(now),
+3211 );
+3212 }
+3213
+3214 /// Handle a [`PathTimer::LossDetection`] timeout.
+3215 ///
+3216 /// This timer expires for two reasons:
+3217 /// - An ACK-eliciting packet we sent should be considered lost.
+3218 /// - The PTO may have expired and a tail-loss probe needs to be scheduled.
+3219 ///
+3220 /// The former needs us to schedule re-transmission of the lost data.
+3221 ///
+3222 /// The latter means we have not received an ACK for an ack-eliciting packet we sent
+3223 /// within the PTO time-window. We need to schedule a tail-loss probe, an ack-eliciting
+3224 /// packet, to try and elicit new acknowledgements. These new acknowledgements will
+3225 /// indicate whether the previously sent packets were lost or not.
+3226 fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) {
+3227 if let Some((_, pn_space)) = self.loss_time_and_space(path_id) {
+3228 // Time threshold loss Detection
+3229 self.detect_lost_packets(now, pn_space, path_id, false);
+3230 self.set_loss_detection_timer(now, path_id);
+3231 return;
+3232 }
+3233
+3234 let Some((_, space)) = self.pto_time_and_space(now, path_id) else {
+3235 error!(%path_id, "PTO expired while unset");
+3236 return;
+3237 };
+3238 trace!(
+3239 in_flight = self.path_data(path_id).in_flight.bytes,
+3240 count = self.path_data(path_id).pto_count,
+3241 ?space,
+3242 %path_id,
+3243 "PTO fired"
+3244 );
+3245
+3246 let count = match self.path_data(path_id).in_flight.ack_eliciting {
+3247 // A PTO when we're not expecting any ACKs must be due to handshake
+3248 // anti-amplification deadlock prevention.
+3249 0 => {
+3250 debug_assert!(!self.peer_completed_handshake_address_validation());
+3251 1
+3252 }
+3253 // Conventional loss probe
+3254 _ => 2,
+3255 };
+3256 let pns = self.spaces[space].for_path(path_id);
+3257 pns.loss_probes = pns.loss_probes.saturating_add(count);
+3258 let path_data = self.path_data_mut(path_id);
+3259 path_data.pto_count = path_data.pto_count.saturating_add(1);
+3260 self.set_loss_detection_timer(now, path_id);
+3261 }
+3262
+3263 /// Detect any lost packets
+3264 ///
+3265 /// There are two cases in which we detects lost packets:
+3266 ///
+3267 /// - We received an ACK packet.
+3268 /// - The [`PathTimer::LossDetection`] timer expired. So there is an un-acknowledged packet
+3269 /// that was followed by an acknowledged packet. The loss timer for this
+3270 /// un-acknowledged packet expired and we need to detect that packet as lost.
+3271 ///
+3272 /// Packets are lost if they are both (See RFC9002 §6.1):
+3273 ///
+3274 /// - Unacknowledged, in flight and sent prior to an acknowledged packet.
+3275 /// - Old enough by either:
+3276 /// - Having a packet number [`TransportConfig::packet_threshold`] lower then the last
+3277 /// acknowledged packet.
+3278 /// - Being sent [`TransportConfig::time_threshold`] * RTT in the past.
+3279 fn detect_lost_packets(
+3280 &mut self,
+3281 now: Instant,
+3282 pn_space: SpaceId,
+3283 path_id: PathId,
+3284 due_to_ack: bool,
+3285 ) {
+3286 let mut lost_packets = Vec::<u64>::new();
+3287 let mut lost_mtu_probe = None;
+3288 let mut in_persistent_congestion = false;
+3289 let mut size_of_lost_packets = 0u64;
+3290 self.spaces[pn_space].for_path(path_id).loss_time = None;
+3291
+3292 // Find all the lost packets, populating all variables initialised above.
+3293
+3294 let path = self.path_data(path_id);
+3295 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
+3296 let loss_delay = path
+3297 .rtt
+3298 .conservative()
+3299 .mul_f32(self.config.time_threshold)
+3300 .max(TIMER_GRANULARITY);
+3301 let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample;
+3302
+3303 let largest_acked_packet_pn = self.spaces[pn_space]
+3304 .for_path(path_id)
+3305 .largest_acked_packet_pn
+3306 .expect("detect_lost_packets only to be called if path received at least one ACK");
+3307 let packet_threshold = self.config.packet_threshold as u64;
+3308
+3309 // InPersistentCongestion: Determine if all packets in the time period before the newest
+3310 // lost packet, including the edges, are marked lost. PTO computation must always
+3311 // include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1).
+3312 let congestion_period = self
+3313 .pto(SpaceKind::Data, path_id)
+3314 .saturating_mul(self.config.persistent_congestion_threshold);
+3315 let mut persistent_congestion_start: Option<Instant> = None;
+3316 let mut prev_packet = None;
+3317 let space = self.spaces[pn_space].for_path(path_id);
+3318
+3319 for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet_pn) {
+3320 if prev_packet != Some(packet.wrapping_sub(1)) {
+3321 // An intervening packet was acknowledged
+3322 persistent_congestion_start = None;
+3323 }
+3324
+3325 // Packets sent before now - loss_delay are deemed lost.
+3326 // However, we avoid subtraction as it can panic and there's no
+3327 // saturating equivalent of this subtraction operation with a Duration.
+3328 let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay;
+3329 if packet_too_old || largest_acked_packet_pn >= packet + packet_threshold {
+3330 // The packet should be declared lost.
+3331 if Some(packet) == in_flight_mtu_probe {
+3332 // Lost MTU probes are not included in `lost_packets`, because they
+3333 // should not trigger a congestion control response
+3334 lost_mtu_probe = in_flight_mtu_probe;
+3335 } else {
+3336 lost_packets.push(packet);
+3337 size_of_lost_packets += info.size as u64;
+3338 if info.ack_eliciting && due_to_ack {
+3339 match persistent_congestion_start {
+3340 // Two ACK-eliciting packets lost more than
+3341 // congestion_period apart, with no ACKed packets in between
+3342 Some(start) if info.time_sent - start > congestion_period => {
+3343 in_persistent_congestion = true;
+3344 }
+3345 // Persistent congestion must start after the first RTT sample
+3346 None if first_packet_after_rtt_sample
+3347 .is_some_and(|x| x < (pn_space.kind(), packet)) =>
+3348 {
+3349 persistent_congestion_start = Some(info.time_sent);
+3350 }
+3351 _ => {}
+3352 }
+3353 }
+3354 }
+3355 } else {
+3356 // The packet should not yet be declared lost.
+3357 if space.loss_time.is_none() {
+3358 // Since we iterate in order the lowest packet number's loss time will
+3359 // always be the earliest.
+3360 space.loss_time = Some(info.time_sent + loss_delay);
+3361 }
+3362 persistent_congestion_start = None;
+3363 }
+3364
+3365 prev_packet = Some(packet);
+3366 }
+3367
+3368 self.handle_lost_packets(
+3369 pn_space,
+3370 path_id,
+3371 now,
+3372 lost_packets,
+3373 lost_mtu_probe,
+3374 loss_delay,
+3375 in_persistent_congestion,
+3376 size_of_lost_packets,
+3377 );
+3378 }
+3379
+3380 /// Drops the path state, declaring any remaining in-flight packets as lost
+3381 fn discard_path(&mut self, path_id: PathId, now: Instant) {
+3382 trace!(%path_id, "dropping path state");
+3383 let path = self.path_data(path_id);
+3384 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
+3385
+3386 let mut size_of_lost_packets = 0u64; // add to path_stats.lost_bytes;
+3387 let lost_pns: Vec<_> = self.spaces[SpaceId::Data]
+3388 .for_path(path_id)
+3389 .sent_packets
+3390 .iter()
+3391 .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe)
+3392 .map(|(pn, info)| {
+3393 size_of_lost_packets += info.size as u64;
+3394 pn
+3395 })
+3396 .collect();
+3397
+3398 if !lost_pns.is_empty() {
+3399 trace!(
+3400 %path_id,
+3401 count = lost_pns.len(),
+3402 lost_bytes = size_of_lost_packets,
+3403 "packets lost on path abandon"
+3404 );
+3405 self.handle_lost_packets(
+3406 SpaceId::Data,
+3407 path_id,
+3408 now,
+3409 lost_pns,
+3410 in_flight_mtu_probe,
+3411 Duration::ZERO,
+3412 false,
+3413 size_of_lost_packets,
+3414 );
+3415 }
+3416 // Before removing the path, we fetch the final path stats via `Self::path_stats`.
+3417 // This updates some values for the last time.
+3418 let path_stats = self.path_stats.discard(&path_id);
+3419 self.partial_stats += path_stats;
+3420 self.paths.remove(&path_id);
+3421 self.spaces[SpaceId::Data].number_spaces.remove(&path_id);
+3422
+3423 self.events.push_back(
+3424 PathEvent::Discarded {
+3425 id: path_id,
+3426 path_stats: Box::new(path_stats),
+3427 }
+3428 .into(),
+3429 );
+3430 }
+3431
+3432 fn handle_lost_packets(
+3433 &mut self,
+3434 pn_space: SpaceId,
+3435 path_id: PathId,
+3436 now: Instant,
+3437 lost_packets: Vec<u64>,
+3438 lost_mtu_probe: Option<u64>,
+3439 loss_delay: Duration,
+3440 in_persistent_congestion: bool,
+3441 size_of_lost_packets: u64,
+3442 ) {
+3443 debug_assert!(lost_packets.is_sorted(), "lost_packets must be sorted");
+3444
+3445 self.drain_lost_packets(now, pn_space, path_id);
+3446
+3447 // OnPacketsLost
+3448 if let Some(largest_lost) = lost_packets.last().cloned() {
+3449 let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes;
+3450 let largest_lost_sent = self.spaces[pn_space]
+3451 .for_path(path_id)
+3452 .sent_packets
+3453 .get(largest_lost)
+3454 .unwrap()
+3455 .time_sent;
+3456 let path_stats = self.path_stats.for_path(path_id);
+3457 path_stats.lost_packets += lost_packets.len() as u64;
+3458 path_stats.lost_bytes += size_of_lost_packets;
+3459 trace!(
+3460 %path_id,
+3461 count = lost_packets.len(),
+3462 lost_bytes = size_of_lost_packets,
+3463 "packets lost",
+3464 );
+3465
+3466 for &packet in &lost_packets {
+3467 let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else {
+3468 continue;
+3469 };
+3470 self.qlog
+3471 .emit_packet_lost(packet, &info, loss_delay, pn_space.kind(), now);
+3472 self.paths
+3473 .get_mut(&path_id)
+3474 .unwrap()
+3475 .remove_in_flight(&info);
+3476
+3477 for frame in info.stream_frames {
+3478 self.streams.retransmit(frame);
+3479 }
+3480 self.spaces[pn_space].pending |= info.retransmits;
+3481 let path = self.path_data_mut(path_id);
+3482 path.pending |= info.path_retransmits;
+3483 path.mtud.on_non_probe_lost(packet, info.size);
+3484 path.congestion.on_packet_lost(info.size, packet, now);
+3485
+3486 self.spaces[pn_space].for_path(path_id).lost_packets.insert(
+3487 packet,
+3488 LostPacket {
+3489 time_sent: info.time_sent,
+3490 },
+3491 );
+3492 }
+3493
+3494 let path = self.path_data_mut(path_id);
+3495 if path.mtud.black_hole_detected(now) {
+3496 path.congestion.on_mtu_update(path.mtud.current_mtu());
+3497 if let Some(max_datagram_size) = self.datagrams().max_size()
+3498 && self.datagrams.drop_oversized(max_datagram_size)
+3499 && self.datagrams.send_blocked
+3500 {
+3501 self.datagrams.send_blocked = false;
+3502 self.events.push_back(Event::DatagramsUnblocked);
+3503 }
+3504 self.path_stats.for_path(path_id).black_holes_detected += 1;
+3505 }
+3506
+3507 // Don't apply congestion penalty for lost ack-only packets
+3508 let lost_ack_eliciting =
+3509 old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes;
+3510
+3511 if lost_ack_eliciting {
+3512 self.path_stats.for_path(path_id).congestion_events += 1;
+3513 self.path_data_mut(path_id).congestion.on_congestion_event(
+3514 now,
+3515 largest_lost_sent,
+3516 in_persistent_congestion,
+3517 false,
+3518 size_of_lost_packets,
+3519 largest_lost,
+3520 );
+3521 }
+3522 }
+3523
+3524 // Handle a lost MTU probe
+3525 if let Some(packet) = lost_mtu_probe {
+3526 let info = self.spaces[SpaceId::Data]
+3527 .for_path(path_id)
+3528 .take(packet)
+3529 .unwrap(); // safe: lost_mtu_probe is omitted from lost_packets, and
+3530 // therefore must not have been removed yet
+3531 self.paths
+3532 .get_mut(&path_id)
+3533 .unwrap()
+3534 .remove_in_flight(&info);
+3535 self.path_data_mut(path_id).mtud.on_probe_lost();
+3536 self.path_stats.for_path(path_id).lost_plpmtud_probes += 1;
+3537 }
+3538 }
+3539
+3540 /// Returns the earliest time packets should be declared lost for all spaces on a path.
+3541 ///
+3542 /// If a path has an acknowledged packet with any prior un-acknowledged packets, the
+3543 /// earliest un-acknowledged packet can be declared lost after a timeout has elapsed.
+3544 /// The time returned is when this packet should be declared lost.
+3545 fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> {
+3546 SpaceId::iter()
+3547 .filter_map(|id| {
+3548 self.spaces[id]
+3549 .number_spaces
+3550 .get(&path_id)
+3551 .and_then(|pns| pns.loss_time)
+3552 .map(|time| (time, id))
+3553 })
+3554 .min_by_key(|&(time, _)| time)
+3555 }
+3556
+3557 /// Returns the earliest next PTO should fire for all spaces on a path.
+3558 ///
+3559 /// This needs to be fully deterministic because it is also used to determine the PTO
+3560 /// that fired, not just to set the next timer. So if it fired in the past it needs to
+3561 /// return the time from the past at which it fired.
+3562 ///
+3563 /// This is the next time a tail-loss probe should be sent.
+3564 fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> {
+3565 let path = self.path(path_id)?;
+3566 let pto_count = path.pto_count;
+3567
+3568 // Cap the maximum interval between two tail-loss probes.
+3569 let max_interval = if path.rtt.get() > SLOW_RTT_THRESHOLD {
+3570 // For slow links we want to increase the interval beyond 2s.
+3571 (path.rtt.get() * 3) / 2
+3572 } else if let Some(idle) = path.idle_timeout.or(self.idle_timeout)
+3573 && idle <= MIN_IDLE_FOR_FAST_PTO
+3574 {
+3575 // If the idle timeout is relatively low, cap at 1s so we get plenty of retries
+3576 // before the idle timeout fires.
+3577 MAX_PTO_FAST_INTERVAL
+3578 } else {
+3579 // Otherwise cap to 2s.
+3580 MAX_PTO_INTERVAL
+3581 };
+3582
+3583 if path_id == PathId::ZERO
+3584 && path.in_flight.ack_eliciting == 0
+3585 && !self.peer_completed_handshake_address_validation()
+3586 {
+3587 // Address Validation during Connection Establishment:
+3588 // https://www.rfc-editor.org/rfc/rfc9000.html#section-8.1. To prevent a
+3589 // deadlock if an Initial or Handshake packet from the server is lost and the
+3590 // server can not send more due to its anti-amplification limit the client must
+3591 // send another packet on PTO.
+3592 let space = match self.highest_space {
+3593 SpaceKind::Handshake => SpaceId::Handshake,
+3594 _ => SpaceId::Initial,
+3595 };
+3596
+3597 let backoff = 2u32.pow(path.pto_count.min(MAX_BACKOFF_EXPONENT));
+3598 let duration = path.rtt.pto_base() * backoff;
+3599 let duration = duration.min(max_interval);
+3600 return Some((now + duration, space));
+3601 }
+3602
+3603 let mut result = None;
+3604 for space in SpaceId::iter() {
+3605 let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else {
+3606 continue;
+3607 };
+3608
+3609 if space == SpaceId::Data && !self.is_handshake_confirmed() {
+3610 // https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-7:
+3611 // An endpoint MUST NOT set its PTO timer for the Application Data packet
+3612 // number space until the handshake is confirmed.
+3613 continue;
+3614 }
+3615
+3616 if !pns.has_in_flight() {
+3617 continue;
+3618 }
+3619
+3620 // Compute the PTO duration for this space, we want to cap the maximum interval
+3621 // between two tail-loss probes so to not do a simple exponential backoff but
+3622 // rather iterate through the probes to compute the capped increment for an
+3623 // exponential backoff at each step.
+3624 let duration = {
+3625 let max_ack_delay = if space == SpaceId::Data {
+3626 self.ack_frequency.max_ack_delay_for_pto()
+3627 } else {
+3628 Duration::ZERO
+3629 };
+3630 let pto_base = path.rtt.pto_base() + max_ack_delay;
+3631 let mut duration = pto_base;
+3632 for i in 1..=pto_count {
+3633 let exponential_duration = pto_base * 2u32.pow(i.min(MAX_BACKOFF_EXPONENT));
+3634 let max_duration = duration + max_interval;
+3635 duration = exponential_duration.min(max_duration);
+3636 }
+3637 duration
+3638 };
+3639
+3640 let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else {
+3641 continue;
+3642 };
+3643 // Base the deadline on when the last probe was sent, so the PTO
+3644 // doesn't fire before the response has had time to arrive.
+3645 let pto = last_ack_eliciting + duration;
+3646 if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) {
+3647 if path.anti_amplification_blocked(1) {
+3648 // Nothing would be able to be sent.
+3649 continue;
+3650 }
+3651 if path.in_flight.ack_eliciting == 0 {
+3652 // Nothing ack-eliciting, no PTO to arm/fire.
+3653 continue;
+3654 }
+3655 result = Some((pto, space));
+3656 }
+3657 }
+3658 result
+3659 }
+3660
+3661 /// Whether the peer validated our address in the connection handshake.
+3662 fn peer_completed_handshake_address_validation(&self) -> bool {
+3663 if self.side.is_server() || self.state.is_closed() {
+3664 return true;
+3665 }
+3666 // The server is guaranteed to have validated our address if any of our handshake or
+3667 // 1-RTT packets are acknowledged or we've seen HANDSHAKE_DONE and discarded
+3668 // handshake keys.
+3669 self.spaces[SpaceId::Handshake]
+3670 .path_space(PathId::ZERO)
+3671 .and_then(|pns| pns.largest_acked_packet_pn)
+3672 .is_some()
+3673 || self.spaces[SpaceId::Data]
+3674 .path_space(PathId::ZERO)
+3675 .and_then(|pns| pns.largest_acked_packet_pn)
+3676 .is_some()
+3677 || (self.crypto_state.has_keys(EncryptionLevel::OneRtt)
+3678 && !self.crypto_state.has_keys(EncryptionLevel::Handshake))
+3679 }
+3680
+3681 /// Resets the the [`PathTimer::LossDetection`] timer to the next instant it may be needed
+3682 ///
+3683 /// The timer must fire if either:
+3684 /// - An ack-eliciting packet we sent needs to be declared lost.
+3685 /// - A tail-loss probe needs to be sent.
+3686 ///
+3687 /// See [`Connection::on_loss_detection_timeout`] for details.
+3688 fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) {
+3689 if self.state.is_closed() {
+3690 // No loss detection takes place on closed connections, and `close_common` already
+3691 // stopped time timer. Ensure we don't restart it inadvertently, e.g. in response to a
+3692 // reordered packet being handled by state-insensitive code.
+3693 return;
+3694 }
+3695
+3696 if let Some((loss_time, _)) = self.loss_time_and_space(path_id) {
+3697 // Time threshold loss detection.
+3698 self.timers.set(
+3699 Timer::PerPath(path_id, PathTimer::LossDetection),
+3700 loss_time,
+3701 self.qlog.with_time(now),
+3702 );
+3703 return;
+3704 }
+3705
+3706 // Determine which PN space to arm PTO for.
+3707 // We can only send tail-loss probes on paths that aren't abandoned yet.
+3708 if !self.abandoned_paths.contains(&path_id)
+3709 && let Some((timeout, _)) = self.pto_time_and_space(now, path_id)
+3710 {
+3711 self.timers.set(
+3712 Timer::PerPath(path_id, PathTimer::LossDetection),
+3713 timeout,
+3714 self.qlog.with_time(now),
+3715 );
+3716 } else {
+3717 self.timers.stop(
+3718 Timer::PerPath(path_id, PathTimer::LossDetection),
+3719 self.qlog.with_time(now),
+3720 );
+3721 }
+3722 }
+3723
+3724 /// The maximum probe timeout across all paths
+3725 ///
+3726 /// See [`Connection::pto`]
+3727 fn max_pto_for_space(&self, space: SpaceKind) -> Duration {
+3728 self.paths
+3729 .keys()
+3730 .map(|path_id| self.pto(space, *path_id))
+3731 .max()
+3732 .unwrap_or_else(|| {
+3733 // No paths remain (e.g. last path was abandoned and the NoAvailablePath grace timer
+3734 // fired before any new path was opened). Fall back to a PTO derived from the
+3735 // configured initial RTT, matching RFC 9002 §6.2.2 initial values.
+3736 let rtt = self.config.initial_rtt;
+3737 let max_ack_delay = match space {
+3738 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
+3739 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
+3740 };
+3741 rtt + cmp::max(4 * (rtt / 2), TIMER_GRANULARITY) + max_ack_delay
+3742 })
+3743 }
+3744
+3745 /// Probe Timeout
+3746 ///
+3747 /// The PTO is logically the time in which you'd expect to receive an acknowledgement
+3748 /// for a packet. So approximately RTT + max_ack_delay.
+3749 fn pto(&self, space: SpaceKind, path_id: PathId) -> Duration {
+3750 let max_ack_delay = match space {
+3751 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
+3752 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
+3753 };
+3754 self.path_data(path_id).rtt.pto_base() + max_ack_delay
+3755 }
+3756
+3757 fn on_packet_authenticated(
+3758 &mut self,
+3759 now: Instant,
+3760 space_id: SpaceKind,
+3761 path_id: PathId,
+3762 ecn: Option<EcnCodepoint>,
+3763 packet_number: Option<u64>,
+3764 spin: bool,
+3765 is_1rtt: bool,
+3766 remote: &FourTuple,
+3767 ) {
+3768 // During the handshake we already have discarded packets that do not match the path
+3769 // remote. So any off-path packet here is either a probing packet or a
+3770 // migration. Handling probing packets here means that the path's idle timeout will
+3771 // be reset and will delay detecting the path as idle. However tail-loss probes
+3772 // would still not get acknowledged if the path was broken so eventually the path
+3773 // would still become idle.
+3774 let is_on_path = self
+3775 .path_data(path_id)
+3776 .network_path
+3777 .is_probably_same_path(remote);
+3778
+3779 self.total_authed_packets += 1;
+3780 self.reset_keep_alive(path_id, now);
+3781 self.reset_idle_timeout(now, space_id, path_id);
+3782 self.path_data_mut(path_id).permit_idle_reset = true;
+3783
+3784 // Do not process ECN for off-path packets. If this is a migration we'll get ECN
+3785 // back once we've migrated.
+3786 if is_on_path {
+3787 self.receiving_ecn |= ecn.is_some();
+3788 if let Some(x) = ecn {
+3789 let space = &mut self.spaces[space_id];
+3790 space.for_path(path_id).ecn_counters += x;
+3791
+3792 if x.is_ce() {
+3793 space
+3794 .for_path(path_id)
+3795 .pending_acks
+3796 .set_immediate_ack_required();
+3797 }
+3798 }
+3799 }
+3800
+3801 let Some(packet_number) = packet_number else {
+3802 return;
+3803 };
+3804 match &self.side {
+3805 ConnectionSide::Client { .. } => {
+3806 // If we received a handshake packet that authenticated, then we're talking to
+3807 // the real server. From now on we should no longer allow the server to migrate
+3808 // its address.
+3809 if space_id == SpaceKind::Handshake
+3810 && let Some(hs) = self.state.as_handshake_mut()
+3811 {
+3812 hs.allow_server_migration = false;
+3813 }
+3814 }
+3815 ConnectionSide::Server { .. } => {
+3816 if self.crypto_state.has_keys(EncryptionLevel::Initial)
+3817 && space_id == SpaceKind::Handshake
+3818 {
+3819 // A server stops sending and processing Initial packets when it receives its first Handshake packet.
+3820 self.discard_space(now, SpaceKind::Initial);
+3821 }
+3822 if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) && is_1rtt {
+3823 // Discard 0-RTT keys soon after receiving a 1-RTT packet
+3824 self.set_key_discard_timer(now, space_id)
+3825 }
+3826 }
+3827 }
+3828 let space = self.spaces[space_id].for_path(path_id);
+3829
+3830 space.pending_acks.insert_one(packet_number, now);
+3831 if packet_number >= space.largest_received_packet_number.unwrap_or_default() {
+3832 space.largest_received_packet_number = Some(packet_number);
+3833
+3834 // Update outgoing spin bit for on-path packets, inverting iff we're the client
+3835 if is_on_path {
+3836 self.spin = self.side.is_client() ^ spin;
+3837 }
+3838 }
+3839 }
+3840
+3841 /// Resets the idle timeout timers
+3842 ///
+3843 /// Without multipath there is only the connection-wide idle timeout. When multipath is
+3844 /// enabled there is an additional per-path idle timeout.
+3845 fn reset_idle_timeout(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
+3846 // First reset the global idle timeout.
+3847 if let Some(timeout) = self.idle_timeout {
+3848 if self.state.is_closed() {
+3849 self.timers
+3850 .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now));
+3851 } else {
+3852 let dt = cmp::max(timeout, 3 * self.max_pto_for_space(space));
+3853 self.timers.set(
+3854 Timer::Conn(ConnTimer::Idle),
+3855 now + dt,
+3856 self.qlog.with_time(now),
+3857 );
+3858 }
+3859 }
+3860
+3861 // Now handle the per-path state
+3862 if let Some(timeout) = self.path_data(path_id).idle_timeout {
+3863 if self.state.is_closed() {
+3864 self.timers.stop(
+3865 Timer::PerPath(path_id, PathTimer::PathIdle),
+3866 self.qlog.with_time(now),
+3867 );
+3868 } else {
+3869 let dt = cmp::max(timeout, 3 * self.pto(space, path_id));
+3870 self.timers.set(
+3871 Timer::PerPath(path_id, PathTimer::PathIdle),
+3872 now + dt,
+3873 self.qlog.with_time(now),
+3874 );
+3875 }
+3876 }
+3877 }
+3878
+3879 /// Resets both the [`ConnTimer::KeepAlive`] and [`PathTimer::PathKeepAlive`] timers
+3880 fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) {
+3881 if !self.state.is_established() {
+3882 return;
+3883 }
+3884
+3885 if let Some(interval) = self.config.keep_alive_interval {
+3886 self.timers.set(
+3887 Timer::Conn(ConnTimer::KeepAlive),
+3888 now + interval,
+3889 self.qlog.with_time(now),
+3890 );
+3891 }
+3892
+3893 if let Some(interval) = self.path_data(path_id).keep_alive {
+3894 self.timers.set(
+3895 Timer::PerPath(path_id, PathTimer::PathKeepAlive),
+3896 now + interval,
+3897 self.qlog.with_time(now),
+3898 );
+3899 }
+3900 }
+3901
+3902 /// Sets the timer for when a previously issued CID should be retired next
+3903 fn reset_cid_retirement(&mut self, now: Instant) {
+3904 if let Some((_path, t)) = self.next_cid_retirement() {
+3905 self.timers.set(
+3906 Timer::Conn(ConnTimer::PushNewCid),
+3907 t,
+3908 self.qlog.with_time(now),
+3909 );
+3910 }
+3911 }
+3912
+3913 /// The next time when a previously issued CID should be retired
+3914 fn next_cid_retirement(&self) -> Option<(PathId, Instant)> {
+3915 self.local_cid_state
+3916 .iter()
+3917 .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t)))
+3918 .min_by_key(|(_path_id, timeout)| *timeout)
+3919 }
+3920
+3921 /// Handle the already-decrypted first packet from the client
+3922 ///
+3923 /// Decrypting the first packet in the `Endpoint` allows stateless packet handling to be more
+3924 /// efficient.
+3925 pub(crate) fn handle_first_packet(
+3926 &mut self,
+3927 now: Instant,
+3928 network_path: FourTuple,
+3929 ecn: Option<EcnCodepoint>,
+3930 packet_number: u64,
+3931 packet: InitialPacket,
+3932 remaining: Option<BytesMut>,
+3933 ) -> Result<(), ConnectionError> {
+3934 let span = trace_span!("first recv");
+3935 let _guard = span.enter();
+3936 debug_assert!(self.side.is_server());
+3937 let len = packet.header_data.len() + packet.payload.len();
+3938 let path_id = PathId::ZERO;
+3939 self.path_data_mut(path_id).total_recvd = len as u64;
+3940
+3941 if let Some(hs) = self.state.as_handshake_mut() {
+3942 hs.expected_token = packet.header.token.clone();
+3943 } else {
+3944 unreachable!("first packet must be delivered in Handshake state");
+3945 }
+3946
+3947 // The first packet is always on PathId::ZERO
+3948 self.on_packet_authenticated(
+3949 now,
+3950 SpaceKind::Initial,
+3951 path_id,
+3952 ecn,
+3953 Some(packet_number),
+3954 false,
3955 false,
-3956 false,
-3957 &network_path,
-3958 );
-3959
-3960 let packet: Packet = packet.into();
-3961
-3962 let mut qlog = QlogRecvPacket::new(len);
-3963 qlog.header(&packet.header, Some(packet_number), path_id);
-3964
-3965 self.process_decrypted_packet(
-3966 now,
-3967 network_path,
-3968 path_id,
-3969 Some(packet_number),
-3970 packet,
-3971 &mut qlog,
-3972 )?;
-3973 self.qlog.emit_packet_received(qlog, now);
-3974 if let Some(data) = remaining {
-3975 self.handle_coalesced(now, network_path, path_id, ecn, data);
-3976 }
-3977
-3978 self.qlog.emit_recovery_metrics(
-3979 path_id,
-3980 &mut self
-3981 .paths
-3982 .get_mut(&path_id)
-3983 .expect("path_id was supplied by the caller for an active path")
-3984 .data,
-3985 now,
-3986 );
-3987
-3988 Ok(())
-3989 }
-3990
-3991 fn init_0rtt(&mut self, now: Instant) {
-3992 let Some((header, packet)) = self.crypto_state.session.early_crypto() else {
-3993 return;
-3994 };
-3995 if self.side.is_client() {
-3996 match self.crypto_state.session.transport_parameters() {
-3997 Ok(params) => {
-3998 let params = params
-3999 .expect("crypto layer didn't supply transport parameters with ticket");
-4000 // Certain values must not be cached
-4001 let params = TransportParameters {
-4002 initial_src_cid: None,
-4003 original_dst_cid: None,
-4004 preferred_address: None,
-4005 retry_src_cid: None,
-4006 stateless_reset_token: None,
-4007 min_ack_delay: None,
-4008 ack_delay_exponent: TransportParameters::default().ack_delay_exponent,
-4009 max_ack_delay: TransportParameters::default().max_ack_delay,
-4010 initial_max_path_id: None,
-4011 ..params
-4012 };
-4013 self.set_peer_params(params);
-4014 self.qlog.emit_peer_transport_params_restored(self, now);
-4015 }
-4016 Err(e) => {
-4017 error!("session ticket has malformed transport parameters: {}", e);
-4018 return;
-4019 }
-4020 }
-4021 }
-4022 trace!("0-RTT enabled");
-4023 self.crypto_state.enable_zero_rtt(header, packet);
-4024 }
-4025
-4026 fn read_crypto(
-4027 &mut self,
-4028 space: SpaceId,
-4029 crypto: &frame::Crypto,
-4030 payload_len: usize,
-4031 ) -> Result<(), TransportError> {
-4032 let expected = if !self.state.is_handshake() {
-4033 SpaceId::Data
-4034 } else if self.highest_space == SpaceKind::Initial {
-4035 SpaceId::Initial
-4036 } else {
-4037 // On the server, self.highest_space can be Data after receiving the client's first
-4038 // flight, but we expect Handshake CRYPTO until the handshake is complete.
-4039 SpaceId::Handshake
-4040 };
-4041 // We can't decrypt Handshake packets when highest_space is Initial, CRYPTO frames in 0-RTT
-4042 // packets are illegal, and we don't process 1-RTT packets until the handshake is
-4043 // complete. Therefore, we will never see CRYPTO data from a later-than-expected space.
-4044 debug_assert!(space <= expected, "received out-of-order CRYPTO data");
-4045
-4046 let end = crypto.offset + crypto.data.len() as u64;
-4047 if space < expected
-4048 && end
-4049 > self.crypto_state.spaces[space.kind()]
-4050 .crypto_stream
-4051 .bytes_read()
-4052 {
-4053 warn!(
-4054 "received new {:?} CRYPTO data when expecting {:?}",
-4055 space, expected
-4056 );
-4057 return Err(TransportError::PROTOCOL_VIOLATION(
-4058 "new data at unexpected encryption level",
-4059 ));
-4060 }
-4061
-4062 let crypto_space = &mut self.crypto_state.spaces[space.kind()];
-4063 let max = end.saturating_sub(crypto_space.crypto_stream.bytes_read());
-4064 if max > self.config.crypto_buffer_size as u64 {
-4065 return Err(TransportError::CRYPTO_BUFFER_EXCEEDED(""));
-4066 }
-4067
-4068 crypto_space
-4069 .crypto_stream
-4070 .insert(crypto.offset, crypto.data.clone(), payload_len);
-4071 while let Some(chunk) = crypto_space.crypto_stream.read(usize::MAX, true) {
-4072 trace!("consumed {} CRYPTO bytes", chunk.bytes.len());
-4073 if self.crypto_state.session.read_handshake(&chunk.bytes)? {
-4074 self.events.push_back(Event::HandshakeDataReady);
-4075 }
-4076 }
-4077
-4078 Ok(())
-4079 }
-4080
-4081 fn write_crypto(&mut self) {
-4082 loop {
-4083 let space = self.highest_space;
-4084 let mut outgoing = Vec::new();
-4085 if let Some(crypto) = self.crypto_state.session.write_handshake(&mut outgoing) {
-4086 match space {
-4087 SpaceKind::Initial => {
-4088 self.upgrade_crypto(SpaceKind::Handshake, crypto);
-4089 }
-4090 SpaceKind::Handshake => {
-4091 self.upgrade_crypto(SpaceKind::Data, crypto);
-4092 }
-4093 SpaceKind::Data => unreachable!("got updated secrets during 1-RTT"),
-4094 }
-4095 }
-4096 if outgoing.is_empty() {
-4097 if space == self.highest_space {
-4098 break;
-4099 } else {
-4100 // Keys updated, check for more data to send
-4101 continue;
-4102 }
-4103 }
-4104 let offset = self.crypto_state.spaces[space].crypto_offset;
-4105 let outgoing = Bytes::from(outgoing);
-4106 if let Some(hs) = self.state.as_handshake_mut()
-4107 && space == SpaceKind::Initial
-4108 && offset == 0
-4109 && self.side.is_client()
-4110 {
-4111 hs.client_hello = Some(outgoing.clone());
-4112 }
-4113 self.crypto_state.spaces[space].crypto_offset += outgoing.len() as u64;
-4114 trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space);
-4115 self.spaces[space].pending.crypto.push_back(frame::Crypto {
-4116 offset,
-4117 data: outgoing,
-4118 });
-4119 }
-4120 }
-4121
-4122 /// Switch to stronger cryptography during handshake
-4123 fn upgrade_crypto(&mut self, space: SpaceKind, crypto: Keys) {
-4124 debug_assert!(
-4125 !self.crypto_state.has_keys(space.encryption_level()),
-4126 "already reached packet space {space:?}"
-4127 );
-4128 trace!("{:?} keys ready", space);
-4129 if space == SpaceKind::Data {
-4130 // Precompute the first key update
-4131 self.crypto_state.next_crypto = Some(
-4132 self.crypto_state
-4133 .session
-4134 .next_1rtt_keys()
-4135 .expect("handshake should be complete"),
-4136 );
-4137 }
-4138
-4139 self.crypto_state.spaces[space].keys = Some(crypto);
-4140 debug_assert!(space > self.highest_space);
-4141 self.highest_space = space;
-4142 if space == SpaceKind::Data && self.side.is_client() {
-4143 // Discard 0-RTT keys because 1-RTT keys are available.
-4144 self.crypto_state.discard_zero_rtt();
-4145 }
-4146 }
-4147
-4148 fn discard_space(&mut self, now: Instant, space: SpaceKind) {
-4149 debug_assert!(space != SpaceKind::Data);
-4150 trace!("discarding {:?} keys", space);
-4151 if space == SpaceKind::Initial {
-4152 // No longer needed
-4153 if let ConnectionSide::Client { token, .. } = &mut self.side {
-4154 *token = Bytes::new();
-4155 }
-4156 }
-4157 self.crypto_state.spaces[space].keys = None;
-4158 let space = &mut self.spaces[space];
-4159 let pns = space.for_path(PathId::ZERO);
-4160 pns.time_of_last_ack_eliciting_packet = None;
-4161 pns.loss_time = None;
-4162 pns.loss_probes = 0;
-4163 let sent_packets = mem::take(&mut pns.sent_packets);
-4164 let path = self
-4165 .paths
-4166 .get_mut(&PathId::ZERO)
-4167 .expect("PathId::ZERO is alive while Initial/Handshake spaces exist");
-4168 for (_, packet) in sent_packets.into_iter() {
-4169 path.data.remove_in_flight(&packet);
-4170 }
-4171
-4172 self.set_loss_detection_timer(now, PathId::ZERO)
-4173 }
-4174
-4175 fn handle_coalesced(
-4176 &mut self,
-4177 now: Instant,
-4178 network_path: FourTuple,
-4179 path_id: PathId,
-4180 ecn: Option<EcnCodepoint>,
-4181 data: BytesMut,
-4182 ) {
-4183 self.path_data_mut(path_id)
-4184 .inc_total_recvd(data.len() as u64);
-4185 let mut remaining = Some(data);
-4186 let cid_len = self
-4187 .local_cid_state
-4188 .values()
-4189 .map(|cid_state| cid_state.cid_len())
-4190 .next()
-4191 .expect("one cid_state must exist");
-4192 while let Some(data) = remaining {
-4193 match PartialDecode::new(
-4194 data,
-4195 &FixedLengthConnectionIdParser::new(cid_len),
-4196 &[self.version],
-4197 self.endpoint_config.grease_quic_bit,
-4198 ) {
-4199 Ok((partial_decode, rest)) => {
-4200 remaining = rest;
-4201 self.handle_decode(now, network_path, path_id, ecn, partial_decode);
-4202 }
-4203 Err(e) => {
-4204 trace!("malformed header: {}", e);
-4205 return;
-4206 }
-4207 }
-4208 }
-4209 }
-4210
-4211 /// Decrypts the packet and processes the payload.
-4212 ///
-4213 /// Processes the entire packet, starting with removing header protection, then handling
-4214 /// a stateless reset if needed, and decrypting and processing the frames in the payload
-4215 /// if not a stateless reset.
-4216 fn handle_decode(
-4217 &mut self,
-4218 now: Instant,
-4219 network_path: FourTuple,
-4220 path_id: PathId,
-4221 ecn: Option<EcnCodepoint>,
-4222 partial_decode: PartialDecode,
-4223 ) {
-4224 let qlog = QlogRecvPacket::new(partial_decode.len());
-4225 if let Some(decoded) = self
-4226 .crypto_state
-4227 .unprotect_header(partial_decode, self.peer_params.stateless_reset_token)
-4228 {
-4229 self.handle_packet(
-4230 now,
-4231 network_path,
-4232 path_id,
-4233 ecn,
-4234 decoded.packet,
-4235 decoded.stateless_reset,
-4236 qlog,
-4237 );
-4238 }
-4239 }
-4240
-4241 /// Handles a packet with header protection removed.
-4242 ///
-4243 /// The packet body is still encrypted at this point.
-4244 ///
-4245 /// If the datagram was a stateless reset we may have failed to remove header protection
-4246 /// and thus `packet` may be `None`.
-4247 fn handle_packet(
-4248 &mut self,
-4249 now: Instant,
-4250 network_path: FourTuple,
-4251 path_id: PathId,
-4252 ecn: Option<EcnCodepoint>,
-4253 packet: Option<Packet>,
-4254 stateless_reset: bool,
-4255 mut qlog: QlogRecvPacket,
-4256 ) {
-4257 self.path_stats.for_path(path_id).udp_rx.ios += 1;
-4258
-4259 if let Some(ref packet) = packet {
-4260 trace!(
-4261 "got {:?} packet ({} bytes) from {} using id {}",
-4262 packet.header.space(),
-4263 packet.payload.len() + packet.header_data.len(),
-4264 network_path,
-4265 packet.header.dst_cid(),
-4266 );
-4267 }
-4268
-4269 let was_closed = self.state.is_closed();
-4270 let was_drained = self.state.is_drained();
-4271
-4272 // Now decrypt the packet payload in-place.
-4273 let decrypted = match packet {
-4274 None => Err(None),
-4275 Some(mut packet) => self
-4276 .decrypt_packet(now, path_id, &mut packet)
-4277 .map(move |number| (packet, number)),
-4278 };
-4279 let result = match decrypted {
-4280 _ if stateless_reset => {
-4281 debug!("got stateless reset");
-4282 Err(ConnectionError::Reset)
-4283 }
-4284 Err(Some(e)) => {
-4285 warn!("illegal packet: {}", e);
-4286 Err(e.into())
-4287 }
-4288 Err(None) => {
-4289 debug!("failed to authenticate packet");
-4290 self.authentication_failures += 1;
-4291 let integrity_limit = self
-4292 .crypto_state
-4293 .integrity_limit(self.highest_space)
-4294 .unwrap();
-4295 if self.authentication_failures > integrity_limit {
-4296 Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into())
-4297 } else {
-4298 return;
-4299 }
-4300 }
-4301 Ok((packet, pn)) => {
-4302 // We received an authenticated packet and decrypted it.
-4303 qlog.header(&packet.header, pn, path_id);
-4304 let span = match pn {
-4305 Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn),
-4306 None => trace_span!("recv", space = ?packet.header.space()),
-4307 };
-4308 let _guard = span.enter();
-4309
-4310 // Now the packet is authenticated we do the migration during the handshake,
-4311 // see Handshake::allow_server_migration for details. Be careful here to
-4312 // not yet rely on the path existing however, new paths are accepted and
-4313 // created later.
-4314 // Note that we can't do any other migrations yet, for those we need to know
-4315 // whether this was a probing packet or not. See the end of
-4316 // Self::process_packet for that.
-4317 if self.is_handshaking()
-4318 && self
-4319 .path(path_id)
-4320 .map(|path_data| {
-4321 !path_data.network_path.is_probably_same_path(&network_path)
-4322 })
-4323 .unwrap_or(false)
-4324 {
-4325 if let Some(hs) = self.state.as_handshake()
-4326 && hs.allow_server_migration
-4327 {
-4328 trace!(
-4329 %network_path,
-4330 prev = %self.path_data(path_id).network_path,
-4331 "server migrated to new remote",
-4332 );
-4333 self.path_data_mut(path_id).network_path = network_path;
-4334 self.qlog.emit_tuple_assigned(path_id, network_path, now);
-4335 } else {
-4336 debug!(
-4337 recv_path = %network_path,
-4338 expected_path = %self.path_data_mut(path_id).network_path,
-4339 "discarding packet with unexpected remote during handshake",
-4340 );
-4341 return;
-4342 }
-4343 }
-4344
-4345 let dedup = self.spaces[packet.header.space()]
-4346 .path_space_mut(path_id)
-4347 .map(|pns| &mut pns.dedup);
-4348 if pn.zip(dedup).is_some_and(|(n, d)| d.insert(n)) {
-4349 debug!("discarding possible duplicate packet");
-4350 self.qlog.emit_packet_received(qlog, now);
-4351 return;
-4352 } else if self.state.is_handshake() && packet.header.is_short() {
-4353 // TODO: SHOULD buffer these to improve reordering tolerance.
-4354 trace!("dropping short packet during handshake");
-4355 self.qlog.emit_packet_received(qlog, now);
-4356 return;
-4357 } else {
-4358 if let Header::Initial(InitialHeader { ref token, .. }) = packet.header
-4359 && let Some(hs) = self.state.as_handshake()
-4360 && self.side.is_server()
-4361 && token != &hs.expected_token
-4362 {
-4363 // Clients must send the same retry token in every Initial. Initial
-4364 // packets can be spoofed, so we discard rather than killing the
-4365 // connection.
-4366 warn!("discarding Initial with invalid retry token");
-4367 self.qlog.emit_packet_received(qlog, now);
-4368 return;
-4369 }
-4370
-4371 if !self.state.is_closed() {
-4372 let spin = match packet.header {
-4373 Header::Short { spin, .. } => spin,
-4374 _ => false,
-4375 };
-4376
-4377 if self.side().is_server() && !self.abandoned_paths.contains(&path_id) {
-4378 // Only the client is allowed to open paths
-4379 self.create_path(path_id, network_path, now, pn);
-4380 }
-4381 if self.paths.contains_key(&path_id) {
-4382 self.on_packet_authenticated(
-4383 now,
-4384 packet.header.space(),
-4385 path_id,
-4386 ecn,
-4387 pn,
-4388 spin,
-4389 packet.header.is_1rtt(),
-4390 &network_path,
-4391 );
-4392 }
-4393 }
-4394
-4395 let res = self.process_decrypted_packet(
-4396 now,
-4397 network_path,
-4398 path_id,
-4399 pn,
-4400 packet,
-4401 &mut qlog,
-4402 );
-4403
-4404 self.qlog.emit_packet_received(qlog, now);
-4405 res
-4406 }
-4407 }
-4408 };
-4409
-4410 // State transitions for error cases
-4411 if let Err(conn_err) = result {
-4412 match conn_err {
-4413 ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason),
-4414 ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason),
-4415 ConnectionError::Reset
-4416 | ConnectionError::TransportError(TransportError {
-4417 code: TransportErrorCode::AEAD_LIMIT_REACHED,
-4418 ..
-4419 }) => {
-4420 let was_draining = self.state.move_to_drained(Some(conn_err));
-4421 if !was_draining {
-4422 self.endpoint_events.push_back(EndpointEventInner::Draining);
-4423 }
-4424 }
-4425 ConnectionError::TimedOut => {
-4426 unreachable!("timeouts aren't generated by packet processing");
-4427 }
-4428 ConnectionError::TransportError(err) => {
-4429 debug!("closing connection due to transport error: {}", err);
-4430 self.state.move_to_closed(err);
-4431 }
-4432 ConnectionError::VersionMismatch => {
-4433 self.state.move_to_draining(Some(conn_err));
-4434 self.endpoint_events.push_back(EndpointEventInner::Draining);
-4435 }
-4436 ConnectionError::LocallyClosed => {
-4437 unreachable!("LocallyClosed isn't generated by packet processing");
-4438 }
-4439 ConnectionError::CidsExhausted => {
-4440 unreachable!("CidsExhausted isn't generated by packet processing");
-4441 }
-4442 };
-4443 }
-4444
-4445 if !was_closed && self.state.is_closed() {
-4446 self.close_common();
-4447 if !self.state.is_drained() {
-4448 self.set_close_timer(now);
-4449 }
-4450 }
-4451 if !was_drained && self.state.is_drained() {
-4452 self.endpoint_events.push_back(EndpointEventInner::Drained);
-4453 // Close timer may have been started previously, e.g. if we sent a close and got a
-4454 // stateless reset in response
-4455 self.timers
-4456 .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now));
-4457 }
-4458
-4459 // Transmit CONNECTION_CLOSE if necessary.
-4460 //
-4461 // If we received a valid packet and we are in the closed state we should respond
-4462 // with a CONNECTION_CLOSE frame.
-4463 // TODO: This SHOULD be rate-limited according to §10.2.1 of QUIC-TRANSPORT, but
-4464 // that does not yet happen. This is triggered by each received packet.
-4465 if matches!(self.state.as_type(), StateType::Closed) {
-4466 // From https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2.1-7
-4467 //
-4468 // While in the closing state we must either:
-4469 // - discard packets coming from an un-validated remote OR
-4470 // - ensure we do not send more than 3 times the received data
-4471 //
-4472 // Doing the 2nd would mean we would be able to send CONNECTION_CLOSE to a peer
-4473 // who was (involuntary) migrated just at the time we initiated immediate
-4474 // close. It is a lot more work though. So while we would like to do this for
-4475 // now we only do 1.
-4476 //
-4477 // Another shortcoming of the current implementation is that when we have a
-4478 // previous PathData which is validated and the remote matches that path, we
-4479 // should schedule CONNECTION_CLOSE on that path. However currently we can not
-4480 // schedule such a packet. We should also fix this some day. This makes us
-4481 // vulnerable to an attacker faking a migration at the right time and then we'd
-4482 // be unable to send the CONNECTION_CLOSE to the real remote.
-4483 if self
-4484 .paths
-4485 .get(&path_id)
-4486 .map(|p| p.data.validated && p.data.network_path == network_path)
-4487 .unwrap_or(false)
-4488 {
-4489 self.connection_close_pending = true;
-4490 }
-4491 }
-4492 }
-4493
-4494 fn process_decrypted_packet(
-4495 &mut self,
-4496 now: Instant,
-4497 network_path: FourTuple,
-4498 path_id: PathId,
-4499 number: Option<u64>,
-4500 packet: Packet,
-4501 qlog: &mut QlogRecvPacket,
-4502 ) -> Result<(), ConnectionError> {
-4503 if !self.paths.contains_key(&path_id) {
-4504 // There is a chance this is a server side, first (for this path) packet, which would
-4505 // be a protocol violation. It's more likely, however, that this is a packet of a
-4506 // pruned path
-4507 trace!(%path_id, ?number, "discarding packet for unknown path");
-4508 return Ok(());
-4509 }
-4510 let state = match self.state.as_type() {
-4511 StateType::Established => {
-4512 match packet.header.space() {
-4513 SpaceKind::Data => self.process_payload(
-4514 now,
-4515 network_path,
-4516 path_id,
-4517 number.unwrap(),
-4518 packet,
-4519 qlog,
-4520 )?,
-4521 _ if packet.header.has_frames() => {
-4522 self.process_early_payload(now, path_id, packet, qlog)?
-4523 }
-4524 _ => {
-4525 trace!("discarding unexpected pre-handshake packet");
-4526 }
-4527 }
-4528 return Ok(());
-4529 }
-4530 StateType::Closed => {
-4531 for result in frame::Iter::new(packet.payload.freeze())? {
-4532 let frame = match result {
-4533 Ok(frame) => frame,
-4534 Err(err) => {
-4535 debug!("frame decoding error: {err:?}");
-4536 continue;
-4537 }
-4538 };
-4539 qlog.frame(&frame);
-4540
-4541 if let Frame::Padding = frame {
-4542 continue;
-4543 };
-4544
-4545 trace!(?frame, "processing frame in closed state");
-4546
-4547 self.path_stats
-4548 .for_path(path_id)
-4549 .frame_rx
-4550 .record(frame.ty());
-4551
-4552 if let Frame::Close(_error) = frame {
-4553 self.state.move_to_draining(None);
-4554 self.endpoint_events.push_back(EndpointEventInner::Draining);
-4555 break;
-4556 }
-4557 }
-4558 return Ok(());
-4559 }
-4560 StateType::Draining | StateType::Drained => return Ok(()),
-4561 StateType::Handshake => self.state.as_handshake_mut().expect("checked"),
-4562 };
-4563
-4564 match packet.header {
-4565 Header::Retry {
-4566 src_cid: remote_cid,
-4567 ..
-4568 } => {
-4569 debug_assert_eq!(path_id, PathId::ZERO);
-4570 if self.side.is_server() {
-4571 return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into());
-4572 }
-4573
-4574 let is_valid_retry = self
-4575 .remote_cids
-4576 .get(&path_id)
-4577 .map(|cids| cids.active())
-4578 .map(|orig_dst_cid| {
-4579 self.crypto_state.session.is_valid_retry(
-4580 orig_dst_cid,
-4581 &packet.header_data,
-4582 &packet.payload,
-4583 )
-4584 })
-4585 .unwrap_or_default();
-4586 if self.total_authed_packets > 1
-4587 || packet.payload.len() <= 16 // token + 16 byte tag
-4588 || !is_valid_retry
-4589 {
-4590 trace!("discarding invalid Retry");
-4591 // - After the client has received and processed an Initial or Retry
-4592 // packet from the server, it MUST discard any subsequent Retry
-4593 // packets that it receives.
-4594 // - A client MUST discard a Retry packet with a zero-length Retry Token
-4595 // field.
-4596 // - Clients MUST discard Retry packets that have a Retry Integrity Tag
-4597 // that cannot be validated
-4598 return Ok(());
-4599 }
-4600
-4601 trace!("retrying with CID {}", remote_cid);
-4602 let client_hello = state.client_hello.take().unwrap();
-4603 self.retry_src_cid = Some(remote_cid);
-4604 self.remote_cids
-4605 .get_mut(&path_id)
-4606 .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false")
-4607 .update_initial_cid(remote_cid);
-4608 self.remote_handshake_cid = remote_cid;
-4609
-4610 let space = &mut self.spaces[SpaceId::Initial];
-4611 if let Some(info) = space.for_path(PathId::ZERO).take(0) {
-4612 self.on_packet_acked(now, PathId::ZERO, 0, info);
-4613 };
-4614
-4615 self.discard_space(now, SpaceKind::Initial); // Make sure we clean up after
-4616 // any retransmitted Initials
-4617 let crypto_space = &mut self.crypto_state.spaces[SpaceKind::Initial];
-4618 crypto_space.keys = Some(
-4619 self.crypto_state
-4620 .session
-4621 .initial_keys(remote_cid, self.side.side()),
-4622 );
-4623 crypto_space.crypto_offset = client_hello.len() as u64;
-4624
-4625 let next_pn = self.spaces[SpaceId::Initial]
-4626 .for_path(path_id)
-4627 .next_packet_number;
-4628 self.spaces[SpaceId::Initial] = {
-4629 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng);
-4630 space.for_path(path_id).next_packet_number = next_pn;
-4631 space.pending.crypto.push_back(frame::Crypto {
-4632 offset: 0,
-4633 data: client_hello,
-4634 });
-4635 space
-4636 };
-4637
-4638 // Retransmit all 0-RTT data
-4639 let zero_rtt = mem::take(
-4640 &mut self.spaces[SpaceId::Data]
-4641 .for_path(PathId::ZERO)
-4642 .sent_packets,
-4643 );
-4644 for (_, info) in zero_rtt.into_iter() {
-4645 self.paths
-4646 .get_mut(&PathId::ZERO)
-4647 .unwrap()
-4648 .remove_in_flight(&info);
-4649 self.spaces[SpaceId::Data].pending |= info.retransmits;
-4650 }
-4651 self.streams.retransmit_all_for_0rtt();
-4652
-4653 let token_len = packet.payload.len() - 16;
-4654 let ConnectionSide::Client { ref mut token, .. } = self.side else {
-4655 unreachable!("we already short-circuited if we're server");
-4656 };
-4657 *token = packet.payload.freeze().split_to(token_len);
-4658
-4659 self.state = State::handshake(state::Handshake {
-4660 expected_token: Bytes::new(),
-4661 remote_cid_set: false,
-4662 client_hello: None,
-4663 allow_server_migration: self.config.server_handshake_migration,
-4664 });
-4665 Ok(())
-4666 }
-4667 Header::Long {
-4668 ty: LongType::Handshake,
-4669 src_cid: remote_cid,
-4670 dst_cid: local_cid,
-4671 ..
-4672 } => {
-4673 debug_assert_eq!(path_id, PathId::ZERO);
-4674 if remote_cid != self.remote_handshake_cid {
-4675 debug!(
-4676 "discarding packet with mismatched remote CID: {} != {}",
-4677 self.remote_handshake_cid, remote_cid
-4678 );
-4679 return Ok(());
-4680 }
-4681 self.on_path_validated(path_id);
-4682
-4683 self.process_early_payload(now, path_id, packet, qlog)?;
-4684 if self.state.is_closed() {
-4685 return Ok(());
-4686 }
-4687
-4688 if self.crypto_state.session.is_handshaking() {
-4689 trace!("handshake ongoing");
-4690 return Ok(());
-4691 }
-4692
-4693 if self.side.is_client() {
-4694 // Client-only because server params were set from the client's Initial
-4695 let params = self
-4696 .crypto_state
-4697 .session
-4698 .transport_parameters()?
-4699 .ok_or_else(|| {
-4700 TransportError::new(
-4701 TransportErrorCode::crypto(0x6d),
-4702 "transport parameters missing".to_owned(),
-4703 )
-4704 })?;
-4705
-4706 if self.has_0rtt() {
-4707 if !self.crypto_state.session.early_data_accepted().unwrap() {
-4708 debug_assert!(self.side.is_client());
-4709 debug!("0-RTT rejected");
-4710 self.crypto_state.accepted_0rtt = false;
-4711 self.streams.zero_rtt_rejected();
-4712
-4713 // Discard already-queued frames
-4714 self.spaces[SpaceId::Data].pending = Retransmits::default();
-4715
-4716 // Discard 0-RTT packets
-4717 let sent_packets = mem::take(
-4718 &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets,
-4719 );
-4720 for (_, packet) in sent_packets.into_iter() {
-4721 self.paths
-4722 .get_mut(&path_id)
-4723 .unwrap()
-4724 .remove_in_flight(&packet);
-4725 }
-4726 } else {
-4727 self.crypto_state.accepted_0rtt = true;
-4728 params.validate_resumption_from(&self.peer_params)?;
-4729 }
-4730 }
-4731 if let Some(token) = params.stateless_reset_token {
-4732 let remote = self.path_data(path_id).network_path.remote;
-4733 debug_assert!(!self.state.is_drained()); // requirement for endpoint events, checked above
-4734 self.endpoint_events
-4735 .push_back(EndpointEventInner::ResetToken(path_id, remote, token));
-4736 }
-4737 self.handle_peer_params(params, local_cid, remote_cid, now)?;
-4738 self.issue_first_cids(now);
-4739 } else {
-4740 // Server-only
-4741 self.spaces[SpaceId::Data].pending.handshake_done = true;
-4742 self.discard_space(now, SpaceKind::Handshake);
-4743 self.events.push_back(Event::HandshakeConfirmed);
-4744 trace!("handshake confirmed");
-4745 }
-4746
-4747 self.events.push_back(Event::Connected);
-4748 self.state.move_to_established();
-4749 trace!("established");
-4750
-4751 // Multipath can only be enabled after the state has reached Established.
-4752 // So this can not happen any earlier.
-4753 self.issue_first_path_cids(now);
-4754 Ok(())
-4755 }
-4756 Header::Initial(InitialHeader {
-4757 src_cid: remote_cid,
-4758 dst_cid: local_cid,
-4759 ..
-4760 }) => {
-4761 debug_assert_eq!(path_id, PathId::ZERO);
-4762 if !state.remote_cid_set {
-4763 trace!("switching remote CID to {}", remote_cid);
-4764 let mut state = state.clone();
-4765 self.remote_cids
-4766 .get_mut(&path_id)
-4767 .expect("PathId::ZERO not yet abandoned")
-4768 .update_initial_cid(remote_cid);
-4769 self.remote_handshake_cid = remote_cid;
-4770 self.original_remote_cid = remote_cid;
-4771 state.remote_cid_set = true;
-4772 self.state.move_to_handshake(state);
-4773 } else if remote_cid != self.remote_handshake_cid {
-4774 debug!(
-4775 "discarding packet with mismatched remote CID: {} != {}",
-4776 self.remote_handshake_cid, remote_cid
-4777 );
-4778 return Ok(());
-4779 }
-4780
-4781 let starting_space = self.highest_space;
-4782 self.process_early_payload(now, path_id, packet, qlog)?;
-4783
-4784 if self.side.is_server()
-4785 && starting_space == SpaceKind::Initial
-4786 && self.highest_space != SpaceKind::Initial
-4787 {
-4788 let params = self
-4789 .crypto_state
-4790 .session
-4791 .transport_parameters()?
-4792 .ok_or_else(|| {
-4793 TransportError::new(
-4794 TransportErrorCode::crypto(0x6d),
-4795 "transport parameters missing".to_owned(),
-4796 )
-4797 })?;
-4798 self.handle_peer_params(params, local_cid, remote_cid, now)?;
-4799 self.issue_first_cids(now);
-4800 self.init_0rtt(now);
-4801 }
-4802 Ok(())
-4803 }
-4804 Header::Long {
-4805 ty: LongType::ZeroRtt,
-4806 ..
-4807 } => {
-4808 self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?;
-4809 Ok(())
-4810 }
-4811 Header::VersionNegotiate { .. } => {
-4812 if self.total_authed_packets > 1 {
-4813 return Ok(());
-4814 }
-4815 let supported = packet
-4816 .payload
-4817 .chunks(4)
-4818 .any(|x| match <[u8; 4]>::try_from(x) {
-4819 Ok(version) => self.version == u32::from_be_bytes(version),
-4820 Err(_) => false,
-4821 });
-4822 if supported {
-4823 return Ok(());
-4824 }
-4825 debug!("remote doesn't support our version");
-4826 Err(ConnectionError::VersionMismatch)
-4827 }
-4828 Header::Short { .. } => unreachable!(
-4829 "short packets received during handshake are discarded in handle_packet"
-4830 ),
-4831 }
-4832 }
-4833
-4834 /// Process an Initial or Handshake packet payload
-4835 fn process_early_payload(
-4836 &mut self,
-4837 now: Instant,
-4838 path_id: PathId,
-4839 packet: Packet,
-4840 #[allow(unused)] qlog: &mut QlogRecvPacket,
-4841 ) -> Result<(), TransportError> {
-4842 debug_assert_ne!(packet.header.space(), SpaceKind::Data);
-4843 debug_assert_eq!(path_id, PathId::ZERO);
-4844 let payload_len = packet.payload.len();
-4845 let mut ack_eliciting = false;
-4846 for result in frame::Iter::new(packet.payload.freeze())? {
-4847 let frame = result?;
-4848 qlog.frame(&frame);
-4849 let span = match frame {
-4850 Frame::Padding => continue,
-4851 _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)),
-4852 };
-4853
-4854 self.path_stats
-4855 .for_path(path_id)
-4856 .frame_rx
-4857 .record(frame.ty());
-4858
-4859 let _guard = span.as_ref().map(|x| x.enter());
-4860 ack_eliciting |= frame.is_ack_eliciting();
-4861
-4862 // Process frames
-4863 if frame.is_1rtt() && packet.header.space() != SpaceKind::Data {
-4864 return Err(TransportError::PROTOCOL_VIOLATION(
-4865 "illegal frame type in handshake",
-4866 ));
-4867 }
-4868
-4869 match frame {
-4870 Frame::Padding | Frame::Ping => {}
-4871 Frame::Crypto(frame) => {
-4872 self.read_crypto(packet.header.space().into(), &frame, payload_len)?;
-4873 }
-4874 Frame::Ack(ack) => {
-4875 self.on_ack_received(now, packet.header.space().into(), ack)?;
-4876 }
-4877 Frame::PathAck(ack) => {
-4878 span.as_ref()
-4879 .map(|span| span.record("path", tracing::field::display(&ack.path_id)));
-4880 self.on_path_ack_received(now, packet.header.space().into(), ack)?;
-4881 }
-4882 Frame::Close(reason) => {
-4883 self.state.move_to_draining(Some(reason.into()));
-4884 self.endpoint_events.push_back(EndpointEventInner::Draining);
-4885 return Ok(());
-4886 }
-4887 _ => {
-4888 let mut err =
-4889 TransportError::PROTOCOL_VIOLATION("illegal frame type in handshake");
-4890 err.frame = frame::MaybeFrame::Known(frame.ty());
-4891 return Err(err);
-4892 }
-4893 }
-4894 }
-4895
-4896 if ack_eliciting {
-4897 // In the initial and handshake spaces, ACKs must be sent immediately
-4898 self.spaces[packet.header.space()]
-4899 .for_path(path_id)
-4900 .pending_acks
-4901 .set_immediate_ack_required();
-4902 }
-4903
-4904 self.write_crypto();
-4905 Ok(())
-4906 }
-4907
-4908 /// Processes the decrypted packet payload, always in the data space.
-4909 fn process_payload(
-4910 &mut self,
-4911 now: Instant,
-4912 network_path: FourTuple,
-4913 path_id: PathId,
-4914 number: u64,
-4915 packet: Packet,
-4916 #[allow(unused)] qlog: &mut QlogRecvPacket,
-4917 ) -> Result<(), TransportError> {
-4918 let payload = packet.payload.freeze();
-4919 let mut is_probing_packet = true;
-4920 let mut close = None;
-4921 let payload_len = payload.len();
-4922 let mut ack_eliciting = false;
-4923 // if this packet triggers a path migration and includes a observed address frame, it's
-4924 // stored here
-4925 let mut migration_observed_addr = None;
-4926 for result in frame::Iter::new(payload)? {
-4927 let frame = result?;
-4928 qlog.frame(&frame);
-4929 let span = match frame {
-4930 Frame::Padding => continue,
-4931 _ => trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty),
-4932 };
-4933
-4934 self.path_stats
-4935 .for_path(path_id)
-4936 .frame_rx
-4937 .record(frame.ty());
-4938 // Crypto, Stream and Datagram frames are special cased in order no pollute
-4939 // the log with payload data
-4940 match &frame {
-4941 Frame::Crypto(f) => {
-4942 trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO");
-4943 }
-4944 Frame::Stream(f) => {
-4945 trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM");
-4946 }
-4947 Frame::Datagram(f) => {
-4948 trace!(len = f.data.len(), "got frame DATAGRAM");
-4949 }
-4950 f => {
-4951 trace!("got frame {f}");
-4952 }
-4953 }
-4954
-4955 let _guard = span.enter();
-4956 if packet.header.is_0rtt() {
-4957 match frame {
-4958 Frame::Crypto(_) | Frame::Close(Close::Application(_)) => {
-4959 return Err(TransportError::PROTOCOL_VIOLATION(
-4960 "illegal frame type in 0-RTT",
-4961 ));
-4962 }
-4963 _ => {
-4964 if frame.is_1rtt() {
-4965 return Err(TransportError::PROTOCOL_VIOLATION(
-4966 "illegal frame type in 0-RTT",
-4967 ));
-4968 }
-4969 }
-4970 }
-4971 }
-4972 ack_eliciting |= frame.is_ack_eliciting();
-4973
-4974 // Check whether this could be a probing packet
-4975 match frame {
-4976 Frame::Padding
-4977 | Frame::PathChallenge(_)
-4978 | Frame::PathResponse(_)
-4979 | Frame::NewConnectionId(_)
-4980 | Frame::ObservedAddr(_) => {}
-4981 _ => {
-4982 is_probing_packet = false;
-4983 }
-4984 }
-4985
-4986 match frame {
-4987 Frame::Crypto(frame) => {
-4988 self.read_crypto(SpaceId::Data, &frame, payload_len)?;
-4989 }
-4990 Frame::Stream(frame) => {
-4991 if self.streams.received(frame, payload_len)?.should_transmit() {
-4992 self.spaces[SpaceId::Data].pending.max_data = true;
-4993 }
-4994 }
-4995 Frame::Ack(ack) => {
-4996 self.on_ack_received(now, SpaceId::Data, ack)?;
-4997 }
-4998 Frame::PathAck(ack) => {
-4999 if !self.is_multipath_negotiated() {
-5000 return Err(TransportError::PROTOCOL_VIOLATION(
-5001 "received PATH_ACK frame when multipath was not negotiated",
-5002 ));
-5003 }
-5004 span.record("path", tracing::field::display(&ack.path_id));
-5005 self.on_path_ack_received(now, SpaceId::Data, ack)?;
-5006 }
-5007 Frame::Padding | Frame::Ping => {}
-5008 Frame::Close(reason) => {
-5009 close = Some(reason);
-5010 }
-5011 Frame::PathChallenge(challenge) => {
-5012 self.spaces[SpaceKind::Data]
-5013 .for_path(path_id)
-5014 .pending_path_responses
-5015 .push(number, challenge.0, network_path);
-5016 // If we were passively migrated (e.g. NAT rebinding), our local_ip will
-5017 // not match. Once we processed a non-probing packet the local_ip will
-5018 // finally be updated.
-5019 let path = &mut self
-5020 .path_mut(path_id)
-5021 .expect("payload is processed only after the path becomes known");
-5022 if network_path.remote == path.network_path.remote {
-5023 // PATH_CHALLENGE on active path, possible off-path packet
-5024 // forwarding attack. Send a non-probing packet to recover the
-5025 // active path. See
-5026 // https://www.rfc-editor.org/rfc/rfc9000.html#section-9.3.3-3. In
-5027 // rare cases NAT probes might also appear on-path and would also
-5028 // get a non-probing packet as response. There is little harm in
-5029 // this.
-5030 match self.peer_supports_ack_frequency() {
-5031 true => self.immediate_ack(path_id),
-5032 false => {
-5033 self.ping_path(path_id).ok();
-5034 }
-5035 }
-5036 }
-5037 }
-5038 Frame::PathResponse(response) => {
-5039 // First try to see if this is a NAT probe response.
-5040 if self
-5041 .n0_nat_traversal
-5042 .handle_path_response(network_path, response.0)
-5043 {
-5044 self.open_nat_traversed_paths(now);
-5045 } else {
-5046 // Try to see if this is a response to an on-path PATH_CHALLENGE.
-5047 self.handle_path_response_on_path(now, response, path_id, network_path);
-5048 }
-5049 }
-5050 Frame::MaxData(frame::MaxData(bytes)) => {
-5051 self.streams.received_max_data(bytes);
-5052 }
-5053 Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => {
-5054 self.streams.received_max_stream_data(id, offset)?;
-5055 }
-5056 Frame::MaxStreams(frame::MaxStreams { dir, count }) => {
-5057 self.streams.received_max_streams(dir, count)?;
-5058 }
-5059 Frame::ResetStream(frame) => {
-5060 if self.streams.received_reset(frame)?.should_transmit() {
-5061 self.spaces[SpaceId::Data].pending.max_data = true;
-5062 }
-5063 }
-5064 Frame::DataBlocked(DataBlocked(offset)) => {
-5065 debug!(offset, "peer claims to be blocked at connection level");
-5066 }
-5067 Frame::StreamDataBlocked(StreamDataBlocked { id, offset }) => {
-5068 if id.initiator() == self.side.side() && id.dir() == Dir::Uni {
-5069 debug!("got STREAM_DATA_BLOCKED on send-only {}", id);
-5070 return Err(TransportError::STREAM_STATE_ERROR(
-5071 "STREAM_DATA_BLOCKED on send-only stream",
-5072 ));
-5073 }
-5074 debug!(
-5075 stream = %id,
-5076 offset, "peer claims to be blocked at stream level"
-5077 );
-5078 }
-5079 Frame::StreamsBlocked(StreamsBlocked { dir, limit }) => {
-5080 if limit > MAX_STREAM_COUNT {
-5081 return Err(TransportError::FRAME_ENCODING_ERROR(
-5082 "unrepresentable stream limit",
-5083 ));
-5084 }
-5085 debug!(
-5086 "peer claims to be blocked opening more than {} {} streams",
-5087 limit, dir
-5088 );
-5089 }
-5090 Frame::StopSending(frame::StopSending { id, error_code }) => {
-5091 if id.initiator() != self.side.side() {
-5092 if id.dir() == Dir::Uni {
-5093 debug!("got STOP_SENDING on recv-only {}", id);
-5094 return Err(TransportError::STREAM_STATE_ERROR(
-5095 "STOP_SENDING on recv-only stream",
-5096 ));
-5097 }
-5098 } else if self.streams.is_local_unopened(id) {
-5099 return Err(TransportError::STREAM_STATE_ERROR(
-5100 "STOP_SENDING on unopened stream",
-5101 ));
-5102 }
-5103 self.streams.received_stop_sending(id, error_code);
-5104 }
-5105 Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => {
-5106 if let Some(ref path_id) = path_id {
-5107 span.record("path", tracing::field::display(&path_id));
-5108 }
-5109 let path_id = path_id.unwrap_or_default();
-5110 match self.local_cid_state.get_mut(&path_id) {
-5111 None => debug!(?path_id, "RETIRE_CONNECTION_ID for unknown path"),
-5112 Some(cid_state) => {
-5113 let allow_more_cids = cid_state
-5114 .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?;
-5115
-5116 // If the path has closed, we do not issue more CIDs for this path
-5117 // For details see https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-3.2.2
-5118 // > an endpoint SHOULD provide new connection IDs for that path, if still open, using PATH_NEW_CONNECTION_ID frames.
-5119 let has_path = !self.abandoned_paths.contains(&path_id);
-5120 let allow_more_cids = allow_more_cids && has_path;
-5121
-5122 debug_assert!(!self.state.is_drained()); // required for adding endpoint events, process_payload is never called for drained connections
-5123 self.endpoint_events
-5124 .push_back(EndpointEventInner::RetireConnectionId(
-5125 now,
-5126 path_id,
-5127 sequence,
-5128 allow_more_cids,
-5129 ));
-5130 }
-5131 }
-5132 }
-5133 Frame::NewConnectionId(frame) => {
-5134 let path_id = if let Some(path_id) = frame.path_id {
-5135 if !self.is_multipath_negotiated() {
-5136 return Err(TransportError::PROTOCOL_VIOLATION(
-5137 "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated",
-5138 ));
-5139 }
-5140 if path_id > self.local_max_path_id {
-5141 return Err(TransportError::PROTOCOL_VIOLATION(
-5142 "PATH_NEW_CONNECTION_ID contains path_id exceeding current max",
-5143 ));
-5144 }
-5145 path_id
-5146 } else {
-5147 PathId::ZERO
-5148 };
-5149
-5150 if let Some(ref path_id) = frame.path_id {
-5151 span.record("path", tracing::field::display(&path_id));
-5152 }
-5153
-5154 if self.abandoned_paths.contains(&path_id) {
-5155 trace!("ignoring issued CID for abandoned path");
-5156 continue;
-5157 }
-5158 let remote_cids = self
-5159 .remote_cids
-5160 .entry(path_id)
-5161 .or_insert_with(|| CidQueue::new(frame.id));
-5162 if remote_cids.active().is_empty() {
-5163 return Err(TransportError::PROTOCOL_VIOLATION(
-5164 "NEW_CONNECTION_ID when CIDs aren't in use",
-5165 ));
-5166 }
-5167 if frame.retire_prior_to > frame.sequence {
-5168 return Err(TransportError::PROTOCOL_VIOLATION(
-5169 "NEW_CONNECTION_ID retiring unissued CIDs",
-5170 ));
-5171 }
-5172
-5173 use crate::cid_queue::InsertError;
-5174 match remote_cids.insert(frame) {
-5175 Ok(None) => {
-5176 self.open_nat_traversed_paths(now);
-5177 }
-5178 Ok(Some((retired, reset_token))) => {
-5179 let pending_retired =
-5180 &mut self.spaces[SpaceId::Data].pending.retire_cids;
-5181 /// Ensure `pending_retired` cannot grow without bound. Limit is
-5182 /// somewhat arbitrary but very permissive.
-5183 const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10;
-5184 // We don't bother counting in-flight frames because those are bounded
-5185 // by congestion control.
-5186 if (pending_retired.len() as u64)
-5187 .saturating_add(retired.end.saturating_sub(retired.start))
-5188 > MAX_PENDING_RETIRED_CIDS
-5189 {
-5190 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(
-5191 "queued too many retired CIDs",
-5192 ));
-5193 }
-5194 pending_retired.extend(retired.map(|seq| (path_id, seq)));
-5195 self.set_reset_token(path_id, network_path.remote, reset_token);
-5196 self.open_nat_traversed_paths(now);
-5197 }
-5198 Err(InsertError::ExceedsLimit) => {
-5199 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(""));
-5200 }
-5201 Err(InsertError::Retired) => {
-5202 trace!("discarding already-retired");
-5203 // RETIRE_CONNECTION_ID might not have been previously sent if e.g. a
-5204 // range of connection IDs larger than the active connection ID limit
-5205 // was retired all at once via retire_prior_to.
-5206 self.spaces[SpaceId::Data]
-5207 .pending
-5208 .retire_cids
-5209 .push((path_id, frame.sequence));
-5210 continue;
-5211 }
-5212 };
-5213
-5214 if self.side.is_server()
-5215 && path_id == PathId::ZERO
-5216 && self
-5217 .remote_cids
-5218 .get(&PathId::ZERO)
-5219 .map(|cids| cids.active_seq() == 0)
-5220 .unwrap_or_default()
-5221 {
-5222 // We're a server still using the initial remote CID for the client, so
-5223 // let's switch immediately to enable clientside stateless resets.
-5224 self.update_remote_cid(PathId::ZERO);
-5225 }
-5226 }
-5227 Frame::NewToken(NewToken { token }) => {
-5228 let ConnectionSide::Client {
-5229 token_store,
-5230 server_name,
-5231 ..
-5232 } = &self.side
-5233 else {
-5234 return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN"));
-5235 };
-5236 if token.is_empty() {
-5237 return Err(TransportError::FRAME_ENCODING_ERROR("empty token"));
-5238 }
-5239 trace!("got new token");
-5240 token_store.insert(server_name, token);
-5241 }
-5242 Frame::Datagram(datagram) => {
-5243 if self
-5244 .datagrams
-5245 .received(datagram, &self.config.datagram_receive_buffer_size)?
-5246 {
-5247 self.events.push_back(Event::DatagramReceived);
-5248 }
-5249 }
-5250 Frame::AckFrequency(ack_frequency) => {
-5251 // This frame can only be sent in the Data space
-5252
-5253 if !self.ack_frequency.ack_frequency_received(&ack_frequency)? {
-5254 // The AckFrequency frame is stale (we have already received a more
-5255 // recent one)
-5256 continue;
-5257 }
-5258
-5259 // Update the params for all of our paths
-5260 for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() {
-5261 space.pending_acks.set_ack_frequency_params(&ack_frequency);
-5262
-5263 // Our `max_ack_delay` has been updated, so we may need to adjust
-5264 // its associated timeout.
-5265 // Packets received on abandoned paths are always acknowledged immediately.
-5266 if !self.abandoned_paths.contains(path_id)
-5267 && let Some(timeout) = space
-5268 .pending_acks
-5269 .max_ack_delay_timeout(self.ack_frequency.max_ack_delay)
-5270 {
-5271 self.timers.set(
-5272 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
-5273 timeout,
-5274 self.qlog.with_time(now),
-5275 );
-5276 }
-5277 }
-5278 }
-5279 Frame::ImmediateAck => {
-5280 // This frame can only be sent in the Data space
-5281 for pns in self.spaces[SpaceId::Data].iter_paths_mut() {
-5282 pns.pending_acks.set_immediate_ack_required();
-5283 }
-5284 }
-5285 Frame::HandshakeDone => {
-5286 if self.side.is_server() {
-5287 return Err(TransportError::PROTOCOL_VIOLATION(
-5288 "client sent HANDSHAKE_DONE",
-5289 ));
-5290 }
-5291 if self.crypto_state.has_keys(EncryptionLevel::Handshake) {
-5292 self.discard_space(now, SpaceKind::Handshake);
-5293 self.events.push_back(Event::HandshakeConfirmed);
-5294 trace!("handshake confirmed");
-5295 }
-5296 }
-5297 Frame::ObservedAddr(observed) => {
-5298 // check if params allows the peer to send report and this node to receive it
-5299 trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port);
-5300 if !self
-5301 .peer_params
-5302 .address_discovery_role
-5303 .should_report(&self.config.address_discovery_role)
-5304 {
-5305 return Err(TransportError::PROTOCOL_VIOLATION(
-5306 "received OBSERVED_ADDRESS frame when not negotiated",
-5307 ));
-5308 }
-5309 // must only be sent in data space
-5310 if packet.header.space() != SpaceKind::Data {
-5311 return Err(TransportError::PROTOCOL_VIOLATION(
-5312 "OBSERVED_ADDRESS frame outside data space",
-5313 ));
-5314 }
-5315
-5316 let space_open_status =
-5317 self.spaces[SpaceKind::Data].for_path(path_id).open_status;
-5318 let path = self.path_data_mut(path_id);
-5319 if path.network_path.remote == network_path.remote {
-5320 if let Some(updated) = path.update_observed_addr_report(observed)
-5321 && space_open_status == OpenStatus::Informed
-5322 {
-5323 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
-5324 id: path_id,
-5325 addr: updated,
-5326 }));
-5327 // otherwise the event is reported when the path is deemed open
-5328 }
-5329 } else {
-5330 // include in migration
-5331 migration_observed_addr = Some(observed)
-5332 }
-5333 }
-5334 Frame::PathAbandon(frame::PathAbandon {
-5335 path_id,
-5336 error_code,
-5337 }) => {
-5338 span.record("path", tracing::field::display(&path_id));
-5339 match self.close_path_inner(
-5340 now,
-5341 path_id,
-5342 PathAbandonReason::RemoteAbandoned {
-5343 error_code: error_code.into(),
-5344 },
-5345 ) {
-5346 Ok(()) => {
-5347 trace!("peer abandoned path");
-5348 }
-5349 Err(ClosePathError::ClosedPath) => {
-5350 trace!("peer abandoned already closed path");
-5351 }
-5352 Err(ClosePathError::MultipathNotNegotiated) => {
-5353 return Err(TransportError::PROTOCOL_VIOLATION(
-5354 "received PATH_ABANDON frame when multipath was not negotiated",
-5355 ));
-5356 }
-5357 Err(ClosePathError::LastOpenPath) => {
-5358 // Not reachable: close_path_inner allows remote abandons
-5359 // for the last path. But handle gracefully just in case.
-5360 error!(
-5361 "peer abandoned last path but close_path_inner returned LastOpenPath"
-5362 );
-5363 }
-5364 };
-5365
-5366 // Start draining the path if it still exists and hasn't started draining yet.
-5367 if let Some(path) = self.paths.get_mut(&path_id)
-5368 && !mem::replace(&mut path.data.draining, true)
-5369 {
-5370 let ack_delay = self.ack_frequency.max_ack_delay_for_pto();
-5371 let pto = path.data.rtt.pto_base() + ack_delay;
-5372 self.timers.set(
-5373 Timer::PerPath(path_id, PathTimer::PathDrained),
-5374 now + 3 * pto,
-5375 self.qlog.with_time(now),
-5376 );
-5377
-5378 self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8));
-5379 }
-5380 }
-5381 Frame::PathStatusAvailable(info) => {
-5382 span.record("path", tracing::field::display(&info.path_id));
-5383 if self.is_multipath_negotiated() {
-5384 self.on_path_status(
-5385 info.path_id,
-5386 PathStatus::Available,
-5387 info.status_seq_no,
-5388 );
-5389 } else {
-5390 return Err(TransportError::PROTOCOL_VIOLATION(
-5391 "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated",
-5392 ));
-5393 }
-5394 }
-5395 Frame::PathStatusBackup(info) => {
-5396 span.record("path", tracing::field::display(&info.path_id));
-5397 if self.is_multipath_negotiated() {
-5398 self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no);
-5399 } else {
-5400 return Err(TransportError::PROTOCOL_VIOLATION(
-5401 "received PATH_STATUS_BACKUP frame when multipath was not negotiated",
-5402 ));
-5403 }
-5404 }
-5405 Frame::MaxPathId(frame::MaxPathId(path_id)) => {
-5406 span.record("path", tracing::field::display(&path_id));
-5407 if !self.is_multipath_negotiated() {
-5408 return Err(TransportError::PROTOCOL_VIOLATION(
-5409 "received MAX_PATH_ID frame when multipath was not negotiated",
-5410 ));
-5411 }
-5412 // frames that do not increase the path id are ignored
-5413 if path_id > self.remote_max_path_id {
-5414 self.remote_max_path_id = path_id;
-5415 self.issue_first_path_cids(now);
-5416 self.open_nat_traversed_paths(now);
-5417 }
-5418 }
-5419 Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => {
-5420 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST
-5421 // be treated as a connection error of type PROTOCOL_VIOLATION.
-5422 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids>
-5423 if self.is_multipath_negotiated() {
-5424 if max_path_id > self.local_max_path_id {
-5425 return Err(TransportError::PROTOCOL_VIOLATION(
-5426 "PATHS_BLOCKED maximum path identifier was larger than local maximum",
-5427 ));
-5428 }
-5429 } else {
-5430 return Err(TransportError::PROTOCOL_VIOLATION(
-5431 "received PATHS_BLOCKED frame when not multipath was not negotiated",
-5432 ));
-5433 }
-5434 }
-5435 Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => {
-5436 // Nothing to do. This is recorded in the frame stats, but otherwise we
-5437 // always issue all CIDs we're allowed to issue, so either this is an
-5438 // impatient peer or a bug on our side.
-5439
-5440 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST
-5441 // be treated as a connection error of type PROTOCOL_VIOLATION.
-5442 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids>
-5443 if self.is_multipath_negotiated() {
-5444 if path_id > self.local_max_path_id {
-5445 return Err(TransportError::PROTOCOL_VIOLATION(
-5446 "PATH_CIDS_BLOCKED path identifier was larger than local maximum",
-5447 ));
-5448 }
-5449 if self
-5450 .local_cid_state
-5451 .get(&path_id)
-5452 // The PATH_CIDS_BLOCKED frame may arrive after we've discarded the path state.
-5453 // In that case, we can't check for the protocol violation.
-5454 .is_some_and(|cid_state| next_seq.0 > cid_state.active_seq().1 + 1)
-5455 {
-5456 return Err(TransportError::PROTOCOL_VIOLATION(
-5457 "PATH_CIDS_BLOCKED next sequence number larger than in local state",
-5458 ));
-5459 }
-5460 debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED");
-5461 } else {
-5462 return Err(TransportError::PROTOCOL_VIOLATION(
-5463 "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated",
-5464 ));
-5465 }
-5466 }
-5467 Frame::AddAddress(addr) => {
-5468 let client_state = match self.n0_nat_traversal.client_side_mut() {
-5469 Ok(state) => state,
-5470 Err(err) => {
-5471 return Err(TransportError::PROTOCOL_VIOLATION(format!(
-5472 "Nat traversal(ADD_ADDRESS): {err}"
-5473 )));
-5474 }
-5475 };
-5476
-5477 if !client_state.check_remote_address(&addr) {
-5478 // if the address is not valid we flag it, but update anyway
-5479 warn!(?addr, "server sent illegal ADD_ADDRESS frame");
-5480 }
-5481
-5482 match client_state.add_remote_address(addr) {
-5483 Ok(maybe_added) => {
-5484 if let Some(added) = maybe_added {
-5485 self.events.push_back(Event::NatTraversal(
-5486 n0_nat_traversal::Event::AddressAdded(added),
-5487 ));
-5488 }
-5489 }
-5490 Err(e) => {
-5491 warn!(%e, "failed to add remote address")
-5492 }
-5493 }
-5494 }
-5495 Frame::RemoveAddress(addr) => {
-5496 let client_state = match self.n0_nat_traversal.client_side_mut() {
-5497 Ok(state) => state,
-5498 Err(err) => {
-5499 return Err(TransportError::PROTOCOL_VIOLATION(format!(
-5500 "Nat traversal(REMOVE_ADDRESS): {err}"
-5501 )));
-5502 }
-5503 };
-5504 if let Some(removed_addr) = client_state.remove_remote_address(addr) {
-5505 self.events.push_back(Event::NatTraversal(
-5506 n0_nat_traversal::Event::AddressRemoved(removed_addr),
-5507 ));
-5508 }
-5509 }
-5510 Frame::ReachOut(reach_out) => {
-5511 let ipv6 = self.is_ipv6();
-5512 let server_state = match self.n0_nat_traversal.server_side_mut() {
-5513 Ok(state) => state,
-5514 Err(err) => {
-5515 return Err(TransportError::PROTOCOL_VIOLATION(format!(
-5516 "Nat traversal(REACH_OUT): {err}"
-5517 )));
-5518 }
-5519 };
-5520
-5521 let round_before = server_state.current_round();
-5522
-5523 if let Err(err) = server_state.handle_reach_out(reach_out, ipv6) {
-5524 return Err(TransportError::PROTOCOL_VIOLATION(format!(
-5525 "Nat traversal(REACH_OUT): {err}"
-5526 )));
-5527 }
-5528
-5529 if server_state.current_round() > round_before {
-5530 // A new round was started, reset the NAT probe retry timer.
-5531 if let Some(delay) =
-5532 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
-5533 {
-5534 self.timers.set(
-5535 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
-5536 now + delay,
-5537 self.qlog.with_time(now),
-5538 );
-5539 }
-5540 }
-5541 }
-5542 }
-5543 }
-5544
-5545 let space = self.spaces[SpaceId::Data].for_path(path_id);
-5546 if space
-5547 .pending_acks
-5548 .packet_received(now, number, ack_eliciting, &space.dedup)
-5549 {
-5550 if self.abandoned_paths.contains(&path_id) {
-5551 // § 3.4.3 QUIC-MULTIPATH: promptly send ACKs for packets received from
-5552 // abandoned paths.
-5553 space.pending_acks.set_immediate_ack_required();
-5554 } else {
-5555 self.timers.set(
-5556 Timer::PerPath(path_id, PathTimer::MaxAckDelay),
-5557 now + self.ack_frequency.max_ack_delay,
-5558 self.qlog.with_time(now),
-5559 );
-5560 }
-5561 }
-5562
-5563 // Issue stream ID credit due to ACKs of outgoing finish/resets and incoming finish/resets
-5564 // on stopped streams. Incoming finishes/resets on open streams are not handled here as they
-5565 // are only freed, and hence only issue credit, once the application has been notified
-5566 // during a read on the stream.
-5567 let pending = &mut self.spaces[SpaceId::Data].pending;
-5568 self.streams.queue_max_stream_id(pending);
-5569
-5570 if let Some(reason) = close {
-5571 self.state.move_to_draining(Some(reason.into()));
-5572 self.endpoint_events.push_back(EndpointEventInner::Draining);
-5573 self.connection_close_pending = true;
-5574 }
-5575
-5576 // For Multipath any packet triggers migration. For RFC9000 or QNT (+ Multipath)
-5577 // only non-probing packets trigger migration.
-5578 let migrate_on_any_packet =
-5579 self.is_multipath_negotiated() && !self.n0_nat_traversal.is_negotiated();
-5580
-5581 // Only migrate if this is the largest packet number seen.
-5582 let is_largest_received_pn = Some(number)
-5583 == self.spaces[SpaceId::Data]
-5584 .for_path(path_id)
-5585 .largest_received_packet_number;
-5586
-5587 // If we receive a non-probing packet on a new local IP that means we had a NAT
-5588 // rebinding-like migration. We update our local address but do not otherwise
-5589 // validate the new path, we only need to validate the path if the peer migrates per
-5590 // RFC9000 §9: https://www.rfc-editor.org/rfc/rfc9000.html#section-9-4
-5591 if (migrate_on_any_packet || !is_probing_packet)
-5592 && is_largest_received_pn
-5593 && self.local_ip_may_migrate()
-5594 && let Some(new_local_ip) = network_path.local_ip
-5595 {
-5596 let path_data = self.path_data_mut(path_id);
-5597 if path_data
-5598 .network_path
-5599 .local_ip
-5600 .is_some_and(|ip| ip != new_local_ip)
-5601 {
-5602 debug!(
-5603 %path_id,
-5604 new_4tuple = %network_path,
-5605 prev_4tuple = %path_data.network_path,
-5606 "local address passive migration"
-5607 );
-5608 }
-5609 path_data.network_path.local_ip = Some(new_local_ip)
-5610 }
-5611
-5612 // If the peer migrated to a new address, trigger migration.
-5613 if self.peer_may_migrate()
-5614 && (migrate_on_any_packet || !is_probing_packet)
-5615 && is_largest_received_pn
-5616 && network_path.remote != self.path_data(path_id).network_path.remote
-5617 {
-5618 self.migrate(path_id, now, network_path, migration_observed_addr);
-5619 // Break linkability, if possible
-5620 self.update_remote_cid(path_id);
-5621 self.spin = false;
-5622 }
-5623
-5624 Ok(())
-5625 }
-5626
-5627 /// Handles any on-path PATH_RESPONSE frames.
-5628 ///
-5629 /// *path_id* and *network_path* are those on which the PATH_RESPONSE was received.
-5630 fn handle_path_response_on_path(
-5631 &mut self,
-5632 now: Instant,
-5633 response: frame::PathResponse,
-5634 path_id: PathId,
-5635 network_path: FourTuple,
-5636 ) {
-5637 let is_multipath_negotiated = self.is_multipath_negotiated();
-5638 let path = self
-5639 .paths
-5640 .get_mut(&path_id)
-5641 .expect("payload is processed only after the path becomes known");
-5642 match path
-5643 .data
-5644 .on_path_response_received(now, response.0, network_path)
-5645 {
-5646 paths::OnPathResponseReceived::OnPath if !self.abandoned_paths.contains(&path_id) => {
-5647 let qlog = self.qlog.with_time(now);
-5648 self.timers.stop(
-5649 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
-5650 qlog.clone(),
-5651 );
-5652 self.timers.stop(
-5653 Timer::PerPath(path_id, PathTimer::AbandonFromValidation),
-5654 qlog.clone(),
-5655 );
-5656 let next_challenge = path
-5657 .data
-5658 .earliest_on_path_expiring_challenge()
-5659 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto());
-5660 self.timers.set_or_stop(
-5661 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
-5662 next_challenge,
-5663 qlog,
-5664 );
-5665 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
-5666 if !matches!(pns.open_status, OpenStatus::Informed) {
-5667 if is_multipath_negotiated {
-5668 self.events
-5669 .push_back(Event::Path(PathEvent::Established { id: path_id }));
-5670 }
-5671 pns.open_status = OpenStatus::Informed;
-5672 if let Some(observed) = path.data.last_observed_addr_report.as_ref() {
-5673 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
-5674 id: path_id,
-5675 addr: observed.socket_addr(),
-5676 }));
-5677 }
-5678 }
-5679 if let Some((_, ref mut prev)) = path.prev {
-5680 // If an on-path response was received while there is a
-5681 // previous path from a migration, then the new path is
-5682 // validated and we can stop sending challenges that try to
-5683 // re-validate the previous path.
-5684 prev.reset_on_path_challenges();
-5685 }
-5686 }
-5687 paths::OnPathResponseReceived::OnPath => {
-5688 trace!(
-5689 %response,
-5690 "ignoring PATH_RESPONSE received after path is abandoned"
-5691 );
-5692 }
-5693 paths::OnPathResponseReceived::Unknown => {
-5694 debug!(%response, "ignoring invalid PATH_RESPONSE");
-5695 }
-5696 paths::OnPathResponseReceived::Ignored {
-5697 sent_on,
-5698 current_path,
-5699 } => {
-5700 debug!(%sent_on, %current_path, %response, "ignoring valid PATH_RESPONSE");
-5701 }
-5702 }
-5703 }
-5704
-5705 /// Opens any paths that have been successfully NAT traversed.
-5706 fn open_nat_traversed_paths(&mut self, now: Instant) {
-5707 while let Some(network_path) = self
-5708 .n0_nat_traversal
-5709 .client_side_mut()
-5710 .ok()
-5711 .and_then(|s| s.pop_pending_path_open())
-5712 {
-5713 match self.open_path_ensure(network_path, PathStatus::Backup, now) {
-5714 Ok((path_id, already_existed)) => {
-5715 debug!(
-5716 %path_id,
-5717 ?network_path,
-5718 new_path = !already_existed,
-5719 "Opened NAT traversal path",
-5720 );
-5721 }
-5722 Err(err) => match err {
-5723 PathError::MultipathNotNegotiated
-5724 | PathError::ServerSideNotAllowed
-5725 | PathError::ValidationFailed
-5726 | PathError::InvalidRemoteAddress(_) => {
-5727 error!(
-5728 ?err,
-5729 ?network_path,
-5730 "Failed to open path for successful NAT traversal"
-5731 );
-5732 }
-5733 PathError::MaxPathIdReached | PathError::RemoteCidsExhausted => {
-5734 // Temporary error, put back.
-5735 self.n0_nat_traversal
-5736 .client_side_mut()
-5737 .map(|s| s.push_pending_path_open(network_path))
-5738 .ok();
-5739 debug!(
-5740 ?err,
-5741 ?network_path,
-5742 "Blocked opening NAT traversal path, enqueued"
-5743 );
-5744 return;
-5745 }
-5746 },
-5747 }
-5748 }
-5749 }
-5750
-5751 /// Migrates the 4-tuple of the path.
-5752 ///
-5753 /// This creates a new [`PathData`] for the migrated path and stores the previous
-5754 /// [`PathData`] in [`PathState::prev`].
-5755 fn migrate(
-5756 &mut self,
-5757 path_id: PathId,
-5758 now: Instant,
-5759 network_path: FourTuple,
-5760 observed_addr: Option<ObservedAddr>,
-5761 ) {
-5762 trace!(
-5763 new_4tuple = %network_path,
-5764 prev_4tuple = %self.path_data(path_id).network_path,
-5765 %path_id,
-5766 "migration initiated",
-5767 );
-5768 self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
-5769 // TODO(@divma): conditions for path migration in multipath are very specific, check them
-5770 // again to prevent path migrations that should actually create a new path
-5771
-5772 // Reset rtt/congestion state for new path unless it looks like a NAT rebinding.
-5773 // Note that the congestion window will not grow until validation terminates. Helps mitigate
-5774 // amplification attacks performed by spoofing source addresses.
-5775 let prev_pto = self.pto(SpaceKind::Data, path_id);
-5776 let path = self.paths.get_mut(&path_id).expect("known path");
-5777 let mut new_path_data = if network_path.remote.is_ipv4()
-5778 && network_path.remote.ip() == path.data.network_path.remote.ip()
-5779 {
-5780 PathData::from_previous(network_path, &path.data, self.path_generation_counter, now)
-5781 } else {
-5782 let peer_max_udp_payload_size =
-5783 u16::try_from(self.peer_params.max_udp_payload_size.into_inner())
-5784 .unwrap_or(u16::MAX);
-5785 PathData::new(
-5786 network_path,
-5787 self.allow_mtud,
-5788 Some(peer_max_udp_payload_size),
-5789 self.path_generation_counter,
-5790 now,
-5791 &self.config,
-5792 )
-5793 };
-5794 new_path_data.last_observed_addr_report = path.data.last_observed_addr_report.clone();
-5795 if let Some(report) = observed_addr
-5796 && let Some(updated) = new_path_data.update_observed_addr_report(report)
-5797 {
-5798 tracing::info!("adding observed addr event from migration");
-5799 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
-5800 id: path_id,
-5801 addr: updated,
-5802 }));
-5803 }
-5804 new_path_data.pending_challenge = true;
-5805 new_path_data.pending.observed_address = self
-5806 .config
-5807 .address_discovery_role
-5808 .should_report(&self.peer_params.address_discovery_role);
-5809
-5810 let mut prev_path_data = mem::replace(&mut path.data, new_path_data);
-5811
-5812 // Only store this as previous path if it was validated. For all we know there could
-5813 // already be a previous path stored which might have been validated in the past,
-5814 // which is more valuable than one that's not yet validated.
-5815 //
-5816 // With multipath it is possible that there are no remote CIDs for the path ID
-5817 // yet. In this case we would never have sent on this path yet and would not be able
-5818 // to send a PATH_CHALLENGE either, which is currently a fire-and-forget affair
-5819 // anyway. So don't store such a path either.
-5820 if !prev_path_data.validated
-5821 && let Some(cid) = self.remote_cids.get(&path_id).map(CidQueue::active)
-5822 {
-5823 prev_path_data.pending_challenge = true;
-5824 // We haven't updated the remote CID yet, this captures the remote CID we were using on
-5825 // the previous path.
-5826 path.prev = Some((cid, prev_path_data));
-5827 }
-5828
-5829 // We need to re-assign the correct remote to this path in qlog
-5830 self.qlog.emit_tuple_assigned(path_id, network_path, now);
-5831
-5832 self.timers.set(
-5833 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
-5834 now + 3 * cmp::max(self.pto(SpaceKind::Data, path_id), prev_pto),
-5835 self.qlog.with_time(now),
-5836 );
-5837 }
-5838
-5839 /// Handle a change in the local address, i.e. an active migration
-5840 ///
-5841 /// In the general (non-multipath) case, paths will perform a RFC9000 migration and be pinged
-5842 /// for a liveness check. This is the behaviour of a path assumed to be recoverable, even if
-5843 /// this is not the case.
-5844 ///
-5845 /// Clients in a connection in which multipath has been negotiated should migrate paths to new
-5846 /// [`PathId`]s. For paths that are known to be non-recoverable can be migrated to a new
-5847 /// [`PathId`] by closing the current path, and opening a new one to the same remote. Treating
-5848 /// paths as non recoverable when necessary accelerates connectivity re-establishment, or might
-5849 /// allow it altogether.
-5850 ///
-5851 /// The optional `hint` allows callers to indicate when paths are non-recoverable and should be
-5852 /// migrated to new a [`PathId`].
-5853 // NOTE: only clients are allowed to migrate, but generally dealing with RFC9000 migrations is
-5854 // lacking <https://github.com/n0-computer/noq/issues/364>
-5855 pub fn handle_network_change(&mut self, hint: Option<&dyn NetworkChangeHint>, now: Instant) {
-5856 debug!("network changed");
-5857 if self.state.is_drained() {
-5858 return;
-5859 }
-5860 if self.highest_space < SpaceKind::Data {
-5861 for path in self.paths.values_mut() {
-5862 // Clear the local address for it to be obtained from the socket again.
-5863 path.data.network_path.local_ip = None;
-5864 }
-5865
-5866 self.update_remote_cid(PathId::ZERO);
-5867 self.ping();
-5868
-5869 return;
-5870 }
-5871
-5872 // Paths that can't recover so a new path should be open instead. If multipath is not
-5873 // negotiated, this will be empty.
-5874 let mut non_recoverable_paths = Vec::default();
-5875 let mut recoverable_paths = Vec::default();
-5876 let mut open_paths = 0;
-5877
-5878 let is_multipath_negotiated = self.is_multipath_negotiated();
-5879 let is_client = self.side().is_client();
-5880 let immediate_ack_allowed = self.peer_supports_ack_frequency();
-5881
-5882 for (path_id, path) in self.paths.iter_mut() {
-5883 if self.abandoned_paths.contains(path_id) {
-5884 continue;
-5885 }
-5886 open_paths += 1;
-5887
-5888 // Read the network path BEFORE clearing local_ip, so the hint can
-5889 // check which interface the path was using.
-5890 let network_path = path.data.network_path;
-5891
-5892 // Clear the local address for it to be obtained from the socket again. This applies to
-5893 // all paths, regardless of being considered recoverable or not
-5894 path.data.network_path.local_ip = None;
-5895 let remote = network_path.remote;
-5896
-5897 // Without multipath, the connection tries to recover the single path, whereas with
-5898 // multipath, even in a single-path scenario, we attempt to migrate the path to a new
-5899 // PathId.
-5900 let attempt_to_recover = if is_multipath_negotiated {
-5901 // Use the hint to determine if the path can recover. When no hint is
-5902 // provided, clients default to non-recoverable (abandon and re-open)
-5903 // while servers default to recoverable (attempt in-place recovery).
-5904 hint.map(|h| h.is_path_recoverable(*path_id, network_path))
-5905 .unwrap_or(!is_client)
-5906 } else {
-5907 // In the non multipath case, we try to recover the single active path
-5908 true
-5909 };
-5910
-5911 if attempt_to_recover {
-5912 recoverable_paths.push((*path_id, remote));
-5913 } else {
-5914 non_recoverable_paths.push((*path_id, remote, path.data.local_status()))
-5915 }
-5916 }
-5917
-5918 /* NON RECOVERABLE PATHS */
-5919 // This are handled first, so that in case the treatment intended for these fails, we can
-5920 // go the recoverable route instead.
-5921
-5922 // Decide if we need to close first or open first in the multipath case.
-5923 // - Opening first has a higher risk of getting limited by the negotiated MAX_PATH_ID.
-5924 // - Closing first risks this being the only open path.
-5925 // We prefer closing paths first unless we identify this is the last open path.
-5926 let open_first = open_paths == non_recoverable_paths.len();
-5927
-5928 for (path_id, remote, status) in non_recoverable_paths.into_iter() {
-5929 let network_path = FourTuple {
-5930 remote,
-5931 local_ip: None, /* allow the local ip to be discovered */
-5932 };
-5933
-5934 if open_first && let Err(e) = self.open_path(network_path, status, now) {
-5935 if self.side().is_client() {
-5936 debug!(%e, "Failed to open new path for network change");
-5937 }
-5938 // if this fails, let the path try to recover itself
-5939 recoverable_paths.push((path_id, remote));
-5940 continue;
-5941 }
-5942
-5943 if let Err(e) =
-5944 self.close_path_inner(now, path_id, PathAbandonReason::UnusableAfterNetworkChange)
-5945 {
-5946 debug!(%e,"Failed to close unrecoverable path after network change");
-5947 recoverable_paths.push((path_id, remote));
-5948 continue;
-5949 }
-5950
-5951 if !open_first && let Err(e) = self.open_path(network_path, status, now) {
-5952 // Path has already been closed if we got here. Since the path was not recoverable,
-5953 // this might be desirable in any case, because other paths exist (!open_first) and
-5954 // this was is considered non recoverable
-5955 debug!(%e,"Failed to open new path for network change");
-5956 }
-5957 }
-5958
-5959 /* RECOVERABLE PATHS */
-5960
-5961 for (path_id, remote) in recoverable_paths.into_iter() {
-5962 // Schedule a Ping for a liveness check.
-5963 if let Some(path_space) = self.spaces[SpaceId::Data].number_spaces.get_mut(&path_id) {
-5964 path_space.pending_ping = true;
-5965
-5966 if immediate_ack_allowed {
-5967 path_space.pending_immediate_ack = true;
-5968 }
-5969 }
-5970
-5971 // Reset PTO backoff so retransmits resume promptly. Congestion controller and
-5972 // RTT are intentionally preserved for recoverable paths. We explicitly allow
-5973 // this reset also during the handshake, so do not check
-5974 // Self::peer_competed_handshake_address_validation.
-5975 if let Some(path) = self.paths.get_mut(&path_id) {
-5976 path.data.pto_count = 0;
-5977 }
-5978 self.set_loss_detection_timer(now, path_id);
-5979
-5980 let Some((reset_token, retired)) =
-5981 self.remote_cids.get_mut(&path_id).and_then(CidQueue::next)
-5982 else {
-5983 continue;
-5984 };
-5985
-5986 // Retire the current remote CID and any CIDs we had to skip.
-5987 self.spaces[SpaceId::Data]
-5988 .pending
-5989 .retire_cids
-5990 .extend(retired.map(|seq| (path_id, seq)));
-5991
-5992 debug_assert!(!self.state.is_drained()); // required for endpoint_events, checked above
-5993 self.endpoint_events
-5994 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
-5995 }
-5996 }
-5997
-5998 /// Switch to a previously unused remote connection ID, if possible
-5999 fn update_remote_cid(&mut self, path_id: PathId) {
-6000 let Some((reset_token, retired)) = self
-6001 .remote_cids
-6002 .get_mut(&path_id)
-6003 .and_then(|cids| cids.next())
-6004 else {
-6005 return;
-6006 };
-6007
-6008 // Retire the current remote CID and any CIDs we had to skip.
-6009 self.spaces[SpaceId::Data]
-6010 .pending
-6011 .retire_cids
-6012 .extend(retired.map(|seq| (path_id, seq)));
-6013 let remote = self.path_data(path_id).network_path.remote;
-6014 self.set_reset_token(path_id, remote, reset_token);
-6015 }
-6016
-6017 /// Sends this reset token to the endpoint
-6018 ///
-6019 /// The endpoint needs to know the reset tokens issued by the peer, so that if the peer
-6020 /// sends a reset token it knows to route it to this connection. See RFC 9000 section
-6021 /// 10.3. Stateless Reset.
-6022 ///
-6023 /// Reset tokens are different for each path, the endpoint identifies paths by peer
-6024 /// socket address however, not by path ID.
-6025 fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) {
-6026 debug_assert!(!self.state.is_drained()); // required for endpoint events, set_reset_token is never called for drained connections
-6027 self.endpoint_events
-6028 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
-6029
-6030 // During the handshake the server sends a reset token in the transport
-6031 // parameters. When we are the client and we receive the reset token during the
-6032 // handshake we want this to affect our peer transport parameters.
-6033 // TODO(flub): Pretty sure this is pointless, the entire params is overwritten
-6034 // shortly after this was called. And then the params don't have this anymore.
-6035 if path_id == PathId::ZERO {
-6036 self.peer_params.stateless_reset_token = Some(reset_token);
-6037 }
-6038 }
-6039
-6040 /// Issue an initial set of connection IDs to the peer upon connection
-6041 fn issue_first_cids(&mut self, now: Instant) {
-6042 if self
-6043 .local_cid_state
-6044 .get(&PathId::ZERO)
-6045 .expect("PathId::ZERO exists when the connection is created")
-6046 .cid_len()
-6047 == 0
-6048 {
-6049 return;
-6050 }
-6051
-6052 // Subtract 1 to account for the CID we supplied while handshaking
-6053 let mut n = self.peer_params.issue_cids_limit() - 1;
-6054 if let ConnectionSide::Server { server_config } = &self.side
-6055 && server_config.has_preferred_address()
-6056 {
-6057 // We also sent a CID in the transport parameters
-6058 n -= 1;
-6059 }
-6060 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events
-6061 self.endpoint_events
-6062 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
-6063 }
-6064
-6065 /// Issues an initial set of CIDs for paths that have not yet had any CIDs issued
-6066 ///
-6067 /// Later CIDs are issued when CIDs expire or are retired by the peer.
-6068 fn issue_first_path_cids(&mut self, now: Instant) {
-6069 if let Some(max_path_id) = self.max_path_id() {
-6070 let mut path_id = self.max_path_id_with_cids.next();
-6071 while path_id <= max_path_id {
-6072 self.endpoint_events
-6073 .push_back(EndpointEventInner::NeedIdentifiers(
-6074 path_id,
-6075 now,
-6076 self.peer_params.issue_cids_limit(),
-6077 ));
-6078 path_id = path_id.next();
-6079 }
-6080 self.max_path_id_with_cids = max_path_id;
-6081 }
-6082 }
-6083
-6084 /// Populates a packet with frames
-6085 ///
-6086 /// This tries to fit as many frames as possible into the packet.
-6087 ///
-6088 /// *path_exclusive_only* means to only build frames which can only be sent on this
-6089 /// *path. This is used in multipath for backup paths while there is still an active
-6090 /// *path.
-6091 fn populate_packet<'a, 'b>(
-6092 &mut self,
-6093 now: Instant,
-6094 space_id: SpaceId,
-6095 path_id: PathId,
-6096 scheduling_info: &PathSchedulingInfo,
-6097 builder: &mut PacketBuilder<'a, 'b>,
-6098 ) {
-6099 let is_multipath_negotiated = self.is_multipath_negotiated();
-6100 let space_has_keys = self.crypto_state.has_keys(space_id.encryption_level());
-6101 let is_0rtt = space_id == SpaceId::Data && !space_has_keys;
-6102 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
-6103 let space = &mut self.spaces[space_id];
-6104 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
-6105 space
-6106 .for_path(path_id)
-6107 .pending_acks
-6108 .maybe_ack_non_eliciting();
-6109
-6110 // HANDSHAKE_DONE
-6111 if !is_0rtt
-6112 && !scheduling_info.is_abandoned
-6113 && scheduling_info.may_send_data
-6114 && mem::replace(&mut space.pending.handshake_done, false)
-6115 {
-6116 builder.write_frame(frame::HandshakeDone, stats);
-6117 }
-6118
-6119 // PING
-6120 if !scheduling_info.is_abandoned
-6121 && mem::replace(&mut space.for_path(path_id).pending_ping, false)
-6122 {
-6123 builder.write_frame(frame::Ping, stats);
-6124 }
-6125
-6126 // IMMEDIATE_ACK
-6127 if !scheduling_info.is_abandoned
-6128 && mem::replace(&mut space.for_path(path_id).pending_immediate_ack, false)
-6129 {
-6130 debug_assert_eq!(
-6131 space_id,
-6132 SpaceId::Data,
-6133 "immediate acks must be sent in the data space"
-6134 );
-6135 builder.write_frame(frame::ImmediateAck, stats);
-6136 }
-6137
-6138 // ACK
-6139 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
-6140 for path_id in space
-6141 .number_spaces
-6142 .iter_mut()
-6143 .filter(|(_, pns)| pns.pending_acks.can_send())
-6144 .map(|(&path_id, _)| path_id)
-6145 .collect::<Vec<_>>()
-6146 {
-6147 Self::populate_acks(
-6148 now,
-6149 self.receiving_ecn,
-6150 path_id,
-6151 space_id,
-6152 space,
-6153 is_multipath_negotiated,
-6154 builder,
-6155 stats,
-6156 space_has_keys,
-6157 );
-6158 }
-6159 }
-6160
-6161 // ACK_FREQUENCY
-6162 if !scheduling_info.is_abandoned
-6163 && scheduling_info.may_send_data
-6164 && mem::replace(&mut space.pending.ack_frequency, false)
-6165 {
-6166 let sequence_number = self.ack_frequency.next_sequence_number();
-6167
-6168 // Safe to unwrap because this is always provided when ACK frequency is enabled
-6169 let config = self.config.ack_frequency_config.as_ref().unwrap();
-6170
-6171 // Ensure the delay is within bounds to avoid a PROTOCOL_VIOLATION error
-6172 let max_ack_delay = self.ack_frequency.candidate_max_ack_delay(
-6173 path.rtt.get(),
-6174 config,
-6175 &self.peer_params,
-6176 );
-6177
-6178 let frame = frame::AckFrequency {
-6179 sequence: sequence_number,
-6180 ack_eliciting_threshold: config.ack_eliciting_threshold,
-6181 request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX),
-6182 reordering_threshold: config.reordering_threshold,
-6183 };
-6184 builder.write_frame(frame, stats);
-6185
-6186 self.ack_frequency
-6187 .ack_frequency_sent(path_id, builder.packet_number, max_ack_delay);
-6188 }
-6189
-6190 // PATH_CHALLENGE (on-path)
-6191 if !scheduling_info.is_abandoned
-6192 && space_id == SpaceId::Data
-6193 && path.pending_challenge
-6194 // we don't want to send new challenges if we are already closing
-6195 && !self.state.is_closed()
-6196 && builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND
-6197 // An on-path PATH_CHALLENGE must be part of datagrams expanded to the
-6198 // MIN_INITIAL_SIZE (1200 bytes).
-6199 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
-6200 {
-6201 path.pending_challenge = false;
-6202
-6203 let token = self.rng.random();
-6204 path.record_path_challenge_sent(now, token, path.network_path);
-6205 // Generate a new challenge every time we send a new PATH_CHALLENGE
-6206 let challenge = frame::PathChallenge(token);
-6207 builder.write_frame(challenge, stats);
-6208 builder.require_padding();
-6209
-6210 if is_multipath_negotiated && !path.validated && path.pending_challenge {
-6211 // queue informing the path status along with the challenge
-6212 space.pending.path_status.insert(path_id);
-6213 }
-6214
-6215 // Always include an OBSERVED_ADDR frame with a PATH_CHALLENGE, regardless
-6216 // of whether one has already been sent on this path.
-6217 if space_id == SpaceId::Data
-6218 && self
-6219 .config
-6220 .address_discovery_role
-6221 .should_report(&self.peer_params.address_discovery_role)
-6222 {
-6223 let frame = frame::ObservedAddr::new(
-6224 path.network_path.remote,
-6225 self.next_observed_addr_seq_no,
-6226 );
-6227 if builder.frame_space_remaining() > frame.size() {
-6228 builder.write_frame(frame, stats);
-6229
-6230 self.next_observed_addr_seq_no =
-6231 self.next_observed_addr_seq_no.saturating_add(1u8);
-6232 path.pending.observed_address = false;
-6233 }
-6234 }
-6235 }
-6236
-6237 // PATH_RESPONSE (on-path)
-6238 if !scheduling_info.is_abandoned
-6239 && space_id == SpaceId::Data
-6240 && builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND
-6241 // An on-path PATH_RESPONSE must be part of datagrams expanded to the
-6242 // MIN_INITIAL_SIZE (1200 bytes).
-6243 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
-6244 && let Some(token) = space.for_path(path_id).pending_path_responses.pop_on_path(path.network_path)
-6245 {
-6246 let response = frame::PathResponse(token);
-6247 builder.write_frame(response, stats);
-6248 builder.require_padding();
-6249
-6250 // NOTE: this is technically not required but might be useful to ride the
-6251 // request/response nature of path challenges to refresh an observation
-6252 // Since PATH_RESPONSE is a probing frame, this is allowed by the spec.
-6253 if space_id == SpaceId::Data
-6254 && self
-6255 .config
-6256 .address_discovery_role
-6257 .should_report(&self.peer_params.address_discovery_role)
-6258 {
-6259 let frame = frame::ObservedAddr::new(
-6260 path.network_path.remote,
-6261 self.next_observed_addr_seq_no,
-6262 );
-6263 if builder.frame_space_remaining() > frame.size() {
-6264 builder.write_frame(frame, stats);
-6265
-6266 self.next_observed_addr_seq_no =
-6267 self.next_observed_addr_seq_no.saturating_add(1u8);
-6268 path.pending.observed_address = false;
-6269 }
-6270 }
-6271 }
-6272
-6273 // ADD_ADDRESS
-6274 while space_id == SpaceId::Data
-6275 && !scheduling_info.is_abandoned
-6276 && scheduling_info.may_send_data
-6277 && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining()
-6278 {
-6279 if let Some(added_address) = space.pending.add_address.pop_last() {
-6280 builder.write_frame(added_address, stats);
-6281 } else {
-6282 break;
-6283 }
-6284 }
-6285
-6286 // REMOVE_ADDRESS
-6287 while space_id == SpaceId::Data
-6288 && !scheduling_info.is_abandoned
-6289 && scheduling_info.may_send_data
-6290 && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining()
-6291 {
-6292 if let Some(removed_address) = space.pending.remove_address.pop_last() {
-6293 builder.write_frame(removed_address, stats);
-6294 } else {
-6295 break;
-6296 }
-6297 }
-6298
-6299 // REACH_OUT
-6300 while !scheduling_info.is_abandoned
-6301 && scheduling_info.may_send_data
-6302 && let Some(reach_out) = space
-6303 .pending
-6304 .reach_out
-6305 .pop_if(|frame| builder.frame_space_remaining() >= frame.size())
-6306 {
-6307 builder.write_frame(reach_out, stats);
-6308 }
-6309
-6310 // PATH_ABANDON
-6311 if space_id == SpaceId::Data
-6312 && scheduling_info.is_abandoned
-6313 && scheduling_info.may_self_abandon
-6314 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
-6315 && let Some(error_code) = space.pending.path_abandon.remove(&path_id)
-6316 {
-6317 let frame = frame::PathAbandon {
-6318 path_id,
-6319 error_code,
-6320 };
-6321 builder.write_frame(frame, stats);
-6322
-6323 // Consider remotely issued CIDs as retired now that we have sent this frame at
-6324 // least once.
-6325 self.remote_cids.remove(&path_id);
-6326 }
-6327 while space_id == SpaceId::Data
-6328 && scheduling_info.may_send_data
-6329 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
-6330 && let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first()
-6331 {
-6332 let frame = frame::PathAbandon {
-6333 path_id: abandoned_path_id,
-6334 error_code,
-6335 };
-6336 builder.write_frame(frame, stats);
-6337
-6338 // Consider remotely issued CIDs as retired now that we have sent this frame at
-6339 // least once.
-6340 self.remote_cids.remove(&abandoned_path_id);
-6341 }
-6342
-6343 // OBSERVED_ADDR
-6344 if !scheduling_info.is_abandoned
-6345 && scheduling_info.may_send_data
-6346 && space_id == SpaceId::Data
-6347 && path.pending.observed_address
-6348 {
-6349 let frame =
-6350 frame::ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no);
-6351 if builder.frame_space_remaining() > frame.size() {
-6352 builder.write_frame(frame, stats);
-6353
-6354 self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8);
-6355 path.pending.observed_address = false;
-6356 }
-6357 }
-6358
-6359 // CRYPTO
-6360 while !is_0rtt
-6361 && !scheduling_info.is_abandoned
-6362 && scheduling_info.may_send_data
-6363 && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND
-6364 {
-6365 let Some(mut frame) = space.pending.crypto.pop_front() else {
-6366 break;
-6367 };
-6368
-6369 // Calculate the maximum amount of crypto data we can store in the buffer.
-6370 // Since the offset is known, we can reserve the exact size required to encode it.
-6371 // For length we reserve 2bytes which allows to encode up to 2^14,
-6372 // which is more than what fits into normally sized QUIC frames.
-6373 let max_crypto_data_size = builder.frame_space_remaining()
-6374 - 1 // Frame Type
-6375 - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) })
-6376 - 2; // Maximum encoded length for frame size, given we send less than 2^14 bytes
-6377
-6378 let len = frame
-6379 .data
-6380 .len()
-6381 .min(2usize.pow(14) - 1)
-6382 .min(max_crypto_data_size);
-6383
-6384 let data = frame.data.split_to(len);
-6385 let offset = frame.offset;
-6386 let truncated = frame::Crypto { offset, data };
-6387 builder.write_frame(truncated, stats);
-6388
-6389 if !frame.data.is_empty() {
-6390 frame.offset += len as u64;
-6391 space.pending.crypto.push_front(frame);
-6392 }
-6393 }
-6394
-6395 // PATH_STATUS_AVAILABLE & PATH_STATUS_BACKUP
-6396 while space_id == SpaceId::Data
-6397 && !scheduling_info.is_abandoned
-6398 && scheduling_info.may_send_data
-6399 && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining()
-6400 {
-6401 let Some(path_id) = space.pending.path_status.pop_first() else {
-6402 break;
-6403 };
-6404 let Some(path) = self.paths.get(&path_id).map(|path_state| &path_state.data) else {
-6405 trace!(%path_id, "discarding queued path status for unknown path");
-6406 continue;
-6407 };
-6408
-6409 let seq = path.status.seq();
-6410 match path.local_status() {
-6411 PathStatus::Available => {
-6412 let frame = frame::PathStatusAvailable {
-6413 path_id,
-6414 status_seq_no: seq,
-6415 };
-6416 builder.write_frame(frame, stats);
-6417 }
-6418 PathStatus::Backup => {
-6419 let frame = frame::PathStatusBackup {
-6420 path_id,
-6421 status_seq_no: seq,
-6422 };
-6423 builder.write_frame(frame, stats);
-6424 }
-6425 }
-6426 }
-6427
-6428 // MAX_PATH_ID
-6429 if space_id == SpaceId::Data
-6430 && !scheduling_info.is_abandoned
-6431 && scheduling_info.may_send_data
-6432 && space.pending.max_path_id
-6433 && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining()
-6434 {
-6435 let frame = frame::MaxPathId(self.local_max_path_id);
-6436 builder.write_frame(frame, stats);
-6437 space.pending.max_path_id = false;
-6438 }
-6439
-6440 // PATHS_BLOCKED
-6441 if space_id == SpaceId::Data
-6442 && !scheduling_info.is_abandoned
-6443 && scheduling_info.may_send_data
-6444 && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
-6445 && let Some(remote_max_path_id) = space.pending.paths_blocked.take()
-6446 {
-6447 let frame = frame::PathsBlocked(remote_max_path_id);
-6448 builder.write_frame(frame, stats);
-6449 }
-6450
-6451 // PATH_CIDS_BLOCKED
-6452 while space_id == SpaceId::Data
-6453 && !scheduling_info.is_abandoned
-6454 && scheduling_info.may_send_data
-6455 && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
-6456 {
-6457 let Some((path_id, next_seq)) = space.pending.path_cids_blocked.pop_first() else {
-6458 break;
-6459 };
-6460 let frame = frame::PathCidsBlocked { path_id, next_seq };
-6461 builder.write_frame(frame, stats);
-6462 }
-6463
-6464 // RESET_STREAM, STOP_SENDING, MAX_DATA, MAX_STREAM_DATA, MAX_STREAMS
-6465 if space_id == SpaceId::Data
-6466 && !scheduling_info.is_abandoned
-6467 && scheduling_info.may_send_data
-6468 {
-6469 self.streams
-6470 .write_control_frames(builder, &mut space.pending, stats);
-6471 }
-6472
-6473 // NEW_CONNECTION_ID
-6474 let cid_len = self
-6475 .local_cid_state
-6476 .values()
-6477 .map(|cid_state| cid_state.cid_len())
-6478 .max()
-6479 .expect("some local CID state must exist");
-6480 let new_cid_size_bound =
-6481 frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len);
-6482 while !scheduling_info.is_abandoned
-6483 && scheduling_info.may_send_data
-6484 && builder.frame_space_remaining() > new_cid_size_bound
-6485 {
-6486 let Some(issued) = space.pending.new_cids.pop() else {
-6487 break;
-6488 };
-6489 // Path was discarded after this CID was queued, drop.
-6490 let Some(cid_state) = self.local_cid_state.get(&issued.path_id) else {
-6491 debug!(
-6492 path = %issued.path_id, seq = issued.sequence,
-6493 "dropping queued NEW_CONNECTION_ID for discarded path",
-6494 );
-6495 continue;
-6496 };
-6497 let retire_prior_to = cid_state.retire_prior_to();
-6498
-6499 let cid_path_id = match is_multipath_negotiated {
-6500 true => Some(issued.path_id),
-6501 false => {
-6502 debug_assert_eq!(issued.path_id, PathId::ZERO);
-6503 None
-6504 }
-6505 };
-6506 let frame = frame::NewConnectionId {
-6507 path_id: cid_path_id,
-6508 sequence: issued.sequence,
-6509 retire_prior_to,
-6510 id: issued.id,
-6511 reset_token: issued.reset_token,
-6512 };
-6513 builder.write_frame(frame, stats);
-6514 }
-6515
-6516 // RETIRE_CONNECTION_ID
-6517 let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated);
-6518 while !scheduling_info.is_abandoned
-6519 && scheduling_info.may_send_data
-6520 && builder.frame_space_remaining() > retire_cid_bound
-6521 {
-6522 let (path_id, sequence) = match space.pending.retire_cids.pop() {
-6523 Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq),
-6524 Some((path_id, seq)) => (Some(path_id), seq),
-6525 None => break,
-6526 };
-6527 let frame = frame::RetireConnectionId { path_id, sequence };
-6528 builder.write_frame(frame, stats);
-6529 }
-6530
-6531 // DATAGRAM
-6532 let mut sent_datagrams = false;
-6533 while !scheduling_info.is_abandoned
-6534 && scheduling_info.may_send_data
-6535 && builder.frame_space_remaining() > Datagram::SIZE_BOUND
-6536 && space_id == SpaceId::Data
-6537 {
-6538 match self.datagrams.write(builder, stats) {
-6539 true => {
-6540 sent_datagrams = true;
-6541 }
-6542 false => break,
-6543 }
-6544 }
-6545 if self.datagrams.send_blocked && sent_datagrams {
-6546 self.events.push_back(Event::DatagramsUnblocked);
-6547 self.datagrams.send_blocked = false;
-6548 }
-6549
-6550 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
-6551
-6552 // NEW_TOKEN
-6553 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
-6554 while let Some(network_path) = space.pending.new_tokens.pop() {
-6555 debug_assert_eq!(space_id, SpaceId::Data);
-6556 let ConnectionSide::Server { server_config } = &self.side else {
-6557 panic!("NEW_TOKEN frames should not be enqueued by clients");
-6558 };
-6559
-6560 if !network_path.is_probably_same_path(&path.network_path) {
-6561 // NEW_TOKEN frames contain tokens bound to a client's IP address, and are only
-6562 // useful if used from the same IP address. Thus, we abandon enqueued NEW_TOKEN
-6563 // frames upon an path change. Instead, when the new path becomes validated,
-6564 // NEW_TOKEN frames may be enqueued for the new path instead.
-6565 continue;
-6566 }
-6567
-6568 let token = Token::new(
-6569 TokenPayload::Validation {
-6570 ip: network_path.remote.ip(),
-6571 issued: server_config.time_source.now(),
-6572 },
-6573 &mut self.rng,
-6574 );
-6575 let new_token = NewToken {
-6576 token: token.encode(&*server_config.token_key).into(),
-6577 };
-6578
-6579 if builder.frame_space_remaining() < new_token.size() {
-6580 space.pending.new_tokens.push(network_path);
-6581 break;
-6582 }
-6583
-6584 builder.write_frame(new_token, stats);
-6585 builder.retransmits_mut().new_tokens.push(network_path);
-6586 }
-6587 }
-6588
-6589 // STREAM
-6590 if !scheduling_info.is_abandoned
-6591 && scheduling_info.may_send_data
-6592 && space_id == SpaceId::Data
-6593 {
-6594 self.streams
-6595 .write_stream_frames(builder, self.config.send_fairness, stats);
-6596 }
-6597 }
-6598
-6599 /// Write pending ACKs into a buffer
-6600 fn populate_acks<'a, 'b>(
-6601 now: Instant,
-6602 receiving_ecn: bool,
-6603 path_id: PathId,
-6604 space_id: SpaceId,
-6605 space: &mut PacketSpace,
-6606 is_multipath_negotiated: bool,
-6607 builder: &mut PacketBuilder<'a, 'b>,
-6608 stats: &mut FrameStats,
-6609 space_has_keys: bool,
-6610 ) {
-6611 // 0-RTT packets must never carry acks (which would have to be of handshake packets)
-6612 debug_assert!(space_has_keys, "tried to send ACK in 0-RTT");
-6613
-6614 debug_assert!(
-6615 is_multipath_negotiated || path_id == PathId::ZERO,
-6616 "Only PathId::ZERO allowed without multipath (have {path_id:?})"
-6617 );
-6618 if is_multipath_negotiated {
-6619 debug_assert!(
-6620 space_id == SpaceId::Data || path_id == PathId::ZERO,
-6621 "path acks must be sent in 1RTT space (have {space_id:?})"
-6622 );
-6623 }
-6624
-6625 let pns = space.for_path(path_id);
-6626 let ranges = pns.pending_acks.ranges();
-6627 debug_assert!(!ranges.is_empty(), "can not send empty ACK range");
-6628 let ecn = if receiving_ecn {
-6629 Some(&pns.ecn_counters)
-6630 } else {
-6631 None
-6632 };
-6633
-6634 let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64;
-6635 // TODO: This should come from `TransportConfig` if that gets configurable.
-6636 let ack_delay_exp = TransportParameters::default().ack_delay_exponent;
-6637 let delay = delay_micros >> ack_delay_exp.into_inner();
-6638
-6639 if is_multipath_negotiated && space_id == SpaceId::Data {
-6640 if !ranges.is_empty() {
-6641 let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn);
-6642 builder.write_frame(frame, stats);
-6643 }
-6644 } else {
-6645 builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats);
-6646 }
-6647 }
-6648
-6649 fn close_common(&mut self) {
-6650 trace!("connection closed");
-6651 self.timers.reset();
-6652 }
-6653
-6654 fn set_close_timer(&mut self, now: Instant) {
-6655 // QUIC-MULTIPATH § 2.6 Connection Closure: draining for 3*PTO using the max PTO of
-6656 // all paths.
-6657 let pto_max = self.max_pto_for_space(self.highest_space);
-6658 self.timers.set(
-6659 Timer::Conn(ConnTimer::Close),
-6660 now + 3 * pto_max,
-6661 self.qlog.with_time(now),
-6662 );
-6663 }
-6664
-6665 /// Handle transport parameters received from the peer
-6666 ///
-6667 /// *remote_cid* and *local_cid* are the source and destination CIDs respectively of the
-6668 /// *packet into which the transport parameters arrived.
-6669 fn handle_peer_params(
-6670 &mut self,
-6671 params: TransportParameters,
-6672 local_cid: ConnectionId,
-6673 remote_cid: ConnectionId,
-6674 now: Instant,
-6675 ) -> Result<(), TransportError> {
-6676 if Some(self.original_remote_cid) != params.initial_src_cid
-6677 || (self.side.is_client()
-6678 && (Some(self.initial_dst_cid) != params.original_dst_cid
-6679 || self.retry_src_cid != params.retry_src_cid))
-6680 {
-6681 return Err(TransportError::TRANSPORT_PARAMETER_ERROR(
-6682 "CID authentication failure",
-6683 ));
-6684 }
-6685 if params.initial_max_path_id.is_some() && (local_cid.is_empty() || remote_cid.is_empty()) {
-6686 return Err(TransportError::PROTOCOL_VIOLATION(
-6687 "multipath must not use zero-length CIDs",
-6688 ));
-6689 }
-6690
-6691 self.set_peer_params(params);
-6692 self.qlog.emit_peer_transport_params_received(self, now);
-6693
-6694 Ok(())
-6695 }
-6696
-6697 fn set_peer_params(&mut self, params: TransportParameters) {
-6698 self.streams.set_params(¶ms);
-6699 self.idle_timeout =
-6700 negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout));
-6701 trace!("negotiated max idle timeout {:?}", self.idle_timeout);
-6702
-6703 if let Some(ref info) = params.preferred_address {
-6704 // During the handshake PathId::ZERO exists.
-6705 self.remote_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId {
-6706 path_id: None,
-6707 sequence: 1,
-6708 id: info.connection_id,
-6709 reset_token: info.stateless_reset_token,
-6710 retire_prior_to: 0,
-6711 })
-6712 .expect(
-6713 "preferred address CID is the first received, and hence is guaranteed to be legal",
-6714 );
-6715 let remote = self.path_data(PathId::ZERO).network_path.remote;
-6716 self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token);
-6717 }
-6718 self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(¶ms);
-6719
-6720 let mut multipath_enabled = false;
-6721 if let (Some(local_max_path_id), Some(remote_max_path_id)) = (
-6722 self.config.get_initial_max_path_id(),
-6723 params.initial_max_path_id,
-6724 ) {
-6725 // multipath is enabled, register the local and remote maximums
-6726 self.local_max_path_id = local_max_path_id;
-6727 self.remote_max_path_id = remote_max_path_id;
-6728 let initial_max_path_id = local_max_path_id.min(remote_max_path_id);
-6729 debug!(%initial_max_path_id, "multipath negotiated");
-6730 multipath_enabled = true;
-6731 }
-6732
-6733 if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) =
-6734 self.config
-6735 .max_remote_nat_traversal_addresses
-6736 .zip(params.max_remote_nat_traversal_addresses)
-6737 {
-6738 if multipath_enabled {
-6739 let max_local_addresses = max_remotely_allowed_remote_addresses.get();
-6740 let max_remote_addresses = max_locally_allowed_remote_addresses.get();
-6741 self.n0_nat_traversal = n0_nat_traversal::State::new(
-6742 max_remote_addresses,
-6743 max_local_addresses,
-6744 self.side(),
-6745 );
-6746 debug!(
-6747 %max_remote_addresses, %max_local_addresses,
-6748 "n0's nat traversal negotiated"
-6749 );
-6750 } else {
-6751 debug!("n0 nat traversal enabled for both endpoints, but multipath is missing")
-6752 }
-6753 }
-6754
-6755 self.peer_params = params;
-6756 let peer_max_udp_payload_size =
-6757 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
-6758 let address_discovery_negotiated = self
-6759 .config
-6760 .address_discovery_role
-6761 .should_report(&self.peer_params.address_discovery_role);
-6762
-6763 let path = self.path_data_mut(PathId::ZERO);
-6764 path.pending.observed_address = address_discovery_negotiated;
-6765 path.mtud
-6766 .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size);
-6767 }
-6768
-6769 /// Decrypts a packet, returning the packet number on success
-6770 fn decrypt_packet(
-6771 &mut self,
-6772 now: Instant,
-6773 path_id: PathId,
-6774 packet: &mut Packet,
-6775 ) -> Result<Option<u64>, Option<TransportError>> {
-6776 let result = self
-6777 .crypto_state
-6778 .decrypt_packet_body(packet, path_id, &self.spaces)?;
-6779
-6780 let Some(result) = result else {
-6781 return Ok(None);
-6782 };
-6783
-6784 if result.outgoing_key_update_acked
-6785 && let Some(prev) = self.crypto_state.prev_crypto.as_mut()
-6786 {
-6787 prev.end_packet = Some((result.packet_number, now));
-6788 self.set_key_discard_timer(now, packet.header.space());
-6789 }
-6790
-6791 if result.incoming_key_update {
-6792 trace!("key update authenticated");
-6793 self.crypto_state
-6794 .update_keys(Some((result.packet_number, now)), true);
-6795 self.set_key_discard_timer(now, packet.header.space());
-6796 }
-6797
-6798 Ok(Some(result.packet_number))
-6799 }
-6800
-6801 fn peer_supports_ack_frequency(&self) -> bool {
-6802 self.peer_params.min_ack_delay.is_some()
-6803 }
-6804
-6805 /// Send an IMMEDIATE_ACK frame to the remote endpoint
-6806 ///
-6807 /// According to the spec, this will result in an error if the remote endpoint does not support
-6808 /// the Acknowledgement Frequency extension
-6809 pub(crate) fn immediate_ack(&mut self, path_id: PathId) {
-6810 debug_assert_eq!(
-6811 self.highest_space,
-6812 SpaceKind::Data,
-6813 "immediate ack must be written in the data space"
-6814 );
-6815 self.spaces[SpaceId::Data]
-6816 .for_path(path_id)
-6817 .pending_immediate_ack = true;
-6818 }
-6819
-6820 /// Decodes a packet, returning its decrypted payload, so it can be inspected in tests
-6821 #[cfg(test)]
-6822 pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> {
-6823 let ConnectionEventInner::Datagram(DatagramConnectionEvent {
-6824 path_id,
-6825 first_decode,
-6826 remaining,
-6827 ..
-6828 }) = &event.0
-6829 else {
-6830 return None;
-6831 };
-6832
-6833 if remaining.is_some() {
-6834 panic!("Packets should never be coalesced in tests");
-6835 }
-6836
-6837 let decrypted_header = self
-6838 .crypto_state
-6839 .unprotect_header(first_decode.clone(), self.peer_params.stateless_reset_token)?;
-6840
-6841 let mut packet = decrypted_header.packet?;
-6842 self.crypto_state
-6843 .decrypt_packet_body(&mut packet, *path_id, &self.spaces)
-6844 .ok()?;
-6845
-6846 Some(packet.payload.to_vec())
-6847 }
-6848
-6849 /// The number of bytes of packets containing retransmittable frames that have not been
-6850 /// acknowledged or declared lost.
-6851 #[cfg(test)]
-6852 pub(crate) fn bytes_in_flight(&self) -> u64 {
-6853 // TODO(@divma): consider including for multipath?
-6854 self.path_data(PathId::ZERO).in_flight.bytes
-6855 }
-6856
-6857 /// Number of bytes worth of non-ack-only packets that may be sent
-6858 #[cfg(test)]
-6859 pub(crate) fn congestion_window(&self) -> u64 {
-6860 let path = self.path_data(PathId::ZERO);
-6861 path.congestion
-6862 .window()
-6863 .saturating_sub(path.in_flight.bytes)
-6864 }
-6865
-6866 /// Whether no timers but keepalive, idle, rtt, pushnewcid, and key discard are running
-6867 #[cfg(test)]
-6868 pub(crate) fn is_idle(&self) -> bool {
-6869 let current_timers = self.timers.values();
-6870 current_timers
-6871 .into_iter()
-6872 .filter(|(timer, _)| {
-6873 !matches!(
-6874 timer,
-6875 Timer::Conn(ConnTimer::KeepAlive)
-6876 | Timer::PerPath(_, PathTimer::PathKeepAlive)
-6877 | Timer::Conn(ConnTimer::PushNewCid)
-6878 | Timer::Conn(ConnTimer::KeyDiscard)
-6879 )
-6880 })
-6881 .min_by_key(|(_, time)| *time)
-6882 .is_none_or(|(timer, _)| {
-6883 matches!(
-6884 timer,
-6885 Timer::Conn(ConnTimer::Idle) | Timer::PerPath(_, PathTimer::PathIdle)
-6886 )
-6887 })
-6888 }
-6889
-6890 /// Whether explicit congestion notification is in use on outgoing packets.
-6891 #[cfg(test)]
-6892 pub(crate) fn using_ecn(&self) -> bool {
-6893 self.path_data(PathId::ZERO).sending_ecn
-6894 }
-6895
-6896 /// The number of received bytes in the current path
-6897 #[cfg(test)]
-6898 pub(crate) fn total_recvd(&self) -> u64 {
-6899 self.path_data(PathId::ZERO).total_recvd
-6900 }
-6901
-6902 #[cfg(test)]
-6903 pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) {
-6904 self.local_cid_state
-6905 .get(&PathId::ZERO)
-6906 .unwrap()
-6907 .active_seq()
-6908 }
-6909
-6910 #[cfg(test)]
-6911 #[track_caller]
-6912 pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) {
-6913 self.local_cid_state
-6914 .get(&PathId(path_id))
-6915 .unwrap()
-6916 .active_seq()
-6917 }
-6918
-6919 /// Instruct the peer to replace previously issued CIDs by sending a NEW_CONNECTION_ID frame
-6920 /// with updated `retire_prior_to` field set to `v`
-6921 #[cfg(test)]
-6922 pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) {
-6923 let n = self
-6924 .local_cid_state
-6925 .get_mut(&PathId::ZERO)
-6926 .unwrap()
-6927 .assign_retire_seq(v);
-6928 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events
-6929 self.endpoint_events
-6930 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
-6931 }
-6932
-6933 /// Check the current active remote CID sequence for `PathId::ZERO`
-6934 #[cfg(test)]
-6935 pub(crate) fn active_remote_cid_seq(&self) -> u64 {
-6936 self.remote_cids.get(&PathId::ZERO).unwrap().active_seq()
-6937 }
-6938
-6939 /// Returns the detected maximum udp payload size for the current path
-6940 #[cfg(test)]
-6941 pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 {
-6942 self.path_data(path_id).current_mtu()
-6943 }
-6944
-6945 /// Triggers path validation on all paths
-6946 #[cfg(test)]
-6947 pub(crate) fn trigger_path_validation(&mut self) {
-6948 for path in self.paths.values_mut() {
-6949 path.data.pending_challenge = true;
-6950 }
-6951 }
-6952
-6953 /// Simulates a protocol violation error for test purposes.
-6954 #[cfg(test)]
-6955 pub fn simulate_protocol_violation(&mut self, now: Instant) {
-6956 if !self.state.is_closed() {
-6957 self.state
-6958 .move_to_closed(TransportError::PROTOCOL_VIOLATION("simulated violation"));
-6959 self.close_common();
-6960 if !self.state.is_drained() {
-6961 self.set_close_timer(now);
-6962 }
-6963 self.connection_close_pending = true;
-6964 }
-6965 }
-6966
-6967 /// Whether we have **on-path** 1-RTT data to send.
-6968 ///
-6969 /// This checks for frames that can only be sent in the data space (1-RTT):
-6970 /// - Pending PATH_CHALLENGE frames on the active and previous path if just migrated.
-6971 /// - Pending PATH_RESPONSE frames.
-6972 /// - Pending data to send in STREAM frames.
-6973 /// - Pending DATAGRAM frames to send.
-6974 ///
-6975 /// See also [`PacketSpace::can_send`] which keeps track of all other frame types that
-6976 /// may need to be sent.
-6977 fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames {
-6978 let network_path = self.path_data(path_id).network_path;
-6979 let space_specific = self
-6980 .paths
-6981 .get(&path_id)
-6982 .is_some_and(|path| path.data.pending_challenge || !path.data.pending.is_empty())
-6983 || self.spaces[SpaceKind::Data]
-6984 .number_spaces
-6985 .get(&path_id)
-6986 .is_some_and(|pns| pns.pending_path_responses.has_pending_on_path(network_path));
-6987
-6988 // Stream control frames are checked in PacketSpace::can_send, only check data here.
-6989 let other = self.streams.can_send_stream_data()
-6990 || self
-6991 .datagrams
-6992 .outgoing
-6993 .front()
-6994 .is_some_and(|x| x.size(true) <= max_size);
-6995
-6996 // All `false` fields are set in PacketSpace::can_send.
-6997 SendableFrames {
-6998 acks: false,
-6999 close: false,
-7000 space_specific,
-7001 other,
-7002 }
-7003 }
-7004
-7005 /// Terminate the connection instantly, without sending a close packet
-7006 fn kill(&mut self, reason: ConnectionError) {
-7007 self.close_common();
-7008 let was_draining = self.state.move_to_drained(Some(reason));
-7009 if !was_draining {
-7010 self.endpoint_events.push_back(EndpointEventInner::Draining);
-7011 }
-7012 // move_to_drained checks that we were never in drained before, so we
-7013 // never sent a `Drained` event before (it's illegal to send more events after drained).
-7014 self.endpoint_events.push_back(EndpointEventInner::Drained);
-7015 }
-7016
-7017 /// Storage size required for the largest packet that can be transmitted on all currently
-7018 /// available paths
-7019 ///
-7020 /// Buffers passed to [`Connection::poll_transmit`] should be at least this large.
-7021 ///
-7022 /// When multipath is enabled, this value is the minimum MTU across all available paths.
-7023 pub fn current_mtu(&self) -> u16 {
-7024 self.paths
-7025 .iter()
-7026 .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id))
-7027 .map(|(_path_id, path_state)| path_state.data.current_mtu())
-7028 .min()
-7029 .unwrap_or(INITIAL_MTU)
-7030 }
-7031
-7032 /// Size of non-frame data for a 1-RTT packet
-7033 ///
-7034 /// Quantifies space consumed by the QUIC header and AEAD tag. All other bytes in a packet are
-7035 /// frames. Changes if the length of the remote connection ID changes, which is expected to be
-7036 /// rare. If `pn` is specified, may additionally change unpredictably due to variations in
-7037 /// latency and packet loss.
-7038 fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize {
-7039 let pn_len = PacketNumber::new(
-7040 pn,
-7041 self.spaces[SpaceId::Data]
-7042 .for_path(path)
-7043 .largest_acked_packet_pn
-7044 .unwrap_or(0),
-7045 )
-7046 .len();
-7047
-7048 // 1 byte for flags
-7049 1 + self
-7050 .remote_cids
-7051 .get(&path)
-7052 .map(|cids| cids.active().len())
-7053 .unwrap_or(20) // Max CID len in QUIC v1
-7054 + pn_len
-7055 + self.tag_len_1rtt()
-7056 }
-7057
-7058 fn predict_1rtt_overhead_no_pn(&self) -> usize {
-7059 let pn_len = 4;
-7060
-7061 let cid_len = self
-7062 .remote_cids
-7063 .values()
-7064 .map(|cids| cids.active().len())
-7065 .max()
-7066 .unwrap_or(20); // Max CID len in QUIC v1
-7067
-7068 // 1 byte for flags
-7069 1 + cid_len + pn_len + self.tag_len_1rtt()
-7070 }
-7071
-7072 fn tag_len_1rtt(&self) -> usize {
-7073 // encryption_keys for Data space returns 1-RTT keys if available, otherwise 0-RTT keys
-7074 let packet_crypto = self
-7075 .crypto_state
-7076 .encryption_keys(SpaceKind::Data, self.side.side())
-7077 .map(|(_header, packet, _level)| packet);
-7078 // If neither Data nor 0-RTT keys are available, make a reasonable tag length guess. As of
-7079 // this writing, all QUIC cipher suites use 16-byte tags. We could return `None` instead,
-7080 // but that would needlessly prevent sending datagrams during 0-RTT.
-7081 packet_crypto.map_or(16, |x| x.tag_len())
-7082 }
-7083
-7084 /// Mark the path as validated, and enqueue NEW_TOKEN frames to be sent as appropriate
-7085 fn on_path_validated(&mut self, path_id: PathId) {
-7086 self.path_data_mut(path_id).validated = true;
-7087 let ConnectionSide::Server { server_config } = &self.side else {
-7088 return;
-7089 };
-7090 let network_path = self.path_data(path_id).network_path;
-7091 let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens;
-7092 new_tokens.clear();
-7093 for _ in 0..server_config.validation_token.sent {
-7094 new_tokens.push(network_path);
-7095 }
-7096 }
-7097
-7098 /// Handle new path status information: PATH_STATUS_AVAILABLE, PATH_STATUS_BACKUP
-7099 fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) {
-7100 if let Some(path) = self.paths.get_mut(&path_id) {
-7101 path.data.status.remote_update(status, status_seq_no);
-7102 } else {
-7103 debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id);
-7104 }
-7105 self.events.push_back(
-7106 PathEvent::RemoteStatus {
-7107 id: path_id,
-7108 status,
-7109 }
-7110 .into(),
-7111 );
-7112 }
-7113
-7114 /// Returns the maximum [`PathId`] to be used for sending in this connection.
-7115 ///
-7116 /// This is calculated as minimum between the local and remote's maximums when multipath is
-7117 /// enabled, or `None` when disabled.
-7118 ///
-7119 /// For data that's received, we should use [`Self::local_max_path_id`] instead.
-7120 /// The reasoning is that the remote might already have updated to its own newer
-7121 /// [`Self::max_path_id`] after sending out a `MAX_PATH_ID` frame, but it got re-ordered.
-7122 fn max_path_id(&self) -> Option<PathId> {
-7123 if self.is_multipath_negotiated() {
-7124 Some(self.remote_max_path_id.min(self.local_max_path_id))
-7125 } else {
-7126 None
-7127 }
-7128 }
-7129
-7130 /// Returns whether this connection has a socket that supports IPv6.
-7131 ///
-7132 /// TODO(matheus23): This is related to noq endpoint state's `ipv6` bool. We should move that info
-7133 /// here instead of trying to hack around not knowing it exactly.
-7134 pub(crate) fn is_ipv6(&self) -> bool {
-7135 self.paths
-7136 .values()
-7137 .any(|p| p.data.network_path.remote.is_ipv6())
-7138 }
-7139
-7140 /// Add addresses the local endpoint considers are reachable for nat traversal.
-7141 pub fn add_nat_traversal_address(
-7142 &mut self,
-7143 address: SocketAddr,
-7144 ) -> Result<(), n0_nat_traversal::Error> {
-7145 if let Some(added) = self.n0_nat_traversal.add_local_address(address)? {
-7146 self.spaces[SpaceId::Data].pending.add_address.insert(added);
-7147 };
-7148 Ok(())
-7149 }
-7150
-7151 /// Removes an address the endpoing no longer considers reachable for nat traversal
-7152 ///
-7153 /// Addresses not present in the set will be silently ignored.
-7154 pub fn remove_nat_traversal_address(
-7155 &mut self,
-7156 address: SocketAddr,
-7157 ) -> Result<(), n0_nat_traversal::Error> {
-7158 if let Some(removed) = self.n0_nat_traversal.remove_local_address(address)? {
-7159 self.spaces[SpaceId::Data]
-7160 .pending
-7161 .remove_address
-7162 .insert(removed);
-7163 }
-7164 Ok(())
-7165 }
-7166
-7167 /// Get the current local nat traversal addresses
-7168 pub fn get_local_nat_traversal_addresses(
-7169 &self,
-7170 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
-7171 self.n0_nat_traversal.get_local_nat_traversal_addresses()
-7172 }
-7173
-7174 /// Get the currently advertised nat traversal addresses by the server
-7175 pub fn get_remote_nat_traversal_addresses(
-7176 &self,
-7177 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
-7178 Ok(self
-7179 .n0_nat_traversal
-7180 .client_side()?
-7181 .get_remote_nat_traversal_addresses())
-7182 }
-7183
-7184 /// Initiates a new nat traversal round
-7185 ///
-7186 /// A nat traversal round involves advertising the client's local addresses in
-7187 /// `REACH_OUT` frames, and initiating probing of the known remote addresses. When a new
-7188 /// round is initiated, the previous one is cancelled.
-7189 ///
-7190 /// For all probes that succeed, if any, a new path will be opened on the successful
-7191 /// 4-tuple.
-7192 ///
-7193 /// Returns the server addresses that are now being probed. If addresses fail due to
-7194 /// spurious errors, these might succeed later and not be returned in this set.
-7195 pub fn initiate_nat_traversal_round(
-7196 &mut self,
-7197 now: Instant,
-7198 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
-7199 if self.state.is_closed() {
-7200 return Err(n0_nat_traversal::Error::Closed);
-7201 }
-7202
-7203 let ipv6 = self.is_ipv6();
-7204 let client_state = self.n0_nat_traversal.client_side_mut()?;
-7205 let (mut reach_out_frames, probed_addrs) =
-7206 client_state.initiate_nat_traversal_round(ipv6)?;
-7207 if let Some(delay) = self.n0_nat_traversal.retry_delay(self.config.initial_rtt) {
-7208 self.timers.set(
-7209 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
-7210 now + delay,
-7211 self.qlog.with_time(now),
-7212 );
-7213 }
-7214
-7215 self.spaces[SpaceId::Data]
-7216 .pending
-7217 .reach_out
-7218 .append(&mut reach_out_frames);
-7219
-7220 Ok(probed_addrs)
-7221 }
-7222
-7223 /// Whether the handshake is considered **confirmed**.
-7224 ///
-7225 /// <https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2> defines a handshake to be
-7226 /// confirmed when you know the peer successfully received and successfully processed
-7227 /// your TLS Finished message.
-7228 ///
-7229 /// Implementation-wise this is the point at which the handshake crypto keys are
-7230 /// discarded. So we can use this to know if the handshake is confirmed.
-7231 fn is_handshake_confirmed(&self) -> bool {
-7232 !self.is_handshaking() && !self.crypto_state.has_keys(EncryptionLevel::Handshake)
-7233 }
-7234}
-7235
-7236impl fmt::Debug for Connection {
-7237 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-7238 f.debug_struct("Connection")
-7239 .field("handshake_cid", &self.handshake_cid)
-7240 .finish()
-7241 }
-7242}
-7243
-7244/// The set of abandoned paths.
-7245///
-7246/// Implementation based on ArrayRangeSet to share more code. The memory space is
-7247/// proportional to the number of concurrently open paths allowed. So does not grow
-7248/// unbounded.
-7249#[derive(Debug, Default)]
-7250struct AbandonedPaths(ArrayRangeSet<ABANDONED_PATH_INLINE_RANGES, u32>);
-7251
-7252/// Size of the stack-allocated array in the [`ArrayRangeSet`].
-7253///
-7254/// A range is 2 u32's, so this is 16 * (4 + 4) = 128 bytes. A good size for inline data,
-7255/// with plenty of ranges for common multipath use.
-7256const ABANDONED_PATH_INLINE_RANGES: usize = 16;
-7257
-7258impl AbandonedPaths {
-7259 /// The number of abandoned paths.
-7260 fn len(&self) -> u32 {
-7261 self.0.elts_count()
-7262 }
-7263
-7264 /// The largest abandoned path.
-7265 fn max(&self) -> Option<PathId> {
-7266 self.0.max().map(PathId::from)
-7267 }
-7268
-7269 /// Whether the path is already abandoned.
-7270 fn contains(&self, val: &PathId) -> bool {
-7271 self.0.contains(val.as_u32())
-7272 }
-7273
-7274 /// Adds another abandoned path.
-7275 fn insert(&mut self, val: PathId) {
-7276 self.0.insert_one(val.as_u32());
-7277 }
-7278}
-7279
-7280/// Hints when the caller identifies a network change.
-7281pub trait NetworkChangeHint: std::fmt::Debug + 'static {
-7282 /// Inform the connection if a path may recover after a network change.
-7283 ///
-7284 /// After network changes, paths may not be recoverable. In this case, waiting for the path to
-7285 /// become idle may take longer than what is desirable. If [`Self::is_path_recoverable`]
-7286 /// returns `false`, a multipath-enabled, client-side connection will establish a new path to
-7287 /// the same remote, closing the current one, instead of migrating the path.
-7288 ///
-7289 /// Paths that are deemed recoverable will simply be sent a PING for a liveness check.
-7290 fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool;
-7291}
-7292
-7293/// Return value for [`Connection::poll_transmit_path_space`].
-7294#[derive(Debug)]
-7295enum PollPathSpaceStatus {
-7296 /// Nothing to send in the space, nothing was written into the [`TransmitBuf`].
-7297 NothingToSend {
-7298 /// If true there was data to send but congestion control did not allow so.
-7299 congestion_blocked: bool,
-7300 },
-7301 /// One or more packets have been written into the [`TransmitBuf`].
-7302 WrotePacket {
-7303 /// The highest packet number.
-7304 last_packet_number: u64,
-7305 /// Whether to pad an already started datagram in the next packet.
-7306 ///
-7307 /// When packets in Initial, 0-RTT or Handshake packet do not fill the entire
-7308 /// datagram they may decide to coalesce with the next packet from a higher
-7309 /// encryption level on the same path. But the earlier packet may require specific
-7310 /// size requirements for the datagram they are sent in.
-7311 ///
-7312 /// If a space did not complete the datagram, they use this to request the correct
-7313 /// padding in the final packet of the datagram so that the final datagram will have
-7314 /// the correct size.
-7315 ///
-7316 /// If a space did fill an entire datagram, it leaves this to the default of
-7317 /// [`PadDatagram::No`].
-7318 pad_datagram: PadDatagram,
-7319 },
-7320 /// Send the contents of the transmit immediately.
-7321 ///
-7322 /// Packets were written and the GSO batch must end now, regardless from whether higher
-7323 /// spaces still have frames to write. This is used when the last datagram written would
-7324 /// require too much padding to continue a GSO batch, which would waste space on the
-7325 /// wire.
-7326 Send {
-7327 /// The highest packet number written into the transmit.
-7328 last_packet_number: u64,
-7329 },
-7330}
-7331
-7332/// Information used to decide what frames to schedule into which packets.
-7333///
-7334/// Primarily used by [`Connection::poll_transmit_on_path`] and the functions that help
-7335/// building packets for it: [`Connection::poll_transmit_path_space`] and
-7336/// [`Connection::populate_packet`].
-7337#[derive(Debug, Copy, Clone)]
-7338struct PathSchedulingInfo {
-7339 /// Whether the path is abandoned.
-7340 ///
-7341 /// Note that a path that is abandoned but still has CIDs can still send a packet. After
-7342 /// sending that packet the CIDs issued by the remote have to be considered retired as
-7343 /// well.
-7344 is_abandoned: bool,
-7345 /// Whether the path may send [`SpaceKind::Data`] frames.
-7346 ///
-7347 /// Some paths should only send frames from [`SendableFrames::space_specific`]. All other
-7348 /// frames are essentially frames that can be sent on any [`SpaceKind::Data`] space. For
-7349 /// those we want to respect packet scheduling rules however.
-7350 ///
-7351 /// Roughly speaking data frames are only sent on spaces that have CIDs, are not
-7352 /// abandoned and have no *better* spaces. However see to comments where this is
-7353 /// populated for the exact packet scheduling implementation.
-7354 ///
-7355 /// This essentially marks this paths as the best validated space ID. Except during
-7356 /// the handshake in which case it does not need to be validated. Several paths could be
-7357 /// equally good and all have this set to `true`, in that case packet scheduling can
-7358 /// choose which path to use. Currently it chooses the lowest path that is not
-7359 /// congestion blocked.
-7360 ///
-7361 /// Note that once in the closed or draining states this will never be true.
-7362 may_send_data: bool,
-7363 /// Whether the path may send a CONNECTION_CLOSE frame.
-7364 ///
-7365 /// This essentially marks this path as the best validated space ID with a fallback
-7366 /// to unvalidated spaces if there are no validated spaces. Like for
-7367 /// [`Self::may_send_data`] other paths could be equally good.
-7368 may_send_close: bool,
-7369 may_self_abandon: bool,
-7370}
-7371
-7372#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-7373enum PathBlocked {
-7374 No,
-7375 AntiAmplification,
-7376 Congestion,
-7377 Pacing,
-7378}
-7379
-7380/// Fields of `Connection` specific to it being client-side or server-side
-7381enum ConnectionSide {
-7382 Client {
-7383 /// Sent in every outgoing Initial packet. Always empty after Initial keys are discarded
-7384 token: Bytes,
-7385 token_store: Arc<dyn TokenStore>,
-7386 server_name: String,
-7387 },
-7388 Server {
-7389 server_config: Arc<ServerConfig>,
-7390 },
-7391}
-7392
-7393impl ConnectionSide {
-7394 fn is_client(&self) -> bool {
-7395 self.side().is_client()
-7396 }
-7397
-7398 fn is_server(&self) -> bool {
-7399 self.side().is_server()
-7400 }
-7401
-7402 fn side(&self) -> Side {
-7403 match *self {
-7404 Self::Client { .. } => Side::Client,
-7405 Self::Server { .. } => Side::Server,
-7406 }
-7407 }
-7408}
-7409
-7410impl From<SideArgs> for ConnectionSide {
-7411 fn from(side: SideArgs) -> Self {
-7412 match side {
-7413 SideArgs::Client {
-7414 token_store,
-7415 server_name,
-7416 } => Self::Client {
-7417 token: token_store.take(&server_name).unwrap_or_default(),
-7418 token_store,
-7419 server_name,
-7420 },
-7421 SideArgs::Server {
-7422 server_config,
-7423 pref_addr_cid: _,
-7424 path_validated: _,
-7425 } => Self::Server { server_config },
-7426 }
-7427 }
-7428}
-7429
-7430/// Parameters to `Connection::new` specific to it being client-side or server-side
-7431pub(crate) enum SideArgs {
-7432 Client {
-7433 token_store: Arc<dyn TokenStore>,
-7434 server_name: String,
-7435 },
-7436 Server {
-7437 server_config: Arc<ServerConfig>,
-7438 pref_addr_cid: Option<ConnectionId>,
-7439 path_validated: bool,
-7440 },
-7441}
-7442
-7443impl SideArgs {
-7444 pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> {
-7445 match *self {
-7446 Self::Client { .. } => None,
-7447 Self::Server { pref_addr_cid, .. } => pref_addr_cid,
-7448 }
-7449 }
-7450
-7451 pub(crate) fn path_validated(&self) -> bool {
-7452 match *self {
-7453 Self::Client { .. } => true,
-7454 Self::Server { path_validated, .. } => path_validated,
-7455 }
-7456 }
-7457
-7458 pub(crate) fn side(&self) -> Side {
-7459 match *self {
-7460 Self::Client { .. } => Side::Client,
-7461 Self::Server { .. } => Side::Server,
-7462 }
-7463 }
-7464}
-7465
-7466/// Reasons why a connection might be lost
-7467#[derive(Debug, Error, Clone, PartialEq, Eq)]
-7468pub enum ConnectionError {
-7469 /// The peer doesn't implement any supported version
-7470 #[error("peer doesn't implement any supported version")]
-7471 VersionMismatch,
-7472 /// The peer violated the QUIC specification as understood by this implementation
-7473 #[error(transparent)]
-7474 TransportError(#[from] TransportError),
-7475 /// The peer's QUIC stack aborted the connection automatically
-7476 #[error("aborted by peer: {0}")]
-7477 ConnectionClosed(frame::ConnectionClose),
-7478 /// The peer closed the connection
-7479 #[error("closed by peer: {0}")]
-7480 ApplicationClosed(frame::ApplicationClose),
-7481 /// The peer is unable to continue processing this connection, usually due to having restarted
-7482 #[error("reset by peer")]
-7483 Reset,
-7484 /// Communication with the peer has lapsed for longer than the negotiated idle timeout
-7485 ///
-7486 /// If neither side is sending keep-alives, a connection will time out after a long enough idle
-7487 /// period even if the peer is still reachable. See also [`TransportConfig::max_idle_timeout()`]
-7488 /// and [`TransportConfig::keep_alive_interval()`].
-7489 #[error("timed out")]
-7490 TimedOut,
-7491 /// The local application closed the connection
-7492 #[error("closed")]
-7493 LocallyClosed,
-7494 /// The connection could not be created because not enough of the CID space is available
-7495 ///
-7496 /// Try using longer connection IDs.
-7497 #[error("CIDs exhausted")]
-7498 CidsExhausted,
-7499}
-7500
-7501impl From<Close> for ConnectionError {
-7502 fn from(x: Close) -> Self {
-7503 match x {
-7504 Close::Connection(reason) => Self::ConnectionClosed(reason),
-7505 Close::Application(reason) => Self::ApplicationClosed(reason),
-7506 }
-7507 }
-7508}
-7509
-7510// For compatibility with API consumers
-7511impl From<ConnectionError> for io::Error {
-7512 fn from(x: ConnectionError) -> Self {
-7513 use ConnectionError::*;
-7514 let kind = match x {
-7515 TimedOut => io::ErrorKind::TimedOut,
-7516 Reset => io::ErrorKind::ConnectionReset,
-7517 ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted,
-7518 TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => {
-7519 io::ErrorKind::Other
-7520 }
-7521 };
-7522 Self::new(kind, x)
-7523 }
-7524}
-7525
-7526/// Errors that might trigger a path being closed
-7527// TODO(@divma): maybe needs to be reworked based on what we want to do with the public API
-7528#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)]
-7529pub enum PathError {
-7530 /// The extension was not negotiated with the peer
-7531 #[error("multipath extension not negotiated")]
-7532 MultipathNotNegotiated,
-7533 /// Paths can only be opened client-side
-7534 #[error("the server side may not open a path")]
-7535 ServerSideNotAllowed,
-7536 /// Current limits do not allow us to open more paths
-7537 #[error("maximum number of concurrent paths reached")]
-7538 MaxPathIdReached,
-7539 /// No remote CIDs available to open a new path
-7540 #[error("remoted CIDs exhausted")]
-7541 RemoteCidsExhausted,
-7542 /// Path could not be validated and will be abandoned
-7543 #[error("path validation failed")]
-7544 ValidationFailed,
-7545 /// The remote address for the path is not supported by the endpoint
-7546 #[error("invalid remote address")]
-7547 InvalidRemoteAddress(SocketAddr),
-7548}
-7549
-7550/// Errors triggered when abandoning a path
-7551#[derive(Debug, Error, Clone, Eq, PartialEq)]
-7552pub enum ClosePathError {
-7553 /// Multipath is not negotiated
-7554 #[error("Multipath extension not negotiated")]
-7555 MultipathNotNegotiated,
-7556 /// The path is already closed or was never opened
-7557 #[error("closed path")]
-7558 ClosedPath,
-7559 /// Cannot close the last remaining open path via the local API.
-7560 ///
-7561 /// Use [`Connection::close`] to end the connection instead.
-7562 #[error("last open path")]
-7563 LastOpenPath,
-7564}
-7565
-7566/// Error when the multipath extension was not negotiated, but attempted to be used.
-7567#[derive(Debug, Error, Clone, Copy)]
-7568#[error("Multipath extension not negotiated")]
-7569pub struct MultipathNotNegotiated {
-7570 _private: (),
-7571}
-7572
-7573/// Events of interest to the application
-7574#[derive(Debug)]
-7575pub enum Event {
-7576 /// The connection's handshake data is ready
-7577 HandshakeDataReady,
-7578 /// The connection was successfully established
-7579 Connected,
-7580 /// The TLS handshake was confirmed
-7581 HandshakeConfirmed,
-7582 /// The connection was lost
-7583 ///
-7584 /// Emitted when the connection is closed due to an error, a timeout, or the peer closing it.
-7585 /// This is **not** emitted when the local application closes the connection via
-7586 /// [`Connection::close()`](crate::Connection::close). In that case, pending operations will
-7587 /// fail with [`ConnectionError::LocallyClosed`].
-7588 ConnectionLost {
-7589 /// Reason that the connection was closed
-7590 reason: ConnectionError,
-7591 },
-7592 /// Stream events
-7593 Stream(StreamEvent),
-7594 /// One or more application datagrams have been received
-7595 DatagramReceived,
-7596 /// One or more application datagrams have been sent after blocking
-7597 DatagramsUnblocked,
-7598 /// (Multi)Path events
-7599 Path(PathEvent),
-7600 /// n0's nat traversal events
-7601 NatTraversal(n0_nat_traversal::Event),
-7602}
-7603
-7604impl From<PathEvent> for Event {
-7605 fn from(source: PathEvent) -> Self {
-7606 Self::Path(source)
-7607 }
-7608}
-7609
-7610fn get_max_ack_delay(params: &TransportParameters) -> Duration {
-7611 Duration::from_micros(params.max_ack_delay.0 * 1000)
-7612}
-7613
-7614/// Prevents overflow and improves behavior in extreme circumstances.
-7615const MAX_BACKOFF_EXPONENT: u32 = 16;
-7616
-7617/// The max interval between successive tail-loss probes.
-7618///
-7619/// This is the "normal" value we use.
-7620const MAX_PTO_INTERVAL: Duration = Duration::from_secs(2);
-7621
-7622/// The idle time, below which we use the shorter [`MAX_PTO_FAST_INTERVAL`].
-7623const MIN_IDLE_FOR_FAST_PTO: Duration = Duration::from_secs(25);
-7624
-7625/// The max interval between successive tail-loss probes with short idle times.
-7626///
-7627/// If the path or connection idle time is less than [`MIN_IDLE_FOR_FAST_PTO`] then we use
-7628/// this value to ensure we have plenty of retransmits before we reach the idle time.
-7629const MAX_PTO_FAST_INTERVAL: Duration = Duration::from_secs(1);
-7630
-7631/// The RTT threshold above which we cap the PTO interval to 1.5 * smoothed_rtt
-7632///
-7633/// This is RTT time above which 1.5 * RTT > [`MAX_PTO_INTERVAL`], for these links we want
-7634/// to extend the interval between tail-loss probes to not fill the entire pipe with them.
-7635const SLOW_RTT_THRESHOLD: Duration =
-7636 Duration::from_millis((MAX_PTO_INTERVAL.as_millis() as u64 * 2) / 3);
-7637
-7638/// Minimal remaining size to allow packet coalescing, excluding cryptographic tag
-7639///
-7640/// This must be at least as large as the header for a well-formed empty packet to be coalesced,
-7641/// plus some space for frames. We only care about handshake headers because short header packets
-7642/// necessarily have smaller headers, and initial packets are only ever the first packet in a
-7643/// datagram (because we coalesce in ascending packet space order and the only reason to split a
-7644/// packet is when packet space changes).
-7645const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32;
-7646
-7647/// Largest amount of space that could be occupied by a Handshake or 0-RTT packet's header
-7648///
-7649/// Excludes packet-type-specific fields such as packet number or Initial token
-7650// https://www.rfc-editor.org/rfc/rfc9000.html#name-0-rtt: flags + version + dcid len + dcid +
-7651// scid len + scid + length + pn
-7652const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize =
-7653 1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4;
-7654
-7655#[derive(Default)]
-7656struct SentFrames {
-7657 retransmits: ThinRetransmits,
-7658 path_retransmits: PathRetransmits,
-7659 /// The packet number of the largest acknowledged packet for each path
-7660 largest_acked: FxHashMap<PathId, u64>,
-7661 stream_frames: StreamMetaVec,
-7662 /// Whether the packet contains non-retransmittable frames (like datagrams)
-7663 non_retransmits: bool,
-7664 /// If the datagram containing these frames should be padded to the min MTU
-7665 requires_padding: bool,
-7666}
-7667
-7668impl SentFrames {
-7669 /// Returns whether the packet contains only ACKs
-7670 fn is_ack_only(&self, streams: &StreamsState) -> bool {
-7671 !self.largest_acked.is_empty()
-7672 && !self.non_retransmits
-7673 && self.stream_frames.is_empty()
-7674 && self.retransmits.is_empty(streams)
-7675 }
-7676
-7677 fn retransmits_mut(&mut self) -> &mut Retransmits {
-7678 self.retransmits.get_or_create()
-7679 }
-7680
-7681 fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) {
-7682 use frame::EncodableFrame::*;
-7683 match frame {
-7684 PathAck(path_ack_encoder) => {
-7685 if let Some(max) = path_ack_encoder.ranges.max() {
-7686 self.largest_acked.insert(path_ack_encoder.path_id, max);
-7687 }
-7688 }
-7689 Ack(ack_encoder) => {
-7690 if let Some(max) = ack_encoder.ranges.max() {
-7691 self.largest_acked.insert(PathId::ZERO, max);
-7692 }
-7693 }
-7694 Close(_) => { /* non retransmittable, but after this we don't really care */ }
-7695 PathResponse(_) => self.non_retransmits = true,
-7696 HandshakeDone(_) => self.retransmits_mut().handshake_done = true,
-7697 ReachOut(frame) => self.retransmits_mut().reach_out.push(frame),
-7698 ObservedAddr(_) => self.path_retransmits.observed_address = true,
-7699 Ping(_) => self.non_retransmits = true,
-7700 ImmediateAck(_) => self.non_retransmits = true,
-7701 AckFrequency(_) => self.retransmits_mut().ack_frequency = true,
-7702 PathChallenge(_) => self.non_retransmits = true,
-7703 Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto),
-7704 PathAbandon(path_abandon) => {
-7705 self.retransmits_mut()
-7706 .path_abandon
-7707 .entry(path_abandon.path_id)
-7708 .or_insert(path_abandon.error_code);
-7709 }
-7710 PathStatusAvailable(frame::PathStatusAvailable { path_id, .. })
-7711 | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => {
-7712 self.retransmits_mut().path_status.insert(path_id);
-7713 }
-7714 MaxPathId(_) => self.retransmits_mut().max_path_id = true,
-7715 PathsBlocked(frame::PathsBlocked(path_id)) => {
-7716 let paths_blocked = &mut self.retransmits_mut().paths_blocked;
-7717 *paths_blocked = cmp::max(*paths_blocked, Some(path_id));
-7718 }
-7719 PathCidsBlocked(path_cids_blocked) => {
-7720 self.retransmits_mut()
-7721 .path_cids_blocked
-7722 .entry(path_cids_blocked.path_id)
-7723 .and_modify(|next_seq| {
-7724 *next_seq = cmp::max(*next_seq, path_cids_blocked.next_seq);
-7725 })
-7726 .or_insert(path_cids_blocked.next_seq);
-7727 }
-7728 ResetStream(reset) => self
-7729 .retransmits_mut()
-7730 .reset_stream
-7731 .push((reset.id, reset.error_code)),
-7732 StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending),
-7733 NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()),
-7734 RetireConnectionId(retire_cid) => self
-7735 .retransmits_mut()
-7736 .retire_cids
-7737 .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)),
-7738 Datagram(_) => self.non_retransmits = true,
-7739 NewToken(_) => {}
-7740 AddAddress(add_address) => {
-7741 self.retransmits_mut().add_address.insert(add_address);
-7742 }
-7743 RemoveAddress(remove_address) => {
-7744 self.retransmits_mut().remove_address.insert(remove_address);
-7745 }
-7746 StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta),
-7747 MaxData(_) => self.retransmits_mut().max_data = true,
-7748 MaxStreamData(max) => {
-7749 self.retransmits_mut().max_stream_data.insert(max.id);
-7750 }
-7751 MaxStreams(max_streams) => {
-7752 self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true
-7753 }
-7754 StreamsBlocked(streams_blocked) => {
-7755 self.retransmits_mut().streams_blocked[streams_blocked.dir as usize] = true
-7756 }
-7757 }
-7758 }
-7759}
-7760
-7761/// Compute the negotiated idle timeout based on local and remote max_idle_timeout transport parameters.
-7762///
-7763/// According to the definition of max_idle_timeout, a value of `0` means the timeout is disabled; see <https://www.rfc-editor.org/rfc/rfc9000#section-18.2-4.4.1.>
-7764///
-7765/// According to the negotiation procedure, either the minimum of the timeouts or one specified is used as the negotiated value; see <https://www.rfc-editor.org/rfc/rfc9000#section-10.1-2.>
-7766///
-7767/// Returns the negotiated idle timeout as a `Duration`, or `None` when both endpoints have opted out of idle timeout.
-7768fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> {
-7769 match (x, y) {
-7770 (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None,
-7771 (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)),
-7772 (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)),
-7773 (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)),
-7774 }
-7775}
-7776
-7777#[cfg(test)]
-7778mod tests {
-7779 use super::*;
-7780
-7781 #[test]
-7782 fn negotiate_max_idle_timeout_commutative() {
-7783 let test_params = [
-7784 (None, None, None),
-7785 (None, Some(VarInt(0)), None),
-7786 (None, Some(VarInt(2)), Some(Duration::from_millis(2))),
-7787 (Some(VarInt(0)), Some(VarInt(0)), None),
-7788 (
-7789 Some(VarInt(2)),
-7790 Some(VarInt(0)),
-7791 Some(Duration::from_millis(2)),
-7792 ),
-7793 (
-7794 Some(VarInt(1)),
-7795 Some(VarInt(4)),
-7796 Some(Duration::from_millis(1)),
-7797 ),
-7798 ];
-7799
-7800 for (left, right, result) in test_params {
-7801 assert_eq!(negotiate_max_idle_timeout(left, right), result);
-7802 assert_eq!(negotiate_max_idle_timeout(right, left), result);
-7803 }
-7804 }
-7805
-7806 #[test]
-7807 fn abandoned_paths() {
-7808 let mut t = AbandonedPaths::default();
-7809
-7810 t.insert(PathId(0));
-7811 t.insert(PathId(1));
-7812 assert_eq!(t.len(), 2);
-7813 assert_eq!(t.0.range_count(), 1); // 2 elements compacted into one range
-7814 assert!(t.contains(&PathId(0)));
-7815 assert!(t.contains(&PathId(1)));
-7816 assert!(!t.contains(&PathId(2)));
-7817 assert!(!t.contains(&PathId(3)));
-7818 assert_eq!(t.max(), Some(PathId(1)));
-7819
-7820 t.insert(PathId(3));
-7821 assert_eq!(t.len(), 3);
-7822 assert_eq!(t.0.range_count(), 2); // 3 elements compacted into 2 ranges
-7823 assert!(t.contains(&PathId(0)));
-7824 assert!(t.contains(&PathId(1)));
-7825 assert!(!t.contains(&PathId(2)));
-7826 assert!(t.contains(&PathId(3)));
-7827 assert_eq!(t.max(), Some(PathId(3)));
-7828
-7829 t.insert(PathId(2));
-7830 assert_eq!(t.len(), 4);
-7831 assert_eq!(t.0.range_count(), 1); // 4 elements compacted into 1 range
-7832 assert!(t.contains(&PathId(0)));
-7833 assert!(t.contains(&PathId(1)));
-7834 assert!(t.contains(&PathId(2)));
-7835 assert!(t.contains(&PathId(3)));
-7836 assert_eq!(t.max(), Some(PathId(3)));
-7837 }
-7838}
\ No newline at end of file
+3956 &network_path,
+3957 );
+3958
+3959 let packet: Packet = packet.into();
+3960
+3961 let mut qlog = QlogRecvPacket::new(len);
+3962 qlog.header(&packet.header, Some(packet_number), path_id);
+3963
+3964 self.process_decrypted_packet(
+3965 now,
+3966 network_path,
+3967 path_id,
+3968 Some(packet_number),
+3969 packet,
+3970 &mut qlog,
+3971 )?;
+3972 self.qlog.emit_packet_received(qlog, now);
+3973 if let Some(data) = remaining {
+3974 self.handle_coalesced(now, network_path, path_id, ecn, data);
+3975 }
+3976
+3977 self.qlog.emit_recovery_metrics(
+3978 path_id,
+3979 &mut self
+3980 .paths
+3981 .get_mut(&path_id)
+3982 .expect("path_id was supplied by the caller for an active path")
+3983 .data,
+3984 now,
+3985 );
+3986
+3987 Ok(())
+3988 }
+3989
+3990 fn init_0rtt(&mut self, now: Instant) {
+3991 let Some((header, packet)) = self.crypto_state.session.early_crypto() else {
+3992 return;
+3993 };
+3994 if self.side.is_client() {
+3995 match self.crypto_state.session.transport_parameters() {
+3996 Ok(params) => {
+3997 let params = params
+3998 .expect("crypto layer didn't supply transport parameters with ticket");
+3999 // Certain values must not be cached
+4000 let params = TransportParameters {
+4001 initial_src_cid: None,
+4002 original_dst_cid: None,
+4003 preferred_address: None,
+4004 retry_src_cid: None,
+4005 stateless_reset_token: None,
+4006 min_ack_delay: None,
+4007 ack_delay_exponent: TransportParameters::default().ack_delay_exponent,
+4008 max_ack_delay: TransportParameters::default().max_ack_delay,
+4009 initial_max_path_id: None,
+4010 ..params
+4011 };
+4012 self.set_peer_params(params);
+4013 self.qlog.emit_peer_transport_params_restored(self, now);
+4014 }
+4015 Err(e) => {
+4016 error!("session ticket has malformed transport parameters: {}", e);
+4017 return;
+4018 }
+4019 }
+4020 }
+4021 trace!("0-RTT enabled");
+4022 self.crypto_state.enable_zero_rtt(header, packet);
+4023 }
+4024
+4025 fn read_crypto(
+4026 &mut self,
+4027 space: SpaceId,
+4028 crypto: &frame::Crypto,
+4029 payload_len: usize,
+4030 ) -> Result<(), TransportError> {
+4031 let expected = if !self.state.is_handshake() {
+4032 SpaceId::Data
+4033 } else if self.highest_space == SpaceKind::Initial {
+4034 SpaceId::Initial
+4035 } else {
+4036 // On the server, self.highest_space can be Data after receiving the client's first
+4037 // flight, but we expect Handshake CRYPTO until the handshake is complete.
+4038 SpaceId::Handshake
+4039 };
+4040 // We can't decrypt Handshake packets when highest_space is Initial, CRYPTO frames in 0-RTT
+4041 // packets are illegal, and we don't process 1-RTT packets until the handshake is
+4042 // complete. Therefore, we will never see CRYPTO data from a later-than-expected space.
+4043 debug_assert!(space <= expected, "received out-of-order CRYPTO data");
+4044
+4045 let end = crypto.offset + crypto.data.len() as u64;
+4046 if space < expected
+4047 && end
+4048 > self.crypto_state.spaces[space.kind()]
+4049 .crypto_stream
+4050 .bytes_read()
+4051 {
+4052 warn!(
+4053 "received new {:?} CRYPTO data when expecting {:?}",
+4054 space, expected
+4055 );
+4056 return Err(TransportError::PROTOCOL_VIOLATION(
+4057 "new data at unexpected encryption level",
+4058 ));
+4059 }
+4060
+4061 let crypto_space = &mut self.crypto_state.spaces[space.kind()];
+4062 let max = end.saturating_sub(crypto_space.crypto_stream.bytes_read());
+4063 if max > self.config.crypto_buffer_size as u64 {
+4064 return Err(TransportError::CRYPTO_BUFFER_EXCEEDED(""));
+4065 }
+4066
+4067 crypto_space
+4068 .crypto_stream
+4069 .insert(crypto.offset, crypto.data.clone(), payload_len);
+4070 while let Some(chunk) = crypto_space.crypto_stream.read(usize::MAX, true) {
+4071 trace!("consumed {} CRYPTO bytes", chunk.bytes.len());
+4072 if self.crypto_state.session.read_handshake(&chunk.bytes)? {
+4073 self.events.push_back(Event::HandshakeDataReady);
+4074 }
+4075 }
+4076
+4077 Ok(())
+4078 }
+4079
+4080 fn write_crypto(&mut self) {
+4081 loop {
+4082 let space = self.highest_space;
+4083 let mut outgoing = Vec::new();
+4084 if let Some(crypto) = self.crypto_state.session.write_handshake(&mut outgoing) {
+4085 match space {
+4086 SpaceKind::Initial => {
+4087 self.upgrade_crypto(SpaceKind::Handshake, crypto);
+4088 }
+4089 SpaceKind::Handshake => {
+4090 self.upgrade_crypto(SpaceKind::Data, crypto);
+4091 }
+4092 SpaceKind::Data => unreachable!("got updated secrets during 1-RTT"),
+4093 }
+4094 }
+4095 if outgoing.is_empty() {
+4096 if space == self.highest_space {
+4097 break;
+4098 } else {
+4099 // Keys updated, check for more data to send
+4100 continue;
+4101 }
+4102 }
+4103 let offset = self.crypto_state.spaces[space].crypto_offset;
+4104 let outgoing = Bytes::from(outgoing);
+4105 if let Some(hs) = self.state.as_handshake_mut()
+4106 && space == SpaceKind::Initial
+4107 && offset == 0
+4108 && self.side.is_client()
+4109 {
+4110 hs.client_hello = Some(outgoing.clone());
+4111 }
+4112 self.crypto_state.spaces[space].crypto_offset += outgoing.len() as u64;
+4113 trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space);
+4114 self.spaces[space].pending.crypto.push_back(frame::Crypto {
+4115 offset,
+4116 data: outgoing,
+4117 });
+4118 }
+4119 }
+4120
+4121 /// Switch to stronger cryptography during handshake
+4122 fn upgrade_crypto(&mut self, space: SpaceKind, crypto: Keys) {
+4123 debug_assert!(
+4124 !self.crypto_state.has_keys(space.encryption_level()),
+4125 "already reached packet space {space:?}"
+4126 );
+4127 trace!("{:?} keys ready", space);
+4128 if space == SpaceKind::Data {
+4129 // Precompute the first key update
+4130 self.crypto_state.next_crypto = Some(
+4131 self.crypto_state
+4132 .session
+4133 .next_1rtt_keys()
+4134 .expect("handshake should be complete"),
+4135 );
+4136 }
+4137
+4138 self.crypto_state.spaces[space].keys = Some(crypto);
+4139 debug_assert!(space > self.highest_space);
+4140 self.highest_space = space;
+4141 if space == SpaceKind::Data && self.side.is_client() {
+4142 // Discard 0-RTT keys because 1-RTT keys are available.
+4143 self.crypto_state.discard_zero_rtt();
+4144 }
+4145 }
+4146
+4147 fn discard_space(&mut self, now: Instant, space: SpaceKind) {
+4148 debug_assert!(space != SpaceKind::Data);
+4149 trace!("discarding {:?} keys", space);
+4150 if space == SpaceKind::Initial {
+4151 // No longer needed
+4152 if let ConnectionSide::Client { token, .. } = &mut self.side {
+4153 *token = Bytes::new();
+4154 }
+4155 }
+4156 self.crypto_state.spaces[space].keys = None;
+4157 let space = &mut self.spaces[space];
+4158 let pns = space.for_path(PathId::ZERO);
+4159 pns.time_of_last_ack_eliciting_packet = None;
+4160 pns.loss_time = None;
+4161 pns.loss_probes = 0;
+4162 let sent_packets = mem::take(&mut pns.sent_packets);
+4163 let path = self
+4164 .paths
+4165 .get_mut(&PathId::ZERO)
+4166 .expect("PathId::ZERO is alive while Initial/Handshake spaces exist");
+4167 for (_, packet) in sent_packets.into_iter() {
+4168 path.data.remove_in_flight(&packet);
+4169 }
+4170
+4171 self.set_loss_detection_timer(now, PathId::ZERO)
+4172 }
+4173
+4174 fn handle_coalesced(
+4175 &mut self,
+4176 now: Instant,
+4177 network_path: FourTuple,
+4178 path_id: PathId,
+4179 ecn: Option<EcnCodepoint>,
+4180 data: BytesMut,
+4181 ) {
+4182 self.path_data_mut(path_id)
+4183 .inc_total_recvd(data.len() as u64);
+4184 let mut remaining = Some(data);
+4185 let cid_len = self
+4186 .local_cid_state
+4187 .values()
+4188 .map(|cid_state| cid_state.cid_len())
+4189 .next()
+4190 .expect("one cid_state must exist");
+4191 while let Some(data) = remaining {
+4192 match PartialDecode::new(
+4193 data,
+4194 &FixedLengthConnectionIdParser::new(cid_len),
+4195 &[self.version],
+4196 self.endpoint_config.grease_quic_bit,
+4197 ) {
+4198 Ok((partial_decode, rest)) => {
+4199 remaining = rest;
+4200 self.handle_decode(now, network_path, path_id, ecn, partial_decode);
+4201 }
+4202 Err(e) => {
+4203 trace!("malformed header: {}", e);
+4204 return;
+4205 }
+4206 }
+4207 }
+4208 }
+4209
+4210 /// Decrypts the packet and processes the payload.
+4211 ///
+4212 /// Processes the entire packet, starting with removing header protection, then handling
+4213 /// a stateless reset if needed, and decrypting and processing the frames in the payload
+4214 /// if not a stateless reset.
+4215 fn handle_decode(
+4216 &mut self,
+4217 now: Instant,
+4218 network_path: FourTuple,
+4219 path_id: PathId,
+4220 ecn: Option<EcnCodepoint>,
+4221 partial_decode: PartialDecode,
+4222 ) {
+4223 let qlog = QlogRecvPacket::new(partial_decode.len());
+4224 if let Some(decoded) = self
+4225 .crypto_state
+4226 .unprotect_header(partial_decode, self.peer_params.stateless_reset_token)
+4227 {
+4228 self.handle_packet(
+4229 now,
+4230 network_path,
+4231 path_id,
+4232 ecn,
+4233 decoded.packet,
+4234 decoded.stateless_reset,
+4235 qlog,
+4236 );
+4237 }
+4238 }
+4239
+4240 /// Handles a packet with header protection removed.
+4241 ///
+4242 /// The packet body is still encrypted at this point.
+4243 ///
+4244 /// If the datagram was a stateless reset we may have failed to remove header protection
+4245 /// and thus `packet` may be `None`.
+4246 fn handle_packet(
+4247 &mut self,
+4248 now: Instant,
+4249 network_path: FourTuple,
+4250 path_id: PathId,
+4251 ecn: Option<EcnCodepoint>,
+4252 packet: Option<Packet>,
+4253 stateless_reset: bool,
+4254 mut qlog: QlogRecvPacket,
+4255 ) {
+4256 self.path_stats.for_path(path_id).udp_rx.ios += 1;
+4257
+4258 if let Some(ref packet) = packet {
+4259 trace!(
+4260 "got {:?} packet ({} bytes) from {} using id {}",
+4261 packet.header.space(),
+4262 packet.payload.len() + packet.header_data.len(),
+4263 network_path,
+4264 packet.header.dst_cid(),
+4265 );
+4266 }
+4267
+4268 let was_closed = self.state.is_closed();
+4269 let was_drained = self.state.is_drained();
+4270
+4271 // Now decrypt the packet payload in-place.
+4272 let decrypted = match packet {
+4273 None => Err(None),
+4274 Some(mut packet) => self
+4275 .decrypt_packet(now, path_id, &mut packet)
+4276 .map(move |number| (packet, number)),
+4277 };
+4278 let result = match decrypted {
+4279 _ if stateless_reset => {
+4280 debug!("got stateless reset");
+4281 Err(ConnectionError::Reset)
+4282 }
+4283 Err(Some(e)) => {
+4284 warn!("illegal packet: {}", e);
+4285 Err(e.into())
+4286 }
+4287 Err(None) => {
+4288 debug!("failed to authenticate packet");
+4289 self.authentication_failures += 1;
+4290 let integrity_limit = self
+4291 .crypto_state
+4292 .integrity_limit(self.highest_space)
+4293 .unwrap();
+4294 if self.authentication_failures > integrity_limit {
+4295 Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into())
+4296 } else {
+4297 return;
+4298 }
+4299 }
+4300 Ok((packet, pn)) => {
+4301 // We received an authenticated packet and decrypted it.
+4302 qlog.header(&packet.header, pn, path_id);
+4303 let span = match pn {
+4304 Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn),
+4305 None => trace_span!("recv", space = ?packet.header.space()),
+4306 };
+4307 let _guard = span.enter();
+4308
+4309 // Now the packet is authenticated we do the migration during the handshake,
+4310 // see Handshake::allow_server_migration for details. Be careful here to
+4311 // not yet rely on the path existing however, new paths are accepted and
+4312 // created later.
+4313 // Note that we can't do any other migrations yet, for those we need to know
+4314 // whether this was a probing packet or not. See the end of
+4315 // Self::process_packet for that.
+4316 if self.is_handshaking()
+4317 && self
+4318 .path(path_id)
+4319 .map(|path_data| {
+4320 !path_data.network_path.is_probably_same_path(&network_path)
+4321 })
+4322 .unwrap_or(false)
+4323 {
+4324 if let Some(hs) = self.state.as_handshake()
+4325 && hs.allow_server_migration
+4326 {
+4327 trace!(
+4328 %network_path,
+4329 prev = %self.path_data(path_id).network_path,
+4330 "server migrated to new remote",
+4331 );
+4332 self.path_data_mut(path_id).network_path = network_path;
+4333 self.qlog.emit_tuple_assigned(path_id, network_path, now);
+4334 } else {
+4335 debug!(
+4336 recv_path = %network_path,
+4337 expected_path = %self.path_data_mut(path_id).network_path,
+4338 "discarding packet with unexpected remote during handshake",
+4339 );
+4340 return;
+4341 }
+4342 }
+4343
+4344 let dedup = self.spaces[packet.header.space()]
+4345 .path_space_mut(path_id)
+4346 .map(|pns| &mut pns.dedup);
+4347 if pn.zip(dedup).is_some_and(|(n, d)| d.insert(n)) {
+4348 debug!("discarding possible duplicate packet");
+4349 self.qlog.emit_packet_received(qlog, now);
+4350 return;
+4351 } else if self.state.is_handshake() && packet.header.is_short() {
+4352 // TODO: SHOULD buffer these to improve reordering tolerance.
+4353 trace!("dropping short packet during handshake");
+4354 self.qlog.emit_packet_received(qlog, now);
+4355 return;
+4356 } else {
+4357 if let Header::Initial(InitialHeader { ref token, .. }) = packet.header
+4358 && let Some(hs) = self.state.as_handshake()
+4359 && self.side.is_server()
+4360 && token != &hs.expected_token
+4361 {
+4362 // Clients must send the same retry token in every Initial. Initial
+4363 // packets can be spoofed, so we discard rather than killing the
+4364 // connection.
+4365 warn!("discarding Initial with invalid retry token");
+4366 self.qlog.emit_packet_received(qlog, now);
+4367 return;
+4368 }
+4369
+4370 if !self.state.is_closed() {
+4371 let spin = match packet.header {
+4372 Header::Short { spin, .. } => spin,
+4373 _ => false,
+4374 };
+4375
+4376 if self.side().is_server() && !self.abandoned_paths.contains(&path_id) {
+4377 // Only the client is allowed to open paths
+4378 self.create_path(path_id, network_path, now, pn);
+4379 }
+4380 if self.paths.contains_key(&path_id) {
+4381 self.on_packet_authenticated(
+4382 now,
+4383 packet.header.space(),
+4384 path_id,
+4385 ecn,
+4386 pn,
+4387 spin,
+4388 packet.header.is_1rtt(),
+4389 &network_path,
+4390 );
+4391 }
+4392 }
+4393
+4394 let res = self.process_decrypted_packet(
+4395 now,
+4396 network_path,
+4397 path_id,
+4398 pn,
+4399 packet,
+4400 &mut qlog,
+4401 );
+4402
+4403 self.qlog.emit_packet_received(qlog, now);
+4404 res
+4405 }
+4406 }
+4407 };
+4408
+4409 // State transitions for error cases
+4410 if let Err(conn_err) = result {
+4411 match conn_err {
+4412 ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason),
+4413 ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason),
+4414 ConnectionError::Reset
+4415 | ConnectionError::TransportError(TransportError {
+4416 code: TransportErrorCode::AEAD_LIMIT_REACHED,
+4417 ..
+4418 }) => {
+4419 let was_draining = self.state.move_to_drained(Some(conn_err));
+4420 if !was_draining {
+4421 self.endpoint_events.push_back(EndpointEventInner::Draining);
+4422 }
+4423 }
+4424 ConnectionError::TimedOut => {
+4425 unreachable!("timeouts aren't generated by packet processing");
+4426 }
+4427 ConnectionError::TransportError(err) => {
+4428 debug!("closing connection due to transport error: {}", err);
+4429 self.state.move_to_closed(err);
+4430 }
+4431 ConnectionError::VersionMismatch => {
+4432 self.state.move_to_draining(Some(conn_err));
+4433 self.endpoint_events.push_back(EndpointEventInner::Draining);
+4434 }
+4435 ConnectionError::LocallyClosed => {
+4436 unreachable!("LocallyClosed isn't generated by packet processing");
+4437 }
+4438 ConnectionError::CidsExhausted => {
+4439 unreachable!("CidsExhausted isn't generated by packet processing");
+4440 }
+4441 };
+4442 }
+4443
+4444 if !was_closed && self.state.is_closed() {
+4445 self.close_common();
+4446 if !self.state.is_drained() {
+4447 self.set_close_timer(now);
+4448 }
+4449 }
+4450 if !was_drained && self.state.is_drained() {
+4451 self.endpoint_events.push_back(EndpointEventInner::Drained);
+4452 // Close timer may have been started previously, e.g. if we sent a close and got a
+4453 // stateless reset in response
+4454 self.timers
+4455 .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now));
+4456 }
+4457
+4458 // Transmit CONNECTION_CLOSE if necessary.
+4459 //
+4460 // If we received a valid packet and we are in the closed state we should respond
+4461 // with a CONNECTION_CLOSE frame.
+4462 // TODO: This SHOULD be rate-limited according to §10.2.1 of QUIC-TRANSPORT, but
+4463 // that does not yet happen. This is triggered by each received packet.
+4464 if matches!(self.state.as_type(), StateType::Closed) {
+4465 // From https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2.1-7
+4466 //
+4467 // While in the closing state we must either:
+4468 // - discard packets coming from an un-validated remote OR
+4469 // - ensure we do not send more than 3 times the received data
+4470 //
+4471 // Doing the 2nd would mean we would be able to send CONNECTION_CLOSE to a peer
+4472 // who was (involuntary) migrated just at the time we initiated immediate
+4473 // close. It is a lot more work though. So while we would like to do this for
+4474 // now we only do 1.
+4475 //
+4476 // Another shortcoming of the current implementation is that when we have a
+4477 // previous PathData which is validated and the remote matches that path, we
+4478 // should schedule CONNECTION_CLOSE on that path. However currently we can not
+4479 // schedule such a packet. We should also fix this some day. This makes us
+4480 // vulnerable to an attacker faking a migration at the right time and then we'd
+4481 // be unable to send the CONNECTION_CLOSE to the real remote.
+4482 if self
+4483 .paths
+4484 .get(&path_id)
+4485 .map(|p| p.data.validated && p.data.network_path == network_path)
+4486 .unwrap_or(false)
+4487 {
+4488 self.connection_close_pending = true;
+4489 }
+4490 }
+4491 }
+4492
+4493 fn process_decrypted_packet(
+4494 &mut self,
+4495 now: Instant,
+4496 network_path: FourTuple,
+4497 path_id: PathId,
+4498 number: Option<u64>,
+4499 packet: Packet,
+4500 qlog: &mut QlogRecvPacket,
+4501 ) -> Result<(), ConnectionError> {
+4502 if !self.paths.contains_key(&path_id) {
+4503 // There is a chance this is a server side, first (for this path) packet, which would
+4504 // be a protocol violation. It's more likely, however, that this is a packet of a
+4505 // pruned path
+4506 trace!(%path_id, ?number, "discarding packet for unknown path");
+4507 return Ok(());
+4508 }
+4509 let state = match self.state.as_type() {
+4510 StateType::Established => {
+4511 match packet.header.space() {
+4512 SpaceKind::Data => self.process_payload(
+4513 now,
+4514 network_path,
+4515 path_id,
+4516 number.unwrap(),
+4517 packet,
+4518 qlog,
+4519 )?,
+4520 _ if packet.header.has_frames() => {
+4521 self.process_early_payload(now, path_id, packet, qlog)?
+4522 }
+4523 _ => {
+4524 trace!("discarding unexpected pre-handshake packet");
+4525 }
+4526 }
+4527 return Ok(());
+4528 }
+4529 StateType::Closed => {
+4530 for result in frame::Iter::new(packet.payload.freeze())? {
+4531 let frame = match result {
+4532 Ok(frame) => frame,
+4533 Err(err) => {
+4534 debug!("frame decoding error: {err:?}");
+4535 continue;
+4536 }
+4537 };
+4538 qlog.frame(&frame);
+4539
+4540 if let Frame::Padding = frame {
+4541 continue;
+4542 };
+4543
+4544 trace!(?frame, "processing frame in closed state");
+4545
+4546 self.path_stats
+4547 .for_path(path_id)
+4548 .frame_rx
+4549 .record(frame.ty());
+4550
+4551 if let Frame::Close(_error) = frame {
+4552 self.state.move_to_draining(None);
+4553 self.endpoint_events.push_back(EndpointEventInner::Draining);
+4554 break;
+4555 }
+4556 }
+4557 return Ok(());
+4558 }
+4559 StateType::Draining | StateType::Drained => return Ok(()),
+4560 StateType::Handshake => self.state.as_handshake_mut().expect("checked"),
+4561 };
+4562
+4563 match packet.header {
+4564 Header::Retry {
+4565 src_cid: remote_cid,
+4566 ..
+4567 } => {
+4568 debug_assert_eq!(path_id, PathId::ZERO);
+4569 if self.side.is_server() {
+4570 return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into());
+4571 }
+4572
+4573 let is_valid_retry = self
+4574 .remote_cids
+4575 .get(&path_id)
+4576 .map(|cids| cids.active())
+4577 .map(|orig_dst_cid| {
+4578 self.crypto_state.session.is_valid_retry(
+4579 orig_dst_cid,
+4580 &packet.header_data,
+4581 &packet.payload,
+4582 )
+4583 })
+4584 .unwrap_or_default();
+4585 if self.total_authed_packets > 1
+4586 || packet.payload.len() <= 16 // token + 16 byte tag
+4587 || !is_valid_retry
+4588 {
+4589 trace!("discarding invalid Retry");
+4590 // - After the client has received and processed an Initial or Retry
+4591 // packet from the server, it MUST discard any subsequent Retry
+4592 // packets that it receives.
+4593 // - A client MUST discard a Retry packet with a zero-length Retry Token
+4594 // field.
+4595 // - Clients MUST discard Retry packets that have a Retry Integrity Tag
+4596 // that cannot be validated
+4597 return Ok(());
+4598 }
+4599
+4600 trace!("retrying with CID {}", remote_cid);
+4601 let client_hello = state.client_hello.take().unwrap();
+4602 self.retry_src_cid = Some(remote_cid);
+4603 self.remote_cids
+4604 .get_mut(&path_id)
+4605 .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false")
+4606 .update_initial_cid(remote_cid);
+4607 self.remote_handshake_cid = remote_cid;
+4608
+4609 let space = &mut self.spaces[SpaceId::Initial];
+4610 if let Some(info) = space.for_path(PathId::ZERO).take(0) {
+4611 self.on_packet_acked(now, PathId::ZERO, 0, info);
+4612 };
+4613
+4614 self.discard_space(now, SpaceKind::Initial); // Make sure we clean up after
+4615 // any retransmitted Initials
+4616 let crypto_space = &mut self.crypto_state.spaces[SpaceKind::Initial];
+4617 crypto_space.keys = Some(
+4618 self.crypto_state
+4619 .session
+4620 .initial_keys(remote_cid, self.side.side()),
+4621 );
+4622 crypto_space.crypto_offset = client_hello.len() as u64;
+4623
+4624 let next_pn = self.spaces[SpaceId::Initial]
+4625 .for_path(path_id)
+4626 .next_packet_number;
+4627 self.spaces[SpaceId::Initial] = {
+4628 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng);
+4629 space.for_path(path_id).next_packet_number = next_pn;
+4630 space.pending.crypto.push_back(frame::Crypto {
+4631 offset: 0,
+4632 data: client_hello,
+4633 });
+4634 space
+4635 };
+4636
+4637 // Retransmit all 0-RTT data
+4638 let zero_rtt = mem::take(
+4639 &mut self.spaces[SpaceId::Data]
+4640 .for_path(PathId::ZERO)
+4641 .sent_packets,
+4642 );
+4643 for (_, info) in zero_rtt.into_iter() {
+4644 self.paths
+4645 .get_mut(&PathId::ZERO)
+4646 .unwrap()
+4647 .remove_in_flight(&info);
+4648 self.spaces[SpaceId::Data].pending |= info.retransmits;
+4649 }
+4650 self.streams.retransmit_all_for_0rtt();
+4651
+4652 let token_len = packet.payload.len() - 16;
+4653 let ConnectionSide::Client { ref mut token, .. } = self.side else {
+4654 unreachable!("we already short-circuited if we're server");
+4655 };
+4656 *token = packet.payload.freeze().split_to(token_len);
+4657
+4658 self.state = State::handshake(state::Handshake {
+4659 expected_token: Bytes::new(),
+4660 remote_cid_set: false,
+4661 client_hello: None,
+4662 allow_server_migration: self.config.server_handshake_migration,
+4663 });
+4664 Ok(())
+4665 }
+4666 Header::Long {
+4667 ty: LongType::Handshake,
+4668 src_cid: remote_cid,
+4669 dst_cid: local_cid,
+4670 ..
+4671 } => {
+4672 debug_assert_eq!(path_id, PathId::ZERO);
+4673 if remote_cid != self.remote_handshake_cid {
+4674 debug!(
+4675 "discarding packet with mismatched remote CID: {} != {}",
+4676 self.remote_handshake_cid, remote_cid
+4677 );
+4678 return Ok(());
+4679 }
+4680 self.on_path_validated(path_id);
+4681
+4682 self.process_early_payload(now, path_id, packet, qlog)?;
+4683 if self.state.is_closed() {
+4684 return Ok(());
+4685 }
+4686
+4687 if self.crypto_state.session.is_handshaking() {
+4688 trace!("handshake ongoing");
+4689 return Ok(());
+4690 }
+4691
+4692 if self.side.is_client() {
+4693 // Client-only because server params were set from the client's Initial
+4694 let params = self
+4695 .crypto_state
+4696 .session
+4697 .transport_parameters()?
+4698 .ok_or_else(|| {
+4699 TransportError::new(
+4700 TransportErrorCode::crypto(0x6d),
+4701 "transport parameters missing".to_owned(),
+4702 )
+4703 })?;
+4704
+4705 if self.has_0rtt() {
+4706 if !self.crypto_state.session.early_data_accepted().unwrap() {
+4707 debug_assert!(self.side.is_client());
+4708 debug!("0-RTT rejected");
+4709 self.crypto_state.accepted_0rtt = false;
+4710 self.streams.zero_rtt_rejected();
+4711
+4712 // Discard already-queued frames
+4713 self.spaces[SpaceId::Data].pending = Retransmits::default();
+4714
+4715 // Discard 0-RTT packets
+4716 let sent_packets = mem::take(
+4717 &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets,
+4718 );
+4719 for (_, packet) in sent_packets.into_iter() {
+4720 self.paths
+4721 .get_mut(&path_id)
+4722 .unwrap()
+4723 .remove_in_flight(&packet);
+4724 }
+4725 } else {
+4726 self.crypto_state.accepted_0rtt = true;
+4727 params.validate_resumption_from(&self.peer_params)?;
+4728 }
+4729 }
+4730 if let Some(token) = params.stateless_reset_token {
+4731 let remote = self.path_data(path_id).network_path.remote;
+4732 debug_assert!(!self.state.is_drained()); // requirement for endpoint events, checked above
+4733 self.endpoint_events
+4734 .push_back(EndpointEventInner::ResetToken(path_id, remote, token));
+4735 }
+4736 self.handle_peer_params(params, local_cid, remote_cid, now)?;
+4737 self.issue_first_cids(now);
+4738 } else {
+4739 // Server-only
+4740 self.spaces[SpaceId::Data].pending.handshake_done = true;
+4741 self.discard_space(now, SpaceKind::Handshake);
+4742 self.events.push_back(Event::HandshakeConfirmed);
+4743 trace!("handshake confirmed");
+4744 }
+4745
+4746 self.events.push_back(Event::Connected);
+4747 self.state.move_to_established();
+4748 trace!("established");
+4749
+4750 // Multipath can only be enabled after the state has reached Established.
+4751 // So this can not happen any earlier.
+4752 self.issue_first_path_cids(now);
+4753 Ok(())
+4754 }
+4755 Header::Initial(InitialHeader {
+4756 src_cid: remote_cid,
+4757 dst_cid: local_cid,
+4758 ..
+4759 }) => {
+4760 debug_assert_eq!(path_id, PathId::ZERO);
+4761 if !state.remote_cid_set {
+4762 trace!("switching remote CID to {}", remote_cid);
+4763 let mut state = state.clone();
+4764 self.remote_cids
+4765 .get_mut(&path_id)
+4766 .expect("PathId::ZERO not yet abandoned")
+4767 .update_initial_cid(remote_cid);
+4768 self.remote_handshake_cid = remote_cid;
+4769 self.original_remote_cid = remote_cid;
+4770 state.remote_cid_set = true;
+4771 self.state.move_to_handshake(state);
+4772 } else if remote_cid != self.remote_handshake_cid {
+4773 debug!(
+4774 "discarding packet with mismatched remote CID: {} != {}",
+4775 self.remote_handshake_cid, remote_cid
+4776 );
+4777 return Ok(());
+4778 }
+4779
+4780 let starting_space = self.highest_space;
+4781 self.process_early_payload(now, path_id, packet, qlog)?;
+4782
+4783 if self.side.is_server()
+4784 && starting_space == SpaceKind::Initial
+4785 && self.highest_space != SpaceKind::Initial
+4786 {
+4787 let params = self
+4788 .crypto_state
+4789 .session
+4790 .transport_parameters()?
+4791 .ok_or_else(|| {
+4792 TransportError::new(
+4793 TransportErrorCode::crypto(0x6d),
+4794 "transport parameters missing".to_owned(),
+4795 )
+4796 })?;
+4797 self.handle_peer_params(params, local_cid, remote_cid, now)?;
+4798 self.issue_first_cids(now);
+4799 self.init_0rtt(now);
+4800 }
+4801 Ok(())
+4802 }
+4803 Header::Long {
+4804 ty: LongType::ZeroRtt,
+4805 ..
+4806 } => {
+4807 self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?;
+4808 Ok(())
+4809 }
+4810 Header::VersionNegotiate { .. } => {
+4811 if self.total_authed_packets > 1 {
+4812 return Ok(());
+4813 }
+4814 let supported = packet
+4815 .payload
+4816 .chunks(4)
+4817 .any(|x| match <[u8; 4]>::try_from(x) {
+4818 Ok(version) => self.version == u32::from_be_bytes(version),
+4819 Err(_) => false,
+4820 });
+4821 if supported {
+4822 return Ok(());
+4823 }
+4824 debug!("remote doesn't support our version");
+4825 Err(ConnectionError::VersionMismatch)
+4826 }
+4827 Header::Short { .. } => unreachable!(
+4828 "short packets received during handshake are discarded in handle_packet"
+4829 ),
+4830 }
+4831 }
+4832
+4833 /// Process an Initial or Handshake packet payload
+4834 fn process_early_payload(
+4835 &mut self,
+4836 now: Instant,
+4837 path_id: PathId,
+4838 packet: Packet,
+4839 #[allow(unused)] qlog: &mut QlogRecvPacket,
+4840 ) -> Result<(), TransportError> {
+4841 debug_assert_ne!(packet.header.space(), SpaceKind::Data);
+4842 debug_assert_eq!(path_id, PathId::ZERO);
+4843 let payload_len = packet.payload.len();
+4844 let mut ack_eliciting = false;
+4845 for result in frame::Iter::new(packet.payload.freeze())? {
+4846 let frame = result?;
+4847 qlog.frame(&frame);
+4848 let span = match frame {
+4849 Frame::Padding => continue,
+4850 _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)),
+4851 };
+4852
+4853 self.path_stats
+4854 .for_path(path_id)
+4855 .frame_rx
+4856 .record(frame.ty());
+4857
+4858 let _guard = span.as_ref().map(|x| x.enter());
+4859 ack_eliciting |= frame.is_ack_eliciting();
+4860
+4861 // Process frames
+4862 if frame.is_1rtt() && packet.header.space() != SpaceKind::Data {
+4863 return Err(TransportError::PROTOCOL_VIOLATION(
+4864 "illegal frame type in handshake",
+4865 ));
+4866 }
+4867
+4868 match frame {
+4869 Frame::Padding | Frame::Ping => {}
+4870 Frame::Crypto(frame) => {
+4871 self.read_crypto(packet.header.space().into(), &frame, payload_len)?;
+4872 }
+4873 Frame::Ack(ack) => {
+4874 self.on_ack_received(now, packet.header.space().into(), ack)?;
+4875 }
+4876 Frame::PathAck(ack) => {
+4877 span.as_ref()
+4878 .map(|span| span.record("path", tracing::field::display(&ack.path_id)));
+4879 self.on_path_ack_received(now, packet.header.space().into(), ack)?;
+4880 }
+4881 Frame::Close(reason) => {
+4882 self.state.move_to_draining(Some(reason.into()));
+4883 self.endpoint_events.push_back(EndpointEventInner::Draining);
+4884 return Ok(());
+4885 }
+4886 _ => {
+4887 let mut err =
+4888 TransportError::PROTOCOL_VIOLATION("illegal frame type in handshake");
+4889 err.frame = frame::MaybeFrame::Known(frame.ty());
+4890 return Err(err);
+4891 }
+4892 }
+4893 }
+4894
+4895 if ack_eliciting {
+4896 // In the initial and handshake spaces, ACKs must be sent immediately
+4897 self.spaces[packet.header.space()]
+4898 .for_path(path_id)
+4899 .pending_acks
+4900 .set_immediate_ack_required();
+4901 }
+4902
+4903 self.write_crypto();
+4904 Ok(())
+4905 }
+4906
+4907 /// Processes the decrypted packet payload, always in the data space.
+4908 fn process_payload(
+4909 &mut self,
+4910 now: Instant,
+4911 network_path: FourTuple,
+4912 path_id: PathId,
+4913 number: u64,
+4914 packet: Packet,
+4915 #[allow(unused)] qlog: &mut QlogRecvPacket,
+4916 ) -> Result<(), TransportError> {
+4917 let payload = packet.payload.freeze();
+4918 let mut is_probing_packet = true;
+4919 let mut close = None;
+4920 let payload_len = payload.len();
+4921 let mut ack_eliciting = false;
+4922 // if this packet triggers a path migration and includes a observed address frame, it's
+4923 // stored here
+4924 let mut migration_observed_addr = None;
+4925 for result in frame::Iter::new(payload)? {
+4926 let frame = result?;
+4927 qlog.frame(&frame);
+4928 let span = match frame {
+4929 Frame::Padding => continue,
+4930 _ => trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty),
+4931 };
+4932
+4933 self.path_stats
+4934 .for_path(path_id)
+4935 .frame_rx
+4936 .record(frame.ty());
+4937 // Crypto, Stream and Datagram frames are special cased in order no pollute
+4938 // the log with payload data
+4939 match &frame {
+4940 Frame::Crypto(f) => {
+4941 trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO");
+4942 }
+4943 Frame::Stream(f) => {
+4944 trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM");
+4945 }
+4946 Frame::Datagram(f) => {
+4947 trace!(len = f.data.len(), "got frame DATAGRAM");
+4948 }
+4949 f => {
+4950 trace!("got frame {f}");
+4951 }
+4952 }
+4953
+4954 let _guard = span.enter();
+4955 if packet.header.is_0rtt() {
+4956 match frame {
+4957 Frame::Crypto(_) | Frame::Close(Close::Application(_)) => {
+4958 return Err(TransportError::PROTOCOL_VIOLATION(
+4959 "illegal frame type in 0-RTT",
+4960 ));
+4961 }
+4962 _ => {
+4963 if frame.is_1rtt() {
+4964 return Err(TransportError::PROTOCOL_VIOLATION(
+4965 "illegal frame type in 0-RTT",
+4966 ));
+4967 }
+4968 }
+4969 }
+4970 }
+4971 ack_eliciting |= frame.is_ack_eliciting();
+4972
+4973 // Check whether this could be a probing packet
+4974 match frame {
+4975 Frame::Padding
+4976 | Frame::PathChallenge(_)
+4977 | Frame::PathResponse(_)
+4978 | Frame::NewConnectionId(_)
+4979 | Frame::ObservedAddr(_) => {}
+4980 _ => {
+4981 is_probing_packet = false;
+4982 }
+4983 }
+4984
+4985 match frame {
+4986 Frame::Crypto(frame) => {
+4987 self.read_crypto(SpaceId::Data, &frame, payload_len)?;
+4988 }
+4989 Frame::Stream(frame) => {
+4990 if self.streams.received(frame, payload_len)?.should_transmit() {
+4991 self.spaces[SpaceId::Data].pending.max_data = true;
+4992 }
+4993 }
+4994 Frame::Ack(ack) => {
+4995 self.on_ack_received(now, SpaceId::Data, ack)?;
+4996 }
+4997 Frame::PathAck(ack) => {
+4998 if !self.is_multipath_negotiated() {
+4999 return Err(TransportError::PROTOCOL_VIOLATION(
+5000 "received PATH_ACK frame when multipath was not negotiated",
+5001 ));
+5002 }
+5003 span.record("path", tracing::field::display(&ack.path_id));
+5004 self.on_path_ack_received(now, SpaceId::Data, ack)?;
+5005 }
+5006 Frame::Padding | Frame::Ping => {}
+5007 Frame::Close(reason) => {
+5008 close = Some(reason);
+5009 }
+5010 Frame::PathChallenge(challenge) => {
+5011 self.spaces[SpaceKind::Data]
+5012 .for_path(path_id)
+5013 .pending_path_responses
+5014 .push(number, challenge.0, network_path);
+5015 // If we were passively migrated (e.g. NAT rebinding), our local_ip will
+5016 // not match. Once we processed a non-probing packet the local_ip will
+5017 // finally be updated.
+5018 let path = &mut self
+5019 .path_mut(path_id)
+5020 .expect("payload is processed only after the path becomes known");
+5021 if network_path.remote == path.network_path.remote {
+5022 // PATH_CHALLENGE on active path, possible off-path packet
+5023 // forwarding attack. Send a non-probing packet to recover the
+5024 // active path. See
+5025 // https://www.rfc-editor.org/rfc/rfc9000.html#section-9.3.3-3. In
+5026 // rare cases NAT probes might also appear on-path and would also
+5027 // get a non-probing packet as response. There is little harm in
+5028 // this.
+5029 match self.peer_supports_ack_frequency() {
+5030 true => self.immediate_ack(path_id),
+5031 false => {
+5032 self.ping_path(path_id).ok();
+5033 }
+5034 }
+5035 }
+5036 }
+5037 Frame::PathResponse(response) => {
+5038 // First try to see if this is a NAT probe response.
+5039 if self
+5040 .n0_nat_traversal
+5041 .handle_path_response(network_path, response.0)
+5042 {
+5043 self.open_nat_traversed_paths(now);
+5044 } else {
+5045 // Try to see if this is a response to an on-path PATH_CHALLENGE.
+5046 self.handle_path_response_on_path(now, response, path_id, network_path);
+5047 }
+5048 }
+5049 Frame::MaxData(frame::MaxData(bytes)) => {
+5050 self.streams.received_max_data(bytes);
+5051 }
+5052 Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => {
+5053 self.streams.received_max_stream_data(id, offset)?;
+5054 }
+5055 Frame::MaxStreams(frame::MaxStreams { dir, count }) => {
+5056 self.streams.received_max_streams(dir, count)?;
+5057 }
+5058 Frame::ResetStream(frame) => {
+5059 if self.streams.received_reset(frame)?.should_transmit() {
+5060 self.spaces[SpaceId::Data].pending.max_data = true;
+5061 }
+5062 }
+5063 Frame::DataBlocked(DataBlocked(offset)) => {
+5064 debug!(offset, "peer claims to be blocked at connection level");
+5065 }
+5066 Frame::StreamDataBlocked(StreamDataBlocked { id, offset }) => {
+5067 if id.initiator() == self.side.side() && id.dir() == Dir::Uni {
+5068 debug!("got STREAM_DATA_BLOCKED on send-only {}", id);
+5069 return Err(TransportError::STREAM_STATE_ERROR(
+5070 "STREAM_DATA_BLOCKED on send-only stream",
+5071 ));
+5072 }
+5073 debug!(
+5074 stream = %id,
+5075 offset, "peer claims to be blocked at stream level"
+5076 );
+5077 }
+5078 Frame::StreamsBlocked(StreamsBlocked { dir, limit }) => {
+5079 if limit > MAX_STREAM_COUNT {
+5080 return Err(TransportError::FRAME_ENCODING_ERROR(
+5081 "unrepresentable stream limit",
+5082 ));
+5083 }
+5084 debug!(
+5085 "peer claims to be blocked opening more than {} {} streams",
+5086 limit, dir
+5087 );
+5088 }
+5089 Frame::StopSending(frame::StopSending { id, error_code }) => {
+5090 if id.initiator() != self.side.side() {
+5091 if id.dir() == Dir::Uni {
+5092 debug!("got STOP_SENDING on recv-only {}", id);
+5093 return Err(TransportError::STREAM_STATE_ERROR(
+5094 "STOP_SENDING on recv-only stream",
+5095 ));
+5096 }
+5097 } else if self.streams.is_local_unopened(id) {
+5098 return Err(TransportError::STREAM_STATE_ERROR(
+5099 "STOP_SENDING on unopened stream",
+5100 ));
+5101 }
+5102 self.streams.received_stop_sending(id, error_code);
+5103 }
+5104 Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => {
+5105 if let Some(ref path_id) = path_id {
+5106 span.record("path", tracing::field::display(&path_id));
+5107 }
+5108 let path_id = path_id.unwrap_or_default();
+5109 match self.local_cid_state.get_mut(&path_id) {
+5110 None => debug!(?path_id, "RETIRE_CONNECTION_ID for unknown path"),
+5111 Some(cid_state) => {
+5112 let allow_more_cids = cid_state
+5113 .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?;
+5114
+5115 // If the path has closed, we do not issue more CIDs for this path
+5116 // For details see https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-3.2.2
+5117 // > an endpoint SHOULD provide new connection IDs for that path, if still open, using PATH_NEW_CONNECTION_ID frames.
+5118 let has_path = !self.abandoned_paths.contains(&path_id);
+5119 let allow_more_cids = allow_more_cids && has_path;
+5120
+5121 debug_assert!(!self.state.is_drained()); // required for adding endpoint events, process_payload is never called for drained connections
+5122 self.endpoint_events
+5123 .push_back(EndpointEventInner::RetireConnectionId(
+5124 now,
+5125 path_id,
+5126 sequence,
+5127 allow_more_cids,
+5128 ));
+5129 }
+5130 }
+5131 }
+5132 Frame::NewConnectionId(frame) => {
+5133 let path_id = if let Some(path_id) = frame.path_id {
+5134 if !self.is_multipath_negotiated() {
+5135 return Err(TransportError::PROTOCOL_VIOLATION(
+5136 "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated",
+5137 ));
+5138 }
+5139 if path_id > self.local_max_path_id {
+5140 return Err(TransportError::PROTOCOL_VIOLATION(
+5141 "PATH_NEW_CONNECTION_ID contains path_id exceeding current max",
+5142 ));
+5143 }
+5144 path_id
+5145 } else {
+5146 PathId::ZERO
+5147 };
+5148
+5149 if let Some(ref path_id) = frame.path_id {
+5150 span.record("path", tracing::field::display(&path_id));
+5151 }
+5152
+5153 if self.abandoned_paths.contains(&path_id) {
+5154 trace!("ignoring issued CID for abandoned path");
+5155 continue;
+5156 }
+5157 let remote_cids = self
+5158 .remote_cids
+5159 .entry(path_id)
+5160 .or_insert_with(|| CidQueue::new(frame.id));
+5161 if remote_cids.active().is_empty() {
+5162 return Err(TransportError::PROTOCOL_VIOLATION(
+5163 "NEW_CONNECTION_ID when CIDs aren't in use",
+5164 ));
+5165 }
+5166 if frame.retire_prior_to > frame.sequence {
+5167 return Err(TransportError::PROTOCOL_VIOLATION(
+5168 "NEW_CONNECTION_ID retiring unissued CIDs",
+5169 ));
+5170 }
+5171
+5172 use crate::cid_queue::InsertError;
+5173 match remote_cids.insert(frame) {
+5174 Ok(None) => {
+5175 self.open_nat_traversed_paths(now);
+5176 }
+5177 Ok(Some((retired, reset_token))) => {
+5178 let pending_retired =
+5179 &mut self.spaces[SpaceId::Data].pending.retire_cids;
+5180 /// Ensure `pending_retired` cannot grow without bound. Limit is
+5181 /// somewhat arbitrary but very permissive.
+5182 const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10;
+5183 // We don't bother counting in-flight frames because those are bounded
+5184 // by congestion control.
+5185 if (pending_retired.len() as u64)
+5186 .saturating_add(retired.end.saturating_sub(retired.start))
+5187 > MAX_PENDING_RETIRED_CIDS
+5188 {
+5189 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(
+5190 "queued too many retired CIDs",
+5191 ));
+5192 }
+5193 pending_retired.extend(retired.map(|seq| (path_id, seq)));
+5194 self.set_reset_token(path_id, network_path.remote, reset_token);
+5195 self.open_nat_traversed_paths(now);
+5196 }
+5197 Err(InsertError::ExceedsLimit) => {
+5198 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(""));
+5199 }
+5200 Err(InsertError::Retired) => {
+5201 trace!("discarding already-retired");
+5202 // RETIRE_CONNECTION_ID might not have been previously sent if e.g. a
+5203 // range of connection IDs larger than the active connection ID limit
+5204 // was retired all at once via retire_prior_to.
+5205 self.spaces[SpaceId::Data]
+5206 .pending
+5207 .retire_cids
+5208 .push((path_id, frame.sequence));
+5209 continue;
+5210 }
+5211 };
+5212
+5213 if self.side.is_server()
+5214 && path_id == PathId::ZERO
+5215 && self
+5216 .remote_cids
+5217 .get(&PathId::ZERO)
+5218 .map(|cids| cids.active_seq() == 0)
+5219 .unwrap_or_default()
+5220 {
+5221 // We're a server still using the initial remote CID for the client, so
+5222 // let's switch immediately to enable clientside stateless resets.
+5223 self.update_remote_cid(PathId::ZERO);
+5224 }
+5225 }
+5226 Frame::NewToken(NewToken { token }) => {
+5227 let ConnectionSide::Client {
+5228 token_store,
+5229 server_name,
+5230 ..
+5231 } = &self.side
+5232 else {
+5233 return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN"));
+5234 };
+5235 if token.is_empty() {
+5236 return Err(TransportError::FRAME_ENCODING_ERROR("empty token"));
+5237 }
+5238 trace!("got new token");
+5239 token_store.insert(server_name, token);
+5240 }
+5241 Frame::Datagram(datagram) => {
+5242 if self
+5243 .datagrams
+5244 .received(datagram, &self.config.datagram_receive_buffer_size)?
+5245 {
+5246 self.events.push_back(Event::DatagramReceived);
+5247 }
+5248 }
+5249 Frame::AckFrequency(ack_frequency) => {
+5250 // This frame can only be sent in the Data space
+5251
+5252 if !self.ack_frequency.ack_frequency_received(&ack_frequency)? {
+5253 // The AckFrequency frame is stale (we have already received a more
+5254 // recent one)
+5255 continue;
+5256 }
+5257
+5258 // Update the params for all of our paths
+5259 for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() {
+5260 space.pending_acks.set_ack_frequency_params(&ack_frequency);
+5261
+5262 // Our `max_ack_delay` has been updated, so we may need to adjust
+5263 // its associated timeout.
+5264 // Packets received on abandoned paths are always acknowledged immediately.
+5265 if !self.abandoned_paths.contains(path_id)
+5266 && let Some(timeout) = space
+5267 .pending_acks
+5268 .max_ack_delay_timeout(self.ack_frequency.max_ack_delay)
+5269 {
+5270 self.timers.set(
+5271 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
+5272 timeout,
+5273 self.qlog.with_time(now),
+5274 );
+5275 }
+5276 }
+5277 }
+5278 Frame::ImmediateAck => {
+5279 // This frame can only be sent in the Data space
+5280 for pns in self.spaces[SpaceId::Data].iter_paths_mut() {
+5281 pns.pending_acks.set_immediate_ack_required();
+5282 }
+5283 }
+5284 Frame::HandshakeDone => {
+5285 if self.side.is_server() {
+5286 return Err(TransportError::PROTOCOL_VIOLATION(
+5287 "client sent HANDSHAKE_DONE",
+5288 ));
+5289 }
+5290 if self.crypto_state.has_keys(EncryptionLevel::Handshake) {
+5291 self.discard_space(now, SpaceKind::Handshake);
+5292 self.events.push_back(Event::HandshakeConfirmed);
+5293 trace!("handshake confirmed");
+5294 }
+5295 }
+5296 Frame::ObservedAddr(observed) => {
+5297 // check if params allows the peer to send report and this node to receive it
+5298 trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port);
+5299 if !self
+5300 .peer_params
+5301 .address_discovery_role
+5302 .should_report(&self.config.address_discovery_role)
+5303 {
+5304 return Err(TransportError::PROTOCOL_VIOLATION(
+5305 "received OBSERVED_ADDRESS frame when not negotiated",
+5306 ));
+5307 }
+5308 // must only be sent in data space
+5309 if packet.header.space() != SpaceKind::Data {
+5310 return Err(TransportError::PROTOCOL_VIOLATION(
+5311 "OBSERVED_ADDRESS frame outside data space",
+5312 ));
+5313 }
+5314
+5315 let space_open_status =
+5316 self.spaces[SpaceKind::Data].for_path(path_id).open_status;
+5317 let path = self.path_data_mut(path_id);
+5318 if path.network_path.remote == network_path.remote {
+5319 if let Some(updated) = path.update_observed_addr_report(observed)
+5320 && space_open_status == OpenStatus::Informed
+5321 {
+5322 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
+5323 id: path_id,
+5324 addr: updated,
+5325 }));
+5326 // otherwise the event is reported when the path is deemed open
+5327 }
+5328 } else {
+5329 // include in migration
+5330 migration_observed_addr = Some(observed)
+5331 }
+5332 }
+5333 Frame::PathAbandon(frame::PathAbandon {
+5334 path_id,
+5335 error_code,
+5336 }) => {
+5337 span.record("path", tracing::field::display(&path_id));
+5338 match self.close_path_inner(
+5339 now,
+5340 path_id,
+5341 PathAbandonReason::RemoteAbandoned {
+5342 error_code: error_code.into(),
+5343 },
+5344 ) {
+5345 Ok(()) => {
+5346 trace!("peer abandoned path");
+5347 }
+5348 Err(ClosePathError::ClosedPath) => {
+5349 trace!("peer abandoned already closed path");
+5350 }
+5351 Err(ClosePathError::MultipathNotNegotiated) => {
+5352 return Err(TransportError::PROTOCOL_VIOLATION(
+5353 "received PATH_ABANDON frame when multipath was not negotiated",
+5354 ));
+5355 }
+5356 Err(ClosePathError::LastOpenPath) => {
+5357 // Not reachable: close_path_inner allows remote abandons
+5358 // for the last path. But handle gracefully just in case.
+5359 error!(
+5360 "peer abandoned last path but close_path_inner returned LastOpenPath"
+5361 );
+5362 }
+5363 };
+5364
+5365 // Start draining the path if it still exists and hasn't started draining yet.
+5366 if let Some(path) = self.paths.get_mut(&path_id)
+5367 && !mem::replace(&mut path.data.draining, true)
+5368 {
+5369 let ack_delay = self.ack_frequency.max_ack_delay_for_pto();
+5370 let pto = path.data.rtt.pto_base() + ack_delay;
+5371 self.timers.set(
+5372 Timer::PerPath(path_id, PathTimer::PathDrained),
+5373 now + 3 * pto,
+5374 self.qlog.with_time(now),
+5375 );
+5376
+5377 self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8));
+5378 }
+5379 }
+5380 Frame::PathStatusAvailable(info) => {
+5381 span.record("path", tracing::field::display(&info.path_id));
+5382 if self.is_multipath_negotiated() {
+5383 self.on_path_status(
+5384 info.path_id,
+5385 PathStatus::Available,
+5386 info.status_seq_no,
+5387 );
+5388 } else {
+5389 return Err(TransportError::PROTOCOL_VIOLATION(
+5390 "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated",
+5391 ));
+5392 }
+5393 }
+5394 Frame::PathStatusBackup(info) => {
+5395 span.record("path", tracing::field::display(&info.path_id));
+5396 if self.is_multipath_negotiated() {
+5397 self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no);
+5398 } else {
+5399 return Err(TransportError::PROTOCOL_VIOLATION(
+5400 "received PATH_STATUS_BACKUP frame when multipath was not negotiated",
+5401 ));
+5402 }
+5403 }
+5404 Frame::MaxPathId(frame::MaxPathId(path_id)) => {
+5405 span.record("path", tracing::field::display(&path_id));
+5406 if !self.is_multipath_negotiated() {
+5407 return Err(TransportError::PROTOCOL_VIOLATION(
+5408 "received MAX_PATH_ID frame when multipath was not negotiated",
+5409 ));
+5410 }
+5411 // frames that do not increase the path id are ignored
+5412 if path_id > self.remote_max_path_id {
+5413 self.remote_max_path_id = path_id;
+5414 self.issue_first_path_cids(now);
+5415 self.open_nat_traversed_paths(now);
+5416 }
+5417 }
+5418 Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => {
+5419 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST
+5420 // be treated as a connection error of type PROTOCOL_VIOLATION.
+5421 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids>
+5422 if self.is_multipath_negotiated() {
+5423 if max_path_id > self.local_max_path_id {
+5424 return Err(TransportError::PROTOCOL_VIOLATION(
+5425 "PATHS_BLOCKED maximum path identifier was larger than local maximum",
+5426 ));
+5427 }
+5428 } else {
+5429 return Err(TransportError::PROTOCOL_VIOLATION(
+5430 "received PATHS_BLOCKED frame when not multipath was not negotiated",
+5431 ));
+5432 }
+5433 }
+5434 Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => {
+5435 // Nothing to do. This is recorded in the frame stats, but otherwise we
+5436 // always issue all CIDs we're allowed to issue, so either this is an
+5437 // impatient peer or a bug on our side.
+5438
+5439 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST
+5440 // be treated as a connection error of type PROTOCOL_VIOLATION.
+5441 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids>
+5442 if self.is_multipath_negotiated() {
+5443 if path_id > self.local_max_path_id {
+5444 return Err(TransportError::PROTOCOL_VIOLATION(
+5445 "PATH_CIDS_BLOCKED path identifier was larger than local maximum",
+5446 ));
+5447 }
+5448 if self
+5449 .local_cid_state
+5450 .get(&path_id)
+5451 // The PATH_CIDS_BLOCKED frame may arrive after we've discarded the path state.
+5452 // In that case, we can't check for the protocol violation.
+5453 .is_some_and(|cid_state| next_seq.0 > cid_state.active_seq().1 + 1)
+5454 {
+5455 return Err(TransportError::PROTOCOL_VIOLATION(
+5456 "PATH_CIDS_BLOCKED next sequence number larger than in local state",
+5457 ));
+5458 }
+5459 debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED");
+5460 } else {
+5461 return Err(TransportError::PROTOCOL_VIOLATION(
+5462 "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated",
+5463 ));
+5464 }
+5465 }
+5466 Frame::AddAddress(addr) => {
+5467 let client_state = match self.n0_nat_traversal.client_side_mut() {
+5468 Ok(state) => state,
+5469 Err(err) => {
+5470 return Err(TransportError::PROTOCOL_VIOLATION(format!(
+5471 "Nat traversal(ADD_ADDRESS): {err}"
+5472 )));
+5473 }
+5474 };
+5475
+5476 if !client_state.check_remote_address(&addr) {
+5477 // if the address is not valid we flag it, but update anyway
+5478 warn!(?addr, "server sent illegal ADD_ADDRESS frame");
+5479 }
+5480
+5481 match client_state.add_remote_address(addr) {
+5482 Ok(maybe_added) => {
+5483 if let Some(added) = maybe_added {
+5484 self.events.push_back(Event::NatTraversal(
+5485 n0_nat_traversal::Event::AddressAdded(added),
+5486 ));
+5487 }
+5488 }
+5489 Err(e) => {
+5490 warn!(%e, "failed to add remote address")
+5491 }
+5492 }
+5493 }
+5494 Frame::RemoveAddress(addr) => {
+5495 let client_state = match self.n0_nat_traversal.client_side_mut() {
+5496 Ok(state) => state,
+5497 Err(err) => {
+5498 return Err(TransportError::PROTOCOL_VIOLATION(format!(
+5499 "Nat traversal(REMOVE_ADDRESS): {err}"
+5500 )));
+5501 }
+5502 };
+5503 if let Some(removed_addr) = client_state.remove_remote_address(addr) {
+5504 self.events.push_back(Event::NatTraversal(
+5505 n0_nat_traversal::Event::AddressRemoved(removed_addr),
+5506 ));
+5507 }
+5508 }
+5509 Frame::ReachOut(reach_out) => {
+5510 let ipv6 = self.is_ipv6();
+5511 let server_state = match self.n0_nat_traversal.server_side_mut() {
+5512 Ok(state) => state,
+5513 Err(err) => {
+5514 return Err(TransportError::PROTOCOL_VIOLATION(format!(
+5515 "Nat traversal(REACH_OUT): {err}"
+5516 )));
+5517 }
+5518 };
+5519
+5520 let round_before = server_state.current_round();
+5521
+5522 if let Err(err) = server_state.handle_reach_out(reach_out, ipv6) {
+5523 return Err(TransportError::PROTOCOL_VIOLATION(format!(
+5524 "Nat traversal(REACH_OUT): {err}"
+5525 )));
+5526 }
+5527
+5528 if server_state.current_round() > round_before {
+5529 // A new round was started, reset the NAT probe retry timer.
+5530 if let Some(delay) =
+5531 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
+5532 {
+5533 self.timers.set(
+5534 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
+5535 now + delay,
+5536 self.qlog.with_time(now),
+5537 );
+5538 }
+5539 }
+5540 }
+5541 }
+5542 }
+5543
+5544 let space = self.spaces[SpaceId::Data].for_path(path_id);
+5545 if space
+5546 .pending_acks
+5547 .packet_received(now, number, ack_eliciting, &space.dedup)
+5548 {
+5549 if self.abandoned_paths.contains(&path_id) {
+5550 // § 3.4.3 QUIC-MULTIPATH: promptly send ACKs for packets received from
+5551 // abandoned paths.
+5552 space.pending_acks.set_immediate_ack_required();
+5553 } else {
+5554 self.timers.set(
+5555 Timer::PerPath(path_id, PathTimer::MaxAckDelay),
+5556 now + self.ack_frequency.max_ack_delay,
+5557 self.qlog.with_time(now),
+5558 );
+5559 }
+5560 }
+5561
+5562 // Issue stream ID credit due to ACKs of outgoing finish/resets and incoming finish/resets
+5563 // on stopped streams. Incoming finishes/resets on open streams are not handled here as they
+5564 // are only freed, and hence only issue credit, once the application has been notified
+5565 // during a read on the stream.
+5566 let pending = &mut self.spaces[SpaceId::Data].pending;
+5567 self.streams.queue_max_stream_id(pending);
+5568
+5569 if let Some(reason) = close {
+5570 self.state.move_to_draining(Some(reason.into()));
+5571 self.endpoint_events.push_back(EndpointEventInner::Draining);
+5572 self.connection_close_pending = true;
+5573 }
+5574
+5575 // For Multipath any packet triggers migration. For RFC9000 or QNT (+ Multipath)
+5576 // only non-probing packets trigger migration.
+5577 let migrate_on_any_packet =
+5578 self.is_multipath_negotiated() && !self.n0_nat_traversal.is_negotiated();
+5579
+5580 // Only migrate if this is the largest packet number seen.
+5581 let is_largest_received_pn = Some(number)
+5582 == self.spaces[SpaceId::Data]
+5583 .for_path(path_id)
+5584 .largest_received_packet_number;
+5585
+5586 // If we receive a non-probing packet on a new local IP that means we had a NAT
+5587 // rebinding-like migration. We update our local address but do not otherwise
+5588 // validate the new path, we only need to validate the path if the peer migrates per
+5589 // RFC9000 §9: https://www.rfc-editor.org/rfc/rfc9000.html#section-9-4
+5590 if (migrate_on_any_packet || !is_probing_packet)
+5591 && is_largest_received_pn
+5592 && self.local_ip_may_migrate()
+5593 && let Some(new_local_ip) = network_path.local_ip
+5594 {
+5595 let path_data = self.path_data_mut(path_id);
+5596 if path_data
+5597 .network_path
+5598 .local_ip
+5599 .is_some_and(|ip| ip != new_local_ip)
+5600 {
+5601 debug!(
+5602 %path_id,
+5603 new_4tuple = %network_path,
+5604 prev_4tuple = %path_data.network_path,
+5605 "local address passive migration"
+5606 );
+5607 }
+5608 path_data.network_path.local_ip = Some(new_local_ip)
+5609 }
+5610
+5611 // If the peer migrated to a new address, trigger migration.
+5612 if self.peer_may_migrate()
+5613 && (migrate_on_any_packet || !is_probing_packet)
+5614 && is_largest_received_pn
+5615 && network_path.remote != self.path_data(path_id).network_path.remote
+5616 {
+5617 self.migrate(path_id, now, network_path, migration_observed_addr);
+5618 // Break linkability, if possible
+5619 self.update_remote_cid(path_id);
+5620 self.spin = false;
+5621 }
+5622
+5623 Ok(())
+5624 }
+5625
+5626 /// Handles any on-path PATH_RESPONSE frames.
+5627 ///
+5628 /// *path_id* and *network_path* are those on which the PATH_RESPONSE was received.
+5629 fn handle_path_response_on_path(
+5630 &mut self,
+5631 now: Instant,
+5632 response: frame::PathResponse,
+5633 path_id: PathId,
+5634 network_path: FourTuple,
+5635 ) {
+5636 let is_multipath_negotiated = self.is_multipath_negotiated();
+5637 let path = self
+5638 .paths
+5639 .get_mut(&path_id)
+5640 .expect("payload is processed only after the path becomes known");
+5641 match path
+5642 .data
+5643 .on_path_response_received(now, response.0, network_path)
+5644 {
+5645 paths::OnPathResponseReceived::OnPath if !self.abandoned_paths.contains(&path_id) => {
+5646 let qlog = self.qlog.with_time(now);
+5647 self.timers.stop(
+5648 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
+5649 qlog.clone(),
+5650 );
+5651 self.timers.stop(
+5652 Timer::PerPath(path_id, PathTimer::AbandonFromValidation),
+5653 qlog.clone(),
+5654 );
+5655 let next_challenge = path
+5656 .data
+5657 .earliest_on_path_expiring_challenge()
+5658 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto());
+5659 self.timers.set_or_stop(
+5660 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
+5661 next_challenge,
+5662 qlog,
+5663 );
+5664 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
+5665 if !matches!(pns.open_status, OpenStatus::Informed) {
+5666 if is_multipath_negotiated {
+5667 self.events
+5668 .push_back(Event::Path(PathEvent::Established { id: path_id }));
+5669 }
+5670 pns.open_status = OpenStatus::Informed;
+5671 if let Some(observed) = path.data.last_observed_addr_report.as_ref() {
+5672 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
+5673 id: path_id,
+5674 addr: observed.socket_addr(),
+5675 }));
+5676 }
+5677 }
+5678 if let Some((_, ref mut prev)) = path.prev {
+5679 // If an on-path response was received while there is a
+5680 // previous path from a migration, then the new path is
+5681 // validated and we can stop sending challenges that try to
+5682 // re-validate the previous path.
+5683 prev.reset_on_path_challenges();
+5684 }
+5685 }
+5686 paths::OnPathResponseReceived::OnPath => {
+5687 trace!(
+5688 %response,
+5689 "ignoring PATH_RESPONSE received after path is abandoned"
+5690 );
+5691 }
+5692 paths::OnPathResponseReceived::Unknown => {
+5693 debug!(%response, "ignoring invalid PATH_RESPONSE");
+5694 }
+5695 paths::OnPathResponseReceived::Ignored {
+5696 sent_on,
+5697 current_path,
+5698 } => {
+5699 debug!(%sent_on, %current_path, %response, "ignoring valid PATH_RESPONSE");
+5700 }
+5701 }
+5702 }
+5703
+5704 /// Opens any paths that have been successfully NAT traversed.
+5705 fn open_nat_traversed_paths(&mut self, now: Instant) {
+5706 while let Some(network_path) = self
+5707 .n0_nat_traversal
+5708 .client_side_mut()
+5709 .ok()
+5710 .and_then(|s| s.pop_pending_path_open())
+5711 {
+5712 match self.open_path_ensure(network_path, PathStatus::Backup, now) {
+5713 Ok((path_id, already_existed)) => {
+5714 debug!(
+5715 %path_id,
+5716 ?network_path,
+5717 new_path = !already_existed,
+5718 "Opened NAT traversal path",
+5719 );
+5720 }
+5721 Err(err) => match err {
+5722 PathError::MultipathNotNegotiated
+5723 | PathError::ServerSideNotAllowed
+5724 | PathError::ValidationFailed
+5725 | PathError::InvalidRemoteAddress(_) => {
+5726 error!(
+5727 ?err,
+5728 ?network_path,
+5729 "Failed to open path for successful NAT traversal"
+5730 );
+5731 }
+5732 PathError::MaxPathIdReached | PathError::RemoteCidsExhausted => {
+5733 // Temporary error, put back.
+5734 self.n0_nat_traversal
+5735 .client_side_mut()
+5736 .map(|s| s.push_pending_path_open(network_path))
+5737 .ok();
+5738 debug!(
+5739 ?err,
+5740 ?network_path,
+5741 "Blocked opening NAT traversal path, enqueued"
+5742 );
+5743 return;
+5744 }
+5745 },
+5746 }
+5747 }
+5748 }
+5749
+5750 /// Migrates the 4-tuple of the path.
+5751 ///
+5752 /// This creates a new [`PathData`] for the migrated path and stores the previous
+5753 /// [`PathData`] in [`PathState::prev`].
+5754 fn migrate(
+5755 &mut self,
+5756 path_id: PathId,
+5757 now: Instant,
+5758 network_path: FourTuple,
+5759 observed_addr: Option<ObservedAddr>,
+5760 ) {
+5761 trace!(
+5762 new_4tuple = %network_path,
+5763 prev_4tuple = %self.path_data(path_id).network_path,
+5764 %path_id,
+5765 "migration initiated",
+5766 );
+5767 self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
+5768 // TODO(@divma): conditions for path migration in multipath are very specific, check them
+5769 // again to prevent path migrations that should actually create a new path
+5770
+5771 // Reset rtt/congestion state for new path unless it looks like a NAT rebinding.
+5772 // Note that the congestion window will not grow until validation terminates. Helps mitigate
+5773 // amplification attacks performed by spoofing source addresses.
+5774 let prev_pto = self.pto(SpaceKind::Data, path_id);
+5775 let path = self.paths.get_mut(&path_id).expect("known path");
+5776 let mut new_path_data = if network_path.remote.is_ipv4()
+5777 && network_path.remote.ip() == path.data.network_path.remote.ip()
+5778 {
+5779 PathData::from_previous(network_path, &path.data, self.path_generation_counter, now)
+5780 } else {
+5781 let peer_max_udp_payload_size =
+5782 u16::try_from(self.peer_params.max_udp_payload_size.into_inner())
+5783 .unwrap_or(u16::MAX);
+5784 PathData::new(
+5785 network_path,
+5786 self.allow_mtud,
+5787 Some(peer_max_udp_payload_size),
+5788 self.path_generation_counter,
+5789 now,
+5790 &self.config,
+5791 )
+5792 };
+5793 new_path_data.last_observed_addr_report = path.data.last_observed_addr_report.clone();
+5794 if let Some(report) = observed_addr
+5795 && let Some(updated) = new_path_data.update_observed_addr_report(report)
+5796 {
+5797 tracing::info!("adding observed addr event from migration");
+5798 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
+5799 id: path_id,
+5800 addr: updated,
+5801 }));
+5802 }
+5803 new_path_data.pending_challenge = true;
+5804 new_path_data.pending.observed_address = self
+5805 .config
+5806 .address_discovery_role
+5807 .should_report(&self.peer_params.address_discovery_role);
+5808
+5809 let mut prev_path_data = mem::replace(&mut path.data, new_path_data);
+5810
+5811 // Only store this as previous path if it was validated. For all we know there could
+5812 // already be a previous path stored which might have been validated in the past,
+5813 // which is more valuable than one that's not yet validated.
+5814 //
+5815 // With multipath it is possible that there are no remote CIDs for the path ID
+5816 // yet. In this case we would never have sent on this path yet and would not be able
+5817 // to send a PATH_CHALLENGE either, which is currently a fire-and-forget affair
+5818 // anyway. So don't store such a path either.
+5819 if !prev_path_data.validated
+5820 && let Some(cid) = self.remote_cids.get(&path_id).map(CidQueue::active)
+5821 {
+5822 prev_path_data.pending_challenge = true;
+5823 // We haven't updated the remote CID yet, this captures the remote CID we were using on
+5824 // the previous path.
+5825 path.prev = Some((cid, prev_path_data));
+5826 }
+5827
+5828 // We need to re-assign the correct remote to this path in qlog
+5829 self.qlog.emit_tuple_assigned(path_id, network_path, now);
+5830
+5831 self.timers.set(
+5832 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
+5833 now + 3 * cmp::max(self.pto(SpaceKind::Data, path_id), prev_pto),
+5834 self.qlog.with_time(now),
+5835 );
+5836 }
+5837
+5838 /// Handle a change in the local address, i.e. an active migration
+5839 ///
+5840 /// In the general (non-multipath) case, paths will perform a RFC9000 migration and be pinged
+5841 /// for a liveness check. This is the behaviour of a path assumed to be recoverable, even if
+5842 /// this is not the case.
+5843 ///
+5844 /// Clients in a connection in which multipath has been negotiated should migrate paths to new
+5845 /// [`PathId`]s. For paths that are known to be non-recoverable can be migrated to a new
+5846 /// [`PathId`] by closing the current path, and opening a new one to the same remote. Treating
+5847 /// paths as non recoverable when necessary accelerates connectivity re-establishment, or might
+5848 /// allow it altogether.
+5849 ///
+5850 /// The optional `hint` allows callers to indicate when paths are non-recoverable and should be
+5851 /// migrated to new a [`PathId`].
+5852 // NOTE: only clients are allowed to migrate, but generally dealing with RFC9000 migrations is
+5853 // lacking <https://github.com/n0-computer/noq/issues/364>
+5854 pub fn handle_network_change(&mut self, hint: Option<&dyn NetworkChangeHint>, now: Instant) {
+5855 debug!("network changed");
+5856 if self.state.is_drained() {
+5857 return;
+5858 }
+5859 if self.highest_space < SpaceKind::Data {
+5860 for path in self.paths.values_mut() {
+5861 // Clear the local address for it to be obtained from the socket again.
+5862 path.data.network_path.local_ip = None;
+5863 }
+5864
+5865 self.update_remote_cid(PathId::ZERO);
+5866 self.ping();
+5867
+5868 return;
+5869 }
+5870
+5871 // Paths that can't recover so a new path should be open instead. If multipath is not
+5872 // negotiated, this will be empty.
+5873 let mut non_recoverable_paths = Vec::default();
+5874 let mut recoverable_paths = Vec::default();
+5875 let mut open_paths = 0;
+5876
+5877 let is_multipath_negotiated = self.is_multipath_negotiated();
+5878 let is_client = self.side().is_client();
+5879 let immediate_ack_allowed = self.peer_supports_ack_frequency();
+5880
+5881 for (path_id, path) in self.paths.iter_mut() {
+5882 if self.abandoned_paths.contains(path_id) {
+5883 continue;
+5884 }
+5885 open_paths += 1;
+5886
+5887 // Read the network path BEFORE clearing local_ip, so the hint can
+5888 // check which interface the path was using.
+5889 let network_path = path.data.network_path;
+5890
+5891 // Clear the local address for it to be obtained from the socket again. This applies to
+5892 // all paths, regardless of being considered recoverable or not
+5893 path.data.network_path.local_ip = None;
+5894 let remote = network_path.remote;
+5895
+5896 // Without multipath, the connection tries to recover the single path, whereas with
+5897 // multipath, even in a single-path scenario, we attempt to migrate the path to a new
+5898 // PathId.
+5899 let attempt_to_recover = if is_multipath_negotiated {
+5900 // Use the hint to determine if the path can recover. When no hint is
+5901 // provided, clients default to non-recoverable (abandon and re-open)
+5902 // while servers default to recoverable (attempt in-place recovery).
+5903 hint.map(|h| h.is_path_recoverable(*path_id, network_path))
+5904 .unwrap_or(!is_client)
+5905 } else {
+5906 // In the non multipath case, we try to recover the single active path
+5907 true
+5908 };
+5909
+5910 if attempt_to_recover {
+5911 recoverable_paths.push((*path_id, remote));
+5912 } else {
+5913 non_recoverable_paths.push((*path_id, remote, path.data.local_status()))
+5914 }
+5915 }
+5916
+5917 /* NON RECOVERABLE PATHS */
+5918 // This are handled first, so that in case the treatment intended for these fails, we can
+5919 // go the recoverable route instead.
+5920
+5921 // Decide if we need to close first or open first in the multipath case.
+5922 // - Opening first has a higher risk of getting limited by the negotiated MAX_PATH_ID.
+5923 // - Closing first risks this being the only open path.
+5924 // We prefer closing paths first unless we identify this is the last open path.
+5925 let open_first = open_paths == non_recoverable_paths.len();
+5926
+5927 for (path_id, remote, status) in non_recoverable_paths.into_iter() {
+5928 let network_path = FourTuple {
+5929 remote,
+5930 local_ip: None, /* allow the local ip to be discovered */
+5931 };
+5932
+5933 if open_first && let Err(e) = self.open_path(network_path, status, now) {
+5934 if self.side().is_client() {
+5935 debug!(%e, "Failed to open new path for network change");
+5936 }
+5937 // if this fails, let the path try to recover itself
+5938 recoverable_paths.push((path_id, remote));
+5939 continue;
+5940 }
+5941
+5942 if let Err(e) =
+5943 self.close_path_inner(now, path_id, PathAbandonReason::UnusableAfterNetworkChange)
+5944 {
+5945 debug!(%e,"Failed to close unrecoverable path after network change");
+5946 recoverable_paths.push((path_id, remote));
+5947 continue;
+5948 }
+5949
+5950 if !open_first && let Err(e) = self.open_path(network_path, status, now) {
+5951 // Path has already been closed if we got here. Since the path was not recoverable,
+5952 // this might be desirable in any case, because other paths exist (!open_first) and
+5953 // this was is considered non recoverable
+5954 debug!(%e,"Failed to open new path for network change");
+5955 }
+5956 }
+5957
+5958 /* RECOVERABLE PATHS */
+5959
+5960 for (path_id, remote) in recoverable_paths.into_iter() {
+5961 // Schedule a Ping for a liveness check.
+5962 if let Some(path_space) = self.spaces[SpaceId::Data].number_spaces.get_mut(&path_id) {
+5963 path_space.pending_ping = true;
+5964
+5965 if immediate_ack_allowed {
+5966 path_space.pending_immediate_ack = true;
+5967 }
+5968 }
+5969
+5970 // Reset PTO backoff so retransmits resume promptly. Congestion controller and
+5971 // RTT are intentionally preserved for recoverable paths. We explicitly allow
+5972 // this reset also during the handshake, so do not check
+5973 // Self::peer_competed_handshake_address_validation.
+5974 if let Some(path) = self.paths.get_mut(&path_id) {
+5975 path.data.pto_count = 0;
+5976 }
+5977 self.set_loss_detection_timer(now, path_id);
+5978
+5979 let Some((reset_token, retired)) =
+5980 self.remote_cids.get_mut(&path_id).and_then(CidQueue::next)
+5981 else {
+5982 continue;
+5983 };
+5984
+5985 // Retire the current remote CID and any CIDs we had to skip.
+5986 self.spaces[SpaceId::Data]
+5987 .pending
+5988 .retire_cids
+5989 .extend(retired.map(|seq| (path_id, seq)));
+5990
+5991 debug_assert!(!self.state.is_drained()); // required for endpoint_events, checked above
+5992 self.endpoint_events
+5993 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
+5994 }
+5995 }
+5996
+5997 /// Switch to a previously unused remote connection ID, if possible
+5998 fn update_remote_cid(&mut self, path_id: PathId) {
+5999 let Some((reset_token, retired)) = self
+6000 .remote_cids
+6001 .get_mut(&path_id)
+6002 .and_then(|cids| cids.next())
+6003 else {
+6004 return;
+6005 };
+6006
+6007 // Retire the current remote CID and any CIDs we had to skip.
+6008 self.spaces[SpaceId::Data]
+6009 .pending
+6010 .retire_cids
+6011 .extend(retired.map(|seq| (path_id, seq)));
+6012 let remote = self.path_data(path_id).network_path.remote;
+6013 self.set_reset_token(path_id, remote, reset_token);
+6014 }
+6015
+6016 /// Sends this reset token to the endpoint
+6017 ///
+6018 /// The endpoint needs to know the reset tokens issued by the peer, so that if the peer
+6019 /// sends a reset token it knows to route it to this connection. See RFC 9000 section
+6020 /// 10.3. Stateless Reset.
+6021 ///
+6022 /// Reset tokens are different for each path, the endpoint identifies paths by peer
+6023 /// socket address however, not by path ID.
+6024 fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) {
+6025 debug_assert!(!self.state.is_drained()); // required for endpoint events, set_reset_token is never called for drained connections
+6026 self.endpoint_events
+6027 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
+6028
+6029 // During the handshake the server sends a reset token in the transport
+6030 // parameters. When we are the client and we receive the reset token during the
+6031 // handshake we want this to affect our peer transport parameters.
+6032 // TODO(flub): Pretty sure this is pointless, the entire params is overwritten
+6033 // shortly after this was called. And then the params don't have this anymore.
+6034 if path_id == PathId::ZERO {
+6035 self.peer_params.stateless_reset_token = Some(reset_token);
+6036 }
+6037 }
+6038
+6039 /// Issue an initial set of connection IDs to the peer upon connection
+6040 fn issue_first_cids(&mut self, now: Instant) {
+6041 if self
+6042 .local_cid_state
+6043 .get(&PathId::ZERO)
+6044 .expect("PathId::ZERO exists when the connection is created")
+6045 .cid_len()
+6046 == 0
+6047 {
+6048 return;
+6049 }
+6050
+6051 // Subtract 1 to account for the CID we supplied while handshaking
+6052 let mut n = self.peer_params.issue_cids_limit() - 1;
+6053 if let ConnectionSide::Server { server_config } = &self.side
+6054 && server_config.has_preferred_address()
+6055 {
+6056 // We also sent a CID in the transport parameters
+6057 n -= 1;
+6058 }
+6059 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events
+6060 self.endpoint_events
+6061 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
+6062 }
+6063
+6064 /// Issues an initial set of CIDs for paths that have not yet had any CIDs issued
+6065 ///
+6066 /// Later CIDs are issued when CIDs expire or are retired by the peer.
+6067 fn issue_first_path_cids(&mut self, now: Instant) {
+6068 if let Some(max_path_id) = self.max_path_id() {
+6069 let mut path_id = self.max_path_id_with_cids.next();
+6070 while path_id <= max_path_id {
+6071 self.endpoint_events
+6072 .push_back(EndpointEventInner::NeedIdentifiers(
+6073 path_id,
+6074 now,
+6075 self.peer_params.issue_cids_limit(),
+6076 ));
+6077 path_id = path_id.next();
+6078 }
+6079 self.max_path_id_with_cids = max_path_id;
+6080 }
+6081 }
+6082
+6083 /// Populates a packet with frames
+6084 ///
+6085 /// This tries to fit as many frames as possible into the packet.
+6086 ///
+6087 /// *path_exclusive_only* means to only build frames which can only be sent on this
+6088 /// *path. This is used in multipath for backup paths while there is still an active
+6089 /// *path.
+6090 fn populate_packet<'a, 'b>(
+6091 &mut self,
+6092 now: Instant,
+6093 space_id: SpaceId,
+6094 path_id: PathId,
+6095 scheduling_info: &PathSchedulingInfo,
+6096 builder: &mut PacketBuilder<'a, 'b>,
+6097 ) {
+6098 let is_multipath_negotiated = self.is_multipath_negotiated();
+6099 let space_has_keys = self.crypto_state.has_keys(space_id.encryption_level());
+6100 let is_0rtt = space_id == SpaceId::Data && !space_has_keys;
+6101 let stats = &mut self.path_stats.for_path(path_id).frame_tx;
+6102 let space = &mut self.spaces[space_id];
+6103 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
+6104 space
+6105 .for_path(path_id)
+6106 .pending_acks
+6107 .maybe_ack_non_eliciting();
+6108
+6109 // HANDSHAKE_DONE
+6110 if !is_0rtt
+6111 && !scheduling_info.is_abandoned
+6112 && scheduling_info.may_send_data
+6113 && mem::replace(&mut space.pending.handshake_done, false)
+6114 {
+6115 builder.write_frame(frame::HandshakeDone, stats);
+6116 }
+6117
+6118 // PING
+6119 if !scheduling_info.is_abandoned
+6120 && mem::replace(&mut space.for_path(path_id).pending_ping, false)
+6121 {
+6122 builder.write_frame(frame::Ping, stats);
+6123 }
+6124
+6125 // IMMEDIATE_ACK
+6126 if !scheduling_info.is_abandoned
+6127 && mem::replace(&mut space.for_path(path_id).pending_immediate_ack, false)
+6128 {
+6129 debug_assert_eq!(
+6130 space_id,
+6131 SpaceId::Data,
+6132 "immediate acks must be sent in the data space"
+6133 );
+6134 builder.write_frame(frame::ImmediateAck, stats);
+6135 }
+6136
+6137 // ACK
+6138 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
+6139 for path_id in space
+6140 .number_spaces
+6141 .iter_mut()
+6142 .filter(|(_, pns)| pns.pending_acks.can_send())
+6143 .map(|(&path_id, _)| path_id)
+6144 .collect::<Vec<_>>()
+6145 {
+6146 Self::populate_acks(
+6147 now,
+6148 self.receiving_ecn,
+6149 path_id,
+6150 space_id,
+6151 space,
+6152 is_multipath_negotiated,
+6153 builder,
+6154 stats,
+6155 space_has_keys,
+6156 );
+6157 }
+6158 }
+6159
+6160 // ACK_FREQUENCY
+6161 if !scheduling_info.is_abandoned
+6162 && scheduling_info.may_send_data
+6163 && mem::replace(&mut space.pending.ack_frequency, false)
+6164 {
+6165 let sequence_number = self.ack_frequency.next_sequence_number();
+6166
+6167 // Safe to unwrap because this is always provided when ACK frequency is enabled
+6168 let config = self.config.ack_frequency_config.as_ref().unwrap();
+6169
+6170 // Ensure the delay is within bounds to avoid a PROTOCOL_VIOLATION error
+6171 let max_ack_delay = self.ack_frequency.candidate_max_ack_delay(
+6172 path.rtt.get(),
+6173 config,
+6174 &self.peer_params,
+6175 );
+6176
+6177 let frame = frame::AckFrequency {
+6178 sequence: sequence_number,
+6179 ack_eliciting_threshold: config.ack_eliciting_threshold,
+6180 request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX),
+6181 reordering_threshold: config.reordering_threshold,
+6182 };
+6183 builder.write_frame(frame, stats);
+6184
+6185 self.ack_frequency
+6186 .ack_frequency_sent(path_id, builder.packet_number, max_ack_delay);
+6187 }
+6188
+6189 // PATH_CHALLENGE (on-path)
+6190 if !scheduling_info.is_abandoned
+6191 && space_id == SpaceId::Data
+6192 && path.pending_challenge
+6193 // we don't want to send new challenges if we are already closing
+6194 && !self.state.is_closed()
+6195 && builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND
+6196 // An on-path PATH_CHALLENGE must be part of datagrams expanded to the
+6197 // MIN_INITIAL_SIZE (1200 bytes).
+6198 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
+6199 {
+6200 path.pending_challenge = false;
+6201
+6202 let token = self.rng.random();
+6203 path.record_path_challenge_sent(now, token, path.network_path);
+6204 // Generate a new challenge every time we send a new PATH_CHALLENGE
+6205 let challenge = frame::PathChallenge(token);
+6206 builder.write_frame(challenge, stats);
+6207 builder.require_padding();
+6208
+6209 if is_multipath_negotiated && !path.validated && path.pending_challenge {
+6210 // queue informing the path status along with the challenge
+6211 space.pending.path_status.insert(path_id);
+6212 }
+6213
+6214 // Always include an OBSERVED_ADDR frame with a PATH_CHALLENGE, regardless
+6215 // of whether one has already been sent on this path.
+6216 if space_id == SpaceId::Data
+6217 && self
+6218 .config
+6219 .address_discovery_role
+6220 .should_report(&self.peer_params.address_discovery_role)
+6221 {
+6222 let frame = frame::ObservedAddr::new(
+6223 path.network_path.remote,
+6224 self.next_observed_addr_seq_no,
+6225 );
+6226 if builder.frame_space_remaining() > frame.size() {
+6227 builder.write_frame(frame, stats);
+6228
+6229 self.next_observed_addr_seq_no =
+6230 self.next_observed_addr_seq_no.saturating_add(1u8);
+6231 path.pending.observed_address = false;
+6232 }
+6233 }
+6234 }
+6235
+6236 // PATH_RESPONSE (on-path)
+6237 if !scheduling_info.is_abandoned
+6238 && space_id == SpaceId::Data
+6239 && builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND
+6240 // An on-path PATH_RESPONSE must be part of datagrams expanded to the
+6241 // MIN_INITIAL_SIZE (1200 bytes).
+6242 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
+6243 && let Some(token) = space.for_path(path_id).pending_path_responses.pop_on_path(path.network_path)
+6244 {
+6245 let response = frame::PathResponse(token);
+6246 builder.write_frame(response, stats);
+6247 builder.require_padding();
+6248
+6249 // NOTE: this is technically not required but might be useful to ride the
+6250 // request/response nature of path challenges to refresh an observation
+6251 // Since PATH_RESPONSE is a probing frame, this is allowed by the spec.
+6252 if space_id == SpaceId::Data
+6253 && self
+6254 .config
+6255 .address_discovery_role
+6256 .should_report(&self.peer_params.address_discovery_role)
+6257 {
+6258 let frame = frame::ObservedAddr::new(
+6259 path.network_path.remote,
+6260 self.next_observed_addr_seq_no,
+6261 );
+6262 if builder.frame_space_remaining() > frame.size() {
+6263 builder.write_frame(frame, stats);
+6264
+6265 self.next_observed_addr_seq_no =
+6266 self.next_observed_addr_seq_no.saturating_add(1u8);
+6267 path.pending.observed_address = false;
+6268 }
+6269 }
+6270 }
+6271
+6272 // ADD_ADDRESS
+6273 while space_id == SpaceId::Data
+6274 && !scheduling_info.is_abandoned
+6275 && scheduling_info.may_send_data
+6276 && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining()
+6277 {
+6278 if let Some(added_address) = space.pending.add_address.pop_last() {
+6279 builder.write_frame(added_address, stats);
+6280 } else {
+6281 break;
+6282 }
+6283 }
+6284
+6285 // REMOVE_ADDRESS
+6286 while space_id == SpaceId::Data
+6287 && !scheduling_info.is_abandoned
+6288 && scheduling_info.may_send_data
+6289 && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining()
+6290 {
+6291 if let Some(removed_address) = space.pending.remove_address.pop_last() {
+6292 builder.write_frame(removed_address, stats);
+6293 } else {
+6294 break;
+6295 }
+6296 }
+6297
+6298 // REACH_OUT
+6299 while !scheduling_info.is_abandoned
+6300 && scheduling_info.may_send_data
+6301 && let Some(reach_out) = space
+6302 .pending
+6303 .reach_out
+6304 .pop_if(|frame| builder.frame_space_remaining() >= frame.size())
+6305 {
+6306 builder.write_frame(reach_out, stats);
+6307 }
+6308
+6309 // PATH_ABANDON
+6310 if space_id == SpaceId::Data
+6311 && scheduling_info.is_abandoned
+6312 && scheduling_info.may_self_abandon
+6313 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
+6314 && let Some(error_code) = space.pending.path_abandon.remove(&path_id)
+6315 {
+6316 let frame = frame::PathAbandon {
+6317 path_id,
+6318 error_code,
+6319 };
+6320 builder.write_frame(frame, stats);
+6321
+6322 // Consider remotely issued CIDs as retired now that we have sent this frame at
+6323 // least once.
+6324 self.remote_cids.remove(&path_id);
+6325 }
+6326 while space_id == SpaceId::Data
+6327 && scheduling_info.may_send_data
+6328 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
+6329 && let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first()
+6330 {
+6331 let frame = frame::PathAbandon {
+6332 path_id: abandoned_path_id,
+6333 error_code,
+6334 };
+6335 builder.write_frame(frame, stats);
+6336
+6337 // Consider remotely issued CIDs as retired now that we have sent this frame at
+6338 // least once.
+6339 self.remote_cids.remove(&abandoned_path_id);
+6340 }
+6341
+6342 // OBSERVED_ADDR
+6343 if !scheduling_info.is_abandoned
+6344 && scheduling_info.may_send_data
+6345 && space_id == SpaceId::Data
+6346 && path.pending.observed_address
+6347 {
+6348 let frame =
+6349 frame::ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no);
+6350 if builder.frame_space_remaining() > frame.size() {
+6351 builder.write_frame(frame, stats);
+6352
+6353 self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8);
+6354 path.pending.observed_address = false;
+6355 }
+6356 }
+6357
+6358 // CRYPTO
+6359 while !is_0rtt
+6360 && !scheduling_info.is_abandoned
+6361 && scheduling_info.may_send_data
+6362 && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND
+6363 {
+6364 let Some(mut frame) = space.pending.crypto.pop_front() else {
+6365 break;
+6366 };
+6367
+6368 // Calculate the maximum amount of crypto data we can store in the buffer.
+6369 // Since the offset is known, we can reserve the exact size required to encode it.
+6370 // For length we reserve 2bytes which allows to encode up to 2^14,
+6371 // which is more than what fits into normally sized QUIC frames.
+6372 let max_crypto_data_size = builder.frame_space_remaining()
+6373 - 1 // Frame Type
+6374 - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) })
+6375 - 2; // Maximum encoded length for frame size, given we send less than 2^14 bytes
+6376
+6377 let len = frame
+6378 .data
+6379 .len()
+6380 .min(2usize.pow(14) - 1)
+6381 .min(max_crypto_data_size);
+6382
+6383 let data = frame.data.split_to(len);
+6384 let offset = frame.offset;
+6385 let truncated = frame::Crypto { offset, data };
+6386 builder.write_frame(truncated, stats);
+6387
+6388 if !frame.data.is_empty() {
+6389 frame.offset += len as u64;
+6390 space.pending.crypto.push_front(frame);
+6391 }
+6392 }
+6393
+6394 // PATH_STATUS_AVAILABLE & PATH_STATUS_BACKUP
+6395 while space_id == SpaceId::Data
+6396 && !scheduling_info.is_abandoned
+6397 && scheduling_info.may_send_data
+6398 && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining()
+6399 {
+6400 let Some(path_id) = space.pending.path_status.pop_first() else {
+6401 break;
+6402 };
+6403 let Some(path) = self.paths.get(&path_id).map(|path_state| &path_state.data) else {
+6404 trace!(%path_id, "discarding queued path status for unknown path");
+6405 continue;
+6406 };
+6407
+6408 let seq = path.status.seq();
+6409 match path.local_status() {
+6410 PathStatus::Available => {
+6411 let frame = frame::PathStatusAvailable {
+6412 path_id,
+6413 status_seq_no: seq,
+6414 };
+6415 builder.write_frame(frame, stats);
+6416 }
+6417 PathStatus::Backup => {
+6418 let frame = frame::PathStatusBackup {
+6419 path_id,
+6420 status_seq_no: seq,
+6421 };
+6422 builder.write_frame(frame, stats);
+6423 }
+6424 }
+6425 }
+6426
+6427 // MAX_PATH_ID
+6428 if space_id == SpaceId::Data
+6429 && !scheduling_info.is_abandoned
+6430 && scheduling_info.may_send_data
+6431 && space.pending.max_path_id
+6432 && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining()
+6433 {
+6434 let frame = frame::MaxPathId(self.local_max_path_id);
+6435 builder.write_frame(frame, stats);
+6436 space.pending.max_path_id = false;
+6437 }
+6438
+6439 // PATHS_BLOCKED
+6440 if space_id == SpaceId::Data
+6441 && !scheduling_info.is_abandoned
+6442 && scheduling_info.may_send_data
+6443 && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
+6444 && let Some(remote_max_path_id) = space.pending.paths_blocked.take()
+6445 {
+6446 let frame = frame::PathsBlocked(remote_max_path_id);
+6447 builder.write_frame(frame, stats);
+6448 }
+6449
+6450 // PATH_CIDS_BLOCKED
+6451 while space_id == SpaceId::Data
+6452 && !scheduling_info.is_abandoned
+6453 && scheduling_info.may_send_data
+6454 && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
+6455 {
+6456 let Some((path_id, next_seq)) = space.pending.path_cids_blocked.pop_first() else {
+6457 break;
+6458 };
+6459 let frame = frame::PathCidsBlocked { path_id, next_seq };
+6460 builder.write_frame(frame, stats);
+6461 }
+6462
+6463 // RESET_STREAM, STOP_SENDING, MAX_DATA, MAX_STREAM_DATA, MAX_STREAMS
+6464 if space_id == SpaceId::Data
+6465 && !scheduling_info.is_abandoned
+6466 && scheduling_info.may_send_data
+6467 {
+6468 self.streams
+6469 .write_control_frames(builder, &mut space.pending, stats);
+6470 }
+6471
+6472 // NEW_CONNECTION_ID
+6473 let cid_len = self
+6474 .local_cid_state
+6475 .values()
+6476 .map(|cid_state| cid_state.cid_len())
+6477 .max()
+6478 .expect("some local CID state must exist");
+6479 let new_cid_size_bound =
+6480 frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len);
+6481 while !scheduling_info.is_abandoned
+6482 && scheduling_info.may_send_data
+6483 && builder.frame_space_remaining() > new_cid_size_bound
+6484 {
+6485 let Some(issued) = space.pending.new_cids.pop() else {
+6486 break;
+6487 };
+6488 // Path was discarded after this CID was queued, drop.
+6489 let Some(cid_state) = self.local_cid_state.get(&issued.path_id) else {
+6490 debug!(
+6491 path = %issued.path_id, seq = issued.sequence,
+6492 "dropping queued NEW_CONNECTION_ID for discarded path",
+6493 );
+6494 continue;
+6495 };
+6496 let retire_prior_to = cid_state.retire_prior_to();
+6497
+6498 let cid_path_id = match is_multipath_negotiated {
+6499 true => Some(issued.path_id),
+6500 false => {
+6501 debug_assert_eq!(issued.path_id, PathId::ZERO);
+6502 None
+6503 }
+6504 };
+6505 let frame = frame::NewConnectionId {
+6506 path_id: cid_path_id,
+6507 sequence: issued.sequence,
+6508 retire_prior_to,
+6509 id: issued.id,
+6510 reset_token: issued.reset_token,
+6511 };
+6512 builder.write_frame(frame, stats);
+6513 }
+6514
+6515 // RETIRE_CONNECTION_ID
+6516 let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated);
+6517 while !scheduling_info.is_abandoned
+6518 && scheduling_info.may_send_data
+6519 && builder.frame_space_remaining() > retire_cid_bound
+6520 {
+6521 let (path_id, sequence) = match space.pending.retire_cids.pop() {
+6522 Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq),
+6523 Some((path_id, seq)) => (Some(path_id), seq),
+6524 None => break,
+6525 };
+6526 let frame = frame::RetireConnectionId { path_id, sequence };
+6527 builder.write_frame(frame, stats);
+6528 }
+6529
+6530 // DATAGRAM
+6531 let mut sent_datagrams = false;
+6532 while !scheduling_info.is_abandoned
+6533 && scheduling_info.may_send_data
+6534 && builder.frame_space_remaining() > Datagram::SIZE_BOUND
+6535 && space_id == SpaceId::Data
+6536 {
+6537 match self.datagrams.write(builder, stats) {
+6538 true => {
+6539 sent_datagrams = true;
+6540 }
+6541 false => break,
+6542 }
+6543 }
+6544 if self.datagrams.send_blocked && sent_datagrams {
+6545 self.events.push_back(Event::DatagramsUnblocked);
+6546 self.datagrams.send_blocked = false;
+6547 }
+6548
+6549 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
+6550
+6551 // NEW_TOKEN
+6552 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
+6553 while let Some(network_path) = space.pending.new_tokens.pop() {
+6554 debug_assert_eq!(space_id, SpaceId::Data);
+6555 let ConnectionSide::Server { server_config } = &self.side else {
+6556 panic!("NEW_TOKEN frames should not be enqueued by clients");
+6557 };
+6558
+6559 if !network_path.is_probably_same_path(&path.network_path) {
+6560 // NEW_TOKEN frames contain tokens bound to a client's IP address, and are only
+6561 // useful if used from the same IP address. Thus, we abandon enqueued NEW_TOKEN
+6562 // frames upon an path change. Instead, when the new path becomes validated,
+6563 // NEW_TOKEN frames may be enqueued for the new path instead.
+6564 continue;
+6565 }
+6566
+6567 let token = Token::new(
+6568 TokenPayload::Validation {
+6569 ip: network_path.remote.ip(),
+6570 issued: server_config.time_source.now(),
+6571 },
+6572 &mut self.rng,
+6573 );
+6574 let new_token = NewToken {
+6575 token: token.encode(&*server_config.token_key).into(),
+6576 };
+6577
+6578 if builder.frame_space_remaining() < new_token.size() {
+6579 space.pending.new_tokens.push(network_path);
+6580 break;
+6581 }
+6582
+6583 builder.write_frame(new_token, stats);
+6584 builder.retransmits_mut().new_tokens.push(network_path);
+6585 }
+6586 }
+6587
+6588 // STREAM
+6589 if !scheduling_info.is_abandoned
+6590 && scheduling_info.may_send_data
+6591 && space_id == SpaceId::Data
+6592 {
+6593 self.streams
+6594 .write_stream_frames(builder, self.config.send_fairness, stats);
+6595 }
+6596 }
+6597
+6598 /// Write pending ACKs into a buffer
+6599 fn populate_acks<'a, 'b>(
+6600 now: Instant,
+6601 receiving_ecn: bool,
+6602 path_id: PathId,
+6603 space_id: SpaceId,
+6604 space: &mut PacketSpace,
+6605 is_multipath_negotiated: bool,
+6606 builder: &mut PacketBuilder<'a, 'b>,
+6607 stats: &mut FrameStats,
+6608 space_has_keys: bool,
+6609 ) {
+6610 // 0-RTT packets must never carry acks (which would have to be of handshake packets)
+6611 debug_assert!(space_has_keys, "tried to send ACK in 0-RTT");
+6612
+6613 debug_assert!(
+6614 is_multipath_negotiated || path_id == PathId::ZERO,
+6615 "Only PathId::ZERO allowed without multipath (have {path_id:?})"
+6616 );
+6617 if is_multipath_negotiated {
+6618 debug_assert!(
+6619 space_id == SpaceId::Data || path_id == PathId::ZERO,
+6620 "path acks must be sent in 1RTT space (have {space_id:?})"
+6621 );
+6622 }
+6623
+6624 let pns = space.for_path(path_id);
+6625 let ranges = pns.pending_acks.ranges();
+6626 debug_assert!(!ranges.is_empty(), "can not send empty ACK range");
+6627 let ecn = if receiving_ecn {
+6628 Some(&pns.ecn_counters)
+6629 } else {
+6630 None
+6631 };
+6632
+6633 let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64;
+6634 // TODO: This should come from `TransportConfig` if that gets configurable.
+6635 let ack_delay_exp = TransportParameters::default().ack_delay_exponent;
+6636 let delay = delay_micros >> ack_delay_exp.into_inner();
+6637
+6638 if is_multipath_negotiated && space_id == SpaceId::Data {
+6639 if !ranges.is_empty() {
+6640 let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn);
+6641 builder.write_frame(frame, stats);
+6642 }
+6643 } else {
+6644 builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats);
+6645 }
+6646 }
+6647
+6648 fn close_common(&mut self) {
+6649 trace!("connection closed");
+6650 self.timers.reset();
+6651 }
+6652
+6653 fn set_close_timer(&mut self, now: Instant) {
+6654 // QUIC-MULTIPATH § 2.6 Connection Closure: draining for 3*PTO using the max PTO of
+6655 // all paths.
+6656 let pto_max = self.max_pto_for_space(self.highest_space);
+6657 self.timers.set(
+6658 Timer::Conn(ConnTimer::Close),
+6659 now + 3 * pto_max,
+6660 self.qlog.with_time(now),
+6661 );
+6662 }
+6663
+6664 /// Handle transport parameters received from the peer
+6665 ///
+6666 /// *remote_cid* and *local_cid* are the source and destination CIDs respectively of the
+6667 /// *packet into which the transport parameters arrived.
+6668 fn handle_peer_params(
+6669 &mut self,
+6670 params: TransportParameters,
+6671 local_cid: ConnectionId,
+6672 remote_cid: ConnectionId,
+6673 now: Instant,
+6674 ) -> Result<(), TransportError> {
+6675 if Some(self.original_remote_cid) != params.initial_src_cid
+6676 || (self.side.is_client()
+6677 && (Some(self.initial_dst_cid) != params.original_dst_cid
+6678 || self.retry_src_cid != params.retry_src_cid))
+6679 {
+6680 return Err(TransportError::TRANSPORT_PARAMETER_ERROR(
+6681 "CID authentication failure",
+6682 ));
+6683 }
+6684 if params.initial_max_path_id.is_some() && (local_cid.is_empty() || remote_cid.is_empty()) {
+6685 return Err(TransportError::PROTOCOL_VIOLATION(
+6686 "multipath must not use zero-length CIDs",
+6687 ));
+6688 }
+6689
+6690 self.set_peer_params(params);
+6691 self.qlog.emit_peer_transport_params_received(self, now);
+6692
+6693 Ok(())
+6694 }
+6695
+6696 fn set_peer_params(&mut self, params: TransportParameters) {
+6697 self.streams.set_params(¶ms);
+6698 self.idle_timeout =
+6699 negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout));
+6700 trace!("negotiated max idle timeout {:?}", self.idle_timeout);
+6701
+6702 if let Some(ref info) = params.preferred_address {
+6703 // During the handshake PathId::ZERO exists.
+6704 self.remote_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId {
+6705 path_id: None,
+6706 sequence: 1,
+6707 id: info.connection_id,
+6708 reset_token: info.stateless_reset_token,
+6709 retire_prior_to: 0,
+6710 })
+6711 .expect(
+6712 "preferred address CID is the first received, and hence is guaranteed to be legal",
+6713 );
+6714 let remote = self.path_data(PathId::ZERO).network_path.remote;
+6715 self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token);
+6716 }
+6717 self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(¶ms);
+6718
+6719 let mut multipath_enabled = false;
+6720 if let (Some(local_max_path_id), Some(remote_max_path_id)) = (
+6721 self.config.get_initial_max_path_id(),
+6722 params.initial_max_path_id,
+6723 ) {
+6724 // multipath is enabled, register the local and remote maximums
+6725 self.local_max_path_id = local_max_path_id;
+6726 self.remote_max_path_id = remote_max_path_id;
+6727 let initial_max_path_id = local_max_path_id.min(remote_max_path_id);
+6728 debug!(%initial_max_path_id, "multipath negotiated");
+6729 multipath_enabled = true;
+6730 }
+6731
+6732 if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) =
+6733 self.config
+6734 .max_remote_nat_traversal_addresses
+6735 .zip(params.max_remote_nat_traversal_addresses)
+6736 {
+6737 if multipath_enabled {
+6738 let max_local_addresses = max_remotely_allowed_remote_addresses.get();
+6739 let max_remote_addresses = max_locally_allowed_remote_addresses.get();
+6740 self.n0_nat_traversal = n0_nat_traversal::State::new(
+6741 max_remote_addresses,
+6742 max_local_addresses,
+6743 self.side(),
+6744 );
+6745 debug!(
+6746 %max_remote_addresses, %max_local_addresses,
+6747 "n0's nat traversal negotiated"
+6748 );
+6749 } else {
+6750 debug!("n0 nat traversal enabled for both endpoints, but multipath is missing")
+6751 }
+6752 }
+6753
+6754 self.peer_params = params;
+6755 let peer_max_udp_payload_size =
+6756 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
+6757 let address_discovery_negotiated = self
+6758 .config
+6759 .address_discovery_role
+6760 .should_report(&self.peer_params.address_discovery_role);
+6761
+6762 let path = self.path_data_mut(PathId::ZERO);
+6763 path.pending.observed_address = address_discovery_negotiated;
+6764 path.mtud
+6765 .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size);
+6766 }
+6767
+6768 /// Decrypts a packet, returning the packet number on success
+6769 fn decrypt_packet(
+6770 &mut self,
+6771 now: Instant,
+6772 path_id: PathId,
+6773 packet: &mut Packet,
+6774 ) -> Result<Option<u64>, Option<TransportError>> {
+6775 let result = self
+6776 .crypto_state
+6777 .decrypt_packet_body(packet, path_id, &self.spaces)?;
+6778
+6779 let Some(result) = result else {
+6780 return Ok(None);
+6781 };
+6782
+6783 if result.outgoing_key_update_acked
+6784 && let Some(prev) = self.crypto_state.prev_crypto.as_mut()
+6785 {
+6786 prev.end_packet = Some((result.packet_number, now));
+6787 self.set_key_discard_timer(now, packet.header.space());
+6788 }
+6789
+6790 if result.incoming_key_update {
+6791 trace!("key update authenticated");
+6792 self.crypto_state
+6793 .update_keys(Some((result.packet_number, now)), true);
+6794 self.set_key_discard_timer(now, packet.header.space());
+6795 }
+6796
+6797 Ok(Some(result.packet_number))
+6798 }
+6799
+6800 fn peer_supports_ack_frequency(&self) -> bool {
+6801 self.peer_params.min_ack_delay.is_some()
+6802 }
+6803
+6804 /// Send an IMMEDIATE_ACK frame to the remote endpoint
+6805 ///
+6806 /// According to the spec, this will result in an error if the remote endpoint does not support
+6807 /// the Acknowledgement Frequency extension
+6808 pub(crate) fn immediate_ack(&mut self, path_id: PathId) {
+6809 debug_assert_eq!(
+6810 self.highest_space,
+6811 SpaceKind::Data,
+6812 "immediate ack must be written in the data space"
+6813 );
+6814 self.spaces[SpaceId::Data]
+6815 .for_path(path_id)
+6816 .pending_immediate_ack = true;
+6817 }
+6818
+6819 /// Decodes a packet, returning its decrypted payload, so it can be inspected in tests
+6820 #[cfg(test)]
+6821 pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> {
+6822 let ConnectionEventInner::Datagram(DatagramConnectionEvent {
+6823 path_id,
+6824 first_decode,
+6825 remaining,
+6826 ..
+6827 }) = &event.0
+6828 else {
+6829 return None;
+6830 };
+6831
+6832 if remaining.is_some() {
+6833 panic!("Packets should never be coalesced in tests");
+6834 }
+6835
+6836 let decrypted_header = self
+6837 .crypto_state
+6838 .unprotect_header(first_decode.clone(), self.peer_params.stateless_reset_token)?;
+6839
+6840 let mut packet = decrypted_header.packet?;
+6841 self.crypto_state
+6842 .decrypt_packet_body(&mut packet, *path_id, &self.spaces)
+6843 .ok()?;
+6844
+6845 Some(packet.payload.to_vec())
+6846 }
+6847
+6848 /// The number of bytes of packets containing retransmittable frames that have not been
+6849 /// acknowledged or declared lost.
+6850 #[cfg(test)]
+6851 pub(crate) fn bytes_in_flight(&self) -> u64 {
+6852 // TODO(@divma): consider including for multipath?
+6853 self.path_data(PathId::ZERO).in_flight.bytes
+6854 }
+6855
+6856 /// Number of bytes worth of non-ack-only packets that may be sent
+6857 #[cfg(test)]
+6858 pub(crate) fn congestion_window(&self) -> u64 {
+6859 let path = self.path_data(PathId::ZERO);
+6860 path.congestion
+6861 .window()
+6862 .saturating_sub(path.in_flight.bytes)
+6863 }
+6864
+6865 /// Whether no timers but keepalive, idle, rtt, pushnewcid, and key discard are running
+6866 #[cfg(test)]
+6867 pub(crate) fn is_idle(&self) -> bool {
+6868 let current_timers = self.timers.values();
+6869 current_timers
+6870 .into_iter()
+6871 .filter(|(timer, _)| {
+6872 !matches!(
+6873 timer,
+6874 Timer::Conn(ConnTimer::KeepAlive)
+6875 | Timer::PerPath(_, PathTimer::PathKeepAlive)
+6876 | Timer::Conn(ConnTimer::PushNewCid)
+6877 | Timer::Conn(ConnTimer::KeyDiscard)
+6878 )
+6879 })
+6880 .min_by_key(|(_, time)| *time)
+6881 .is_none_or(|(timer, _)| {
+6882 matches!(
+6883 timer,
+6884 Timer::Conn(ConnTimer::Idle) | Timer::PerPath(_, PathTimer::PathIdle)
+6885 )
+6886 })
+6887 }
+6888
+6889 /// Whether explicit congestion notification is in use on outgoing packets.
+6890 #[cfg(test)]
+6891 pub(crate) fn using_ecn(&self) -> bool {
+6892 self.path_data(PathId::ZERO).sending_ecn
+6893 }
+6894
+6895 /// The number of received bytes in the current path
+6896 #[cfg(test)]
+6897 pub(crate) fn total_recvd(&self) -> u64 {
+6898 self.path_data(PathId::ZERO).total_recvd
+6899 }
+6900
+6901 #[cfg(test)]
+6902 pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) {
+6903 self.local_cid_state
+6904 .get(&PathId::ZERO)
+6905 .unwrap()
+6906 .active_seq()
+6907 }
+6908
+6909 #[cfg(test)]
+6910 #[track_caller]
+6911 pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) {
+6912 self.local_cid_state
+6913 .get(&PathId(path_id))
+6914 .unwrap()
+6915 .active_seq()
+6916 }
+6917
+6918 /// Instruct the peer to replace previously issued CIDs by sending a NEW_CONNECTION_ID frame
+6919 /// with updated `retire_prior_to` field set to `v`
+6920 #[cfg(test)]
+6921 pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) {
+6922 let n = self
+6923 .local_cid_state
+6924 .get_mut(&PathId::ZERO)
+6925 .unwrap()
+6926 .assign_retire_seq(v);
+6927 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events
+6928 self.endpoint_events
+6929 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
+6930 }
+6931
+6932 /// Check the current active remote CID sequence for `PathId::ZERO`
+6933 #[cfg(test)]
+6934 pub(crate) fn active_remote_cid_seq(&self) -> u64 {
+6935 self.remote_cids.get(&PathId::ZERO).unwrap().active_seq()
+6936 }
+6937
+6938 /// Returns the detected maximum udp payload size for the current path
+6939 #[cfg(test)]
+6940 pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 {
+6941 self.path_data(path_id).current_mtu()
+6942 }
+6943
+6944 /// Triggers path validation on all paths
+6945 #[cfg(test)]
+6946 pub(crate) fn trigger_path_validation(&mut self) {
+6947 for path in self.paths.values_mut() {
+6948 path.data.pending_challenge = true;
+6949 }
+6950 }
+6951
+6952 /// Simulates a protocol violation error for test purposes.
+6953 #[cfg(test)]
+6954 pub fn simulate_protocol_violation(&mut self, now: Instant) {
+6955 if !self.state.is_closed() {
+6956 self.state
+6957 .move_to_closed(TransportError::PROTOCOL_VIOLATION("simulated violation"));
+6958 self.close_common();
+6959 if !self.state.is_drained() {
+6960 self.set_close_timer(now);
+6961 }
+6962 self.connection_close_pending = true;
+6963 }
+6964 }
+6965
+6966 /// Whether we have **on-path** 1-RTT data to send.
+6967 ///
+6968 /// This checks for frames that can only be sent in the data space (1-RTT):
+6969 /// - Pending PATH_CHALLENGE frames on the active and previous path if just migrated.
+6970 /// - Pending PATH_RESPONSE frames.
+6971 /// - Pending data to send in STREAM frames.
+6972 /// - Pending DATAGRAM frames to send.
+6973 ///
+6974 /// See also [`PacketSpace::can_send`] which keeps track of all other frame types that
+6975 /// may need to be sent.
+6976 fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames {
+6977 let network_path = self.path_data(path_id).network_path;
+6978 let space_specific = self
+6979 .paths
+6980 .get(&path_id)
+6981 .is_some_and(|path| path.data.pending_challenge || !path.data.pending.is_empty())
+6982 || self.spaces[SpaceKind::Data]
+6983 .number_spaces
+6984 .get(&path_id)
+6985 .is_some_and(|pns| pns.pending_path_responses.has_pending_on_path(network_path));
+6986
+6987 // Stream control frames are checked in PacketSpace::can_send, only check data here.
+6988 let other = self.streams.can_send_stream_data()
+6989 || self
+6990 .datagrams
+6991 .outgoing
+6992 .front()
+6993 .is_some_and(|x| x.size(true) <= max_size);
+6994
+6995 // All `false` fields are set in PacketSpace::can_send.
+6996 SendableFrames {
+6997 acks: false,
+6998 close: false,
+6999 space_specific,
+7000 other,
+7001 }
+7002 }
+7003
+7004 /// Terminate the connection instantly, without sending a close packet
+7005 fn kill(&mut self, reason: ConnectionError) {
+7006 self.close_common();
+7007 let was_draining = self.state.move_to_drained(Some(reason));
+7008 if !was_draining {
+7009 self.endpoint_events.push_back(EndpointEventInner::Draining);
+7010 }
+7011 // move_to_drained checks that we were never in drained before, so we
+7012 // never sent a `Drained` event before (it's illegal to send more events after drained).
+7013 self.endpoint_events.push_back(EndpointEventInner::Drained);
+7014 }
+7015
+7016 /// Storage size required for the largest packet that can be transmitted on all currently
+7017 /// available paths
+7018 ///
+7019 /// Buffers passed to [`Connection::poll_transmit`] should be at least this large.
+7020 ///
+7021 /// When multipath is enabled, this value is the minimum MTU across all available paths.
+7022 pub fn current_mtu(&self) -> u16 {
+7023 self.paths
+7024 .iter()
+7025 .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id))
+7026 .map(|(_path_id, path_state)| path_state.data.current_mtu())
+7027 .min()
+7028 .unwrap_or(INITIAL_MTU)
+7029 }
+7030
+7031 /// Size of non-frame data for a 1-RTT packet
+7032 ///
+7033 /// Quantifies space consumed by the QUIC header and AEAD tag. All other bytes in a packet are
+7034 /// frames. Changes if the length of the remote connection ID changes, which is expected to be
+7035 /// rare. If `pn` is specified, may additionally change unpredictably due to variations in
+7036 /// latency and packet loss.
+7037 fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize {
+7038 let pn_len = PacketNumber::new(
+7039 pn,
+7040 self.spaces[SpaceId::Data]
+7041 .for_path(path)
+7042 .largest_acked_packet_pn
+7043 .unwrap_or(0),
+7044 )
+7045 .len();
+7046
+7047 // 1 byte for flags
+7048 1 + self
+7049 .remote_cids
+7050 .get(&path)
+7051 .map(|cids| cids.active().len())
+7052 .unwrap_or(20) // Max CID len in QUIC v1
+7053 + pn_len
+7054 + self.tag_len_1rtt()
+7055 }
+7056
+7057 fn predict_1rtt_overhead_no_pn(&self) -> usize {
+7058 let pn_len = 4;
+7059
+7060 let cid_len = self
+7061 .remote_cids
+7062 .values()
+7063 .map(|cids| cids.active().len())
+7064 .max()
+7065 .unwrap_or(20); // Max CID len in QUIC v1
+7066
+7067 // 1 byte for flags
+7068 1 + cid_len + pn_len + self.tag_len_1rtt()
+7069 }
+7070
+7071 fn tag_len_1rtt(&self) -> usize {
+7072 // encryption_keys for Data space returns 1-RTT keys if available, otherwise 0-RTT keys
+7073 let packet_crypto = self
+7074 .crypto_state
+7075 .encryption_keys(SpaceKind::Data, self.side.side())
+7076 .map(|(_header, packet, _level)| packet);
+7077 // If neither Data nor 0-RTT keys are available, make a reasonable tag length guess. As of
+7078 // this writing, all QUIC cipher suites use 16-byte tags. We could return `None` instead,
+7079 // but that would needlessly prevent sending datagrams during 0-RTT.
+7080 packet_crypto.map_or(16, |x| x.tag_len())
+7081 }
+7082
+7083 /// Mark the path as validated, and enqueue NEW_TOKEN frames to be sent as appropriate
+7084 fn on_path_validated(&mut self, path_id: PathId) {
+7085 self.path_data_mut(path_id).validated = true;
+7086 let ConnectionSide::Server { server_config } = &self.side else {
+7087 return;
+7088 };
+7089 let network_path = self.path_data(path_id).network_path;
+7090 let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens;
+7091 new_tokens.clear();
+7092 for _ in 0..server_config.validation_token.sent {
+7093 new_tokens.push(network_path);
+7094 }
+7095 }
+7096
+7097 /// Handle new path status information: PATH_STATUS_AVAILABLE, PATH_STATUS_BACKUP
+7098 fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) {
+7099 if let Some(path) = self.paths.get_mut(&path_id) {
+7100 path.data.status.remote_update(status, status_seq_no);
+7101 } else {
+7102 debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id);
+7103 }
+7104 self.events.push_back(
+7105 PathEvent::RemoteStatus {
+7106 id: path_id,
+7107 status,
+7108 }
+7109 .into(),
+7110 );
+7111 }
+7112
+7113 /// Returns the maximum [`PathId`] to be used for sending in this connection.
+7114 ///
+7115 /// This is calculated as minimum between the local and remote's maximums when multipath is
+7116 /// enabled, or `None` when disabled.
+7117 ///
+7118 /// For data that's received, we should use [`Self::local_max_path_id`] instead.
+7119 /// The reasoning is that the remote might already have updated to its own newer
+7120 /// [`Self::max_path_id`] after sending out a `MAX_PATH_ID` frame, but it got re-ordered.
+7121 fn max_path_id(&self) -> Option<PathId> {
+7122 if self.is_multipath_negotiated() {
+7123 Some(self.remote_max_path_id.min(self.local_max_path_id))
+7124 } else {
+7125 None
+7126 }
+7127 }
+7128
+7129 /// Returns whether this connection has a socket that supports IPv6.
+7130 ///
+7131 /// TODO(matheus23): This is related to noq endpoint state's `ipv6` bool. We should move that info
+7132 /// here instead of trying to hack around not knowing it exactly.
+7133 pub(crate) fn is_ipv6(&self) -> bool {
+7134 self.paths
+7135 .values()
+7136 .any(|p| p.data.network_path.remote.is_ipv6())
+7137 }
+7138
+7139 /// Add addresses the local endpoint considers are reachable for nat traversal.
+7140 pub fn add_nat_traversal_address(
+7141 &mut self,
+7142 address: SocketAddr,
+7143 ) -> Result<(), n0_nat_traversal::Error> {
+7144 if let Some(added) = self.n0_nat_traversal.add_local_address(address)? {
+7145 self.spaces[SpaceId::Data].pending.add_address.insert(added);
+7146 };
+7147 Ok(())
+7148 }
+7149
+7150 /// Removes an address the endpoing no longer considers reachable for nat traversal
+7151 ///
+7152 /// Addresses not present in the set will be silently ignored.
+7153 pub fn remove_nat_traversal_address(
+7154 &mut self,
+7155 address: SocketAddr,
+7156 ) -> Result<(), n0_nat_traversal::Error> {
+7157 if let Some(removed) = self.n0_nat_traversal.remove_local_address(address)? {
+7158 self.spaces[SpaceId::Data]
+7159 .pending
+7160 .remove_address
+7161 .insert(removed);
+7162 }
+7163 Ok(())
+7164 }
+7165
+7166 /// Get the current local nat traversal addresses
+7167 pub fn get_local_nat_traversal_addresses(
+7168 &self,
+7169 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
+7170 self.n0_nat_traversal.get_local_nat_traversal_addresses()
+7171 }
+7172
+7173 /// Get the currently advertised nat traversal addresses by the server
+7174 pub fn get_remote_nat_traversal_addresses(
+7175 &self,
+7176 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
+7177 Ok(self
+7178 .n0_nat_traversal
+7179 .client_side()?
+7180 .get_remote_nat_traversal_addresses())
+7181 }
+7182
+7183 /// Initiates a new nat traversal round
+7184 ///
+7185 /// A nat traversal round involves advertising the client's local addresses in
+7186 /// `REACH_OUT` frames, and initiating probing of the known remote addresses. When a new
+7187 /// round is initiated, the previous one is cancelled.
+7188 ///
+7189 /// For all probes that succeed, if any, a new path will be opened on the successful
+7190 /// 4-tuple.
+7191 ///
+7192 /// Returns the server addresses that are now being probed. If addresses fail due to
+7193 /// spurious errors, these might succeed later and not be returned in this set.
+7194 pub fn initiate_nat_traversal_round(
+7195 &mut self,
+7196 now: Instant,
+7197 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
+7198 if self.state.is_closed() {
+7199 return Err(n0_nat_traversal::Error::Closed);
+7200 }
+7201
+7202 let ipv6 = self.is_ipv6();
+7203 let client_state = self.n0_nat_traversal.client_side_mut()?;
+7204 let (mut reach_out_frames, probed_addrs) =
+7205 client_state.initiate_nat_traversal_round(ipv6)?;
+7206 if let Some(delay) = self.n0_nat_traversal.retry_delay(self.config.initial_rtt) {
+7207 self.timers.set(
+7208 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
+7209 now + delay,
+7210 self.qlog.with_time(now),
+7211 );
+7212 }
+7213
+7214 self.spaces[SpaceId::Data]
+7215 .pending
+7216 .reach_out
+7217 .append(&mut reach_out_frames);
+7218
+7219 Ok(probed_addrs)
+7220 }
+7221
+7222 /// Whether the handshake is considered **confirmed**.
+7223 ///
+7224 /// <https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2> defines a handshake to be
+7225 /// confirmed when you know the peer successfully received and successfully processed
+7226 /// your TLS Finished message.
+7227 ///
+7228 /// Implementation-wise this is the point at which the handshake crypto keys are
+7229 /// discarded. So we can use this to know if the handshake is confirmed.
+7230 fn is_handshake_confirmed(&self) -> bool {
+7231 !self.is_handshaking() && !self.crypto_state.has_keys(EncryptionLevel::Handshake)
+7232 }
+7233}
+7234
+7235impl fmt::Debug for Connection {
+7236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+7237 f.debug_struct("Connection")
+7238 .field("handshake_cid", &self.handshake_cid)
+7239 .finish()
+7240 }
+7241}
+7242
+7243/// The set of abandoned paths.
+7244///
+7245/// Implementation based on ArrayRangeSet to share more code. The memory space is
+7246/// proportional to the number of concurrently open paths allowed. So does not grow
+7247/// unbounded.
+7248#[derive(Debug, Default)]
+7249struct AbandonedPaths(ArrayRangeSet<ABANDONED_PATH_INLINE_RANGES, u32>);
+7250
+7251/// Size of the stack-allocated array in the [`ArrayRangeSet`].
+7252///
+7253/// A range is 2 u32's, so this is 16 * (4 + 4) = 128 bytes. A good size for inline data,
+7254/// with plenty of ranges for common multipath use.
+7255const ABANDONED_PATH_INLINE_RANGES: usize = 16;
+7256
+7257impl AbandonedPaths {
+7258 /// The number of abandoned paths.
+7259 fn len(&self) -> u32 {
+7260 self.0.elts_count()
+7261 }
+7262
+7263 /// The largest abandoned path.
+7264 fn max(&self) -> Option<PathId> {
+7265 self.0.max().map(PathId::from)
+7266 }
+7267
+7268 /// Whether the path is already abandoned.
+7269 fn contains(&self, val: &PathId) -> bool {
+7270 self.0.contains(val.as_u32())
+7271 }
+7272
+7273 /// Adds another abandoned path.
+7274 fn insert(&mut self, val: PathId) {
+7275 self.0.insert_one(val.as_u32());
+7276 }
+7277}
+7278
+7279/// Hints when the caller identifies a network change.
+7280pub trait NetworkChangeHint: std::fmt::Debug + 'static {
+7281 /// Inform the connection if a path may recover after a network change.
+7282 ///
+7283 /// After network changes, paths may not be recoverable. In this case, waiting for the path to
+7284 /// become idle may take longer than what is desirable. If [`Self::is_path_recoverable`]
+7285 /// returns `false`, a multipath-enabled, client-side connection will establish a new path to
+7286 /// the same remote, closing the current one, instead of migrating the path.
+7287 ///
+7288 /// Paths that are deemed recoverable will simply be sent a PING for a liveness check.
+7289 fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool;
+7290}
+7291
+7292/// Return value for [`Connection::poll_transmit_path_space`].
+7293#[derive(Debug)]
+7294enum PollPathSpaceStatus {
+7295 /// Nothing to send in the space, nothing was written into the [`TransmitBuf`].
+7296 NothingToSend {
+7297 /// If true there was data to send but congestion control did not allow so.
+7298 congestion_blocked: bool,
+7299 },
+7300 /// One or more packets have been written into the [`TransmitBuf`].
+7301 WrotePacket {
+7302 /// The highest packet number.
+7303 last_packet_number: u64,
+7304 /// Whether to pad an already started datagram in the next packet.
+7305 ///
+7306 /// When packets in Initial, 0-RTT or Handshake packet do not fill the entire
+7307 /// datagram they may decide to coalesce with the next packet from a higher
+7308 /// encryption level on the same path. But the earlier packet may require specific
+7309 /// size requirements for the datagram they are sent in.
+7310 ///
+7311 /// If a space did not complete the datagram, they use this to request the correct
+7312 /// padding in the final packet of the datagram so that the final datagram will have
+7313 /// the correct size.
+7314 ///
+7315 /// If a space did fill an entire datagram, it leaves this to the default of
+7316 /// [`PadDatagram::No`].
+7317 pad_datagram: PadDatagram,
+7318 },
+7319 /// Send the contents of the transmit immediately.
+7320 ///
+7321 /// Packets were written and the GSO batch must end now, regardless from whether higher
+7322 /// spaces still have frames to write. This is used when the last datagram written would
+7323 /// require too much padding to continue a GSO batch, which would waste space on the
+7324 /// wire.
+7325 Send {
+7326 /// The highest packet number written into the transmit.
+7327 last_packet_number: u64,
+7328 },
+7329}
+7330
+7331/// Information used to decide what frames to schedule into which packets.
+7332///
+7333/// Primarily used by [`Connection::poll_transmit_on_path`] and the functions that help
+7334/// building packets for it: [`Connection::poll_transmit_path_space`] and
+7335/// [`Connection::populate_packet`].
+7336#[derive(Debug, Copy, Clone)]
+7337struct PathSchedulingInfo {
+7338 /// Whether the path is abandoned.
+7339 ///
+7340 /// Note that a path that is abandoned but still has CIDs can still send a packet. After
+7341 /// sending that packet the CIDs issued by the remote have to be considered retired as
+7342 /// well.
+7343 is_abandoned: bool,
+7344 /// Whether the path may send [`SpaceKind::Data`] frames.
+7345 ///
+7346 /// Some paths should only send frames from [`SendableFrames::space_specific`]. All other
+7347 /// frames are essentially frames that can be sent on any [`SpaceKind::Data`] space. For
+7348 /// those we want to respect packet scheduling rules however.
+7349 ///
+7350 /// Roughly speaking data frames are only sent on spaces that have CIDs, are not
+7351 /// abandoned and have no *better* spaces. However see to comments where this is
+7352 /// populated for the exact packet scheduling implementation.
+7353 ///
+7354 /// This essentially marks this paths as the best validated space ID. Except during
+7355 /// the handshake in which case it does not need to be validated. Several paths could be
+7356 /// equally good and all have this set to `true`, in that case packet scheduling can
+7357 /// choose which path to use. Currently it chooses the lowest path that is not
+7358 /// congestion blocked.
+7359 ///
+7360 /// Note that once in the closed or draining states this will never be true.
+7361 may_send_data: bool,
+7362 /// Whether the path may send a CONNECTION_CLOSE frame.
+7363 ///
+7364 /// This essentially marks this path as the best validated space ID with a fallback
+7365 /// to unvalidated spaces if there are no validated spaces. Like for
+7366 /// [`Self::may_send_data`] other paths could be equally good.
+7367 may_send_close: bool,
+7368 may_self_abandon: bool,
+7369}
+7370
+7371#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+7372enum PathBlocked {
+7373 No,
+7374 AntiAmplification,
+7375 Congestion,
+7376 Pacing,
+7377}
+7378
+7379/// Fields of `Connection` specific to it being client-side or server-side
+7380enum ConnectionSide {
+7381 Client {
+7382 /// Sent in every outgoing Initial packet. Always empty after Initial keys are discarded
+7383 token: Bytes,
+7384 token_store: Arc<dyn TokenStore>,
+7385 server_name: String,
+7386 },
+7387 Server {
+7388 server_config: Arc<ServerConfig>,
+7389 },
+7390}
+7391
+7392impl ConnectionSide {
+7393 fn is_client(&self) -> bool {
+7394 self.side().is_client()
+7395 }
+7396
+7397 fn is_server(&self) -> bool {
+7398 self.side().is_server()
+7399 }
+7400
+7401 fn side(&self) -> Side {
+7402 match *self {
+7403 Self::Client { .. } => Side::Client,
+7404 Self::Server { .. } => Side::Server,
+7405 }
+7406 }
+7407}
+7408
+7409impl From<SideArgs> for ConnectionSide {
+7410 fn from(side: SideArgs) -> Self {
+7411 match side {
+7412 SideArgs::Client {
+7413 token_store,
+7414 server_name,
+7415 } => Self::Client {
+7416 token: token_store.take(&server_name).unwrap_or_default(),
+7417 token_store,
+7418 server_name,
+7419 },
+7420 SideArgs::Server {
+7421 server_config,
+7422 pref_addr_cid: _,
+7423 path_validated: _,
+7424 } => Self::Server { server_config },
+7425 }
+7426 }
+7427}
+7428
+7429/// Parameters to `Connection::new` specific to it being client-side or server-side
+7430pub(crate) enum SideArgs {
+7431 Client {
+7432 token_store: Arc<dyn TokenStore>,
+7433 server_name: String,
+7434 },
+7435 Server {
+7436 server_config: Arc<ServerConfig>,
+7437 pref_addr_cid: Option<ConnectionId>,
+7438 path_validated: bool,
+7439 },
+7440}
+7441
+7442impl SideArgs {
+7443 pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> {
+7444 match *self {
+7445 Self::Client { .. } => None,
+7446 Self::Server { pref_addr_cid, .. } => pref_addr_cid,
+7447 }
+7448 }
+7449
+7450 pub(crate) fn path_validated(&self) -> bool {
+7451 match *self {
+7452 Self::Client { .. } => true,
+7453 Self::Server { path_validated, .. } => path_validated,
+7454 }
+7455 }
+7456
+7457 pub(crate) fn side(&self) -> Side {
+7458 match *self {
+7459 Self::Client { .. } => Side::Client,
+7460 Self::Server { .. } => Side::Server,
+7461 }
+7462 }
+7463}
+7464
+7465/// Reasons why a connection might be lost
+7466#[derive(Debug, Error, Clone, PartialEq, Eq)]
+7467pub enum ConnectionError {
+7468 /// The peer doesn't implement any supported version
+7469 #[error("peer doesn't implement any supported version")]
+7470 VersionMismatch,
+7471 /// The peer violated the QUIC specification as understood by this implementation
+7472 #[error(transparent)]
+7473 TransportError(#[from] TransportError),
+7474 /// The peer's QUIC stack aborted the connection automatically
+7475 #[error("aborted by peer: {0}")]
+7476 ConnectionClosed(frame::ConnectionClose),
+7477 /// The peer closed the connection
+7478 #[error("closed by peer: {0}")]
+7479 ApplicationClosed(frame::ApplicationClose),
+7480 /// The peer is unable to continue processing this connection, usually due to having restarted
+7481 #[error("reset by peer")]
+7482 Reset,
+7483 /// Communication with the peer has lapsed for longer than the negotiated idle timeout
+7484 ///
+7485 /// If neither side is sending keep-alives, a connection will time out after a long enough idle
+7486 /// period even if the peer is still reachable. See also [`TransportConfig::max_idle_timeout()`]
+7487 /// and [`TransportConfig::keep_alive_interval()`].
+7488 #[error("timed out")]
+7489 TimedOut,
+7490 /// The local application closed the connection
+7491 #[error("closed")]
+7492 LocallyClosed,
+7493 /// The connection could not be created because not enough of the CID space is available
+7494 ///
+7495 /// Try using longer connection IDs.
+7496 #[error("CIDs exhausted")]
+7497 CidsExhausted,
+7498}
+7499
+7500impl From<Close> for ConnectionError {
+7501 fn from(x: Close) -> Self {
+7502 match x {
+7503 Close::Connection(reason) => Self::ConnectionClosed(reason),
+7504 Close::Application(reason) => Self::ApplicationClosed(reason),
+7505 }
+7506 }
+7507}
+7508
+7509// For compatibility with API consumers
+7510impl From<ConnectionError> for io::Error {
+7511 fn from(x: ConnectionError) -> Self {
+7512 use ConnectionError::*;
+7513 let kind = match x {
+7514 TimedOut => io::ErrorKind::TimedOut,
+7515 Reset => io::ErrorKind::ConnectionReset,
+7516 ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted,
+7517 TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => {
+7518 io::ErrorKind::Other
+7519 }
+7520 };
+7521 Self::new(kind, x)
+7522 }
+7523}
+7524
+7525/// Errors that might trigger a path being closed
+7526// TODO(@divma): maybe needs to be reworked based on what we want to do with the public API
+7527#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)]
+7528pub enum PathError {
+7529 /// The extension was not negotiated with the peer
+7530 #[error("multipath extension not negotiated")]
+7531 MultipathNotNegotiated,
+7532 /// Paths can only be opened client-side
+7533 #[error("the server side may not open a path")]
+7534 ServerSideNotAllowed,
+7535 /// Current limits do not allow us to open more paths
+7536 #[error("maximum number of concurrent paths reached")]
+7537 MaxPathIdReached,
+7538 /// No remote CIDs available to open a new path
+7539 #[error("remoted CIDs exhausted")]
+7540 RemoteCidsExhausted,
+7541 /// Path could not be validated and will be abandoned
+7542 #[error("path validation failed")]
+7543 ValidationFailed,
+7544 /// The remote address for the path is not supported by the endpoint
+7545 #[error("invalid remote address")]
+7546 InvalidRemoteAddress(SocketAddr),
+7547}
+7548
+7549/// Errors triggered when abandoning a path
+7550#[derive(Debug, Error, Clone, Eq, PartialEq)]
+7551pub enum ClosePathError {
+7552 /// Multipath is not negotiated
+7553 #[error("Multipath extension not negotiated")]
+7554 MultipathNotNegotiated,
+7555 /// The path is already closed or was never opened
+7556 #[error("closed path")]
+7557 ClosedPath,
+7558 /// Cannot close the last remaining open path via the local API.
+7559 ///
+7560 /// Use [`Connection::close`] to end the connection instead.
+7561 #[error("last open path")]
+7562 LastOpenPath,
+7563}
+7564
+7565/// Error when the multipath extension was not negotiated, but attempted to be used.
+7566#[derive(Debug, Error, Clone, Copy)]
+7567#[error("Multipath extension not negotiated")]
+7568pub struct MultipathNotNegotiated {
+7569 _private: (),
+7570}
+7571
+7572/// Events of interest to the application
+7573#[derive(Debug)]
+7574pub enum Event {
+7575 /// The connection's handshake data is ready
+7576 HandshakeDataReady,
+7577 /// The connection was successfully established
+7578 Connected,
+7579 /// The TLS handshake was confirmed
+7580 HandshakeConfirmed,
+7581 /// The connection was lost
+7582 ///
+7583 /// Emitted when the connection is closed due to an error, a timeout, or the peer closing it.
+7584 /// This is **not** emitted when the local application closes the connection via
+7585 /// [`Connection::close()`](crate::Connection::close). In that case, pending operations will
+7586 /// fail with [`ConnectionError::LocallyClosed`].
+7587 ConnectionLost {
+7588 /// Reason that the connection was closed
+7589 reason: ConnectionError,
+7590 },
+7591 /// Stream events
+7592 Stream(StreamEvent),
+7593 /// One or more application datagrams have been received
+7594 DatagramReceived,
+7595 /// One or more application datagrams have been sent after blocking
+7596 DatagramsUnblocked,
+7597 /// (Multi)Path events
+7598 Path(PathEvent),
+7599 /// n0's nat traversal events
+7600 NatTraversal(n0_nat_traversal::Event),
+7601}
+7602
+7603impl From<PathEvent> for Event {
+7604 fn from(source: PathEvent) -> Self {
+7605 Self::Path(source)
+7606 }
+7607}
+7608
+7609fn get_max_ack_delay(params: &TransportParameters) -> Duration {
+7610 Duration::from_micros(params.max_ack_delay.0 * 1000)
+7611}
+7612
+7613/// Prevents overflow and improves behavior in extreme circumstances.
+7614const MAX_BACKOFF_EXPONENT: u32 = 16;
+7615
+7616/// The max interval between successive tail-loss probes.
+7617///
+7618/// This is the "normal" value we use.
+7619const MAX_PTO_INTERVAL: Duration = Duration::from_secs(2);
+7620
+7621/// The idle time, below which we use the shorter [`MAX_PTO_FAST_INTERVAL`].
+7622const MIN_IDLE_FOR_FAST_PTO: Duration = Duration::from_secs(25);
+7623
+7624/// The max interval between successive tail-loss probes with short idle times.
+7625///
+7626/// If the path or connection idle time is less than [`MIN_IDLE_FOR_FAST_PTO`] then we use
+7627/// this value to ensure we have plenty of retransmits before we reach the idle time.
+7628const MAX_PTO_FAST_INTERVAL: Duration = Duration::from_secs(1);
+7629
+7630/// The RTT threshold above which we cap the PTO interval to 1.5 * smoothed_rtt
+7631///
+7632/// This is RTT time above which 1.5 * RTT > [`MAX_PTO_INTERVAL`], for these links we want
+7633/// to extend the interval between tail-loss probes to not fill the entire pipe with them.
+7634const SLOW_RTT_THRESHOLD: Duration =
+7635 Duration::from_millis((MAX_PTO_INTERVAL.as_millis() as u64 * 2) / 3);
+7636
+7637/// Minimal remaining size to allow packet coalescing, excluding cryptographic tag
+7638///
+7639/// This must be at least as large as the header for a well-formed empty packet to be coalesced,
+7640/// plus some space for frames. We only care about handshake headers because short header packets
+7641/// necessarily have smaller headers, and initial packets are only ever the first packet in a
+7642/// datagram (because we coalesce in ascending packet space order and the only reason to split a
+7643/// packet is when packet space changes).
+7644const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32;
+7645
+7646/// Largest amount of space that could be occupied by a Handshake or 0-RTT packet's header
+7647///
+7648/// Excludes packet-type-specific fields such as packet number or Initial token
+7649// https://www.rfc-editor.org/rfc/rfc9000.html#name-0-rtt: flags + version + dcid len + dcid +
+7650// scid len + scid + length + pn
+7651const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize =
+7652 1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4;
+7653
+7654#[derive(Default)]
+7655struct SentFrames {
+7656 retransmits: ThinRetransmits,
+7657 path_retransmits: PathRetransmits,
+7658 /// The packet number of the largest acknowledged packet for each path
+7659 largest_acked: FxHashMap<PathId, u64>,
+7660 stream_frames: StreamMetaVec,
+7661 /// Whether the packet contains non-retransmittable frames (like datagrams)
+7662 non_retransmits: bool,
+7663 /// If the datagram containing these frames should be padded to the min MTU
+7664 requires_padding: bool,
+7665}
+7666
+7667impl SentFrames {
+7668 /// Returns whether the packet contains only ACKs
+7669 fn is_ack_only(&self, streams: &StreamsState) -> bool {
+7670 !self.largest_acked.is_empty()
+7671 && !self.non_retransmits
+7672 && self.stream_frames.is_empty()
+7673 && self.retransmits.is_empty(streams)
+7674 }
+7675
+7676 fn retransmits_mut(&mut self) -> &mut Retransmits {
+7677 self.retransmits.get_or_create()
+7678 }
+7679
+7680 fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) {
+7681 use frame::EncodableFrame::*;
+7682 match frame {
+7683 PathAck(path_ack_encoder) => {
+7684 if let Some(max) = path_ack_encoder.ranges.max() {
+7685 self.largest_acked.insert(path_ack_encoder.path_id, max);
+7686 }
+7687 }
+7688 Ack(ack_encoder) => {
+7689 if let Some(max) = ack_encoder.ranges.max() {
+7690 self.largest_acked.insert(PathId::ZERO, max);
+7691 }
+7692 }
+7693 Close(_) => { /* non retransmittable, but after this we don't really care */ }
+7694 PathResponse(_) => self.non_retransmits = true,
+7695 HandshakeDone(_) => self.retransmits_mut().handshake_done = true,
+7696 ReachOut(frame) => self.retransmits_mut().reach_out.push(frame),
+7697 ObservedAddr(_) => self.path_retransmits.observed_address = true,
+7698 Ping(_) => self.non_retransmits = true,
+7699 ImmediateAck(_) => self.non_retransmits = true,
+7700 AckFrequency(_) => self.retransmits_mut().ack_frequency = true,
+7701 PathChallenge(_) => self.non_retransmits = true,
+7702 Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto),
+7703 PathAbandon(path_abandon) => {
+7704 self.retransmits_mut()
+7705 .path_abandon
+7706 .entry(path_abandon.path_id)
+7707 .or_insert(path_abandon.error_code);
+7708 }
+7709 PathStatusAvailable(frame::PathStatusAvailable { path_id, .. })
+7710 | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => {
+7711 self.retransmits_mut().path_status.insert(path_id);
+7712 }
+7713 MaxPathId(_) => self.retransmits_mut().max_path_id = true,
+7714 PathsBlocked(frame::PathsBlocked(path_id)) => {
+7715 let paths_blocked = &mut self.retransmits_mut().paths_blocked;
+7716 *paths_blocked = cmp::max(*paths_blocked, Some(path_id));
+7717 }
+7718 PathCidsBlocked(path_cids_blocked) => {
+7719 self.retransmits_mut()
+7720 .path_cids_blocked
+7721 .entry(path_cids_blocked.path_id)
+7722 .and_modify(|next_seq| {
+7723 *next_seq = cmp::max(*next_seq, path_cids_blocked.next_seq);
+7724 })
+7725 .or_insert(path_cids_blocked.next_seq);
+7726 }
+7727 ResetStream(reset) => self
+7728 .retransmits_mut()
+7729 .reset_stream
+7730 .push((reset.id, reset.error_code)),
+7731 StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending),
+7732 NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()),
+7733 RetireConnectionId(retire_cid) => self
+7734 .retransmits_mut()
+7735 .retire_cids
+7736 .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)),
+7737 Datagram(_) => self.non_retransmits = true,
+7738 NewToken(_) => {}
+7739 AddAddress(add_address) => {
+7740 self.retransmits_mut().add_address.insert(add_address);
+7741 }
+7742 RemoveAddress(remove_address) => {
+7743 self.retransmits_mut().remove_address.insert(remove_address);
+7744 }
+7745 StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta),
+7746 MaxData(_) => self.retransmits_mut().max_data = true,
+7747 MaxStreamData(max) => {
+7748 self.retransmits_mut().max_stream_data.insert(max.id);
+7749 }
+7750 MaxStreams(max_streams) => {
+7751 self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true
+7752 }
+7753 StreamsBlocked(streams_blocked) => {
+7754 self.retransmits_mut().streams_blocked[streams_blocked.dir as usize] = true
+7755 }
+7756 }
+7757 }
+7758}
+7759
+7760/// Compute the negotiated idle timeout based on local and remote max_idle_timeout transport parameters.
+7761///
+7762/// According to the definition of max_idle_timeout, a value of `0` means the timeout is disabled; see <https://www.rfc-editor.org/rfc/rfc9000#section-18.2-4.4.1.>
+7763///
+7764/// According to the negotiation procedure, either the minimum of the timeouts or one specified is used as the negotiated value; see <https://www.rfc-editor.org/rfc/rfc9000#section-10.1-2.>
+7765///
+7766/// Returns the negotiated idle timeout as a `Duration`, or `None` when both endpoints have opted out of idle timeout.
+7767fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> {
+7768 match (x, y) {
+7769 (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None,
+7770 (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)),
+7771 (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)),
+7772 (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)),
+7773 }
+7774}
+7775
+7776#[cfg(test)]
+7777mod tests {
+7778 use super::*;
+7779
+7780 #[test]
+7781 fn negotiate_max_idle_timeout_commutative() {
+7782 let test_params = [
+7783 (None, None, None),
+7784 (None, Some(VarInt(0)), None),
+7785 (None, Some(VarInt(2)), Some(Duration::from_millis(2))),
+7786 (Some(VarInt(0)), Some(VarInt(0)), None),
+7787 (
+7788 Some(VarInt(2)),
+7789 Some(VarInt(0)),
+7790 Some(Duration::from_millis(2)),
+7791 ),
+7792 (
+7793 Some(VarInt(1)),
+7794 Some(VarInt(4)),
+7795 Some(Duration::from_millis(1)),
+7796 ),
+7797 ];
+7798
+7799 for (left, right, result) in test_params {
+7800 assert_eq!(negotiate_max_idle_timeout(left, right), result);
+7801 assert_eq!(negotiate_max_idle_timeout(right, left), result);
+7802 }
+7803 }
+7804
+7805 #[test]
+7806 fn abandoned_paths() {
+7807 let mut t = AbandonedPaths::default();
+7808
+7809 t.insert(PathId(0));
+7810 t.insert(PathId(1));
+7811 assert_eq!(t.len(), 2);
+7812 assert_eq!(t.0.range_count(), 1); // 2 elements compacted into one range
+7813 assert!(t.contains(&PathId(0)));
+7814 assert!(t.contains(&PathId(1)));
+7815 assert!(!t.contains(&PathId(2)));
+7816 assert!(!t.contains(&PathId(3)));
+7817 assert_eq!(t.max(), Some(PathId(1)));
+7818
+7819 t.insert(PathId(3));
+7820 assert_eq!(t.len(), 3);
+7821 assert_eq!(t.0.range_count(), 2); // 3 elements compacted into 2 ranges
+7822 assert!(t.contains(&PathId(0)));
+7823 assert!(t.contains(&PathId(1)));
+7824 assert!(!t.contains(&PathId(2)));
+7825 assert!(t.contains(&PathId(3)));
+7826 assert_eq!(t.max(), Some(PathId(3)));
+7827
+7828 t.insert(PathId(2));
+7829 assert_eq!(t.len(), 4);
+7830 assert_eq!(t.0.range_count(), 1); // 4 elements compacted into 1 range
+7831 assert!(t.contains(&PathId(0)));
+7832 assert!(t.contains(&PathId(1)));
+7833 assert!(t.contains(&PathId(2)));
+7834 assert!(t.contains(&PathId(3)));
+7835 assert_eq!(t.max(), Some(PathId(3)));
+7836 }
+7837}
\ No newline at end of file
diff --git a/pr/721/docs/src/noq_proto/connection/spaces.rs.html b/pr/721/docs/src/noq_proto/connection/spaces.rs.html
index f0b4c6064..d4c0444f0 100644
--- a/pr/721/docs/src/noq_proto/connection/spaces.rs.html
+++ b/pr/721/docs/src/noq_proto/connection/spaces.rs.html
@@ -496,1140 +496,1137 @@
496
497#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
498pub(super) enum OpenStatus {
-499 /// A first packet has not been sent using this [`PathId`].
+499 /// The application has not yet been informed of this path.
500 #[default]
501 Pending,
-502 /// The first packet has been sent using this [`PathId`]. However, it is not yet deemed good
-503 /// enough to be reported to the application.
-504 Sent,
-505 /// The application has been informed of this path.
-506 Informed,
-507}
-508
-509/// Represents one or more packets subject to retransmission
-510#[derive(Debug, Clone)]
-511pub(super) struct SentPacket {
-512 /// [`PathData::generation`](super::PathData::generation) of the path on which this packet was sent
-513 pub(super) path_generation: u64,
-514 /// The time the packet was sent.
-515 pub(super) time_sent: Instant,
-516 /// The number of bytes sent in the packet, not including UDP or IP overhead, but including QUIC
-517 /// framing overhead. Zero if this packet is not counted towards congestion control, i.e. not an
-518 /// "in flight" packet.
-519 pub(super) size: u16,
-520 /// Whether an acknowledgement is expected directly in response to this packet.
-521 pub(super) ack_eliciting: bool,
-522 /// The largest packet number acknowledged by this packet
-523 pub(super) largest_acked: FxHashMap<PathId, u64>,
-524 /// Data which needs to be retransmitted in case the packet is lost.
-525 ///
-526 /// These might be retransmitted over any available path in the same [`SpaceKind`].
-527 pub(super) retransmits: ThinRetransmits,
-528 /// Retransmittable data specific to a path generation.
-529 pub(super) path_retransmits: PathRetransmits,
-530 /// Metadata for stream frames in a packet
-531 ///
-532 /// The actual application data is stored with the stream state.
-533 pub(super) stream_frames: frame::StreamMetaVec,
-534}
-535
-536/// Represents one or more packets that are deemed lost.
-537#[derive(Debug)]
-538pub(super) struct LostPacket {
-539 /// The time the packet was sent.
-540 pub(super) time_sent: Instant,
-541}
-542
-543/// Retransmittable data queue.
-544///
-545/// Data in this queue must be retransmittable over any path in the same [`SpaceKind`].
-546#[allow(unreachable_pub)] // fuzzing only
-547#[derive(Debug, Default, Clone)]
-548pub struct Retransmits {
-549 pub(super) max_data: bool,
-550 pub(super) max_stream_id: [bool; 2],
-551 pub(super) streams_blocked: [bool; 2],
-552 pub(super) reset_stream: Vec<(StreamId, VarInt)>,
-553 pub(super) stop_sending: Vec<frame::StopSending>,
-554 pub(super) max_stream_data: FxHashSet<StreamId>,
-555 pub(super) crypto: VecDeque<frame::Crypto>,
-556 pub(super) new_cids: PendingNewCids,
-557 pub(super) retire_cids: Vec<(PathId, u64)>,
-558 pub(super) ack_frequency: bool,
-559 pub(super) handshake_done: bool,
-560 /// Whether we should inform the peer we will allow higher [`PathId`]s.
-561 pub(super) max_path_id: bool,
-562 /// Whether we should inform the peer that their max [`PathId`] is blocking our attempt to open
-563 /// new paths.
-564 ///
-565 /// Stores the remote_max_path_id at the time this was generated.
-566 /// This frame is entirely informational, so when it's retransmitted, the remote_max_path_id is
-567 /// intentionally not updated to preserve the fact that this was the state of the client at some
-568 /// point.
-569 pub(super) paths_blocked: Option<PathId>,
-570 /// For each enqueued NEW_TOKEN frame, a copy of the path's remote address
-571 ///
-572 /// There are 2 reasons this is unusual:
-573 ///
-574 /// - If the path changes, NEW_TOKEN frames bound for the old path are not retransmitted on the
-575 /// new path. That is why this field stores the remote address: so that ones for old paths
-576 /// can be filtered out.
-577 /// - If a token is lost, a new randomly generated token is re-transmitted, rather than the
-578 /// original. This is so that if both transmissions are received, the client won't risk
-579 /// sending the same token twice. That is why this field does _not_ store any actual token.
-580 ///
-581 /// It is true that a QUIC endpoint will only want to effectively have NEW_TOKEN frames
-582 /// enqueued for its current path at a given point in time. Based on that, we could conceivably
-583 /// change this from a vector to an `Option<(FourTuple, usize)>` or just a `usize` or
-584 /// something. However, due to the architecture of noq, it is considerably simpler to not do
-585 /// that; consider what such a change would mean for implementing `BitOrAssign` on Self.
-586 pub(super) new_tokens: Vec<FourTuple>,
-587 /// Paths which need to be abandoned
-588 pub(super) path_abandon: BTreeMap<PathId, TransportErrorCode>,
-589 /// If a [`frame::PathStatusAvailable`] and [`frame::PathStatusBackup`] need to be sent for a path
-590 pub(super) path_status: BTreeSet<PathId>,
-591 /// Whether a PATH_CIDS_BLOCKED frame needs to be sent for a path.
-592 ///
-593 /// Stores the next_seq number for the blocked path. This number can be "outdated" at the time of
-594 /// sending when this is a retransmission. This is intentional, as this frame is purely
-595 /// informational, and this would preserve this information.
-596 pub(super) path_cids_blocked: BTreeMap<PathId, VarInt>,
-597
-598 // Nat traversal data
-599 /// Addresses to report in `ADD_ADDRESS` frames
-600 pub(super) add_address: BTreeSet<AddAddress>,
-601 /// Address IDs to remove in `REMOVE_ADDRESS` frames
-602 pub(super) remove_address: BTreeSet<RemoveAddress>,
-603 /// Round and local addresses to advertise in `REACH_OUT` frames
-604 pub(super) reach_out: PendingReachOutFrames,
-605}
-606
-607impl Retransmits {
-608 pub(super) fn is_empty(&self, streams: &StreamsState) -> bool {
-609 let Self {
-610 max_data,
-611 max_stream_id,
-612 streams_blocked,
-613 reset_stream,
-614 stop_sending,
-615 max_stream_data,
-616 crypto,
-617 new_cids,
-618 retire_cids,
-619 ack_frequency,
-620 handshake_done,
-621 max_path_id,
-622 paths_blocked,
-623 new_tokens,
-624 path_abandon,
-625 path_status,
-626 path_cids_blocked,
-627 add_address,
-628 remove_address,
-629 reach_out,
-630 } = &self;
-631 !max_data
-632 && !max_stream_id.iter().any(|x| *x)
-633 && !streams_blocked.iter().any(|x| *x)
-634 && reset_stream.is_empty()
-635 && stop_sending.is_empty()
-636 && max_stream_data
-637 .iter()
-638 .all(|&id| !streams.can_send_flow_control(id))
-639 && crypto.is_empty()
-640 && new_cids.is_empty()
-641 && retire_cids.is_empty()
-642 && !ack_frequency
-643 && !handshake_done
-644 && !max_path_id
-645 && paths_blocked.is_none()
-646 && new_tokens.is_empty()
-647 && path_abandon.is_empty()
-648 && path_status.is_empty()
-649 && path_cids_blocked.is_empty()
-650 && add_address.is_empty()
-651 && remove_address.is_empty()
-652 && reach_out.is_empty()
-653 }
-654}
-655
-656impl ::std::ops::BitOrAssign for Retransmits {
-657 fn bitor_assign(&mut self, rhs: Self) {
-658 let Self {
-659 max_data,
-660 max_stream_id,
-661 streams_blocked,
-662 reset_stream,
-663 stop_sending,
-664 max_stream_data,
-665 crypto,
-666 new_cids,
-667 retire_cids,
-668 ack_frequency,
-669 handshake_done,
-670 max_path_id,
-671 paths_blocked,
-672 new_tokens,
-673 mut path_abandon,
-674 mut path_status,
-675 mut path_cids_blocked,
-676 add_address,
-677 remove_address,
-678 mut reach_out,
-679 } = rhs;
-680
-681 // We reduce in-stream head-of-line blocking by queueing retransmits before other data for
-682 // STREAM and CRYPTO frames.
-683 self.max_data |= max_data;
-684 for dir in Dir::iter() {
-685 self.max_stream_id[dir as usize] |= max_stream_id[dir as usize];
-686 self.streams_blocked[dir as usize] |= streams_blocked[dir as usize];
-687 }
-688 self.reset_stream.extend_from_slice(&reset_stream);
-689 self.stop_sending.extend_from_slice(&stop_sending);
-690 self.max_stream_data.extend(&max_stream_data);
-691 for crypto in crypto.into_iter().rev() {
-692 self.crypto.push_front(crypto);
-693 }
-694 self.new_cids.extend(&new_cids);
-695 self.retire_cids.extend(retire_cids);
-696 self.ack_frequency |= ack_frequency;
-697 self.handshake_done |= handshake_done;
-698 self.max_path_id |= max_path_id;
-699 self.paths_blocked = cmp::max(self.paths_blocked, paths_blocked);
-700 self.new_tokens.extend_from_slice(&new_tokens);
-701 self.path_abandon.append(&mut path_abandon);
-702 self.path_status.append(&mut path_status);
-703 self.path_cids_blocked.append(&mut path_cids_blocked);
-704 self.add_address.extend(add_address.iter().copied());
-705 self.remove_address.extend(remove_address.iter().copied());
-706 self.reach_out.append(&mut reach_out);
-707 }
-708}
-709
-710impl ::std::ops::BitOrAssign<ThinRetransmits> for Retransmits {
-711 fn bitor_assign(&mut self, rhs: ThinRetransmits) {
-712 let ThinRetransmits { retransmits } = rhs;
-713 if let Some(retransmits) = retransmits {
-714 self.bitor_assign(*retransmits)
-715 }
-716 }
-717}
-718
-719impl ::std::iter::FromIterator<Self> for Retransmits {
-720 fn from_iter<T>(iter: T) -> Self
-721 where
-722 T: IntoIterator<Item = Self>,
-723 {
-724 let mut result = Self::default();
-725 for packet in iter {
-726 result |= packet;
-727 }
-728 result
-729 }
-730}
-731
-732/// The queue of new CIDs to be transmitted to the peer.
+502 /// The application has been informed of this path.
+503 Informed,
+504}
+505
+506/// Represents one or more packets subject to retransmission
+507#[derive(Debug, Clone)]
+508pub(super) struct SentPacket {
+509 /// [`PathData::generation`](super::PathData::generation) of the path on which this packet was sent
+510 pub(super) path_generation: u64,
+511 /// The time the packet was sent.
+512 pub(super) time_sent: Instant,
+513 /// The number of bytes sent in the packet, not including UDP or IP overhead, but including QUIC
+514 /// framing overhead. Zero if this packet is not counted towards congestion control, i.e. not an
+515 /// "in flight" packet.
+516 pub(super) size: u16,
+517 /// Whether an acknowledgement is expected directly in response to this packet.
+518 pub(super) ack_eliciting: bool,
+519 /// The largest packet number acknowledged by this packet
+520 pub(super) largest_acked: FxHashMap<PathId, u64>,
+521 /// Data which needs to be retransmitted in case the packet is lost.
+522 ///
+523 /// These might be retransmitted over any available path in the same [`SpaceKind`].
+524 pub(super) retransmits: ThinRetransmits,
+525 /// Retransmittable data specific to a path generation.
+526 pub(super) path_retransmits: PathRetransmits,
+527 /// Metadata for stream frames in a packet
+528 ///
+529 /// The actual application data is stored with the stream state.
+530 pub(super) stream_frames: frame::StreamMetaVec,
+531}
+532
+533/// Represents one or more packets that are deemed lost.
+534#[derive(Debug)]
+535pub(super) struct LostPacket {
+536 /// The time the packet was sent.
+537 pub(super) time_sent: Instant,
+538}
+539
+540/// Retransmittable data queue.
+541///
+542/// Data in this queue must be retransmittable over any path in the same [`SpaceKind`].
+543#[allow(unreachable_pub)] // fuzzing only
+544#[derive(Debug, Default, Clone)]
+545pub struct Retransmits {
+546 pub(super) max_data: bool,
+547 pub(super) max_stream_id: [bool; 2],
+548 pub(super) streams_blocked: [bool; 2],
+549 pub(super) reset_stream: Vec<(StreamId, VarInt)>,
+550 pub(super) stop_sending: Vec<frame::StopSending>,
+551 pub(super) max_stream_data: FxHashSet<StreamId>,
+552 pub(super) crypto: VecDeque<frame::Crypto>,
+553 pub(super) new_cids: PendingNewCids,
+554 pub(super) retire_cids: Vec<(PathId, u64)>,
+555 pub(super) ack_frequency: bool,
+556 pub(super) handshake_done: bool,
+557 /// Whether we should inform the peer we will allow higher [`PathId`]s.
+558 pub(super) max_path_id: bool,
+559 /// Whether we should inform the peer that their max [`PathId`] is blocking our attempt to open
+560 /// new paths.
+561 ///
+562 /// Stores the remote_max_path_id at the time this was generated.
+563 /// This frame is entirely informational, so when it's retransmitted, the remote_max_path_id is
+564 /// intentionally not updated to preserve the fact that this was the state of the client at some
+565 /// point.
+566 pub(super) paths_blocked: Option<PathId>,
+567 /// For each enqueued NEW_TOKEN frame, a copy of the path's remote address
+568 ///
+569 /// There are 2 reasons this is unusual:
+570 ///
+571 /// - If the path changes, NEW_TOKEN frames bound for the old path are not retransmitted on the
+572 /// new path. That is why this field stores the remote address: so that ones for old paths
+573 /// can be filtered out.
+574 /// - If a token is lost, a new randomly generated token is re-transmitted, rather than the
+575 /// original. This is so that if both transmissions are received, the client won't risk
+576 /// sending the same token twice. That is why this field does _not_ store any actual token.
+577 ///
+578 /// It is true that a QUIC endpoint will only want to effectively have NEW_TOKEN frames
+579 /// enqueued for its current path at a given point in time. Based on that, we could conceivably
+580 /// change this from a vector to an `Option<(FourTuple, usize)>` or just a `usize` or
+581 /// something. However, due to the architecture of noq, it is considerably simpler to not do
+582 /// that; consider what such a change would mean for implementing `BitOrAssign` on Self.
+583 pub(super) new_tokens: Vec<FourTuple>,
+584 /// Paths which need to be abandoned
+585 pub(super) path_abandon: BTreeMap<PathId, TransportErrorCode>,
+586 /// If a [`frame::PathStatusAvailable`] and [`frame::PathStatusBackup`] need to be sent for a path
+587 pub(super) path_status: BTreeSet<PathId>,
+588 /// Whether a PATH_CIDS_BLOCKED frame needs to be sent for a path.
+589 ///
+590 /// Stores the next_seq number for the blocked path. This number can be "outdated" at the time of
+591 /// sending when this is a retransmission. This is intentional, as this frame is purely
+592 /// informational, and this would preserve this information.
+593 pub(super) path_cids_blocked: BTreeMap<PathId, VarInt>,
+594
+595 // Nat traversal data
+596 /// Addresses to report in `ADD_ADDRESS` frames
+597 pub(super) add_address: BTreeSet<AddAddress>,
+598 /// Address IDs to remove in `REMOVE_ADDRESS` frames
+599 pub(super) remove_address: BTreeSet<RemoveAddress>,
+600 /// Round and local addresses to advertise in `REACH_OUT` frames
+601 pub(super) reach_out: PendingReachOutFrames,
+602}
+603
+604impl Retransmits {
+605 pub(super) fn is_empty(&self, streams: &StreamsState) -> bool {
+606 let Self {
+607 max_data,
+608 max_stream_id,
+609 streams_blocked,
+610 reset_stream,
+611 stop_sending,
+612 max_stream_data,
+613 crypto,
+614 new_cids,
+615 retire_cids,
+616 ack_frequency,
+617 handshake_done,
+618 max_path_id,
+619 paths_blocked,
+620 new_tokens,
+621 path_abandon,
+622 path_status,
+623 path_cids_blocked,
+624 add_address,
+625 remove_address,
+626 reach_out,
+627 } = &self;
+628 !max_data
+629 && !max_stream_id.iter().any(|x| *x)
+630 && !streams_blocked.iter().any(|x| *x)
+631 && reset_stream.is_empty()
+632 && stop_sending.is_empty()
+633 && max_stream_data
+634 .iter()
+635 .all(|&id| !streams.can_send_flow_control(id))
+636 && crypto.is_empty()
+637 && new_cids.is_empty()
+638 && retire_cids.is_empty()
+639 && !ack_frequency
+640 && !handshake_done
+641 && !max_path_id
+642 && paths_blocked.is_none()
+643 && new_tokens.is_empty()
+644 && path_abandon.is_empty()
+645 && path_status.is_empty()
+646 && path_cids_blocked.is_empty()
+647 && add_address.is_empty()
+648 && remove_address.is_empty()
+649 && reach_out.is_empty()
+650 }
+651}
+652
+653impl ::std::ops::BitOrAssign for Retransmits {
+654 fn bitor_assign(&mut self, rhs: Self) {
+655 let Self {
+656 max_data,
+657 max_stream_id,
+658 streams_blocked,
+659 reset_stream,
+660 stop_sending,
+661 max_stream_data,
+662 crypto,
+663 new_cids,
+664 retire_cids,
+665 ack_frequency,
+666 handshake_done,
+667 max_path_id,
+668 paths_blocked,
+669 new_tokens,
+670 mut path_abandon,
+671 mut path_status,
+672 mut path_cids_blocked,
+673 add_address,
+674 remove_address,
+675 mut reach_out,
+676 } = rhs;
+677
+678 // We reduce in-stream head-of-line blocking by queueing retransmits before other data for
+679 // STREAM and CRYPTO frames.
+680 self.max_data |= max_data;
+681 for dir in Dir::iter() {
+682 self.max_stream_id[dir as usize] |= max_stream_id[dir as usize];
+683 self.streams_blocked[dir as usize] |= streams_blocked[dir as usize];
+684 }
+685 self.reset_stream.extend_from_slice(&reset_stream);
+686 self.stop_sending.extend_from_slice(&stop_sending);
+687 self.max_stream_data.extend(&max_stream_data);
+688 for crypto in crypto.into_iter().rev() {
+689 self.crypto.push_front(crypto);
+690 }
+691 self.new_cids.extend(&new_cids);
+692 self.retire_cids.extend(retire_cids);
+693 self.ack_frequency |= ack_frequency;
+694 self.handshake_done |= handshake_done;
+695 self.max_path_id |= max_path_id;
+696 self.paths_blocked = cmp::max(self.paths_blocked, paths_blocked);
+697 self.new_tokens.extend_from_slice(&new_tokens);
+698 self.path_abandon.append(&mut path_abandon);
+699 self.path_status.append(&mut path_status);
+700 self.path_cids_blocked.append(&mut path_cids_blocked);
+701 self.add_address.extend(add_address.iter().copied());
+702 self.remove_address.extend(remove_address.iter().copied());
+703 self.reach_out.append(&mut reach_out);
+704 }
+705}
+706
+707impl ::std::ops::BitOrAssign<ThinRetransmits> for Retransmits {
+708 fn bitor_assign(&mut self, rhs: ThinRetransmits) {
+709 let ThinRetransmits { retransmits } = rhs;
+710 if let Some(retransmits) = retransmits {
+711 self.bitor_assign(*retransmits)
+712 }
+713 }
+714}
+715
+716impl ::std::iter::FromIterator<Self> for Retransmits {
+717 fn from_iter<T>(iter: T) -> Self
+718 where
+719 T: IntoIterator<Item = Self>,
+720 {
+721 let mut result = Self::default();
+722 for packet in iter {
+723 result |= packet;
+724 }
+725 result
+726 }
+727}
+728
+729/// The queue of new CIDs to be transmitted to the peer.
+730///
+731/// This queue is always sorted, so that popping off the last item is always the lowest
+732/// sequence number of the lowest path ID. Which is the CID you want to be issued next.
733///
-734/// This queue is always sorted, so that popping off the last item is always the lowest
-735/// sequence number of the lowest path ID. Which is the CID you want to be issued next.
-736///
-737/// This is but a newtype over a `Vec` to enforce the sorted invariant.
-738#[derive(Clone, Debug, Default)]
-739pub(super) struct PendingNewCids {
-740 /// The CIDs themselves.
-741 cids: Vec<IssuedCid>,
-742 /// Whether [`Self::cids`] is sorted or not.
-743 sorted: bool,
-744}
-745
-746impl PendingNewCids {
-747 /// Inserts an issued CID into the queue.
-748 pub(super) fn push(&mut self, cid: IssuedCid) {
-749 self.cids.push(cid);
-750 self.sorted = false;
-751 }
-752
-753 /// Pops the next issued CID to transmit from the queue.
-754 pub(super) fn pop(&mut self) -> Option<IssuedCid> {
-755 if !std::mem::replace(&mut self.sorted, true) {
-756 self.cids
-757 .sort_by_key(|cid| cmp::Reverse((cid.path_id, cid.sequence)));
-758 }
-759 self.cids.pop()
-760 }
-761
-762 pub(super) fn is_empty(&self) -> bool {
-763 self.cids.is_empty()
-764 }
-765
-766 pub(super) fn extend(&mut self, other: &Self) {
-767 self.cids.extend(&other.cids);
-768 self.sorted = false;
-769 }
-770
-771 pub(super) fn retain<F>(&mut self, f: F)
-772 where
-773 F: FnMut(&IssuedCid) -> bool,
-774 {
-775 self.cids.retain(f);
-776 }
-777}
-778
-779/// Logically a Vec of REACH_OUT frames queued for transmit.
+734/// This is but a newtype over a `Vec` to enforce the sorted invariant.
+735#[derive(Clone, Debug, Default)]
+736pub(super) struct PendingNewCids {
+737 /// The CIDs themselves.
+738 cids: Vec<IssuedCid>,
+739 /// Whether [`Self::cids`] is sorted or not.
+740 sorted: bool,
+741}
+742
+743impl PendingNewCids {
+744 /// Inserts an issued CID into the queue.
+745 pub(super) fn push(&mut self, cid: IssuedCid) {
+746 self.cids.push(cid);
+747 self.sorted = false;
+748 }
+749
+750 /// Pops the next issued CID to transmit from the queue.
+751 pub(super) fn pop(&mut self) -> Option<IssuedCid> {
+752 if !std::mem::replace(&mut self.sorted, true) {
+753 self.cids
+754 .sort_by_key(|cid| cmp::Reverse((cid.path_id, cid.sequence)));
+755 }
+756 self.cids.pop()
+757 }
+758
+759 pub(super) fn is_empty(&self) -> bool {
+760 self.cids.is_empty()
+761 }
+762
+763 pub(super) fn extend(&mut self, other: &Self) {
+764 self.cids.extend(&other.cids);
+765 self.sorted = false;
+766 }
+767
+768 pub(super) fn retain<F>(&mut self, f: F)
+769 where
+770 F: FnMut(&IssuedCid) -> bool,
+771 {
+772 self.cids.retain(f);
+773 }
+774}
+775
+776/// Logically a Vec of REACH_OUT frames queued for transmit.
+777///
+778/// This keeps track of the highest round ID and automatically drops frames with a lower
+779/// round ID.
780///
-781/// This keeps track of the highest round ID and automatically drops frames with a lower
-782/// round ID.
-783///
-784/// The API is directly modelled on [`Vec`].
-785#[derive(Debug, Default, Clone)]
-786pub(crate) struct PendingReachOutFrames {
-787 /// The round ID of the REACH_OUT frames currently pending.
-788 round: VarInt,
-789 /// The REACH_OUT frames, always all having the same round ID.
-790 frames: Vec<frame::ReachOut>,
-791}
-792
-793impl PendingReachOutFrames {
-794 pub(crate) fn len(&self) -> usize {
-795 self.frames.len()
-796 }
-797
-798 pub(crate) fn is_empty(&self) -> bool {
-799 self.frames.is_empty()
-800 }
-801
-802 pub(crate) fn push(&mut self, frame: frame::ReachOut) {
-803 if frame.round < self.round {
-804 return;
-805 } else if frame.round > self.round {
-806 self.round = frame.round;
-807 self.frames.clear();
-808 }
-809 self.frames.push(frame);
-810 }
-811
-812 pub(crate) fn append(&mut self, other: &mut Self) {
-813 if other.round < self.round {
-814 other.frames.clear();
-815 return;
-816 } else if other.round > self.round {
-817 self.round = other.round;
-818 self.frames.clear();
-819 }
-820 self.frames.append(&mut other.frames);
-821 }
-822
-823 pub(crate) fn pop_if(
-824 &mut self,
-825 predicate: impl FnOnce(&mut frame::ReachOut) -> bool,
-826 ) -> Option<frame::ReachOut> {
-827 self.frames.pop_if(predicate)
-828 }
-829}
-830
-831impl FromIterator<frame::ReachOut> for PendingReachOutFrames {
-832 fn from_iter<T: IntoIterator<Item = frame::ReachOut>>(iter: T) -> Self {
-833 let iter = iter.into_iter();
-834 let size_hint = iter.size_hint();
-835 let mut this = Self {
-836 round: Default::default(),
-837 frames: Vec::with_capacity(size_hint.1.unwrap_or(size_hint.0)),
-838 };
-839 for frame in iter {
-840 this.push(frame);
-841 }
-842 this
-843 }
-844}
-845
-846/// A variant of `Retransmits` which only allocates storage when required
-847#[derive(Debug, Default, Clone)]
-848pub(super) struct ThinRetransmits {
-849 retransmits: Option<Box<Retransmits>>,
-850}
-851
-852impl ThinRetransmits {
-853 /// Returns `true` if no retransmits are necessary
-854 pub(super) fn is_empty(&self, streams: &StreamsState) -> bool {
-855 match &self.retransmits {
-856 Some(retransmits) => retransmits.is_empty(streams),
-857 None => true,
-858 }
-859 }
-860
-861 /// Returns a reference to the retransmits stored in this box
-862 pub(super) fn get(&self) -> Option<&Retransmits> {
-863 self.retransmits.as_deref()
-864 }
-865
-866 /// Returns a mutable reference to the retransmits stored in this box
-867 pub(super) fn get_mut(&mut self) -> Option<&mut Retransmits> {
-868 self.retransmits.as_deref_mut()
-869 }
-870
-871 /// Returns a mutable reference to the stored retransmits
-872 ///
-873 /// This function will allocate a backing storage if required.
-874 pub(super) fn get_or_create(&mut self) -> &mut Retransmits {
-875 if self.retransmits.is_none() {
-876 self.retransmits = Some(Box::default());
-877 }
-878 self.retransmits.as_deref_mut().unwrap()
-879 }
-880}
-881
-882/// RFC4303-style sliding window packet number deduplicator.
-883///
-884/// A contiguous bitfield, where each bit corresponds to a packet number and the rightmost bit is
-885/// always set. A set bit represents a packet that has been successfully authenticated. Bits left of
-886/// the window are assumed to be set.
-887///
-888/// ```text
-889/// ...xxxxxxxxx 1 0
-890/// ^ ^ ^
-891/// window highest next
-892/// ```
-893#[derive(Debug, Default)]
-894pub(super) struct Dedup {
-895 window: Window,
-896 /// Lowest packet number higher than all yet authenticated.
-897 next: u64,
-898}
-899
-900/// Inner bitfield type.
-901///
-902/// Because QUIC never reuses packet numbers, this only needs to be large enough to deal with
-903/// packets that are reordered but still delivered in a timely manner.
-904type Window = u128;
+781/// The API is directly modelled on [`Vec`].
+782#[derive(Debug, Default, Clone)]
+783pub(crate) struct PendingReachOutFrames {
+784 /// The round ID of the REACH_OUT frames currently pending.
+785 round: VarInt,
+786 /// The REACH_OUT frames, always all having the same round ID.
+787 frames: Vec<frame::ReachOut>,
+788}
+789
+790impl PendingReachOutFrames {
+791 pub(crate) fn len(&self) -> usize {
+792 self.frames.len()
+793 }
+794
+795 pub(crate) fn is_empty(&self) -> bool {
+796 self.frames.is_empty()
+797 }
+798
+799 pub(crate) fn push(&mut self, frame: frame::ReachOut) {
+800 if frame.round < self.round {
+801 return;
+802 } else if frame.round > self.round {
+803 self.round = frame.round;
+804 self.frames.clear();
+805 }
+806 self.frames.push(frame);
+807 }
+808
+809 pub(crate) fn append(&mut self, other: &mut Self) {
+810 if other.round < self.round {
+811 other.frames.clear();
+812 return;
+813 } else if other.round > self.round {
+814 self.round = other.round;
+815 self.frames.clear();
+816 }
+817 self.frames.append(&mut other.frames);
+818 }
+819
+820 pub(crate) fn pop_if(
+821 &mut self,
+822 predicate: impl FnOnce(&mut frame::ReachOut) -> bool,
+823 ) -> Option<frame::ReachOut> {
+824 self.frames.pop_if(predicate)
+825 }
+826}
+827
+828impl FromIterator<frame::ReachOut> for PendingReachOutFrames {
+829 fn from_iter<T: IntoIterator<Item = frame::ReachOut>>(iter: T) -> Self {
+830 let iter = iter.into_iter();
+831 let size_hint = iter.size_hint();
+832 let mut this = Self {
+833 round: Default::default(),
+834 frames: Vec::with_capacity(size_hint.1.unwrap_or(size_hint.0)),
+835 };
+836 for frame in iter {
+837 this.push(frame);
+838 }
+839 this
+840 }
+841}
+842
+843/// A variant of `Retransmits` which only allocates storage when required
+844#[derive(Debug, Default, Clone)]
+845pub(super) struct ThinRetransmits {
+846 retransmits: Option<Box<Retransmits>>,
+847}
+848
+849impl ThinRetransmits {
+850 /// Returns `true` if no retransmits are necessary
+851 pub(super) fn is_empty(&self, streams: &StreamsState) -> bool {
+852 match &self.retransmits {
+853 Some(retransmits) => retransmits.is_empty(streams),
+854 None => true,
+855 }
+856 }
+857
+858 /// Returns a reference to the retransmits stored in this box
+859 pub(super) fn get(&self) -> Option<&Retransmits> {
+860 self.retransmits.as_deref()
+861 }
+862
+863 /// Returns a mutable reference to the retransmits stored in this box
+864 pub(super) fn get_mut(&mut self) -> Option<&mut Retransmits> {
+865 self.retransmits.as_deref_mut()
+866 }
+867
+868 /// Returns a mutable reference to the stored retransmits
+869 ///
+870 /// This function will allocate a backing storage if required.
+871 pub(super) fn get_or_create(&mut self) -> &mut Retransmits {
+872 if self.retransmits.is_none() {
+873 self.retransmits = Some(Box::default());
+874 }
+875 self.retransmits.as_deref_mut().unwrap()
+876 }
+877}
+878
+879/// RFC4303-style sliding window packet number deduplicator.
+880///
+881/// A contiguous bitfield, where each bit corresponds to a packet number and the rightmost bit is
+882/// always set. A set bit represents a packet that has been successfully authenticated. Bits left of
+883/// the window are assumed to be set.
+884///
+885/// ```text
+886/// ...xxxxxxxxx 1 0
+887/// ^ ^ ^
+888/// window highest next
+889/// ```
+890#[derive(Debug, Default)]
+891pub(super) struct Dedup {
+892 window: Window,
+893 /// Lowest packet number higher than all yet authenticated.
+894 next: u64,
+895}
+896
+897/// Inner bitfield type.
+898///
+899/// Because QUIC never reuses packet numbers, this only needs to be large enough to deal with
+900/// packets that are reordered but still delivered in a timely manner.
+901type Window = u128;
+902
+903/// Number of packets tracked by `Dedup`.
+904const WINDOW_SIZE: u64 = 1 + mem::size_of::<Window>() as u64 * 8;
905
-906/// Number of packets tracked by `Dedup`.
-907const WINDOW_SIZE: u64 = 1 + mem::size_of::<Window>() as u64 * 8;
-908
-909impl Dedup {
-910 /// Construct an empty window positioned at the start.
-911 #[cfg(test)]
-912 pub(super) fn new() -> Self {
-913 Self { window: 0, next: 0 }
-914 }
-915
-916 /// Highest packet number authenticated.
-917 fn highest(&self) -> u64 {
-918 self.next - 1
-919 }
-920
-921 /// Record a newly authenticated packet number.
-922 ///
-923 /// Returns whether the packet might be a duplicate.
-924 pub(super) fn insert(&mut self, packet: u64) -> bool {
-925 if let Some(diff) = packet.checked_sub(self.next) {
-926 // Right of window
-927 self.window = ((self.window << 1) | 1)
-928 .checked_shl(cmp::min(diff, u64::from(u32::MAX)) as u32)
-929 .unwrap_or(0);
-930 self.next = packet + 1;
-931 false
-932 } else if self.highest() - packet < WINDOW_SIZE {
-933 // Within window
-934 if let Some(bit) = (self.highest() - packet).checked_sub(1) {
-935 // < highest
-936 let mask = 1 << bit;
-937 let duplicate = self.window & mask != 0;
-938 self.window |= mask;
-939 duplicate
-940 } else {
-941 // == highest
-942 true
-943 }
-944 } else {
-945 // Left of window
-946 true
-947 }
-948 }
-949
-950 /// Returns the packet number of the smallest packet missing between the provided interval
-951 ///
-952 /// If there are no missing packets, returns `None`
-953 fn smallest_missing_in_interval(&self, lower_bound: u64, upper_bound: u64) -> Option<u64> {
-954 debug_assert!(lower_bound <= upper_bound);
-955 debug_assert!(upper_bound <= self.highest());
-956 const BITFIELD_SIZE: u64 = (mem::size_of::<Window>() * 8) as u64;
-957
-958 // Since we already know the packets at the boundaries have been received, we only need to
-959 // check those in between them (this removes the necessity of extra logic to deal with the
-960 // highest packet, which is stored outside the bitfield)
-961 let lower_bound = lower_bound + 1;
-962 let upper_bound = upper_bound.saturating_sub(1);
-963
-964 // Note: the offsets are counted from the right
-965 // The highest packet is not included in the bitfield, so we subtract 1 to account for that
-966 let start_offset = (self.highest() - upper_bound).max(1) - 1;
-967 if start_offset >= BITFIELD_SIZE {
-968 // The start offset is outside of the window. All packets outside of the window are
-969 // considered to be received.
-970 return None;
-971 }
-972
-973 let end_offset_exclusive = self.highest().saturating_sub(lower_bound);
-974
-975 // The range is clamped at the edge of the window, because any earlier packets are
-976 // considered to be received
-977 let range_len = end_offset_exclusive
-978 .saturating_sub(start_offset)
-979 .min(BITFIELD_SIZE);
-980 if range_len == 0 {
-981 return None;
-982 }
-983
-984 // Ensure the shift is within bounds (we already know start_offset < BITFIELD_SIZE,
-985 // because of the early return)
-986 let mask = if range_len == BITFIELD_SIZE {
-987 u128::MAX
-988 } else {
-989 ((1u128 << range_len) - 1) << start_offset
-990 };
-991 let gaps = !self.window & mask;
+906impl Dedup {
+907 /// Construct an empty window positioned at the start.
+908 #[cfg(test)]
+909 pub(super) fn new() -> Self {
+910 Self { window: 0, next: 0 }
+911 }
+912
+913 /// Highest packet number authenticated.
+914 fn highest(&self) -> u64 {
+915 self.next - 1
+916 }
+917
+918 /// Record a newly authenticated packet number.
+919 ///
+920 /// Returns whether the packet might be a duplicate.
+921 pub(super) fn insert(&mut self, packet: u64) -> bool {
+922 if let Some(diff) = packet.checked_sub(self.next) {
+923 // Right of window
+924 self.window = ((self.window << 1) | 1)
+925 .checked_shl(cmp::min(diff, u64::from(u32::MAX)) as u32)
+926 .unwrap_or(0);
+927 self.next = packet + 1;
+928 false
+929 } else if self.highest() - packet < WINDOW_SIZE {
+930 // Within window
+931 if let Some(bit) = (self.highest() - packet).checked_sub(1) {
+932 // < highest
+933 let mask = 1 << bit;
+934 let duplicate = self.window & mask != 0;
+935 self.window |= mask;
+936 duplicate
+937 } else {
+938 // == highest
+939 true
+940 }
+941 } else {
+942 // Left of window
+943 true
+944 }
+945 }
+946
+947 /// Returns the packet number of the smallest packet missing between the provided interval
+948 ///
+949 /// If there are no missing packets, returns `None`
+950 fn smallest_missing_in_interval(&self, lower_bound: u64, upper_bound: u64) -> Option<u64> {
+951 debug_assert!(lower_bound <= upper_bound);
+952 debug_assert!(upper_bound <= self.highest());
+953 const BITFIELD_SIZE: u64 = (mem::size_of::<Window>() * 8) as u64;
+954
+955 // Since we already know the packets at the boundaries have been received, we only need to
+956 // check those in between them (this removes the necessity of extra logic to deal with the
+957 // highest packet, which is stored outside the bitfield)
+958 let lower_bound = lower_bound + 1;
+959 let upper_bound = upper_bound.saturating_sub(1);
+960
+961 // Note: the offsets are counted from the right
+962 // The highest packet is not included in the bitfield, so we subtract 1 to account for that
+963 let start_offset = (self.highest() - upper_bound).max(1) - 1;
+964 if start_offset >= BITFIELD_SIZE {
+965 // The start offset is outside of the window. All packets outside of the window are
+966 // considered to be received.
+967 return None;
+968 }
+969
+970 let end_offset_exclusive = self.highest().saturating_sub(lower_bound);
+971
+972 // The range is clamped at the edge of the window, because any earlier packets are
+973 // considered to be received
+974 let range_len = end_offset_exclusive
+975 .saturating_sub(start_offset)
+976 .min(BITFIELD_SIZE);
+977 if range_len == 0 {
+978 return None;
+979 }
+980
+981 // Ensure the shift is within bounds (we already know start_offset < BITFIELD_SIZE,
+982 // because of the early return)
+983 let mask = if range_len == BITFIELD_SIZE {
+984 u128::MAX
+985 } else {
+986 ((1u128 << range_len) - 1) << start_offset
+987 };
+988 let gaps = !self.window & mask;
+989
+990 let smallest_missing_offset = 128 - gaps.leading_zeros() as u64;
+991 let smallest_missing_packet = self.highest() - smallest_missing_offset;
992
-993 let smallest_missing_offset = 128 - gaps.leading_zeros() as u64;
-994 let smallest_missing_packet = self.highest() - smallest_missing_offset;
-995
-996 if smallest_missing_packet <= upper_bound {
-997 Some(smallest_missing_packet)
-998 } else {
-999 None
-1000 }
-1001 }
-1002
-1003 /// Returns true if there are any missing packets between the provided interval
-1004 ///
-1005 /// The provided packet numbers must have been received before calling this function
-1006 fn missing_in_interval(&self, lower_bound: u64, upper_bound: u64) -> bool {
-1007 self.smallest_missing_in_interval(lower_bound, upper_bound)
-1008 .is_some()
-1009 }
-1010}
-1011
-1012/// Indicates which data is available for sending.
-1013///
-1014/// This applies to a particular space ID that was queried and all refers to on-path data.
-1015#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-1016pub(super) struct SendableFrames {
-1017 /// Whether there are ACK frames to send, these are not ack-eliciting.
-1018 pub(super) acks: bool,
-1019 /// Whether there is a CONNECTION_CLOSE to send, this is not ack-eliciting.
-1020 pub(super) close: bool,
-1021 /// Whether there are any frames that must be sent on this specific space.
+993 if smallest_missing_packet <= upper_bound {
+994 Some(smallest_missing_packet)
+995 } else {
+996 None
+997 }
+998 }
+999
+1000 /// Returns true if there are any missing packets between the provided interval
+1001 ///
+1002 /// The provided packet numbers must have been received before calling this function
+1003 fn missing_in_interval(&self, lower_bound: u64, upper_bound: u64) -> bool {
+1004 self.smallest_missing_in_interval(lower_bound, upper_bound)
+1005 .is_some()
+1006 }
+1007}
+1008
+1009/// Indicates which data is available for sending.
+1010///
+1011/// This applies to a particular space ID that was queried and all refers to on-path data.
+1012#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+1013pub(super) struct SendableFrames {
+1014 /// Whether there are ACK frames to send, these are not ack-eliciting.
+1015 pub(super) acks: bool,
+1016 /// Whether there is a CONNECTION_CLOSE to send, this is not ack-eliciting.
+1017 pub(super) close: bool,
+1018 /// Whether there are any frames that must be sent on this specific space.
+1019 ///
+1020 /// A space here in the sense of a QUIC Multipath packet number space: `Initial`,
+1021 /// `Handshake` and all `Data(PathId)` spaces.
1022 ///
-1023 /// A space here in the sense of a QUIC Multipath packet number space: `Initial`,
-1024 /// `Handshake` and all `Data(PathId)` spaces.
-1025 ///
-1026 /// These are ack-eliciting. Some frames are scheduled per path, e.g. PING,
-1027 /// IMMEDIATE_ACK, PATH_CHALLENGE or PATH_RESPONSE.
-1028 pub(super) space_specific: bool,
-1029 /// Whether there are any other frames to send, these are ack-eliciting.
-1030 pub(super) other: bool,
-1031}
-1032
-1033impl SendableFrames {
-1034 /// Returns that no data is available for sending
-1035 pub(super) fn empty() -> Self {
-1036 Self {
-1037 acks: false,
-1038 close: false,
-1039 space_specific: false,
-1040 other: false,
-1041 }
-1042 }
-1043
-1044 /// Whether an ack-eliciting packet will be sent.
-1045 pub(super) fn is_ack_eliciting(&self) -> bool {
-1046 let Self {
-1047 acks: _,
-1048 close,
-1049 space_specific,
-1050 other,
-1051 } = *self;
-1052 if close {
-1053 // No ack-eliciting frames are included with a CONNECTION_CLOSE, only acks.
-1054 return false;
-1055 }
-1056 space_specific || other
-1057 }
-1058
-1059 /// Whether no data is sendable.
-1060 pub(super) fn is_empty(&self) -> bool {
-1061 let Self {
-1062 acks,
-1063 close,
-1064 space_specific,
-1065 other,
-1066 } = *self;
-1067 !acks && !close && !space_specific && !other
-1068 }
-1069}
-1070
-1071impl ::std::ops::BitOrAssign for SendableFrames {
-1072 fn bitor_assign(&mut self, rhs: Self) {
-1073 let Self {
-1074 acks,
-1075 close,
-1076 space_specific,
-1077 other,
-1078 } = rhs;
-1079
-1080 self.acks |= acks;
-1081 self.close |= close;
-1082 self.space_specific |= space_specific;
-1083 self.other |= other;
-1084 }
-1085}
-1086
-1087#[derive(Debug)]
-1088pub(super) struct PendingAcks {
-1089 /// Whether we should send an ACK immediately, even if that means sending an ACK-only packet
-1090 ///
-1091 /// When `immediate_ack_required` is false, the normal behavior is to send ACK frames only when
-1092 /// there is other data to send, or when the `MaxAckDelay` timer expires.
-1093 immediate_ack_required: bool,
-1094 /// The number of ack-eliciting packets received since the last ACK frame was sent
-1095 ///
-1096 /// Once the count _exceeds_ `ack_eliciting_threshold`, an immediate ACK is required
-1097 ack_eliciting_since_last_ack_sent: u64,
-1098 non_ack_eliciting_since_last_ack_sent: u64,
-1099 ack_eliciting_threshold: u64,
-1100 /// The reordering threshold, controlling how we respond to out-of-order ack-eliciting packets
-1101 ///
-1102 /// Different values enable different behavior:
-1103 ///
-1104 /// * `0`: no special action is taken
-1105 /// * `1`: an ACK is immediately sent if it is out-of-order according to RFC 9000
-1106 /// * `>1`: an ACK is immediately sent if it is out-of-order according to the ACK frequency draft
-1107 reordering_threshold: u64,
-1108 /// The earliest ack-eliciting packet since the last ACK was sent, used to calculate the moment
-1109 /// upon which `max_ack_delay` elapses
-1110 earliest_ack_eliciting_since_last_ack_sent: Option<Instant>,
-1111 /// Packet number ranges for which to still send acknowledgements.
-1112 ///
-1113 /// These are packet number ranges of ack-eliciting packets the peer has sent and which
-1114 /// need to be acknowledged. Packet numbers are only removed from here once the peer has
-1115 /// acknowledged the ACKs for them.
-1116 ranges: ArrayRangeSet,
-1117 /// The largest packet number received and the time it was received
-1118 ///
-1119 /// Used to calculate ACK delay in [`PendingAcks::ack_delay`].
-1120 largest_packet: Option<(u64, Instant)>,
-1121 /// The ack-eliciting packet we have received with the largest packet number
-1122 largest_ack_eliciting_packet: Option<u64>,
-1123 /// The largest acknowledged packet number sent in an ACK frame
-1124 largest_acked: Option<u64>,
-1125}
-1126
-1127impl PendingAcks {
-1128 fn new() -> Self {
-1129 Self {
-1130 immediate_ack_required: false,
-1131 ack_eliciting_since_last_ack_sent: 0,
-1132 non_ack_eliciting_since_last_ack_sent: 0,
-1133 ack_eliciting_threshold: 1,
-1134 reordering_threshold: 1,
-1135 earliest_ack_eliciting_since_last_ack_sent: None,
-1136 ranges: Default::default(),
-1137 largest_packet: Default::default(),
-1138 largest_ack_eliciting_packet: Default::default(),
-1139 largest_acked: Default::default(),
-1140 }
-1141 }
-1142
-1143 pub(super) fn set_ack_frequency_params(&mut self, frame: &frame::AckFrequency) {
-1144 self.ack_eliciting_threshold = frame.ack_eliciting_threshold.into_inner();
-1145 self.reordering_threshold = frame.reordering_threshold.into_inner();
-1146 }
-1147
-1148 pub(super) fn set_immediate_ack_required(&mut self) {
-1149 self.immediate_ack_required = true;
-1150 }
-1151
-1152 pub(super) fn on_max_ack_delay_timeout(&mut self) {
-1153 self.immediate_ack_required = self.ack_eliciting_since_last_ack_sent > 0;
-1154 }
-1155
-1156 pub(super) fn max_ack_delay_timeout(&self, max_ack_delay: Duration) -> Option<Instant> {
-1157 self.earliest_ack_eliciting_since_last_ack_sent
-1158 .map(|earliest_unacked| earliest_unacked + max_ack_delay)
-1159 }
-1160
-1161 /// Whether any ACK frames SHOULD be sent
-1162 ///
-1163 /// This is used in the top-level [`Connection::space_can_send`], so determines if a
-1164 /// packet will be built. It is often possible to construct new ACK ranges to send
-1165 /// before this returns `true`. This results in more ACK frames being sent, and
-1166 /// processing those at the receiver costs CPU for very little improvements.
-1167 ///
-1168 /// [`Connection::space_can_send`]: super::Connection::space_can_send
-1169 pub(super) fn can_send(&self) -> bool {
-1170 self.immediate_ack_required && !self.ranges.is_empty()
-1171 }
-1172
-1173 /// Returns the delay since the packet with the largest packet number was received
-1174 pub(super) fn ack_delay(&self, now: Instant) -> Duration {
-1175 self.largest_packet
-1176 .map_or_else(Duration::default, |(_, received)| now - received)
-1177 }
-1178
-1179 /// Handle receipt of a new packet
-1180 ///
-1181 /// Returns true if the max ack delay timer should be armed
-1182 pub(super) fn packet_received(
-1183 &mut self,
-1184 now: Instant,
-1185 packet_number: u64,
-1186 ack_eliciting: bool,
-1187 dedup: &Dedup,
-1188 ) -> bool {
-1189 if !ack_eliciting {
-1190 self.non_ack_eliciting_since_last_ack_sent += 1;
-1191 return false;
-1192 }
-1193
-1194 let prev_largest_ack_eliciting = self.largest_ack_eliciting_packet.unwrap_or(0);
-1195
-1196 // Track largest ack-eliciting packet
-1197 self.largest_ack_eliciting_packet = self
-1198 .largest_ack_eliciting_packet
-1199 .map(|pn| pn.max(packet_number))
-1200 .or(Some(packet_number));
-1201
-1202 // Handle ack_eliciting_threshold
-1203 self.ack_eliciting_since_last_ack_sent += 1;
-1204 self.immediate_ack_required |=
-1205 self.ack_eliciting_since_last_ack_sent > self.ack_eliciting_threshold;
-1206
-1207 // Handle out-of-order packets
-1208 self.immediate_ack_required |=
-1209 self.is_out_of_order(packet_number, prev_largest_ack_eliciting, dedup);
-1210
-1211 // Arm max_ack_delay timer if necessary
-1212 if self.earliest_ack_eliciting_since_last_ack_sent.is_none() && !self.can_send() {
-1213 self.earliest_ack_eliciting_since_last_ack_sent = Some(now);
-1214 return true;
-1215 }
+1023 /// These are ack-eliciting. Some frames are scheduled per path, e.g. PING,
+1024 /// IMMEDIATE_ACK, PATH_CHALLENGE or PATH_RESPONSE.
+1025 pub(super) space_specific: bool,
+1026 /// Whether there are any other frames to send, these are ack-eliciting.
+1027 pub(super) other: bool,
+1028}
+1029
+1030impl SendableFrames {
+1031 /// Returns that no data is available for sending
+1032 pub(super) fn empty() -> Self {
+1033 Self {
+1034 acks: false,
+1035 close: false,
+1036 space_specific: false,
+1037 other: false,
+1038 }
+1039 }
+1040
+1041 /// Whether an ack-eliciting packet will be sent.
+1042 pub(super) fn is_ack_eliciting(&self) -> bool {
+1043 let Self {
+1044 acks: _,
+1045 close,
+1046 space_specific,
+1047 other,
+1048 } = *self;
+1049 if close {
+1050 // No ack-eliciting frames are included with a CONNECTION_CLOSE, only acks.
+1051 return false;
+1052 }
+1053 space_specific || other
+1054 }
+1055
+1056 /// Whether no data is sendable.
+1057 pub(super) fn is_empty(&self) -> bool {
+1058 let Self {
+1059 acks,
+1060 close,
+1061 space_specific,
+1062 other,
+1063 } = *self;
+1064 !acks && !close && !space_specific && !other
+1065 }
+1066}
+1067
+1068impl ::std::ops::BitOrAssign for SendableFrames {
+1069 fn bitor_assign(&mut self, rhs: Self) {
+1070 let Self {
+1071 acks,
+1072 close,
+1073 space_specific,
+1074 other,
+1075 } = rhs;
+1076
+1077 self.acks |= acks;
+1078 self.close |= close;
+1079 self.space_specific |= space_specific;
+1080 self.other |= other;
+1081 }
+1082}
+1083
+1084#[derive(Debug)]
+1085pub(super) struct PendingAcks {
+1086 /// Whether we should send an ACK immediately, even if that means sending an ACK-only packet
+1087 ///
+1088 /// When `immediate_ack_required` is false, the normal behavior is to send ACK frames only when
+1089 /// there is other data to send, or when the `MaxAckDelay` timer expires.
+1090 immediate_ack_required: bool,
+1091 /// The number of ack-eliciting packets received since the last ACK frame was sent
+1092 ///
+1093 /// Once the count _exceeds_ `ack_eliciting_threshold`, an immediate ACK is required
+1094 ack_eliciting_since_last_ack_sent: u64,
+1095 non_ack_eliciting_since_last_ack_sent: u64,
+1096 ack_eliciting_threshold: u64,
+1097 /// The reordering threshold, controlling how we respond to out-of-order ack-eliciting packets
+1098 ///
+1099 /// Different values enable different behavior:
+1100 ///
+1101 /// * `0`: no special action is taken
+1102 /// * `1`: an ACK is immediately sent if it is out-of-order according to RFC 9000
+1103 /// * `>1`: an ACK is immediately sent if it is out-of-order according to the ACK frequency draft
+1104 reordering_threshold: u64,
+1105 /// The earliest ack-eliciting packet since the last ACK was sent, used to calculate the moment
+1106 /// upon which `max_ack_delay` elapses
+1107 earliest_ack_eliciting_since_last_ack_sent: Option<Instant>,
+1108 /// Packet number ranges for which to still send acknowledgements.
+1109 ///
+1110 /// These are packet number ranges of ack-eliciting packets the peer has sent and which
+1111 /// need to be acknowledged. Packet numbers are only removed from here once the peer has
+1112 /// acknowledged the ACKs for them.
+1113 ranges: ArrayRangeSet,
+1114 /// The largest packet number received and the time it was received
+1115 ///
+1116 /// Used to calculate ACK delay in [`PendingAcks::ack_delay`].
+1117 largest_packet: Option<(u64, Instant)>,
+1118 /// The ack-eliciting packet we have received with the largest packet number
+1119 largest_ack_eliciting_packet: Option<u64>,
+1120 /// The largest acknowledged packet number sent in an ACK frame
+1121 largest_acked: Option<u64>,
+1122}
+1123
+1124impl PendingAcks {
+1125 fn new() -> Self {
+1126 Self {
+1127 immediate_ack_required: false,
+1128 ack_eliciting_since_last_ack_sent: 0,
+1129 non_ack_eliciting_since_last_ack_sent: 0,
+1130 ack_eliciting_threshold: 1,
+1131 reordering_threshold: 1,
+1132 earliest_ack_eliciting_since_last_ack_sent: None,
+1133 ranges: Default::default(),
+1134 largest_packet: Default::default(),
+1135 largest_ack_eliciting_packet: Default::default(),
+1136 largest_acked: Default::default(),
+1137 }
+1138 }
+1139
+1140 pub(super) fn set_ack_frequency_params(&mut self, frame: &frame::AckFrequency) {
+1141 self.ack_eliciting_threshold = frame.ack_eliciting_threshold.into_inner();
+1142 self.reordering_threshold = frame.reordering_threshold.into_inner();
+1143 }
+1144
+1145 pub(super) fn set_immediate_ack_required(&mut self) {
+1146 self.immediate_ack_required = true;
+1147 }
+1148
+1149 pub(super) fn on_max_ack_delay_timeout(&mut self) {
+1150 self.immediate_ack_required = self.ack_eliciting_since_last_ack_sent > 0;
+1151 }
+1152
+1153 pub(super) fn max_ack_delay_timeout(&self, max_ack_delay: Duration) -> Option<Instant> {
+1154 self.earliest_ack_eliciting_since_last_ack_sent
+1155 .map(|earliest_unacked| earliest_unacked + max_ack_delay)
+1156 }
+1157
+1158 /// Whether any ACK frames SHOULD be sent
+1159 ///
+1160 /// This is used in the top-level [`Connection::space_can_send`], so determines if a
+1161 /// packet will be built. It is often possible to construct new ACK ranges to send
+1162 /// before this returns `true`. This results in more ACK frames being sent, and
+1163 /// processing those at the receiver costs CPU for very little improvements.
+1164 ///
+1165 /// [`Connection::space_can_send`]: super::Connection::space_can_send
+1166 pub(super) fn can_send(&self) -> bool {
+1167 self.immediate_ack_required && !self.ranges.is_empty()
+1168 }
+1169
+1170 /// Returns the delay since the packet with the largest packet number was received
+1171 pub(super) fn ack_delay(&self, now: Instant) -> Duration {
+1172 self.largest_packet
+1173 .map_or_else(Duration::default, |(_, received)| now - received)
+1174 }
+1175
+1176 /// Handle receipt of a new packet
+1177 ///
+1178 /// Returns true if the max ack delay timer should be armed
+1179 pub(super) fn packet_received(
+1180 &mut self,
+1181 now: Instant,
+1182 packet_number: u64,
+1183 ack_eliciting: bool,
+1184 dedup: &Dedup,
+1185 ) -> bool {
+1186 if !ack_eliciting {
+1187 self.non_ack_eliciting_since_last_ack_sent += 1;
+1188 return false;
+1189 }
+1190
+1191 let prev_largest_ack_eliciting = self.largest_ack_eliciting_packet.unwrap_or(0);
+1192
+1193 // Track largest ack-eliciting packet
+1194 self.largest_ack_eliciting_packet = self
+1195 .largest_ack_eliciting_packet
+1196 .map(|pn| pn.max(packet_number))
+1197 .or(Some(packet_number));
+1198
+1199 // Handle ack_eliciting_threshold
+1200 self.ack_eliciting_since_last_ack_sent += 1;
+1201 self.immediate_ack_required |=
+1202 self.ack_eliciting_since_last_ack_sent > self.ack_eliciting_threshold;
+1203
+1204 // Handle out-of-order packets
+1205 self.immediate_ack_required |=
+1206 self.is_out_of_order(packet_number, prev_largest_ack_eliciting, dedup);
+1207
+1208 // Arm max_ack_delay timer if necessary
+1209 if self.earliest_ack_eliciting_since_last_ack_sent.is_none() && !self.can_send() {
+1210 self.earliest_ack_eliciting_since_last_ack_sent = Some(now);
+1211 return true;
+1212 }
+1213
+1214 false
+1215 }
1216
-1217 false
-1218 }
-1219
-1220 fn is_out_of_order(
-1221 &self,
-1222 packet_number: u64,
-1223 prev_largest_ack_eliciting: u64,
-1224 dedup: &Dedup,
-1225 ) -> bool {
-1226 match self.reordering_threshold {
-1227 0 => false,
-1228 1 => {
-1229 // From https://www.rfc-editor.org/rfc/rfc9000#section-13.2.1-7
-1230 packet_number < prev_largest_ack_eliciting
-1231 || dedup.missing_in_interval(prev_largest_ack_eliciting, packet_number)
-1232 }
-1233 _ => {
-1234 // From acknowledgement frequency draft, section 6.1: send an ACK immediately if
-1235 // doing so would cause the sender to detect a new packet loss
-1236 let Some((largest_acked, largest_unacked)) =
-1237 self.largest_acked.zip(self.largest_ack_eliciting_packet)
-1238 else {
+1217 fn is_out_of_order(
+1218 &self,
+1219 packet_number: u64,
+1220 prev_largest_ack_eliciting: u64,
+1221 dedup: &Dedup,
+1222 ) -> bool {
+1223 match self.reordering_threshold {
+1224 0 => false,
+1225 1 => {
+1226 // From https://www.rfc-editor.org/rfc/rfc9000#section-13.2.1-7
+1227 packet_number < prev_largest_ack_eliciting
+1228 || dedup.missing_in_interval(prev_largest_ack_eliciting, packet_number)
+1229 }
+1230 _ => {
+1231 // From acknowledgement frequency draft, section 6.1: send an ACK immediately if
+1232 // doing so would cause the sender to detect a new packet loss
+1233 let Some((largest_acked, largest_unacked)) =
+1234 self.largest_acked.zip(self.largest_ack_eliciting_packet)
+1235 else {
+1236 return false;
+1237 };
+1238 if self.reordering_threshold > largest_acked {
1239 return false;
-1240 };
-1241 if self.reordering_threshold > largest_acked {
-1242 return false;
-1243 }
-1244 // The largest packet number that could be declared lost without a new ACK being
-1245 // sent
-1246 let largest_reported = largest_acked - self.reordering_threshold + 1;
-1247 let Some(smallest_missing_unreported) =
-1248 dedup.smallest_missing_in_interval(largest_reported, largest_unacked)
-1249 else {
-1250 return false;
-1251 };
-1252 largest_unacked - smallest_missing_unreported >= self.reordering_threshold
-1253 }
-1254 }
-1255 }
-1256
-1257 /// Should be called whenever ACKs have been sent
-1258 ///
-1259 /// This will suppress sending further ACKs until additional ACK eliciting frames arrive
-1260 pub(super) fn acks_sent(&mut self) {
-1261 // It is possible (though unlikely) that the ACKs we just sent do not cover all the
-1262 // ACK-eliciting packets we have received (e.g. if there is not enough room in the packet to
-1263 // fit all the ranges). To keep things simple, however, we assume they do. If there are
-1264 // indeed some ACKs that weren't covered, the packets might be ACKed later anyway, because
-1265 // they are still contained in `self.ranges`. If we somehow fail to send the ACKs at a later
-1266 // moment, the peer will assume the packets got lost and will retransmit their frames in a
-1267 // new packet, which is suboptimal, because we already received them. Our assumption here is
-1268 // that simplicity results in code that is more performant, even in the presence of
-1269 // occasional redundant retransmits.
-1270 self.immediate_ack_required = false;
-1271 self.ack_eliciting_since_last_ack_sent = 0;
-1272 self.non_ack_eliciting_since_last_ack_sent = 0;
-1273 self.earliest_ack_eliciting_since_last_ack_sent = None;
-1274 self.largest_acked = self.largest_ack_eliciting_packet;
-1275 }
-1276
-1277 /// Insert one packet that needs to be acknowledged
-1278 pub(super) fn insert_one(&mut self, packet: u64, now: Instant) {
-1279 self.ranges.insert_one(packet);
-1280
-1281 if self.largest_packet.is_none_or(|(pn, _)| packet > pn) {
-1282 self.largest_packet = Some((packet, now));
-1283 }
-1284
-1285 if self.ranges.range_count() > MAX_ACK_BLOCKS {
-1286 self.ranges.pop_min();
-1287 }
-1288 }
-1289
-1290 /// Remove ACKs of packets numbered at or below `max` from the set of pending ACKs
-1291 pub(super) fn subtract_below(&mut self, max: u64) {
-1292 self.ranges.remove(0..(max + 1));
-1293 }
-1294
-1295 /// Returns the set of currently pending ACK ranges
-1296 pub(super) fn ranges(&self) -> &ArrayRangeSet {
-1297 &self.ranges
-1298 }
-1299
-1300 /// Queue an ACK if a significant number of non-ACK-eliciting packets have not yet been
-1301 /// acknowledged
-1302 ///
-1303 /// Should be called immediately before a non-probing packet is composed, when we've already
-1304 /// committed to sending a packet regardless.
-1305 pub(super) fn maybe_ack_non_eliciting(&mut self) {
-1306 // If we're going to send a packet anyway, and we've received a significant number of
-1307 // non-ACK-eliciting packets, then include an ACK to help the peer perform timely loss
-1308 // detection even if they're not sending any ACK-eliciting packets themselves. Exact
-1309 // threshold chosen somewhat arbitrarily.
-1310 const LAZY_ACK_THRESHOLD: u64 = 10;
-1311 if self.non_ack_eliciting_since_last_ack_sent > LAZY_ACK_THRESHOLD {
-1312 self.immediate_ack_required = true;
-1313 }
-1314 }
-1315}
-1316
-1317/// Helper for mitigating [optimistic ACK attacks]
-1318///
-1319/// A malicious peer could prompt the local application to begin a large data transfer, and then
-1320/// send ACKs without first waiting for data to be received. This could defeat congestion control,
-1321/// allowing the connection to consume disproportionate resources. We therefore occasionally skip
-1322/// packet numbers, and classify any ACK referencing a skipped packet number as a transport error.
-1323///
-1324/// Skipped packet numbers occur only in the application data space (where costly transfers might
-1325/// take place) and are distributed exponentially to reflect the reduced likelihood and impact of
-1326/// bad behavior from a peer that has been well-behaved for an extended period.
-1327///
-1328/// ACKs for packet numbers that have not yet been allocated are also a transport error, but an
-1329/// attacker with knowledge of the congestion control algorithm in use could time falsified ACKs to
-1330/// arrive after the packets they reference are sent.
-1331///
-1332/// [optimistic ACK attacks]: https://www.rfc-editor.org/rfc/rfc9000.html#name-optimistic-ack-attack
-1333pub(super) struct PacketNumberFilter {
-1334 /// Next outgoing packet number to skip
-1335 next_skipped_packet_number: u64,
-1336 /// Most recently skipped packet number
-1337 prev_skipped_packet_number: Option<u64>,
-1338 /// Next packet number to skip is randomly selected from 2^n..2^n+1
-1339 exponent: u32,
-1340}
-1341
-1342impl PacketNumberFilter {
-1343 pub(super) fn new(rng: &mut (impl CryptoRng + ?Sized)) -> Self {
-1344 // First skipped PN is in 0..64
-1345 let exponent = 6;
-1346 Self {
-1347 next_skipped_packet_number: rng.random_range(0..2u64.saturating_pow(exponent)),
-1348 prev_skipped_packet_number: None,
-1349 exponent,
-1350 }
-1351 }
-1352
-1353 #[cfg(test)]
-1354 pub(super) fn disabled() -> Self {
-1355 Self {
-1356 next_skipped_packet_number: u64::MAX,
-1357 prev_skipped_packet_number: None,
-1358 exponent: u32::MAX,
-1359 }
-1360 }
-1361
-1362 /// Whether to use the provided packet number (false) or to skip it (true)
-1363 pub(super) fn skip_pn(&mut self, n: u64, rng: &mut (impl CryptoRng + ?Sized)) -> bool {
-1364 if n != self.next_skipped_packet_number {
-1365 return false;
-1366 }
-1367
-1368 trace!("skipping pn {n}");
-1369 // Skip this packet number, and choose the next one to skip
-1370 self.prev_skipped_packet_number = Some(self.next_skipped_packet_number);
-1371 let next_exponent = self.exponent.saturating_add(1);
-1372 self.next_skipped_packet_number = rng
-1373 .random_range(2u64.saturating_pow(self.exponent)..2u64.saturating_pow(next_exponent));
-1374 self.exponent = next_exponent;
-1375 true
-1376 }
-1377}
+1240 }
+1241 // The largest packet number that could be declared lost without a new ACK being
+1242 // sent
+1243 let largest_reported = largest_acked - self.reordering_threshold + 1;
+1244 let Some(smallest_missing_unreported) =
+1245 dedup.smallest_missing_in_interval(largest_reported, largest_unacked)
+1246 else {
+1247 return false;
+1248 };
+1249 largest_unacked - smallest_missing_unreported >= self.reordering_threshold
+1250 }
+1251 }
+1252 }
+1253
+1254 /// Should be called whenever ACKs have been sent
+1255 ///
+1256 /// This will suppress sending further ACKs until additional ACK eliciting frames arrive
+1257 pub(super) fn acks_sent(&mut self) {
+1258 // It is possible (though unlikely) that the ACKs we just sent do not cover all the
+1259 // ACK-eliciting packets we have received (e.g. if there is not enough room in the packet to
+1260 // fit all the ranges). To keep things simple, however, we assume they do. If there are
+1261 // indeed some ACKs that weren't covered, the packets might be ACKed later anyway, because
+1262 // they are still contained in `self.ranges`. If we somehow fail to send the ACKs at a later
+1263 // moment, the peer will assume the packets got lost and will retransmit their frames in a
+1264 // new packet, which is suboptimal, because we already received them. Our assumption here is
+1265 // that simplicity results in code that is more performant, even in the presence of
+1266 // occasional redundant retransmits.
+1267 self.immediate_ack_required = false;
+1268 self.ack_eliciting_since_last_ack_sent = 0;
+1269 self.non_ack_eliciting_since_last_ack_sent = 0;
+1270 self.earliest_ack_eliciting_since_last_ack_sent = None;
+1271 self.largest_acked = self.largest_ack_eliciting_packet;
+1272 }
+1273
+1274 /// Insert one packet that needs to be acknowledged
+1275 pub(super) fn insert_one(&mut self, packet: u64, now: Instant) {
+1276 self.ranges.insert_one(packet);
+1277
+1278 if self.largest_packet.is_none_or(|(pn, _)| packet > pn) {
+1279 self.largest_packet = Some((packet, now));
+1280 }
+1281
+1282 if self.ranges.range_count() > MAX_ACK_BLOCKS {
+1283 self.ranges.pop_min();
+1284 }
+1285 }
+1286
+1287 /// Remove ACKs of packets numbered at or below `max` from the set of pending ACKs
+1288 pub(super) fn subtract_below(&mut self, max: u64) {
+1289 self.ranges.remove(0..(max + 1));
+1290 }
+1291
+1292 /// Returns the set of currently pending ACK ranges
+1293 pub(super) fn ranges(&self) -> &ArrayRangeSet {
+1294 &self.ranges
+1295 }
+1296
+1297 /// Queue an ACK if a significant number of non-ACK-eliciting packets have not yet been
+1298 /// acknowledged
+1299 ///
+1300 /// Should be called immediately before a non-probing packet is composed, when we've already
+1301 /// committed to sending a packet regardless.
+1302 pub(super) fn maybe_ack_non_eliciting(&mut self) {
+1303 // If we're going to send a packet anyway, and we've received a significant number of
+1304 // non-ACK-eliciting packets, then include an ACK to help the peer perform timely loss
+1305 // detection even if they're not sending any ACK-eliciting packets themselves. Exact
+1306 // threshold chosen somewhat arbitrarily.
+1307 const LAZY_ACK_THRESHOLD: u64 = 10;
+1308 if self.non_ack_eliciting_since_last_ack_sent > LAZY_ACK_THRESHOLD {
+1309 self.immediate_ack_required = true;
+1310 }
+1311 }
+1312}
+1313
+1314/// Helper for mitigating [optimistic ACK attacks]
+1315///
+1316/// A malicious peer could prompt the local application to begin a large data transfer, and then
+1317/// send ACKs without first waiting for data to be received. This could defeat congestion control,
+1318/// allowing the connection to consume disproportionate resources. We therefore occasionally skip
+1319/// packet numbers, and classify any ACK referencing a skipped packet number as a transport error.
+1320///
+1321/// Skipped packet numbers occur only in the application data space (where costly transfers might
+1322/// take place) and are distributed exponentially to reflect the reduced likelihood and impact of
+1323/// bad behavior from a peer that has been well-behaved for an extended period.
+1324///
+1325/// ACKs for packet numbers that have not yet been allocated are also a transport error, but an
+1326/// attacker with knowledge of the congestion control algorithm in use could time falsified ACKs to
+1327/// arrive after the packets they reference are sent.
+1328///
+1329/// [optimistic ACK attacks]: https://www.rfc-editor.org/rfc/rfc9000.html#name-optimistic-ack-attack
+1330pub(super) struct PacketNumberFilter {
+1331 /// Next outgoing packet number to skip
+1332 next_skipped_packet_number: u64,
+1333 /// Most recently skipped packet number
+1334 prev_skipped_packet_number: Option<u64>,
+1335 /// Next packet number to skip is randomly selected from 2^n..2^n+1
+1336 exponent: u32,
+1337}
+1338
+1339impl PacketNumberFilter {
+1340 pub(super) fn new(rng: &mut (impl CryptoRng + ?Sized)) -> Self {
+1341 // First skipped PN is in 0..64
+1342 let exponent = 6;
+1343 Self {
+1344 next_skipped_packet_number: rng.random_range(0..2u64.saturating_pow(exponent)),
+1345 prev_skipped_packet_number: None,
+1346 exponent,
+1347 }
+1348 }
+1349
+1350 #[cfg(test)]
+1351 pub(super) fn disabled() -> Self {
+1352 Self {
+1353 next_skipped_packet_number: u64::MAX,
+1354 prev_skipped_packet_number: None,
+1355 exponent: u32::MAX,
+1356 }
+1357 }
+1358
+1359 /// Whether to use the provided packet number (false) or to skip it (true)
+1360 pub(super) fn skip_pn(&mut self, n: u64, rng: &mut (impl CryptoRng + ?Sized)) -> bool {
+1361 if n != self.next_skipped_packet_number {
+1362 return false;
+1363 }
+1364
+1365 trace!("skipping pn {n}");
+1366 // Skip this packet number, and choose the next one to skip
+1367 self.prev_skipped_packet_number = Some(self.next_skipped_packet_number);
+1368 let next_exponent = self.exponent.saturating_add(1);
+1369 self.next_skipped_packet_number = rng
+1370 .random_range(2u64.saturating_pow(self.exponent)..2u64.saturating_pow(next_exponent));
+1371 self.exponent = next_exponent;
+1372 true
+1373 }
+1374}
+1375
+1376/// Ensures we can always fit all our ACKs in a single minimum-MTU packet with room to spare
+1377const MAX_ACK_BLOCKS: usize = 64;
1378
-1379/// Ensures we can always fit all our ACKs in a single minimum-MTU packet with room to spare
-1380const MAX_ACK_BLOCKS: usize = 64;
-1381
-1382#[cfg(test)]
-1383mod test {
-1384 use rand::Rng;
-1385 use rand::seq::SliceRandom;
+1379#[cfg(test)]
+1380mod test {
+1381 use rand::Rng;
+1382 use rand::seq::SliceRandom;
+1383
+1384 use crate::token::ResetToken;
+1385 use crate::{ConnectionIdGenerator, RandomConnectionIdGenerator};
1386
-1387 use crate::token::ResetToken;
-1388 use crate::{ConnectionIdGenerator, RandomConnectionIdGenerator};
-1389
-1390 use super::*;
-1391
-1392 #[test]
-1393 fn sanity() {
-1394 let mut dedup = Dedup::new();
-1395 assert!(!dedup.insert(0));
+1387 use super::*;
+1388
+1389 #[test]
+1390 fn sanity() {
+1391 let mut dedup = Dedup::new();
+1392 assert!(!dedup.insert(0));
+1393 assert_eq!(dedup.next, 1);
+1394 assert_eq!(dedup.window, 0b1);
+1395 assert!(dedup.insert(0));
1396 assert_eq!(dedup.next, 1);
1397 assert_eq!(dedup.window, 0b1);
-1398 assert!(dedup.insert(0));
-1399 assert_eq!(dedup.next, 1);
-1400 assert_eq!(dedup.window, 0b1);
-1401 assert!(!dedup.insert(1));
-1402 assert_eq!(dedup.next, 2);
-1403 assert_eq!(dedup.window, 0b11);
-1404 assert!(!dedup.insert(2));
-1405 assert_eq!(dedup.next, 3);
-1406 assert_eq!(dedup.window, 0b111);
-1407 assert!(!dedup.insert(4));
-1408 assert_eq!(dedup.next, 5);
-1409 assert_eq!(dedup.window, 0b11110);
-1410 assert!(!dedup.insert(7));
-1411 assert_eq!(dedup.next, 8);
-1412 assert_eq!(dedup.window, 0b1111_0100);
-1413 assert!(dedup.insert(4));
-1414 assert!(!dedup.insert(3));
+1398 assert!(!dedup.insert(1));
+1399 assert_eq!(dedup.next, 2);
+1400 assert_eq!(dedup.window, 0b11);
+1401 assert!(!dedup.insert(2));
+1402 assert_eq!(dedup.next, 3);
+1403 assert_eq!(dedup.window, 0b111);
+1404 assert!(!dedup.insert(4));
+1405 assert_eq!(dedup.next, 5);
+1406 assert_eq!(dedup.window, 0b11110);
+1407 assert!(!dedup.insert(7));
+1408 assert_eq!(dedup.next, 8);
+1409 assert_eq!(dedup.window, 0b1111_0100);
+1410 assert!(dedup.insert(4));
+1411 assert!(!dedup.insert(3));
+1412 assert_eq!(dedup.next, 8);
+1413 assert_eq!(dedup.window, 0b1111_1100);
+1414 assert!(!dedup.insert(6));
1415 assert_eq!(dedup.next, 8);
-1416 assert_eq!(dedup.window, 0b1111_1100);
-1417 assert!(!dedup.insert(6));
+1416 assert_eq!(dedup.window, 0b1111_1101);
+1417 assert!(!dedup.insert(5));
1418 assert_eq!(dedup.next, 8);
-1419 assert_eq!(dedup.window, 0b1111_1101);
-1420 assert!(!dedup.insert(5));
-1421 assert_eq!(dedup.next, 8);
-1422 assert_eq!(dedup.window, 0b1111_1111);
-1423 }
-1424
-1425 #[test]
-1426 fn happypath() {
-1427 let mut dedup = Dedup::new();
-1428 for i in 0..(2 * WINDOW_SIZE) {
-1429 assert!(!dedup.insert(i));
-1430 for j in 0..=i {
-1431 assert!(dedup.insert(j));
-1432 }
-1433 }
-1434 }
-1435
-1436 #[test]
-1437 fn jump() {
-1438 let mut dedup = Dedup::new();
-1439 dedup.insert(2 * WINDOW_SIZE);
-1440 assert!(dedup.insert(WINDOW_SIZE));
+1419 assert_eq!(dedup.window, 0b1111_1111);
+1420 }
+1421
+1422 #[test]
+1423 fn happypath() {
+1424 let mut dedup = Dedup::new();
+1425 for i in 0..(2 * WINDOW_SIZE) {
+1426 assert!(!dedup.insert(i));
+1427 for j in 0..=i {
+1428 assert!(dedup.insert(j));
+1429 }
+1430 }
+1431 }
+1432
+1433 #[test]
+1434 fn jump() {
+1435 let mut dedup = Dedup::new();
+1436 dedup.insert(2 * WINDOW_SIZE);
+1437 assert!(dedup.insert(WINDOW_SIZE));
+1438 assert_eq!(dedup.next, 2 * WINDOW_SIZE + 1);
+1439 assert_eq!(dedup.window, 0);
+1440 assert!(!dedup.insert(WINDOW_SIZE + 1));
1441 assert_eq!(dedup.next, 2 * WINDOW_SIZE + 1);
-1442 assert_eq!(dedup.window, 0);
-1443 assert!(!dedup.insert(WINDOW_SIZE + 1));
-1444 assert_eq!(dedup.next, 2 * WINDOW_SIZE + 1);
-1445 assert_eq!(dedup.window, 1 << (WINDOW_SIZE - 2));
-1446 }
-1447
-1448 #[test]
-1449 fn dedup_has_missing() {
-1450 let mut dedup = Dedup::new();
+1442 assert_eq!(dedup.window, 1 << (WINDOW_SIZE - 2));
+1443 }
+1444
+1445 #[test]
+1446 fn dedup_has_missing() {
+1447 let mut dedup = Dedup::new();
+1448
+1449 dedup.insert(0);
+1450 assert!(!dedup.missing_in_interval(0, 0));
1451
-1452 dedup.insert(0);
-1453 assert!(!dedup.missing_in_interval(0, 0));
+1452 dedup.insert(1);
+1453 assert!(!dedup.missing_in_interval(0, 1));
1454
-1455 dedup.insert(1);
-1456 assert!(!dedup.missing_in_interval(0, 1));
+1455 dedup.insert(3);
+1456 assert!(dedup.missing_in_interval(1, 3));
1457
-1458 dedup.insert(3);
-1459 assert!(dedup.missing_in_interval(1, 3));
-1460
-1461 dedup.insert(4);
-1462 assert!(!dedup.missing_in_interval(3, 4));
-1463 assert!(dedup.missing_in_interval(0, 4));
-1464
-1465 dedup.insert(2);
-1466 assert!(!dedup.missing_in_interval(0, 4));
-1467 }
-1468
-1469 #[test]
-1470 fn dedup_outside_of_window_has_missing() {
-1471 let mut dedup = Dedup::new();
-1472
-1473 for i in 0..140 {
-1474 dedup.insert(i);
-1475 }
-1476
-1477 // 0 and 4 are outside of the window
-1478 assert!(!dedup.missing_in_interval(0, 4));
-1479 dedup.insert(160);
-1480 assert!(!dedup.missing_in_interval(0, 4));
-1481 assert!(!dedup.missing_in_interval(0, 140));
-1482 assert!(dedup.missing_in_interval(0, 160));
-1483 }
-1484
-1485 #[test]
-1486 fn dedup_smallest_missing() {
-1487 let mut dedup = Dedup::new();
+1458 dedup.insert(4);
+1459 assert!(!dedup.missing_in_interval(3, 4));
+1460 assert!(dedup.missing_in_interval(0, 4));
+1461
+1462 dedup.insert(2);
+1463 assert!(!dedup.missing_in_interval(0, 4));
+1464 }
+1465
+1466 #[test]
+1467 fn dedup_outside_of_window_has_missing() {
+1468 let mut dedup = Dedup::new();
+1469
+1470 for i in 0..140 {
+1471 dedup.insert(i);
+1472 }
+1473
+1474 // 0 and 4 are outside of the window
+1475 assert!(!dedup.missing_in_interval(0, 4));
+1476 dedup.insert(160);
+1477 assert!(!dedup.missing_in_interval(0, 4));
+1478 assert!(!dedup.missing_in_interval(0, 140));
+1479 assert!(dedup.missing_in_interval(0, 160));
+1480 }
+1481
+1482 #[test]
+1483 fn dedup_smallest_missing() {
+1484 let mut dedup = Dedup::new();
+1485
+1486 dedup.insert(0);
+1487 assert_eq!(dedup.smallest_missing_in_interval(0, 0), None);
1488
-1489 dedup.insert(0);
-1490 assert_eq!(dedup.smallest_missing_in_interval(0, 0), None);
+1489 dedup.insert(1);
+1490 assert_eq!(dedup.smallest_missing_in_interval(0, 1), None);
1491
-1492 dedup.insert(1);
-1493 assert_eq!(dedup.smallest_missing_in_interval(0, 1), None);
-1494
-1495 dedup.insert(5);
-1496 dedup.insert(7);
-1497 assert_eq!(dedup.smallest_missing_in_interval(0, 7), Some(2));
-1498 assert_eq!(dedup.smallest_missing_in_interval(5, 7), Some(6));
+1492 dedup.insert(5);
+1493 dedup.insert(7);
+1494 assert_eq!(dedup.smallest_missing_in_interval(0, 7), Some(2));
+1495 assert_eq!(dedup.smallest_missing_in_interval(5, 7), Some(6));
+1496
+1497 dedup.insert(2);
+1498 assert_eq!(dedup.smallest_missing_in_interval(1, 7), Some(3));
1499
-1500 dedup.insert(2);
-1501 assert_eq!(dedup.smallest_missing_in_interval(1, 7), Some(3));
-1502
-1503 dedup.insert(170);
-1504 dedup.insert(172);
-1505 dedup.insert(300);
-1506 assert_eq!(dedup.smallest_missing_in_interval(170, 172), None);
-1507
-1508 dedup.insert(500);
-1509 assert_eq!(dedup.smallest_missing_in_interval(0, 500), Some(372));
-1510 assert_eq!(dedup.smallest_missing_in_interval(0, 373), Some(372));
-1511 assert_eq!(dedup.smallest_missing_in_interval(0, 372), None);
-1512 }
-1513
-1514 #[test]
-1515 fn pending_acks_first_packet_is_not_considered_reordered() {
-1516 let mut acks = PendingAcks::new();
-1517 let mut dedup = Dedup::new();
-1518 dedup.insert(0);
-1519 acks.packet_received(Instant::now(), 0, true, &dedup);
-1520 assert!(!acks.immediate_ack_required);
-1521 }
-1522
-1523 #[test]
-1524 fn pending_acks_after_immediate_ack_set() {
-1525 let mut acks = PendingAcks::new();
-1526 let mut dedup = Dedup::new();
-1527
-1528 // Receive ack-eliciting packet
-1529 dedup.insert(0);
-1530 let now = Instant::now();
-1531 acks.insert_one(0, now);
-1532 acks.packet_received(now, 0, true, &dedup);
-1533
-1534 // Sanity check
-1535 assert!(!acks.ranges.is_empty());
-1536 assert!(!acks.can_send());
-1537
-1538 // Can send ACK after max_ack_delay exceeded
-1539 acks.set_immediate_ack_required();
-1540 assert!(acks.can_send());
-1541 }
-1542
-1543 #[test]
-1544 fn pending_acks_ack_delay() {
-1545 let mut acks = PendingAcks::new();
-1546 let mut dedup = Dedup::new();
-1547
-1548 let t1 = Instant::now();
-1549 let t2 = t1 + Duration::from_millis(2);
-1550 let t3 = t2 + Duration::from_millis(5);
-1551 assert_eq!(acks.ack_delay(t1), Duration::from_millis(0));
-1552 assert_eq!(acks.ack_delay(t2), Duration::from_millis(0));
-1553 assert_eq!(acks.ack_delay(t3), Duration::from_millis(0));
-1554
-1555 // In-order packet
-1556 dedup.insert(0);
-1557 acks.insert_one(0, t1);
-1558 acks.packet_received(t1, 0, true, &dedup);
-1559 assert_eq!(acks.ack_delay(t1), Duration::from_millis(0));
-1560 assert_eq!(acks.ack_delay(t2), Duration::from_millis(2));
-1561 assert_eq!(acks.ack_delay(t3), Duration::from_millis(7));
-1562
-1563 // Out of order (higher than expected)
-1564 dedup.insert(3);
-1565 acks.insert_one(3, t2);
-1566 acks.packet_received(t2, 3, true, &dedup);
-1567 assert_eq!(acks.ack_delay(t2), Duration::from_millis(0));
-1568 assert_eq!(acks.ack_delay(t3), Duration::from_millis(5));
-1569
-1570 // Out of order (lower than expected, so previous instant is kept)
-1571 dedup.insert(2);
-1572 acks.insert_one(2, t3);
-1573 acks.packet_received(t3, 2, true, &dedup);
-1574 assert_eq!(acks.ack_delay(t3), Duration::from_millis(5));
-1575 }
-1576
-1577 #[test]
-1578 fn sent_packet_size() {
-1579 // The tracking state of sent packets should be minimal, and not grow
-1580 // over time.
-1581 assert!(std::mem::size_of::<SentPacket>() <= 128);
-1582 }
-1583
-1584 #[test]
-1585 fn pending_new_cids() {
-1586 #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
-1587 use aws_lc_rs::hmac;
-1588 #[cfg(feature = "ring")]
-1589 use ring::hmac;
-1590
-1591 let mut cid_generator = RandomConnectionIdGenerator::new(8);
-1592 let mut reset_key = [0; 64];
-1593 rand::rng().fill_bytes(&mut reset_key);
-1594 let hmac = hmac::Key::new(hmac::HMAC_SHA256, &reset_key);
-1595
-1596 let cid_a = cid_generator.generate_cid();
-1597 let a = IssuedCid {
-1598 path_id: PathId::ZERO,
-1599 sequence: 1,
-1600 id: cid_a,
-1601 reset_token: ResetToken::new(&hmac, cid_a),
-1602 };
-1603 let cid_b = cid_generator.generate_cid();
-1604 let b = IssuedCid {
-1605 path_id: PathId::ZERO,
-1606 sequence: 2,
-1607 id: cid_b,
-1608 reset_token: ResetToken::new(&hmac, cid_b),
-1609 };
-1610 let cid_c = cid_generator.generate_cid();
-1611 let c = IssuedCid {
-1612 path_id: PathId(1),
-1613 sequence: 1,
-1614 id: cid_c,
-1615 reset_token: ResetToken::new(&hmac, cid_c),
-1616 };
-1617
-1618 let mut pending_cids = PendingNewCids::default();
-1619
-1620 for _ in 0..9 {
-1621 // Push CIDs in a random order
-1622 let mut input = vec![a, b, c];
-1623 input.shuffle(&mut rand::rng());
-1624 for cid in input {
-1625 pending_cids.push(cid);
-1626 }
-1627
-1628 // Pop order is always the same
-1629 assert_eq!(pending_cids.pop().map(|i| i.id), Some(a.id));
-1630 assert_eq!(pending_cids.pop().map(|i| i.id), Some(b.id));
-1631 assert_eq!(pending_cids.pop().map(|i| i.id), Some(c.id));
-1632 assert!(pending_cids.pop().is_none());
-1633 }
-1634 }
-1635}
\ No newline at end of file
+1500 dedup.insert(170);
+1501 dedup.insert(172);
+1502 dedup.insert(300);
+1503 assert_eq!(dedup.smallest_missing_in_interval(170, 172), None);
+1504
+1505 dedup.insert(500);
+1506 assert_eq!(dedup.smallest_missing_in_interval(0, 500), Some(372));
+1507 assert_eq!(dedup.smallest_missing_in_interval(0, 373), Some(372));
+1508 assert_eq!(dedup.smallest_missing_in_interval(0, 372), None);
+1509 }
+1510
+1511 #[test]
+1512 fn pending_acks_first_packet_is_not_considered_reordered() {
+1513 let mut acks = PendingAcks::new();
+1514 let mut dedup = Dedup::new();
+1515 dedup.insert(0);
+1516 acks.packet_received(Instant::now(), 0, true, &dedup);
+1517 assert!(!acks.immediate_ack_required);
+1518 }
+1519
+1520 #[test]
+1521 fn pending_acks_after_immediate_ack_set() {
+1522 let mut acks = PendingAcks::new();
+1523 let mut dedup = Dedup::new();
+1524
+1525 // Receive ack-eliciting packet
+1526 dedup.insert(0);
+1527 let now = Instant::now();
+1528 acks.insert_one(0, now);
+1529 acks.packet_received(now, 0, true, &dedup);
+1530
+1531 // Sanity check
+1532 assert!(!acks.ranges.is_empty());
+1533 assert!(!acks.can_send());
+1534
+1535 // Can send ACK after max_ack_delay exceeded
+1536 acks.set_immediate_ack_required();
+1537 assert!(acks.can_send());
+1538 }
+1539
+1540 #[test]
+1541 fn pending_acks_ack_delay() {
+1542 let mut acks = PendingAcks::new();
+1543 let mut dedup = Dedup::new();
+1544
+1545 let t1 = Instant::now();
+1546 let t2 = t1 + Duration::from_millis(2);
+1547 let t3 = t2 + Duration::from_millis(5);
+1548 assert_eq!(acks.ack_delay(t1), Duration::from_millis(0));
+1549 assert_eq!(acks.ack_delay(t2), Duration::from_millis(0));
+1550 assert_eq!(acks.ack_delay(t3), Duration::from_millis(0));
+1551
+1552 // In-order packet
+1553 dedup.insert(0);
+1554 acks.insert_one(0, t1);
+1555 acks.packet_received(t1, 0, true, &dedup);
+1556 assert_eq!(acks.ack_delay(t1), Duration::from_millis(0));
+1557 assert_eq!(acks.ack_delay(t2), Duration::from_millis(2));
+1558 assert_eq!(acks.ack_delay(t3), Duration::from_millis(7));
+1559
+1560 // Out of order (higher than expected)
+1561 dedup.insert(3);
+1562 acks.insert_one(3, t2);
+1563 acks.packet_received(t2, 3, true, &dedup);
+1564 assert_eq!(acks.ack_delay(t2), Duration::from_millis(0));
+1565 assert_eq!(acks.ack_delay(t3), Duration::from_millis(5));
+1566
+1567 // Out of order (lower than expected, so previous instant is kept)
+1568 dedup.insert(2);
+1569 acks.insert_one(2, t3);
+1570 acks.packet_received(t3, 2, true, &dedup);
+1571 assert_eq!(acks.ack_delay(t3), Duration::from_millis(5));
+1572 }
+1573
+1574 #[test]
+1575 fn sent_packet_size() {
+1576 // The tracking state of sent packets should be minimal, and not grow
+1577 // over time.
+1578 assert!(std::mem::size_of::<SentPacket>() <= 128);
+1579 }
+1580
+1581 #[test]
+1582 fn pending_new_cids() {
+1583 #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
+1584 use aws_lc_rs::hmac;
+1585 #[cfg(feature = "ring")]
+1586 use ring::hmac;
+1587
+1588 let mut cid_generator = RandomConnectionIdGenerator::new(8);
+1589 let mut reset_key = [0; 64];
+1590 rand::rng().fill_bytes(&mut reset_key);
+1591 let hmac = hmac::Key::new(hmac::HMAC_SHA256, &reset_key);
+1592
+1593 let cid_a = cid_generator.generate_cid();
+1594 let a = IssuedCid {
+1595 path_id: PathId::ZERO,
+1596 sequence: 1,
+1597 id: cid_a,
+1598 reset_token: ResetToken::new(&hmac, cid_a),
+1599 };
+1600 let cid_b = cid_generator.generate_cid();
+1601 let b = IssuedCid {
+1602 path_id: PathId::ZERO,
+1603 sequence: 2,
+1604 id: cid_b,
+1605 reset_token: ResetToken::new(&hmac, cid_b),
+1606 };
+1607 let cid_c = cid_generator.generate_cid();
+1608 let c = IssuedCid {
+1609 path_id: PathId(1),
+1610 sequence: 1,
+1611 id: cid_c,
+1612 reset_token: ResetToken::new(&hmac, cid_c),
+1613 };
+1614
+1615 let mut pending_cids = PendingNewCids::default();
+1616
+1617 for _ in 0..9 {
+1618 // Push CIDs in a random order
+1619 let mut input = vec![a, b, c];
+1620 input.shuffle(&mut rand::rng());
+1621 for cid in input {
+1622 pending_cids.push(cid);
+1623 }
+1624
+1625 // Pop order is always the same
+1626 assert_eq!(pending_cids.pop().map(|i| i.id), Some(a.id));
+1627 assert_eq!(pending_cids.pop().map(|i| i.id), Some(b.id));
+1628 assert_eq!(pending_cids.pop().map(|i| i.id), Some(c.id));
+1629 assert!(pending_cids.pop().is_none());
+1630 }
+1631 }
+1632}
\ No newline at end of file