From 68ddcd749fad4414def35834cee2832c1a191e9b Mon Sep 17 00:00:00 2001 From: Cameron Bytheway Date: Tue, 29 Oct 2024 21:50:00 -0600 Subject: [PATCH] feat(s2n-quic-dc): add map events --- dc/s2n-quic-dc/events/common.rs | 10 + dc/s2n-quic-dc/events/map.rs | 176 ++ dc/s2n-quic-dc/src/event.rs | 22 +- dc/s2n-quic-dc/src/event/generated.rs | 2504 ++++++++++++++++- dc/s2n-quic-dc/src/path/secret/map.rs | 26 +- dc/s2n-quic-dc/src/path/secret/map/cleaner.rs | 5 +- .../src/path/secret/map/handshake.rs | 4 +- dc/s2n-quic-dc/src/path/secret/map/state.rs | 350 ++- .../src/path/secret/map/state/tests.rs | 23 +- dc/s2n-quic-dc/src/path/secret/map/status.rs | 32 +- dc/s2n-quic-dc/src/path/secret/map/store.rs | 15 +- dc/s2n-quic-dc/src/stream/recv/shared.rs | 10 +- dc/s2n-quic-dc/src/stream/send/worker.rs | 6 +- quic/s2n-quic-core/src/event/generated.rs | 88 +- quic/s2n-quic-events/src/main.rs | 126 +- quic/s2n-quic-events/src/parser.rs | 9 +- 16 files changed, 3024 insertions(+), 382 deletions(-) create mode 100644 dc/s2n-quic-dc/events/common.rs create mode 100644 dc/s2n-quic-dc/events/map.rs diff --git a/dc/s2n-quic-dc/events/common.rs b/dc/s2n-quic-dc/events/common.rs new file mode 100644 index 000000000..29ce73ff6 --- /dev/null +++ b/dc/s2n-quic-dc/events/common.rs @@ -0,0 +1,10 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +struct ConnectionMeta { + id: u64, +} + +struct EndpointMeta {} + +struct ConnectionInfo {} diff --git a/dc/s2n-quic-dc/events/map.rs b/dc/s2n-quic-dc/events/map.rs new file mode 100644 index 000000000..245273848 --- /dev/null +++ b/dc/s2n-quic-dc/events/map.rs @@ -0,0 +1,176 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#[event("path_secret_map:initialized")] +#[subject(endpoint)] +struct PathSecretMapInitialized { + /// The capacity of the path secret map + capacity: usize, + + /// The port that the path secret is listening on + control_socket_port: u16, +} + +#[event("path_secret_map:uninitialized")] +#[subject(endpoint)] +struct PathSecretMapUninitialized { + /// The capacity of the path secret map + capacity: usize, + + /// The port that the path secret is listening on + control_socket_port: u16, + + /// The number of entries in the map + entries: usize, +} + +#[event("path_secret_map:background_handshake_requested")] +#[subject(endpoint)] +/// Emitted when a background handshake is requested +struct PathSecretMapBackgroundHandshakeRequested<'a> { + peer_address: SocketAddress<'a>, +} + +#[event("path_secret_map:entry_replaced")] +#[subject(endpoint)] +/// Emitted when the entry is inserted into the path secret map +struct PathSecretMapEntryInserted<'a> { + peer_address: SocketAddress<'a>, + + credential_id: &'a [u8], +} + +#[event("path_secret_map:entry_replaced")] +#[subject(endpoint)] +/// Emitted when the entry is considered ready for use +struct PathSecretMapEntryReady<'a> { + peer_address: SocketAddress<'a>, + + credential_id: &'a [u8], +} + +#[event("path_secret_map:entry_replaced")] +#[subject(endpoint)] +/// Emitted when an entry is replaced by a new one for the same `peer_address` +struct PathSecretMapEntryReplaced<'a> { + peer_address: SocketAddress<'a>, + + new_credential_id: &'a [u8], + + previous_credential_id: &'a [u8], +} + +#[event("path_secret_map:unknown_path_secret_packet_sent")] +#[subject(endpoint)] +/// Emitted when an UnknownPathSecret packet was sent +struct UnknownPathSecretPacketSent<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:unknown_path_secret_packet_received")] +#[subject(endpoint)] +/// Emitted when an UnknownPathSecret packet was received +struct UnknownPathSecretPacketReceived<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:unknown_path_secret_packet_accepted")] +#[subject(endpoint)] +/// Emitted when an UnknownPathSecret packet was authentic and processed +struct UnknownPathSecretPacketAccepted<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:unknown_path_secret_packet_rejected")] +#[subject(endpoint)] +/// Emitted when an UnknownPathSecret packet was rejected as invalid +struct UnknownPathSecretPacketRejected<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:replay_definitely_detected")] +#[subject(endpoint)] +/// Emitted when credential replay was definitely detected +struct ReplayDefinitelyDetected<'a> { + credential_id: &'a [u8], + key_id: u64, +} + +#[event("path_secret_map:replay_potentially_detected")] +#[subject(endpoint)] +/// Emitted when credential replay was potentially detected, but could not be verified +/// due to a limiting tracking window +struct ReplayPotentiallyDetected<'a> { + credential_id: &'a [u8], + key_id: u64, + gap: u64, +} + +#[event("path_secret_map:replay_detected_packet_sent")] +#[subject(endpoint)] +/// Emitted when an ReplayDetected packet was sent +struct ReplayDetectedPacketSent<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:replay_detected_packet_received")] +#[subject(endpoint)] +/// Emitted when an ReplayDetected packet was received +struct ReplayDetectedPacketReceived<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:replay_detected_packet_accepted")] +#[subject(endpoint)] +/// Emitted when an StaleKey packet was authentic and processed +struct ReplayDetectedPacketAccepted<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], + key_id: u64, +} + +#[event("path_secret_map:replay_detected_packet_rejected")] +#[subject(endpoint)] +/// Emitted when an ReplayDetected packet was rejected as invalid +struct ReplayDetectedPacketRejected<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:stale_key_packet_sent")] +#[subject(endpoint)] +/// Emitted when an StaleKey packet was sent +struct StaleKeyPacketSent<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:stale_key_packet_received")] +#[subject(endpoint)] +/// Emitted when an StaleKey packet was received +struct StaleKeyPacketReceived<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:stale_key_packet_accepted")] +#[subject(endpoint)] +/// Emitted when an StaleKey packet was authentic and processed +struct StaleKeyPacketAccepted<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} + +#[event("path_secret_map:stale_key_packet_rejected")] +#[subject(endpoint)] +/// Emitted when an StaleKey packet was rejected as invalid +struct StaleKeyPacketRejected<'a> { + peer_address: SocketAddress<'a>, + credential_id: &'a [u8], +} diff --git a/dc/s2n-quic-dc/src/event.rs b/dc/s2n-quic-dc/src/event.rs index b4ca61d92..8445158d5 100644 --- a/dc/s2n-quic-dc/src/event.rs +++ b/dc/s2n-quic-dc/src/event.rs @@ -4,7 +4,27 @@ #[cfg(any(test, feature = "testing"))] use s2n_quic_core::event::snapshot; -pub use s2n_quic_core::event::{Event, IntoEvent, Timestamp}; +pub use s2n_quic_core::event::{Event, IntoEvent}; + +/// Provides metadata related to an event +pub trait Meta: core::fmt::Debug { + /// A context from which the event is being emitted + /// + /// An event can occur in the context of an Endpoint or Connection + fn subject(&self) -> api::Subject; +} + +impl Meta for api::ConnectionMeta { + fn subject(&self) -> api::Subject { + builder::Subject::Connection { id: self.id }.into_event() + } +} + +impl Meta for api::EndpointMeta { + fn subject(&self) -> api::Subject { + builder::Subject::Endpoint {}.into_event() + } +} mod generated; pub use generated::*; diff --git a/dc/s2n-quic-dc/src/event/generated.rs b/dc/s2n-quic-dc/src/event/generated.rs index bd55f188a..c1f461e20 100644 --- a/dc/s2n-quic-dc/src/event/generated.rs +++ b/dc/s2n-quic-dc/src/event/generated.rs @@ -9,12 +9,21 @@ use super::*; pub mod api { #![doc = r" This module contains events that are emitted to the [`Subscriber`](crate::event::Subscriber)"] use super::*; - pub use s2n_quic_core::event::api::{ - ConnectionInfo, ConnectionMeta, EndpointMeta, EndpointType, SocketAddress, Subject, - }; + pub use s2n_quic_core::event::api::{EndpointType, SocketAddress, Subject}; pub use traits::Subscriber; #[derive(Clone, Debug)] #[non_exhaustive] + pub struct ConnectionMeta { + pub id: u64, + } + #[derive(Clone, Debug)] + #[non_exhaustive] + pub struct EndpointMeta {} + #[derive(Clone, Debug)] + #[non_exhaustive] + pub struct ConnectionInfo {} + #[derive(Clone, Debug)] + #[non_exhaustive] pub struct ApplicationWrite { #[doc = " The number of bytes that the application tried to write"] pub len: usize, @@ -42,6 +51,213 @@ pub mod api { impl<'a> Event for EndpointInitialized<'a> { const NAME: &'static str = "endpoint:initialized"; } + #[derive(Clone, Debug)] + #[non_exhaustive] + pub struct PathSecretMapInitialized { + #[doc = " The capacity of the path secret map"] + pub capacity: usize, + #[doc = " The port that the path secret is listening on"] + pub control_socket_port: u16, + } + impl Event for PathSecretMapInitialized { + const NAME: &'static str = "path_secret_map:initialized"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + pub struct PathSecretMapUninitialized { + #[doc = " The capacity of the path secret map"] + pub capacity: usize, + #[doc = " The port that the path secret is listening on"] + pub control_socket_port: u16, + #[doc = " The number of entries in the map"] + pub entries: usize, + } + impl Event for PathSecretMapUninitialized { + const NAME: &'static str = "path_secret_map:uninitialized"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when a background handshake is requested"] + pub struct PathSecretMapBackgroundHandshakeRequested<'a> { + pub peer_address: SocketAddress<'a>, + } + impl<'a> Event for PathSecretMapBackgroundHandshakeRequested<'a> { + const NAME: &'static str = "path_secret_map:background_handshake_requested"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when the entry is inserted into the path secret map"] + pub struct PathSecretMapEntryInserted<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for PathSecretMapEntryInserted<'a> { + const NAME: &'static str = "path_secret_map:entry_replaced"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when the entry is considered ready for use"] + pub struct PathSecretMapEntryReady<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for PathSecretMapEntryReady<'a> { + const NAME: &'static str = "path_secret_map:entry_replaced"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an entry is replaced by a new one for the same `peer_address`"] + pub struct PathSecretMapEntryReplaced<'a> { + pub peer_address: SocketAddress<'a>, + pub new_credential_id: &'a [u8], + pub previous_credential_id: &'a [u8], + } + impl<'a> Event for PathSecretMapEntryReplaced<'a> { + const NAME: &'static str = "path_secret_map:entry_replaced"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an UnknownPathSecret packet was sent"] + pub struct UnknownPathSecretPacketSent<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for UnknownPathSecretPacketSent<'a> { + const NAME: &'static str = "path_secret_map:unknown_path_secret_packet_sent"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an UnknownPathSecret packet was received"] + pub struct UnknownPathSecretPacketReceived<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for UnknownPathSecretPacketReceived<'a> { + const NAME: &'static str = "path_secret_map:unknown_path_secret_packet_received"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an UnknownPathSecret packet was authentic and processed"] + pub struct UnknownPathSecretPacketAccepted<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for UnknownPathSecretPacketAccepted<'a> { + const NAME: &'static str = "path_secret_map:unknown_path_secret_packet_accepted"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an UnknownPathSecret packet was rejected as invalid"] + pub struct UnknownPathSecretPacketRejected<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for UnknownPathSecretPacketRejected<'a> { + const NAME: &'static str = "path_secret_map:unknown_path_secret_packet_rejected"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when credential replay was definitely detected"] + pub struct ReplayDefinitelyDetected<'a> { + pub credential_id: &'a [u8], + pub key_id: u64, + } + impl<'a> Event for ReplayDefinitelyDetected<'a> { + const NAME: &'static str = "path_secret_map:replay_definitely_detected"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when credential replay was potentially detected, but could not be verified"] + #[doc = " due to a limiting tracking window"] + pub struct ReplayPotentiallyDetected<'a> { + pub credential_id: &'a [u8], + pub key_id: u64, + pub gap: u64, + } + impl<'a> Event for ReplayPotentiallyDetected<'a> { + const NAME: &'static str = "path_secret_map:replay_potentially_detected"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an ReplayDetected packet was sent"] + pub struct ReplayDetectedPacketSent<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for ReplayDetectedPacketSent<'a> { + const NAME: &'static str = "path_secret_map:replay_detected_packet_sent"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an ReplayDetected packet was received"] + pub struct ReplayDetectedPacketReceived<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for ReplayDetectedPacketReceived<'a> { + const NAME: &'static str = "path_secret_map:replay_detected_packet_received"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an StaleKey packet was authentic and processed"] + pub struct ReplayDetectedPacketAccepted<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + pub key_id: u64, + } + impl<'a> Event for ReplayDetectedPacketAccepted<'a> { + const NAME: &'static str = "path_secret_map:replay_detected_packet_accepted"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an ReplayDetected packet was rejected as invalid"] + pub struct ReplayDetectedPacketRejected<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for ReplayDetectedPacketRejected<'a> { + const NAME: &'static str = "path_secret_map:replay_detected_packet_rejected"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an StaleKey packet was sent"] + pub struct StaleKeyPacketSent<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for StaleKeyPacketSent<'a> { + const NAME: &'static str = "path_secret_map:stale_key_packet_sent"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an StaleKey packet was received"] + pub struct StaleKeyPacketReceived<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for StaleKeyPacketReceived<'a> { + const NAME: &'static str = "path_secret_map:stale_key_packet_received"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an StaleKey packet was authentic and processed"] + pub struct StaleKeyPacketAccepted<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for StaleKeyPacketAccepted<'a> { + const NAME: &'static str = "path_secret_map:stale_key_packet_accepted"; + } + #[derive(Clone, Debug)] + #[non_exhaustive] + #[doc = " Emitted when an StaleKey packet was rejected as invalid"] + pub struct StaleKeyPacketRejected<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> Event for StaleKeyPacketRejected<'a> { + const NAME: &'static str = "path_secret_map:stale_key_packet_rejected"; + } } pub mod tracing { #![doc = r" This module contains event integration with [`tracing`](https://docs.rs/tracing)"] @@ -49,17 +265,17 @@ pub mod tracing { #[doc = r" Emits events with [`tracing`](https://docs.rs/tracing)"] #[derive(Clone, Debug)] pub struct Subscriber { - client: tracing::Span, - server: tracing::Span, + root: tracing::Span, } impl Default for Subscriber { fn default() -> Self { let root = tracing :: span ! (target : "s2n_quic_dc" , tracing :: Level :: DEBUG , "s2n_quic_dc"); - let client = - tracing :: span ! (parent : root . id () , tracing :: Level :: DEBUG , "client"); - let server = - tracing :: span ! (parent : root . id () , tracing :: Level :: DEBUG , "server"); - Self { client, server } + Self { root } + } + } + impl Subscriber { + fn parent(&self, _meta: &M) -> Option { + self.root.id() } } impl super::Subscriber for Subscriber { @@ -69,10 +285,7 @@ pub mod tracing { meta: &api::ConnectionMeta, _info: &api::ConnectionInfo, ) -> Self::ConnectionContext { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); tracing :: span ! (target : "s2n_quic_dc" , parent : parent , tracing :: Level :: DEBUG , "conn" , id = meta . id) } #[inline] @@ -103,10 +316,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::EndpointInitialized, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::EndpointInitialized { acceptor_addr, handshake_addr, @@ -115,13 +325,303 @@ pub mod tracing { } = event; tracing :: event ! (target : "endpoint_initialized" , parent : parent , tracing :: Level :: DEBUG , acceptor_addr = tracing :: field :: debug (acceptor_addr) , handshake_addr = tracing :: field :: debug (handshake_addr) , tcp = tracing :: field :: debug (tcp) , udp = tracing :: field :: debug (udp)); } + #[inline] + fn on_path_secret_map_initialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapInitialized, + ) { + let parent = self.parent(meta); + let api::PathSecretMapInitialized { + capacity, + control_socket_port, + } = event; + tracing :: event ! (target : "path_secret_map_initialized" , parent : parent , tracing :: Level :: DEBUG , capacity = tracing :: field :: debug (capacity) , control_socket_port = tracing :: field :: debug (control_socket_port)); + } + #[inline] + fn on_path_secret_map_uninitialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapUninitialized, + ) { + let parent = self.parent(meta); + let api::PathSecretMapUninitialized { + capacity, + control_socket_port, + entries, + } = event; + tracing :: event ! (target : "path_secret_map_uninitialized" , parent : parent , tracing :: Level :: DEBUG , capacity = tracing :: field :: debug (capacity) , control_socket_port = tracing :: field :: debug (control_socket_port) , entries = tracing :: field :: debug (entries)); + } + #[inline] + fn on_path_secret_map_background_handshake_requested( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapBackgroundHandshakeRequested, + ) { + let parent = self.parent(meta); + let api::PathSecretMapBackgroundHandshakeRequested { peer_address } = event; + tracing :: event ! (target : "path_secret_map_background_handshake_requested" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address)); + } + #[inline] + fn on_path_secret_map_entry_inserted( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryInserted, + ) { + let parent = self.parent(meta); + let api::PathSecretMapEntryInserted { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "path_secret_map_entry_inserted" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_path_secret_map_entry_ready( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReady, + ) { + let parent = self.parent(meta); + let api::PathSecretMapEntryReady { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "path_secret_map_entry_ready" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_path_secret_map_entry_replaced( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReplaced, + ) { + let parent = self.parent(meta); + let api::PathSecretMapEntryReplaced { + peer_address, + new_credential_id, + previous_credential_id, + } = event; + tracing :: event ! (target : "path_secret_map_entry_replaced" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , new_credential_id = tracing :: field :: debug (new_credential_id) , previous_credential_id = tracing :: field :: debug (previous_credential_id)); + } + #[inline] + fn on_unknown_path_secret_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketSent, + ) { + let parent = self.parent(meta); + let api::UnknownPathSecretPacketSent { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "unknown_path_secret_packet_sent" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_unknown_path_secret_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketReceived, + ) { + let parent = self.parent(meta); + let api::UnknownPathSecretPacketReceived { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "unknown_path_secret_packet_received" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_unknown_path_secret_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketAccepted, + ) { + let parent = self.parent(meta); + let api::UnknownPathSecretPacketAccepted { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "unknown_path_secret_packet_accepted" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_unknown_path_secret_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketRejected, + ) { + let parent = self.parent(meta); + let api::UnknownPathSecretPacketRejected { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "unknown_path_secret_packet_rejected" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_replay_definitely_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDefinitelyDetected, + ) { + let parent = self.parent(meta); + let api::ReplayDefinitelyDetected { + credential_id, + key_id, + } = event; + tracing :: event ! (target : "replay_definitely_detected" , parent : parent , tracing :: Level :: DEBUG , credential_id = tracing :: field :: debug (credential_id) , key_id = tracing :: field :: debug (key_id)); + } + #[inline] + fn on_replay_potentially_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayPotentiallyDetected, + ) { + let parent = self.parent(meta); + let api::ReplayPotentiallyDetected { + credential_id, + key_id, + gap, + } = event; + tracing :: event ! (target : "replay_potentially_detected" , parent : parent , tracing :: Level :: DEBUG , credential_id = tracing :: field :: debug (credential_id) , key_id = tracing :: field :: debug (key_id) , gap = tracing :: field :: debug (gap)); + } + #[inline] + fn on_replay_detected_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketSent, + ) { + let parent = self.parent(meta); + let api::ReplayDetectedPacketSent { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "replay_detected_packet_sent" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_replay_detected_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketReceived, + ) { + let parent = self.parent(meta); + let api::ReplayDetectedPacketReceived { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "replay_detected_packet_received" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_replay_detected_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketAccepted, + ) { + let parent = self.parent(meta); + let api::ReplayDetectedPacketAccepted { + peer_address, + credential_id, + key_id, + } = event; + tracing :: event ! (target : "replay_detected_packet_accepted" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id) , key_id = tracing :: field :: debug (key_id)); + } + #[inline] + fn on_replay_detected_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketRejected, + ) { + let parent = self.parent(meta); + let api::ReplayDetectedPacketRejected { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "replay_detected_packet_rejected" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_stale_key_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketSent, + ) { + let parent = self.parent(meta); + let api::StaleKeyPacketSent { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "stale_key_packet_sent" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_stale_key_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketReceived, + ) { + let parent = self.parent(meta); + let api::StaleKeyPacketReceived { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "stale_key_packet_received" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_stale_key_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketAccepted, + ) { + let parent = self.parent(meta); + let api::StaleKeyPacketAccepted { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "stale_key_packet_accepted" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } + #[inline] + fn on_stale_key_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketRejected, + ) { + let parent = self.parent(meta); + let api::StaleKeyPacketRejected { + peer_address, + credential_id, + } = event; + tracing :: event ! (target : "stale_key_packet_rejected" , parent : parent , tracing :: Level :: DEBUG , peer_address = tracing :: field :: debug (peer_address) , credential_id = tracing :: field :: debug (credential_id)); + } } } pub mod builder { use super::*; - pub use s2n_quic_core::event::builder::{ - ConnectionInfo, ConnectionMeta, EndpointMeta, EndpointType, SocketAddress, Subject, - }; + pub use s2n_quic_core::event::builder::{EndpointType, SocketAddress, Subject}; + #[derive(Clone, Debug)] + pub struct ConnectionMeta { + pub id: u64, + } + impl IntoEvent for ConnectionMeta { + #[inline] + fn into_event(self) -> api::ConnectionMeta { + let ConnectionMeta { id } = self; + api::ConnectionMeta { + id: id.into_event(), + } + } + } + #[derive(Clone, Debug)] + pub struct EndpointMeta {} + impl IntoEvent for EndpointMeta { + #[inline] + fn into_event(self) -> api::EndpointMeta { + let EndpointMeta {} = self; + api::EndpointMeta {} + } + } + #[derive(Clone, Debug)] + pub struct ConnectionInfo {} + impl IntoEvent for ConnectionInfo { + #[inline] + fn into_event(self) -> api::ConnectionInfo { + let ConnectionInfo {} = self; + api::ConnectionInfo {} + } + } #[derive(Clone, Debug)] pub struct ApplicationWrite { #[doc = " The number of bytes that the application tried to write"] @@ -174,41 +674,441 @@ pub mod builder { } } } -} -pub use traits::*; -mod traits { - use super::*; - use core::fmt; - use s2n_quic_core::{event::Meta, query}; - #[doc = r" Allows for events to be subscribed to"] - pub trait Subscriber: 'static + Send { - #[doc = r" An application provided type associated with each connection."] - #[doc = r""] - #[doc = r" The context provides a mechanism for applications to provide a custom type"] - #[doc = r" and update it on each event, e.g. computing statistics. Each event"] - #[doc = r" invocation (e.g. [`Subscriber::on_packet_sent`]) also provides mutable"] - #[doc = r" access to the context `&mut ConnectionContext` and allows for updating the"] - #[doc = r" context."] - #[doc = r""] - #[doc = r" ```no_run"] - #[doc = r" # mod s2n_quic { pub mod provider { pub mod event {"] - #[doc = r" # pub use s2n_quic_core::event::{api as events, api::ConnectionInfo, api::ConnectionMeta, Subscriber};"] - #[doc = r" # }}}"] - #[doc = r" use s2n_quic::provider::event::{"] - #[doc = r" ConnectionInfo, ConnectionMeta, Subscriber, events::PacketSent"] - #[doc = r" };"] - #[doc = r""] - #[doc = r" pub struct MyEventSubscriber;"] - #[doc = r""] - #[doc = r" pub struct MyEventContext {"] - #[doc = r" packet_sent: u64,"] - #[doc = r" }"] - #[doc = r""] - #[doc = r" impl Subscriber for MyEventSubscriber {"] - #[doc = r" type ConnectionContext = MyEventContext;"] - #[doc = r""] - #[doc = r" fn create_connection_context("] - #[doc = r" &mut self, _meta: &ConnectionMeta,"] + #[derive(Clone, Debug)] + pub struct PathSecretMapInitialized { + #[doc = " The capacity of the path secret map"] + pub capacity: usize, + #[doc = " The port that the path secret is listening on"] + pub control_socket_port: u16, + } + impl IntoEvent for PathSecretMapInitialized { + #[inline] + fn into_event(self) -> api::PathSecretMapInitialized { + let PathSecretMapInitialized { + capacity, + control_socket_port, + } = self; + api::PathSecretMapInitialized { + capacity: capacity.into_event(), + control_socket_port: control_socket_port.into_event(), + } + } + } + #[derive(Clone, Debug)] + pub struct PathSecretMapUninitialized { + #[doc = " The capacity of the path secret map"] + pub capacity: usize, + #[doc = " The port that the path secret is listening on"] + pub control_socket_port: u16, + #[doc = " The number of entries in the map"] + pub entries: usize, + } + impl IntoEvent for PathSecretMapUninitialized { + #[inline] + fn into_event(self) -> api::PathSecretMapUninitialized { + let PathSecretMapUninitialized { + capacity, + control_socket_port, + entries, + } = self; + api::PathSecretMapUninitialized { + capacity: capacity.into_event(), + control_socket_port: control_socket_port.into_event(), + entries: entries.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when a background handshake is requested"] + pub struct PathSecretMapBackgroundHandshakeRequested<'a> { + pub peer_address: SocketAddress<'a>, + } + impl<'a> IntoEvent> + for PathSecretMapBackgroundHandshakeRequested<'a> + { + #[inline] + fn into_event(self) -> api::PathSecretMapBackgroundHandshakeRequested<'a> { + let PathSecretMapBackgroundHandshakeRequested { peer_address } = self; + api::PathSecretMapBackgroundHandshakeRequested { + peer_address: peer_address.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when the entry is inserted into the path secret map"] + pub struct PathSecretMapEntryInserted<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for PathSecretMapEntryInserted<'a> { + #[inline] + fn into_event(self) -> api::PathSecretMapEntryInserted<'a> { + let PathSecretMapEntryInserted { + peer_address, + credential_id, + } = self; + api::PathSecretMapEntryInserted { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when the entry is considered ready for use"] + pub struct PathSecretMapEntryReady<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for PathSecretMapEntryReady<'a> { + #[inline] + fn into_event(self) -> api::PathSecretMapEntryReady<'a> { + let PathSecretMapEntryReady { + peer_address, + credential_id, + } = self; + api::PathSecretMapEntryReady { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an entry is replaced by a new one for the same `peer_address`"] + pub struct PathSecretMapEntryReplaced<'a> { + pub peer_address: SocketAddress<'a>, + pub new_credential_id: &'a [u8], + pub previous_credential_id: &'a [u8], + } + impl<'a> IntoEvent> for PathSecretMapEntryReplaced<'a> { + #[inline] + fn into_event(self) -> api::PathSecretMapEntryReplaced<'a> { + let PathSecretMapEntryReplaced { + peer_address, + new_credential_id, + previous_credential_id, + } = self; + api::PathSecretMapEntryReplaced { + peer_address: peer_address.into_event(), + new_credential_id: new_credential_id.into_event(), + previous_credential_id: previous_credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an UnknownPathSecret packet was sent"] + pub struct UnknownPathSecretPacketSent<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for UnknownPathSecretPacketSent<'a> { + #[inline] + fn into_event(self) -> api::UnknownPathSecretPacketSent<'a> { + let UnknownPathSecretPacketSent { + peer_address, + credential_id, + } = self; + api::UnknownPathSecretPacketSent { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an UnknownPathSecret packet was received"] + pub struct UnknownPathSecretPacketReceived<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> + for UnknownPathSecretPacketReceived<'a> + { + #[inline] + fn into_event(self) -> api::UnknownPathSecretPacketReceived<'a> { + let UnknownPathSecretPacketReceived { + peer_address, + credential_id, + } = self; + api::UnknownPathSecretPacketReceived { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an UnknownPathSecret packet was authentic and processed"] + pub struct UnknownPathSecretPacketAccepted<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> + for UnknownPathSecretPacketAccepted<'a> + { + #[inline] + fn into_event(self) -> api::UnknownPathSecretPacketAccepted<'a> { + let UnknownPathSecretPacketAccepted { + peer_address, + credential_id, + } = self; + api::UnknownPathSecretPacketAccepted { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an UnknownPathSecret packet was rejected as invalid"] + pub struct UnknownPathSecretPacketRejected<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> + for UnknownPathSecretPacketRejected<'a> + { + #[inline] + fn into_event(self) -> api::UnknownPathSecretPacketRejected<'a> { + let UnknownPathSecretPacketRejected { + peer_address, + credential_id, + } = self; + api::UnknownPathSecretPacketRejected { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when credential replay was definitely detected"] + pub struct ReplayDefinitelyDetected<'a> { + pub credential_id: &'a [u8], + pub key_id: u64, + } + impl<'a> IntoEvent> for ReplayDefinitelyDetected<'a> { + #[inline] + fn into_event(self) -> api::ReplayDefinitelyDetected<'a> { + let ReplayDefinitelyDetected { + credential_id, + key_id, + } = self; + api::ReplayDefinitelyDetected { + credential_id: credential_id.into_event(), + key_id: key_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when credential replay was potentially detected, but could not be verified"] + #[doc = " due to a limiting tracking window"] + pub struct ReplayPotentiallyDetected<'a> { + pub credential_id: &'a [u8], + pub key_id: u64, + pub gap: u64, + } + impl<'a> IntoEvent> for ReplayPotentiallyDetected<'a> { + #[inline] + fn into_event(self) -> api::ReplayPotentiallyDetected<'a> { + let ReplayPotentiallyDetected { + credential_id, + key_id, + gap, + } = self; + api::ReplayPotentiallyDetected { + credential_id: credential_id.into_event(), + key_id: key_id.into_event(), + gap: gap.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an ReplayDetected packet was sent"] + pub struct ReplayDetectedPacketSent<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for ReplayDetectedPacketSent<'a> { + #[inline] + fn into_event(self) -> api::ReplayDetectedPacketSent<'a> { + let ReplayDetectedPacketSent { + peer_address, + credential_id, + } = self; + api::ReplayDetectedPacketSent { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an ReplayDetected packet was received"] + pub struct ReplayDetectedPacketReceived<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for ReplayDetectedPacketReceived<'a> { + #[inline] + fn into_event(self) -> api::ReplayDetectedPacketReceived<'a> { + let ReplayDetectedPacketReceived { + peer_address, + credential_id, + } = self; + api::ReplayDetectedPacketReceived { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an StaleKey packet was authentic and processed"] + pub struct ReplayDetectedPacketAccepted<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + pub key_id: u64, + } + impl<'a> IntoEvent> for ReplayDetectedPacketAccepted<'a> { + #[inline] + fn into_event(self) -> api::ReplayDetectedPacketAccepted<'a> { + let ReplayDetectedPacketAccepted { + peer_address, + credential_id, + key_id, + } = self; + api::ReplayDetectedPacketAccepted { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + key_id: key_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an ReplayDetected packet was rejected as invalid"] + pub struct ReplayDetectedPacketRejected<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for ReplayDetectedPacketRejected<'a> { + #[inline] + fn into_event(self) -> api::ReplayDetectedPacketRejected<'a> { + let ReplayDetectedPacketRejected { + peer_address, + credential_id, + } = self; + api::ReplayDetectedPacketRejected { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an StaleKey packet was sent"] + pub struct StaleKeyPacketSent<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for StaleKeyPacketSent<'a> { + #[inline] + fn into_event(self) -> api::StaleKeyPacketSent<'a> { + let StaleKeyPacketSent { + peer_address, + credential_id, + } = self; + api::StaleKeyPacketSent { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an StaleKey packet was received"] + pub struct StaleKeyPacketReceived<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for StaleKeyPacketReceived<'a> { + #[inline] + fn into_event(self) -> api::StaleKeyPacketReceived<'a> { + let StaleKeyPacketReceived { + peer_address, + credential_id, + } = self; + api::StaleKeyPacketReceived { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an StaleKey packet was authentic and processed"] + pub struct StaleKeyPacketAccepted<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for StaleKeyPacketAccepted<'a> { + #[inline] + fn into_event(self) -> api::StaleKeyPacketAccepted<'a> { + let StaleKeyPacketAccepted { + peer_address, + credential_id, + } = self; + api::StaleKeyPacketAccepted { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } + #[derive(Clone, Debug)] + #[doc = " Emitted when an StaleKey packet was rejected as invalid"] + pub struct StaleKeyPacketRejected<'a> { + pub peer_address: SocketAddress<'a>, + pub credential_id: &'a [u8], + } + impl<'a> IntoEvent> for StaleKeyPacketRejected<'a> { + #[inline] + fn into_event(self) -> api::StaleKeyPacketRejected<'a> { + let StaleKeyPacketRejected { + peer_address, + credential_id, + } = self; + api::StaleKeyPacketRejected { + peer_address: peer_address.into_event(), + credential_id: credential_id.into_event(), + } + } + } +} +pub use traits::*; +mod traits { + use super::*; + use crate::event::Meta; + use core::fmt; + use s2n_quic_core::query; + #[doc = r" Allows for events to be subscribed to"] + pub trait Subscriber: 'static + Send + Sync { + #[doc = r" An application provided type associated with each connection."] + #[doc = r""] + #[doc = r" The context provides a mechanism for applications to provide a custom type"] + #[doc = r" and update it on each event, e.g. computing statistics. Each event"] + #[doc = r" invocation (e.g. [`Subscriber::on_packet_sent`]) also provides mutable"] + #[doc = r" access to the context `&mut ConnectionContext` and allows for updating the"] + #[doc = r" context."] + #[doc = r""] + #[doc = r" ```no_run"] + #[doc = r" # mod s2n_quic { pub mod provider { pub mod event {"] + #[doc = r" # pub use s2n_quic_core::event::{api as events, api::ConnectionInfo, api::ConnectionMeta, Subscriber};"] + #[doc = r" # }}}"] + #[doc = r" use s2n_quic::provider::event::{"] + #[doc = r" ConnectionInfo, ConnectionMeta, Subscriber, events::PacketSent"] + #[doc = r" };"] + #[doc = r""] + #[doc = r" pub struct MyEventSubscriber;"] + #[doc = r""] + #[doc = r" pub struct MyEventContext {"] + #[doc = r" packet_sent: u64,"] + #[doc = r" }"] + #[doc = r""] + #[doc = r" impl Subscriber for MyEventSubscriber {"] + #[doc = r" type ConnectionContext = MyEventContext;"] + #[doc = r""] + #[doc = r" fn create_connection_context("] + #[doc = r" &mut self, _meta: &ConnectionMeta,"] #[doc = r" _info: &ConnectionInfo,"] #[doc = r" ) -> Self::ConnectionContext {"] #[doc = r" MyEventContext { packet_sent: 0 }"] @@ -233,34 +1133,234 @@ mod traits { ) -> Self::ConnectionContext; #[doc = "Called when the `ApplicationWrite` event is triggered"] #[inline] - fn on_application_write( + fn on_application_write( + &self, + context: &Self::ConnectionContext, + meta: &api::ConnectionMeta, + event: &api::ApplicationWrite, + ) { + let _ = context; + let _ = meta; + let _ = event; + } + #[doc = "Called when the `ApplicationRead` event is triggered"] + #[inline] + fn on_application_read( + &self, + context: &Self::ConnectionContext, + meta: &api::ConnectionMeta, + event: &api::ApplicationRead, + ) { + let _ = context; + let _ = meta; + let _ = event; + } + #[doc = "Called when the `EndpointInitialized` event is triggered"] + #[inline] + fn on_endpoint_initialized( + &self, + meta: &api::EndpointMeta, + event: &api::EndpointInitialized, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `PathSecretMapInitialized` event is triggered"] + #[inline] + fn on_path_secret_map_initialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapInitialized, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `PathSecretMapUninitialized` event is triggered"] + #[inline] + fn on_path_secret_map_uninitialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapUninitialized, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `PathSecretMapBackgroundHandshakeRequested` event is triggered"] + #[inline] + fn on_path_secret_map_background_handshake_requested( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapBackgroundHandshakeRequested, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `PathSecretMapEntryInserted` event is triggered"] + #[inline] + fn on_path_secret_map_entry_inserted( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryInserted, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `PathSecretMapEntryReady` event is triggered"] + #[inline] + fn on_path_secret_map_entry_ready( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReady, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `PathSecretMapEntryReplaced` event is triggered"] + #[inline] + fn on_path_secret_map_entry_replaced( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReplaced, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `UnknownPathSecretPacketSent` event is triggered"] + #[inline] + fn on_unknown_path_secret_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketSent, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `UnknownPathSecretPacketReceived` event is triggered"] + #[inline] + fn on_unknown_path_secret_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketReceived, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `UnknownPathSecretPacketAccepted` event is triggered"] + #[inline] + fn on_unknown_path_secret_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketAccepted, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `UnknownPathSecretPacketRejected` event is triggered"] + #[inline] + fn on_unknown_path_secret_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketRejected, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `ReplayDefinitelyDetected` event is triggered"] + #[inline] + fn on_replay_definitely_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDefinitelyDetected, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `ReplayPotentiallyDetected` event is triggered"] + #[inline] + fn on_replay_potentially_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayPotentiallyDetected, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `ReplayDetectedPacketSent` event is triggered"] + #[inline] + fn on_replay_detected_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketSent, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `ReplayDetectedPacketReceived` event is triggered"] + #[inline] + fn on_replay_detected_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketReceived, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `ReplayDetectedPacketAccepted` event is triggered"] + #[inline] + fn on_replay_detected_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketAccepted, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `ReplayDetectedPacketRejected` event is triggered"] + #[inline] + fn on_replay_detected_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketRejected, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `StaleKeyPacketSent` event is triggered"] + #[inline] + fn on_stale_key_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketSent, + ) { + let _ = meta; + let _ = event; + } + #[doc = "Called when the `StaleKeyPacketReceived` event is triggered"] + #[inline] + fn on_stale_key_packet_received( &self, - context: &Self::ConnectionContext, - meta: &api::ConnectionMeta, - event: &api::ApplicationWrite, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketReceived, ) { - let _ = context; let _ = meta; let _ = event; } - #[doc = "Called when the `ApplicationRead` event is triggered"] + #[doc = "Called when the `StaleKeyPacketAccepted` event is triggered"] #[inline] - fn on_application_read( + fn on_stale_key_packet_accepted( &self, - context: &Self::ConnectionContext, - meta: &api::ConnectionMeta, - event: &api::ApplicationRead, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketAccepted, ) { - let _ = context; let _ = meta; let _ = event; } - #[doc = "Called when the `EndpointInitialized` event is triggered"] + #[doc = "Called when the `StaleKeyPacketRejected` event is triggered"] #[inline] - fn on_endpoint_initialized( + fn on_stale_key_packet_rejected( &self, meta: &api::EndpointMeta, - event: &api::EndpointInitialized, + event: &api::StaleKeyPacketRejected, ) { let _ = meta; let _ = event; @@ -322,88 +1422,471 @@ mod traits { (self.1).on_application_write(&context.1, meta, event); } #[inline] - fn on_application_read( + fn on_application_read( + &self, + context: &Self::ConnectionContext, + meta: &api::ConnectionMeta, + event: &api::ApplicationRead, + ) { + (self.0).on_application_read(&context.0, meta, event); + (self.1).on_application_read(&context.1, meta, event); + } + #[inline] + fn on_endpoint_initialized( + &self, + meta: &api::EndpointMeta, + event: &api::EndpointInitialized, + ) { + (self.0).on_endpoint_initialized(meta, event); + (self.1).on_endpoint_initialized(meta, event); + } + #[inline] + fn on_path_secret_map_initialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapInitialized, + ) { + (self.0).on_path_secret_map_initialized(meta, event); + (self.1).on_path_secret_map_initialized(meta, event); + } + #[inline] + fn on_path_secret_map_uninitialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapUninitialized, + ) { + (self.0).on_path_secret_map_uninitialized(meta, event); + (self.1).on_path_secret_map_uninitialized(meta, event); + } + #[inline] + fn on_path_secret_map_background_handshake_requested( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapBackgroundHandshakeRequested, + ) { + (self.0).on_path_secret_map_background_handshake_requested(meta, event); + (self.1).on_path_secret_map_background_handshake_requested(meta, event); + } + #[inline] + fn on_path_secret_map_entry_inserted( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryInserted, + ) { + (self.0).on_path_secret_map_entry_inserted(meta, event); + (self.1).on_path_secret_map_entry_inserted(meta, event); + } + #[inline] + fn on_path_secret_map_entry_ready( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReady, + ) { + (self.0).on_path_secret_map_entry_ready(meta, event); + (self.1).on_path_secret_map_entry_ready(meta, event); + } + #[inline] + fn on_path_secret_map_entry_replaced( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReplaced, + ) { + (self.0).on_path_secret_map_entry_replaced(meta, event); + (self.1).on_path_secret_map_entry_replaced(meta, event); + } + #[inline] + fn on_unknown_path_secret_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketSent, + ) { + (self.0).on_unknown_path_secret_packet_sent(meta, event); + (self.1).on_unknown_path_secret_packet_sent(meta, event); + } + #[inline] + fn on_unknown_path_secret_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketReceived, + ) { + (self.0).on_unknown_path_secret_packet_received(meta, event); + (self.1).on_unknown_path_secret_packet_received(meta, event); + } + #[inline] + fn on_unknown_path_secret_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketAccepted, + ) { + (self.0).on_unknown_path_secret_packet_accepted(meta, event); + (self.1).on_unknown_path_secret_packet_accepted(meta, event); + } + #[inline] + fn on_unknown_path_secret_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketRejected, + ) { + (self.0).on_unknown_path_secret_packet_rejected(meta, event); + (self.1).on_unknown_path_secret_packet_rejected(meta, event); + } + #[inline] + fn on_replay_definitely_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDefinitelyDetected, + ) { + (self.0).on_replay_definitely_detected(meta, event); + (self.1).on_replay_definitely_detected(meta, event); + } + #[inline] + fn on_replay_potentially_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayPotentiallyDetected, + ) { + (self.0).on_replay_potentially_detected(meta, event); + (self.1).on_replay_potentially_detected(meta, event); + } + #[inline] + fn on_replay_detected_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketSent, + ) { + (self.0).on_replay_detected_packet_sent(meta, event); + (self.1).on_replay_detected_packet_sent(meta, event); + } + #[inline] + fn on_replay_detected_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketReceived, + ) { + (self.0).on_replay_detected_packet_received(meta, event); + (self.1).on_replay_detected_packet_received(meta, event); + } + #[inline] + fn on_replay_detected_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketAccepted, + ) { + (self.0).on_replay_detected_packet_accepted(meta, event); + (self.1).on_replay_detected_packet_accepted(meta, event); + } + #[inline] + fn on_replay_detected_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketRejected, + ) { + (self.0).on_replay_detected_packet_rejected(meta, event); + (self.1).on_replay_detected_packet_rejected(meta, event); + } + #[inline] + fn on_stale_key_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketSent, + ) { + (self.0).on_stale_key_packet_sent(meta, event); + (self.1).on_stale_key_packet_sent(meta, event); + } + #[inline] + fn on_stale_key_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketReceived, + ) { + (self.0).on_stale_key_packet_received(meta, event); + (self.1).on_stale_key_packet_received(meta, event); + } + #[inline] + fn on_stale_key_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketAccepted, + ) { + (self.0).on_stale_key_packet_accepted(meta, event); + (self.1).on_stale_key_packet_accepted(meta, event); + } + #[inline] + fn on_stale_key_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketRejected, + ) { + (self.0).on_stale_key_packet_rejected(meta, event); + (self.1).on_stale_key_packet_rejected(meta, event); + } + #[inline] + fn on_event(&self, meta: &M, event: &E) { + self.0.on_event(meta, event); + self.1.on_event(meta, event); + } + #[inline] + fn on_connection_event( + &self, + context: &Self::ConnectionContext, + meta: &api::ConnectionMeta, + event: &E, + ) { + self.0.on_connection_event(&context.0, meta, event); + self.1.on_connection_event(&context.1, meta, event); + } + #[inline] + fn query( + context: &Self::ConnectionContext, + query: &mut dyn query::Query, + ) -> query::ControlFlow { + query + .execute(context) + .and_then(|| A::query(&context.0, query)) + .and_then(|| B::query(&context.1, query)) + } + } + pub trait EndpointPublisher { + #[doc = "Publishes a `EndpointInitialized` event to the publisher's subscriber"] + fn on_endpoint_initialized(&self, event: builder::EndpointInitialized); + #[doc = "Publishes a `PathSecretMapInitialized` event to the publisher's subscriber"] + fn on_path_secret_map_initialized(&self, event: builder::PathSecretMapInitialized); + #[doc = "Publishes a `PathSecretMapUninitialized` event to the publisher's subscriber"] + fn on_path_secret_map_uninitialized(&self, event: builder::PathSecretMapUninitialized); + #[doc = "Publishes a `PathSecretMapBackgroundHandshakeRequested` event to the publisher's subscriber"] + fn on_path_secret_map_background_handshake_requested( + &self, + event: builder::PathSecretMapBackgroundHandshakeRequested, + ); + #[doc = "Publishes a `PathSecretMapEntryInserted` event to the publisher's subscriber"] + fn on_path_secret_map_entry_inserted(&self, event: builder::PathSecretMapEntryInserted); + #[doc = "Publishes a `PathSecretMapEntryReady` event to the publisher's subscriber"] + fn on_path_secret_map_entry_ready(&self, event: builder::PathSecretMapEntryReady); + #[doc = "Publishes a `PathSecretMapEntryReplaced` event to the publisher's subscriber"] + fn on_path_secret_map_entry_replaced(&self, event: builder::PathSecretMapEntryReplaced); + #[doc = "Publishes a `UnknownPathSecretPacketSent` event to the publisher's subscriber"] + fn on_unknown_path_secret_packet_sent(&self, event: builder::UnknownPathSecretPacketSent); + #[doc = "Publishes a `UnknownPathSecretPacketReceived` event to the publisher's subscriber"] + fn on_unknown_path_secret_packet_received( + &self, + event: builder::UnknownPathSecretPacketReceived, + ); + #[doc = "Publishes a `UnknownPathSecretPacketAccepted` event to the publisher's subscriber"] + fn on_unknown_path_secret_packet_accepted( + &self, + event: builder::UnknownPathSecretPacketAccepted, + ); + #[doc = "Publishes a `UnknownPathSecretPacketRejected` event to the publisher's subscriber"] + fn on_unknown_path_secret_packet_rejected( + &self, + event: builder::UnknownPathSecretPacketRejected, + ); + #[doc = "Publishes a `ReplayDefinitelyDetected` event to the publisher's subscriber"] + fn on_replay_definitely_detected(&self, event: builder::ReplayDefinitelyDetected); + #[doc = "Publishes a `ReplayPotentiallyDetected` event to the publisher's subscriber"] + fn on_replay_potentially_detected(&self, event: builder::ReplayPotentiallyDetected); + #[doc = "Publishes a `ReplayDetectedPacketSent` event to the publisher's subscriber"] + fn on_replay_detected_packet_sent(&self, event: builder::ReplayDetectedPacketSent); + #[doc = "Publishes a `ReplayDetectedPacketReceived` event to the publisher's subscriber"] + fn on_replay_detected_packet_received(&self, event: builder::ReplayDetectedPacketReceived); + #[doc = "Publishes a `ReplayDetectedPacketAccepted` event to the publisher's subscriber"] + fn on_replay_detected_packet_accepted(&self, event: builder::ReplayDetectedPacketAccepted); + #[doc = "Publishes a `ReplayDetectedPacketRejected` event to the publisher's subscriber"] + fn on_replay_detected_packet_rejected(&self, event: builder::ReplayDetectedPacketRejected); + #[doc = "Publishes a `StaleKeyPacketSent` event to the publisher's subscriber"] + fn on_stale_key_packet_sent(&self, event: builder::StaleKeyPacketSent); + #[doc = "Publishes a `StaleKeyPacketReceived` event to the publisher's subscriber"] + fn on_stale_key_packet_received(&self, event: builder::StaleKeyPacketReceived); + #[doc = "Publishes a `StaleKeyPacketAccepted` event to the publisher's subscriber"] + fn on_stale_key_packet_accepted(&self, event: builder::StaleKeyPacketAccepted); + #[doc = "Publishes a `StaleKeyPacketRejected` event to the publisher's subscriber"] + fn on_stale_key_packet_rejected(&self, event: builder::StaleKeyPacketRejected); + #[doc = r" Returns the QUIC version, if any"] + fn quic_version(&self) -> Option; + } + pub struct EndpointPublisherSubscriber<'a, Sub: Subscriber> { + meta: api::EndpointMeta, + quic_version: Option, + subscriber: &'a Sub, + } + impl<'a, Sub: Subscriber> fmt::Debug for EndpointPublisherSubscriber<'a, Sub> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ConnectionPublisherSubscriber") + .field("meta", &self.meta) + .field("quic_version", &self.quic_version) + .finish() + } + } + impl<'a, Sub: Subscriber> EndpointPublisherSubscriber<'a, Sub> { + #[inline] + pub fn new( + meta: builder::EndpointMeta, + quic_version: Option, + subscriber: &'a Sub, + ) -> Self { + Self { + meta: meta.into_event(), + quic_version, + subscriber, + } + } + } + impl<'a, Sub: Subscriber> EndpointPublisher for EndpointPublisherSubscriber<'a, Sub> { + #[inline] + fn on_endpoint_initialized(&self, event: builder::EndpointInitialized) { + let event = event.into_event(); + self.subscriber.on_endpoint_initialized(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_path_secret_map_initialized(&self, event: builder::PathSecretMapInitialized) { + let event = event.into_event(); + self.subscriber + .on_path_secret_map_initialized(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_path_secret_map_uninitialized(&self, event: builder::PathSecretMapUninitialized) { + let event = event.into_event(); + self.subscriber + .on_path_secret_map_uninitialized(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_path_secret_map_background_handshake_requested( + &self, + event: builder::PathSecretMapBackgroundHandshakeRequested, + ) { + let event = event.into_event(); + self.subscriber + .on_path_secret_map_background_handshake_requested(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_path_secret_map_entry_inserted(&self, event: builder::PathSecretMapEntryInserted) { + let event = event.into_event(); + self.subscriber + .on_path_secret_map_entry_inserted(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_path_secret_map_entry_ready(&self, event: builder::PathSecretMapEntryReady) { + let event = event.into_event(); + self.subscriber + .on_path_secret_map_entry_ready(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_path_secret_map_entry_replaced(&self, event: builder::PathSecretMapEntryReplaced) { + let event = event.into_event(); + self.subscriber + .on_path_secret_map_entry_replaced(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_unknown_path_secret_packet_sent(&self, event: builder::UnknownPathSecretPacketSent) { + let event = event.into_event(); + self.subscriber + .on_unknown_path_secret_packet_sent(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_unknown_path_secret_packet_received( + &self, + event: builder::UnknownPathSecretPacketReceived, + ) { + let event = event.into_event(); + self.subscriber + .on_unknown_path_secret_packet_received(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_unknown_path_secret_packet_accepted( + &self, + event: builder::UnknownPathSecretPacketAccepted, + ) { + let event = event.into_event(); + self.subscriber + .on_unknown_path_secret_packet_accepted(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_unknown_path_secret_packet_rejected( &self, - context: &Self::ConnectionContext, - meta: &api::ConnectionMeta, - event: &api::ApplicationRead, + event: builder::UnknownPathSecretPacketRejected, ) { - (self.0).on_application_read(&context.0, meta, event); - (self.1).on_application_read(&context.1, meta, event); + let event = event.into_event(); + self.subscriber + .on_unknown_path_secret_packet_rejected(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); } #[inline] - fn on_endpoint_initialized( - &self, - meta: &api::EndpointMeta, - event: &api::EndpointInitialized, - ) { - (self.0).on_endpoint_initialized(meta, event); - (self.1).on_endpoint_initialized(meta, event); + fn on_replay_definitely_detected(&self, event: builder::ReplayDefinitelyDetected) { + let event = event.into_event(); + self.subscriber + .on_replay_definitely_detected(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); } #[inline] - fn on_event(&self, meta: &M, event: &E) { - self.0.on_event(meta, event); - self.1.on_event(meta, event); + fn on_replay_potentially_detected(&self, event: builder::ReplayPotentiallyDetected) { + let event = event.into_event(); + self.subscriber + .on_replay_potentially_detected(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); } #[inline] - fn on_connection_event( - &self, - context: &Self::ConnectionContext, - meta: &api::ConnectionMeta, - event: &E, - ) { - self.0.on_connection_event(&context.0, meta, event); - self.1.on_connection_event(&context.1, meta, event); + fn on_replay_detected_packet_sent(&self, event: builder::ReplayDetectedPacketSent) { + let event = event.into_event(); + self.subscriber + .on_replay_detected_packet_sent(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); } #[inline] - fn query( - context: &Self::ConnectionContext, - query: &mut dyn query::Query, - ) -> query::ControlFlow { - query - .execute(context) - .and_then(|| A::query(&context.0, query)) - .and_then(|| B::query(&context.1, query)) + fn on_replay_detected_packet_received(&self, event: builder::ReplayDetectedPacketReceived) { + let event = event.into_event(); + self.subscriber + .on_replay_detected_packet_received(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); } - } - pub trait EndpointPublisher { - #[doc = "Publishes a `EndpointInitialized` event to the publisher's subscriber"] - fn on_endpoint_initialized(&self, event: builder::EndpointInitialized); - #[doc = r" Returns the QUIC version, if any"] - fn quic_version(&self) -> Option; - } - pub struct EndpointPublisherSubscriber<'a, Sub: Subscriber> { - meta: api::EndpointMeta, - quic_version: Option, - subscriber: &'a Sub, - } - impl<'a, Sub: Subscriber> fmt::Debug for EndpointPublisherSubscriber<'a, Sub> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("ConnectionPublisherSubscriber") - .field("meta", &self.meta) - .field("quic_version", &self.quic_version) - .finish() + #[inline] + fn on_replay_detected_packet_accepted(&self, event: builder::ReplayDetectedPacketAccepted) { + let event = event.into_event(); + self.subscriber + .on_replay_detected_packet_accepted(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); } - } - impl<'a, Sub: Subscriber> EndpointPublisherSubscriber<'a, Sub> { #[inline] - pub fn new( - meta: builder::EndpointMeta, - quic_version: Option, - subscriber: &'a Sub, - ) -> Self { - Self { - meta: meta.into_event(), - quic_version, - subscriber, - } + fn on_replay_detected_packet_rejected(&self, event: builder::ReplayDetectedPacketRejected) { + let event = event.into_event(); + self.subscriber + .on_replay_detected_packet_rejected(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); } - } - impl<'a, Sub: Subscriber> EndpointPublisher for EndpointPublisherSubscriber<'a, Sub> { #[inline] - fn on_endpoint_initialized(&self, event: builder::EndpointInitialized) { + fn on_stale_key_packet_sent(&self, event: builder::StaleKeyPacketSent) { let event = event.into_event(); - self.subscriber.on_endpoint_initialized(&self.meta, &event); + self.subscriber.on_stale_key_packet_sent(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_stale_key_packet_received(&self, event: builder::StaleKeyPacketReceived) { + let event = event.into_event(); + self.subscriber + .on_stale_key_packet_received(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_stale_key_packet_accepted(&self, event: builder::StaleKeyPacketAccepted) { + let event = event.into_event(); + self.subscriber + .on_stale_key_packet_accepted(&self.meta, &event); + self.subscriber.on_event(&self.meta, &event); + } + #[inline] + fn on_stale_key_packet_rejected(&self, event: builder::StaleKeyPacketRejected) { + let event = event.into_event(); + self.subscriber + .on_stale_key_packet_rejected(&self.meta, &event); self.subscriber.on_event(&self.meta, &event); } #[inline] @@ -568,6 +2051,26 @@ pub mod testing { location: Option, output: Mutex>, pub endpoint_initialized: AtomicU32, + pub path_secret_map_initialized: AtomicU32, + pub path_secret_map_uninitialized: AtomicU32, + pub path_secret_map_background_handshake_requested: AtomicU32, + pub path_secret_map_entry_inserted: AtomicU32, + pub path_secret_map_entry_ready: AtomicU32, + pub path_secret_map_entry_replaced: AtomicU32, + pub unknown_path_secret_packet_sent: AtomicU32, + pub unknown_path_secret_packet_received: AtomicU32, + pub unknown_path_secret_packet_accepted: AtomicU32, + pub unknown_path_secret_packet_rejected: AtomicU32, + pub replay_definitely_detected: AtomicU32, + pub replay_potentially_detected: AtomicU32, + pub replay_detected_packet_sent: AtomicU32, + pub replay_detected_packet_received: AtomicU32, + pub replay_detected_packet_accepted: AtomicU32, + pub replay_detected_packet_rejected: AtomicU32, + pub stale_key_packet_sent: AtomicU32, + pub stale_key_packet_received: AtomicU32, + pub stale_key_packet_accepted: AtomicU32, + pub stale_key_packet_rejected: AtomicU32, } impl Drop for Subscriber { fn drop(&mut self) { @@ -600,23 +2103,282 @@ pub mod testing { location: None, output: Default::default(), endpoint_initialized: AtomicU32::new(0), + path_secret_map_initialized: AtomicU32::new(0), + path_secret_map_uninitialized: AtomicU32::new(0), + path_secret_map_background_handshake_requested: AtomicU32::new(0), + path_secret_map_entry_inserted: AtomicU32::new(0), + path_secret_map_entry_ready: AtomicU32::new(0), + path_secret_map_entry_replaced: AtomicU32::new(0), + unknown_path_secret_packet_sent: AtomicU32::new(0), + unknown_path_secret_packet_received: AtomicU32::new(0), + unknown_path_secret_packet_accepted: AtomicU32::new(0), + unknown_path_secret_packet_rejected: AtomicU32::new(0), + replay_definitely_detected: AtomicU32::new(0), + replay_potentially_detected: AtomicU32::new(0), + replay_detected_packet_sent: AtomicU32::new(0), + replay_detected_packet_received: AtomicU32::new(0), + replay_detected_packet_accepted: AtomicU32::new(0), + replay_detected_packet_rejected: AtomicU32::new(0), + stale_key_packet_sent: AtomicU32::new(0), + stale_key_packet_received: AtomicU32::new(0), + stale_key_packet_accepted: AtomicU32::new(0), + stale_key_packet_rejected: AtomicU32::new(0), } } - } - impl super::super::Subscriber for Subscriber { - type ConnectionContext = (); - fn create_connection_context( + } + impl super::super::Subscriber for Subscriber { + type ConnectionContext = (); + fn create_connection_context( + &self, + _meta: &api::ConnectionMeta, + _info: &api::ConnectionInfo, + ) -> Self::ConnectionContext { + } + fn on_endpoint_initialized( + &self, + meta: &api::EndpointMeta, + event: &api::EndpointInitialized, + ) { + self.endpoint_initialized.fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_initialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapInitialized, + ) { + self.path_secret_map_initialized + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_uninitialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapUninitialized, + ) { + self.path_secret_map_uninitialized + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_background_handshake_requested( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapBackgroundHandshakeRequested, + ) { + self.path_secret_map_background_handshake_requested + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_entry_inserted( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryInserted, + ) { + self.path_secret_map_entry_inserted + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_entry_ready( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReady, + ) { + self.path_secret_map_entry_ready + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_entry_replaced( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReplaced, + ) { + self.path_secret_map_entry_replaced + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_unknown_path_secret_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketSent, + ) { + self.unknown_path_secret_packet_sent + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_unknown_path_secret_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketReceived, + ) { + self.unknown_path_secret_packet_received + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_unknown_path_secret_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketAccepted, + ) { + self.unknown_path_secret_packet_accepted + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_unknown_path_secret_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketRejected, + ) { + self.unknown_path_secret_packet_rejected + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_definitely_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDefinitelyDetected, + ) { + self.replay_definitely_detected + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_potentially_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayPotentiallyDetected, + ) { + self.replay_potentially_detected + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_detected_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketSent, + ) { + self.replay_detected_packet_sent + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_detected_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketReceived, + ) { + self.replay_detected_packet_received + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_detected_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketAccepted, + ) { + self.replay_detected_packet_accepted + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_detected_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketRejected, + ) { + self.replay_detected_packet_rejected + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_stale_key_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketSent, + ) { + self.stale_key_packet_sent.fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_stale_key_packet_received( &self, - _meta: &api::ConnectionMeta, - _info: &api::ConnectionInfo, - ) -> Self::ConnectionContext { + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketReceived, + ) { + self.stale_key_packet_received + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); } - fn on_endpoint_initialized( + fn on_stale_key_packet_accepted( &self, meta: &api::EndpointMeta, - event: &api::EndpointInitialized, + event: &api::StaleKeyPacketAccepted, ) { - self.endpoint_initialized.fetch_add(1, Ordering::Relaxed); + self.stale_key_packet_accepted + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_stale_key_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketRejected, + ) { + self.stale_key_packet_rejected + .fetch_add(1, Ordering::Relaxed); self.output .lock() .unwrap() @@ -631,6 +2393,26 @@ pub mod testing { pub application_write: AtomicU32, pub application_read: AtomicU32, pub endpoint_initialized: AtomicU32, + pub path_secret_map_initialized: AtomicU32, + pub path_secret_map_uninitialized: AtomicU32, + pub path_secret_map_background_handshake_requested: AtomicU32, + pub path_secret_map_entry_inserted: AtomicU32, + pub path_secret_map_entry_ready: AtomicU32, + pub path_secret_map_entry_replaced: AtomicU32, + pub unknown_path_secret_packet_sent: AtomicU32, + pub unknown_path_secret_packet_received: AtomicU32, + pub unknown_path_secret_packet_accepted: AtomicU32, + pub unknown_path_secret_packet_rejected: AtomicU32, + pub replay_definitely_detected: AtomicU32, + pub replay_potentially_detected: AtomicU32, + pub replay_detected_packet_sent: AtomicU32, + pub replay_detected_packet_received: AtomicU32, + pub replay_detected_packet_accepted: AtomicU32, + pub replay_detected_packet_rejected: AtomicU32, + pub stale_key_packet_sent: AtomicU32, + pub stale_key_packet_received: AtomicU32, + pub stale_key_packet_accepted: AtomicU32, + pub stale_key_packet_rejected: AtomicU32, } impl Drop for Subscriber { fn drop(&mut self) { @@ -665,6 +2447,26 @@ pub mod testing { application_write: AtomicU32::new(0), application_read: AtomicU32::new(0), endpoint_initialized: AtomicU32::new(0), + path_secret_map_initialized: AtomicU32::new(0), + path_secret_map_uninitialized: AtomicU32::new(0), + path_secret_map_background_handshake_requested: AtomicU32::new(0), + path_secret_map_entry_inserted: AtomicU32::new(0), + path_secret_map_entry_ready: AtomicU32::new(0), + path_secret_map_entry_replaced: AtomicU32::new(0), + unknown_path_secret_packet_sent: AtomicU32::new(0), + unknown_path_secret_packet_received: AtomicU32::new(0), + unknown_path_secret_packet_accepted: AtomicU32::new(0), + unknown_path_secret_packet_rejected: AtomicU32::new(0), + replay_definitely_detected: AtomicU32::new(0), + replay_potentially_detected: AtomicU32::new(0), + replay_detected_packet_sent: AtomicU32::new(0), + replay_detected_packet_received: AtomicU32::new(0), + replay_detected_packet_accepted: AtomicU32::new(0), + replay_detected_packet_rejected: AtomicU32::new(0), + stale_key_packet_sent: AtomicU32::new(0), + stale_key_packet_received: AtomicU32::new(0), + stale_key_packet_accepted: AtomicU32::new(0), + stale_key_packet_rejected: AtomicU32::new(0), } } } @@ -715,6 +2517,245 @@ pub mod testing { .unwrap() .push(format!("{meta:?} {event:?}")); } + fn on_path_secret_map_initialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapInitialized, + ) { + self.path_secret_map_initialized + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_uninitialized( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapUninitialized, + ) { + self.path_secret_map_uninitialized + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_background_handshake_requested( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapBackgroundHandshakeRequested, + ) { + self.path_secret_map_background_handshake_requested + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_entry_inserted( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryInserted, + ) { + self.path_secret_map_entry_inserted + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_entry_ready( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReady, + ) { + self.path_secret_map_entry_ready + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_path_secret_map_entry_replaced( + &self, + meta: &api::EndpointMeta, + event: &api::PathSecretMapEntryReplaced, + ) { + self.path_secret_map_entry_replaced + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_unknown_path_secret_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketSent, + ) { + self.unknown_path_secret_packet_sent + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_unknown_path_secret_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketReceived, + ) { + self.unknown_path_secret_packet_received + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_unknown_path_secret_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketAccepted, + ) { + self.unknown_path_secret_packet_accepted + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_unknown_path_secret_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::UnknownPathSecretPacketRejected, + ) { + self.unknown_path_secret_packet_rejected + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_definitely_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDefinitelyDetected, + ) { + self.replay_definitely_detected + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_potentially_detected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayPotentiallyDetected, + ) { + self.replay_potentially_detected + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_detected_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketSent, + ) { + self.replay_detected_packet_sent + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_detected_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketReceived, + ) { + self.replay_detected_packet_received + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_detected_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketAccepted, + ) { + self.replay_detected_packet_accepted + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_replay_detected_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::ReplayDetectedPacketRejected, + ) { + self.replay_detected_packet_rejected + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_stale_key_packet_sent( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketSent, + ) { + self.stale_key_packet_sent.fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_stale_key_packet_received( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketReceived, + ) { + self.stale_key_packet_received + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_stale_key_packet_accepted( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketAccepted, + ) { + self.stale_key_packet_accepted + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } + fn on_stale_key_packet_rejected( + &self, + meta: &api::EndpointMeta, + event: &api::StaleKeyPacketRejected, + ) { + self.stale_key_packet_rejected + .fetch_add(1, Ordering::Relaxed); + self.output + .lock() + .unwrap() + .push(format!("{meta:?} {event:?}")); + } } #[derive(Debug)] pub struct Publisher { @@ -723,6 +2764,26 @@ pub mod testing { pub application_write: AtomicU32, pub application_read: AtomicU32, pub endpoint_initialized: AtomicU32, + pub path_secret_map_initialized: AtomicU32, + pub path_secret_map_uninitialized: AtomicU32, + pub path_secret_map_background_handshake_requested: AtomicU32, + pub path_secret_map_entry_inserted: AtomicU32, + pub path_secret_map_entry_ready: AtomicU32, + pub path_secret_map_entry_replaced: AtomicU32, + pub unknown_path_secret_packet_sent: AtomicU32, + pub unknown_path_secret_packet_received: AtomicU32, + pub unknown_path_secret_packet_accepted: AtomicU32, + pub unknown_path_secret_packet_rejected: AtomicU32, + pub replay_definitely_detected: AtomicU32, + pub replay_potentially_detected: AtomicU32, + pub replay_detected_packet_sent: AtomicU32, + pub replay_detected_packet_received: AtomicU32, + pub replay_detected_packet_accepted: AtomicU32, + pub replay_detected_packet_rejected: AtomicU32, + pub stale_key_packet_sent: AtomicU32, + pub stale_key_packet_received: AtomicU32, + pub stale_key_packet_accepted: AtomicU32, + pub stale_key_packet_rejected: AtomicU32, } impl Publisher { #[doc = r" Creates a publisher with snapshot assertions enabled"] @@ -747,6 +2808,26 @@ pub mod testing { application_write: AtomicU32::new(0), application_read: AtomicU32::new(0), endpoint_initialized: AtomicU32::new(0), + path_secret_map_initialized: AtomicU32::new(0), + path_secret_map_uninitialized: AtomicU32::new(0), + path_secret_map_background_handshake_requested: AtomicU32::new(0), + path_secret_map_entry_inserted: AtomicU32::new(0), + path_secret_map_entry_ready: AtomicU32::new(0), + path_secret_map_entry_replaced: AtomicU32::new(0), + unknown_path_secret_packet_sent: AtomicU32::new(0), + unknown_path_secret_packet_received: AtomicU32::new(0), + unknown_path_secret_packet_accepted: AtomicU32::new(0), + unknown_path_secret_packet_rejected: AtomicU32::new(0), + replay_definitely_detected: AtomicU32::new(0), + replay_potentially_detected: AtomicU32::new(0), + replay_detected_packet_sent: AtomicU32::new(0), + replay_detected_packet_received: AtomicU32::new(0), + replay_detected_packet_accepted: AtomicU32::new(0), + replay_detected_packet_rejected: AtomicU32::new(0), + stale_key_packet_sent: AtomicU32::new(0), + stale_key_packet_received: AtomicU32::new(0), + stale_key_packet_accepted: AtomicU32::new(0), + stale_key_packet_rejected: AtomicU32::new(0), } } } @@ -756,6 +2837,137 @@ pub mod testing { let event = event.into_event(); self.output.lock().unwrap().push(format!("{event:?}")); } + fn on_path_secret_map_initialized(&self, event: builder::PathSecretMapInitialized) { + self.path_secret_map_initialized + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_path_secret_map_uninitialized(&self, event: builder::PathSecretMapUninitialized) { + self.path_secret_map_uninitialized + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_path_secret_map_background_handshake_requested( + &self, + event: builder::PathSecretMapBackgroundHandshakeRequested, + ) { + self.path_secret_map_background_handshake_requested + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_path_secret_map_entry_inserted(&self, event: builder::PathSecretMapEntryInserted) { + self.path_secret_map_entry_inserted + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_path_secret_map_entry_ready(&self, event: builder::PathSecretMapEntryReady) { + self.path_secret_map_entry_ready + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_path_secret_map_entry_replaced(&self, event: builder::PathSecretMapEntryReplaced) { + self.path_secret_map_entry_replaced + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_unknown_path_secret_packet_sent(&self, event: builder::UnknownPathSecretPacketSent) { + self.unknown_path_secret_packet_sent + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_unknown_path_secret_packet_received( + &self, + event: builder::UnknownPathSecretPacketReceived, + ) { + self.unknown_path_secret_packet_received + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_unknown_path_secret_packet_accepted( + &self, + event: builder::UnknownPathSecretPacketAccepted, + ) { + self.unknown_path_secret_packet_accepted + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_unknown_path_secret_packet_rejected( + &self, + event: builder::UnknownPathSecretPacketRejected, + ) { + self.unknown_path_secret_packet_rejected + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_replay_definitely_detected(&self, event: builder::ReplayDefinitelyDetected) { + self.replay_definitely_detected + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_replay_potentially_detected(&self, event: builder::ReplayPotentiallyDetected) { + self.replay_potentially_detected + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_replay_detected_packet_sent(&self, event: builder::ReplayDetectedPacketSent) { + self.replay_detected_packet_sent + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_replay_detected_packet_received(&self, event: builder::ReplayDetectedPacketReceived) { + self.replay_detected_packet_received + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_replay_detected_packet_accepted(&self, event: builder::ReplayDetectedPacketAccepted) { + self.replay_detected_packet_accepted + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_replay_detected_packet_rejected(&self, event: builder::ReplayDetectedPacketRejected) { + self.replay_detected_packet_rejected + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_stale_key_packet_sent(&self, event: builder::StaleKeyPacketSent) { + self.stale_key_packet_sent.fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_stale_key_packet_received(&self, event: builder::StaleKeyPacketReceived) { + self.stale_key_packet_received + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_stale_key_packet_accepted(&self, event: builder::StaleKeyPacketAccepted) { + self.stale_key_packet_accepted + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } + fn on_stale_key_packet_rejected(&self, event: builder::StaleKeyPacketRejected) { + self.stale_key_packet_rejected + .fetch_add(1, Ordering::Relaxed); + let event = event.into_event(); + self.output.lock().unwrap().push(format!("{event:?}")); + } fn quic_version(&self) -> Option { Some(1) } diff --git a/dc/s2n-quic-dc/src/path/secret/map.rs b/dc/s2n-quic-dc/src/path/secret/map.rs index 22deb37a7..09f36a8c3 100644 --- a/dc/s2n-quic-dc/src/path/secret/map.rs +++ b/dc/s2n-quic-dc/src/path/secret/map.rs @@ -3,6 +3,7 @@ use crate::{ credentials::{Credentials, Id}, + event, packet::{secret_control as control, Packet}, path::secret::{open, seal, stateless_reset}, stream::TransportFeatures, @@ -43,10 +44,13 @@ pub struct Map { } impl Map { - pub fn new(signer: stateless_reset::Signer, capacity: usize) -> Self { - // TODO add the subscriber - let state = state::State::new(signer, capacity); - Self { store: state } + pub fn new( + signer: stateless_reset::Signer, + capacity: usize, + subscriber: S, + ) -> Self { + let store = state::State::new(signer, capacity, subscriber); + Self { store } } /// The number of trusted secrets. @@ -134,12 +138,12 @@ impl Map { /// /// For secret control packets, this will process those. /// For other packets, the map may collect metrics but will otherwise drop the packets. - pub fn handle_unexpected_packet(&self, packet: &Packet) { - self.store.handle_unexpected_packet(packet); + pub fn handle_unexpected_packet(&self, packet: &Packet, peer: &SocketAddr) { + self.store.handle_unexpected_packet(packet, peer); } - pub fn handle_control_packet(&self, packet: &control::Packet) { - self.store.handle_control_packet(packet) + pub fn handle_control_packet(&self, packet: &control::Packet, peer: &SocketAddr) { + self.store.handle_control_packet(packet, peer) } #[doc(hidden)] @@ -153,7 +157,11 @@ impl Map { ) -> (Self, Vec) { use crate::path::secret::{receiver, schedule, sender}; - let provider = Self::new(stateless_reset::Signer::random(), peers.len() * 3); + let provider = Self::new( + stateless_reset::Signer::random(), + peers.len() * 3, + event::testing::Subscriber::no_snapshot(), + ); let mut secret = [0; 32]; aws_lc_rs::rand::fill(&mut secret).unwrap(); let mut stateless_reset = [0; control::TAG_LEN]; diff --git a/dc/s2n-quic-dc/src/path/secret/map/cleaner.rs b/dc/s2n-quic-dc/src/path/secret/map/cleaner.rs index a5081407f..b47d08742 100644 --- a/dc/s2n-quic-dc/src/path/secret/map/cleaner.rs +++ b/dc/s2n-quic-dc/src/path/secret/map/cleaner.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use super::state::State; +use crate::event; use rand::Rng as _; use std::{ sync::{ @@ -50,7 +51,7 @@ impl Cleaner { } } - pub fn spawn_thread(&self, state: Arc) { + pub fn spawn_thread(&self, state: Arc>) { let state = Arc::downgrade(&state); let handle = std::thread::spawn(move || loop { let Some(state) = state.upgrade() else { @@ -68,7 +69,7 @@ impl Cleaner { } /// Periodic maintenance for various maps. - pub fn clean(&self, state: &State, eviction_cycles: u64) { + pub fn clean(&self, state: &State, eviction_cycles: u64) { let current_epoch = self.epoch.fetch_add(1, Ordering::Relaxed); let now = Instant::now(); diff --git a/dc/s2n-quic-dc/src/path/secret/map/handshake.rs b/dc/s2n-quic-dc/src/path/secret/map/handshake.rs index cb9ccf7aa..5d574c9a8 100644 --- a/dc/s2n-quic-dc/src/path/secret/map/handshake.rs +++ b/dc/s2n-quic-dc/src/path/secret/map/handshake.rs @@ -57,7 +57,7 @@ impl dc::Endpoint for Map { &mut self, // TODO: Maybe we should confirm that the sender IP at least matches the IP for the // corresponding control secret? - _datagram_info: &DatagramInfo, + datagram_info: &DatagramInfo, payload: &mut [u8], ) -> bool { let payload = s2n_codec::DecoderBufferMut::new(payload); @@ -68,7 +68,7 @@ impl dc::Endpoint for Map { ensure!(tail.is_empty(), false); // If we successfully decoded a control packet, pass it into our map to handle. - self.handle_control_packet(&packet); + self.handle_control_packet(&packet, &datagram_info.remote_address.clone().into()); true } diff --git a/dc/s2n-quic-dc/src/path/secret/map/state.rs b/dc/s2n-quic-dc/src/path/secret/map/state.rs index 141236f86..6fc3cd4e8 100644 --- a/dc/s2n-quic-dc/src/path/secret/map/state.rs +++ b/dc/s2n-quic-dc/src/path/secret/map/state.rs @@ -3,18 +3,18 @@ use super::{cleaner::Cleaner, stateless_reset, Entry, Store}; use crate::{ - credentials::Id, + credentials::{Credentials, Id}, + crypto, + event::{self, EndpointPublisher as _, IntoEvent as _}, fixed_map::{self, ReadGuard}, packet::{secret_control as control, Packet}, path::secret::receiver, }; +use s2n_quic_core::inet::SocketAddress; use std::{ hash::{BuildHasherDefault, Hasher}, net::{Ipv4Addr, SocketAddr}, - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, - }, + sync::Arc, time::Duration, }; @@ -39,7 +39,7 @@ mod tests; // is defined by access to the entry in the map. Unfortunately we lack any good way to authenticate // a peer as *not* having credentials, especially after the peer is gone. It's possible that in the // future information could also come from the TLS provider. -pub(super) struct State { +pub(super) struct State { // This is in number of entries. max_capacity: usize, @@ -70,16 +70,17 @@ pub(super) struct State { // This socket is used *only* for sending secret control packets. // FIXME: This will get replaced with sending on a handshake socket associated with the map. pub(super) control_socket: std::net::UdpSocket, + control_socket_port: u16, pub(super) receiver_shared: Arc, - handled_control_packets: AtomicUsize, - cleaner: Cleaner, + + subscriber: S, } -impl State { - pub fn new(signer: stateless_reset::Signer, capacity: usize) -> Arc { +impl State { + pub fn new(signer: stateless_reset::Signer, capacity: usize, subscriber: S) -> Arc { // FIXME: Avoid unwrap and the whole socket. // // We only ever send on this socket - but we really should be sending on the same @@ -89,6 +90,7 @@ impl State { // of implementation). let control_socket = std::net::UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).unwrap(); control_socket.set_nonblocking(true).unwrap(); + let control_socket_port = control_socket.local_addr().unwrap().port(); let state = Self { // This is around 500MB with current entry size. @@ -100,17 +102,23 @@ impl State { requested_handshakes: Default::default(), cleaner: Cleaner::new(), signer, - receiver_shared: receiver::Shared::new(), - - handled_control_packets: AtomicUsize::new(0), control_socket, + control_socket_port, + subscriber, }; let state = Arc::new(state); state.cleaner.spawn_thread(state.clone()); + state.subscriber().on_path_secret_map_initialized( + event::builder::PathSecretMapInitialized { + capacity, + control_socket_port, + }, + ); + state } @@ -119,13 +127,33 @@ impl State { let handshakes = self.requested_handshakes.pin(); if handshakes.len() <= 6000 { handshakes.insert(peer); + self.subscriber() + .on_path_secret_map_background_handshake_requested( + event::builder::PathSecretMapBackgroundHandshakeRequested { + peer_address: SocketAddress::from(peer).into_event(), + }, + ); } } - fn handle_unknown_secret_packet(&self, packet: &control::unknown_path_secret::Packet) { + fn handle_unknown_secret( + &self, + packet: &control::unknown_path_secret::Packet, + peer: &SocketAddress, + ) { + let peer_address = peer.into_event(); + + self.subscriber().on_unknown_path_secret_packet_received( + event::builder::UnknownPathSecretPacketReceived { + credential_id: packet.credential_id().into_event(), + peer_address, + }, + ); + let Some(entry) = self.get_by_id(packet.credential_id()) else { return; }; + // Do not mark as live, this is lightly authenticated. // ensure the packet is authentic @@ -133,16 +161,120 @@ impl State { .authenticate(&entry.sender().stateless_reset) .is_none() { + self.subscriber().on_unknown_path_secret_packet_rejected( + event::builder::UnknownPathSecretPacketRejected { + credential_id: packet.credential_id().into_event(), + peer_address, + }, + ); + return; } - self.handled_control_packets.fetch_add(1, Ordering::Relaxed); + self.subscriber().on_unknown_path_secret_packet_accepted( + event::builder::UnknownPathSecretPacketAccepted { + credential_id: packet.credential_id().into_event(), + peer_address, + }, + ); // FIXME: More actively schedule a new handshake. // See comment on requested_handshakes for details. self.request_handshake(*entry.peer()); } + fn handle_stale_key(&self, packet: &control::stale_key::Packet, peer: &SocketAddress) { + let peer_address = peer.into_event(); + + self.subscriber() + .on_stale_key_packet_received(event::builder::StaleKeyPacketReceived { + credential_id: packet.credential_id().into_event(), + peer_address, + }); + + let Some(entry) = self.ids.get_by_key(packet.credential_id()) else { + // If we get a control packet we don't have a registered path secret for, ignore the + // packet. + return; + }; + + let key = entry.control_secret(); + + let Some(packet) = packet.authenticate(&key) else { + self.subscriber().on_stale_key_packet_rejected( + event::builder::StaleKeyPacketRejected { + credential_id: packet.credential_id().into_event(), + peer_address, + }, + ); + + return; + }; + + self.subscriber() + .on_stale_key_packet_accepted(event::builder::StaleKeyPacketAccepted { + credential_id: packet.credential_id.into_event(), + peer_address, + }); + + entry.sender().update_for_stale_key(packet.min_key_id); + } + + fn handle_replay_detected( + &self, + packet: &control::replay_detected::Packet, + peer: &SocketAddress, + ) { + let peer_address = peer.into_event(); + + self.subscriber().on_replay_detected_packet_received( + event::builder::ReplayDetectedPacketReceived { + credential_id: packet.credential_id().into_event(), + peer_address, + }, + ); + + let Some(entry) = self.ids.get_by_key(packet.credential_id()) else { + // If we get a control packet we don't have a registered path secret for, ignore the + // packet. + return; + }; + + let key = entry.control_secret(); + + let Some(packet) = packet.authenticate(&key) else { + self.subscriber().on_replay_detected_packet_rejected( + event::builder::ReplayDetectedPacketRejected { + credential_id: packet.credential_id().into_event(), + peer_address, + }, + ); + return; + }; + + self.subscriber().on_replay_detected_packet_accepted( + event::builder::ReplayDetectedPacketAccepted { + credential_id: packet.credential_id.into_event(), + key_id: packet.rejected_key_id.into_event(), + peer_address, + }, + ); + + // If we see replay then we're going to assume that we should re-handshake in the + // background with this peer. Currently we can't handshake in the background (only + // in the foreground on next handshake_with). + // + // Note that there's no good way for us to prevent an attacker causing us to hit + // this code: they can always trivially replay a packet we send. At most we could + // de-duplicate *receiving* so there's one handshake per sent packet at most, but + // that's not particularly useful: we expect to send a lot of new packets that + // could be harvested. + // + // Handshaking will be rate limited per destination peer (and at least + // de-duplicated). + self.request_handshake(*entry.peer()); + } + pub fn cleaner(&self) -> &Cleaner { &self.cleaner } @@ -154,9 +286,17 @@ impl State { self.peers = fixed_map::Map::with_capacity(new, Default::default()); self.ids = fixed_map::Map::with_capacity(new, Default::default()); } + + fn subscriber(&self) -> event::EndpointPublisherSubscriber { + event::EndpointPublisherSubscriber::new( + event::builder::EndpointMeta {}, + None, + &self.subscriber, + ) + } } -impl Store for State { +impl Store for State { fn secrets_len(&self) -> usize { self.ids.len() } @@ -179,26 +319,52 @@ impl Store for State { } fn on_new_path_secrets(&self, entry: Arc) { - // On insert clear our interest in a handshake. - self.requested_handshakes.pin().remove(entry.peer()); let id = *entry.id(); + let peer = entry.peer(); + + // On insert clear our interest in a handshake. + self.requested_handshakes.pin().remove(peer); + if self.ids.insert(id, entry.clone()).is_some() { // FIXME: Make insertion fallible and fail handshakes instead? panic!("inserting a path secret ID twice"); } + + self.subscriber().on_path_secret_map_entry_inserted( + event::builder::PathSecretMapEntryInserted { + peer_address: SocketAddress::from(*peer).into_event(), + credential_id: id.into_event(), + }, + ); } fn on_handshake_complete(&self, entry: Arc) { let id = *entry.id(); let peer = *entry.peer(); + if let Some(prev) = self.peers.insert(peer, entry) { // This shouldn't happen due to the panic in on_new_path_secrets, but just // in case something went wrong with the secret map we double check here. // FIXME: Make insertion fallible and fail handshakes instead? - assert_ne!(*prev.id(), id, "duplicate path secret id"); + let prev_id = *prev.id(); + assert_ne!(prev_id, id, "duplicate path secret id"); prev.retire(self.cleaner.epoch()); + + self.subscriber().on_path_secret_map_entry_replaced( + event::builder::PathSecretMapEntryReplaced { + peer_address: SocketAddress::from(peer).into_event(), + new_credential_id: id.into_event(), + previous_credential_id: prev_id.into_event(), + }, + ); } + + self.subscriber() + .on_path_secret_map_entry_ready(event::builder::PathSecretMapEntryReady { + peer_address: SocketAddress::from(peer).into_event(), + credential_id: id.into_event(), + }); } fn get_by_addr(&self, peer: &SocketAddr) -> Option>> { @@ -209,52 +375,19 @@ impl Store for State { self.ids.get_by_key(id) } - fn handle_control_packet(&self, packet: &control::Packet) { - if let control::Packet::UnknownPathSecret(ref packet) = &packet { - return self.handle_unknown_secret_packet(packet); - } - - let Some(entry) = self.ids.get_by_key(packet.credential_id()) else { - // If we get a control packet we don't have a registered path secret for, ignore the - // packet. - return; - }; - - let key = entry.control_secret(); - + fn handle_control_packet(&self, packet: &control::Packet, peer: &SocketAddr) { match packet { - control::Packet::StaleKey(packet) => { - let Some(packet) = packet.authenticate(&key) else { - return; - }; - entry.sender().update_for_stale_key(packet.min_key_id); - self.handled_control_packets.fetch_add(1, Ordering::Relaxed); - } + control::Packet::StaleKey(packet) => self.handle_stale_key(packet, &(*peer).into()), control::Packet::ReplayDetected(packet) => { - let Some(_packet) = packet.authenticate(&key) else { - return; - }; - self.handled_control_packets.fetch_add(1, Ordering::Relaxed); - - // If we see replay then we're going to assume that we should re-handshake in the - // background with this peer. Currently we can't handshake in the background (only - // in the foreground on next handshake_with). - // - // Note that there's no good way for us to prevent an attacker causing us to hit - // this code: they can always trivially replay a packet we send. At most we could - // de-duplicate *receiving* so there's one handshake per sent packet at most, but - // that's not particularly useful: we expect to send a lot of new packets that - // could be harvested. - // - // Handshaking will be rate limited per destination peer (and at least - // de-duplicated). - self.request_handshake(*entry.peer()); + self.handle_replay_detected(packet, &(*peer).into()) + } + control::Packet::UnknownPathSecret(packet) => { + self.handle_unknown_secret(packet, &(*peer).into()) } - control::Packet::UnknownPathSecret(_) => unreachable!(), } } - fn handle_unexpected_packet(&self, packet: &Packet) { + fn handle_unexpected_packet(&self, packet: &Packet, peer: &SocketAddr) { match packet { Packet::Stream(_) => { // no action for now. FIXME: Add metrics. @@ -265,9 +398,11 @@ impl Store for State { Packet::Control(_) => { // no action for now. FIXME: Add metrics. } - Packet::StaleKey(packet) => self.handle_control_packet(&(*packet).into()), - Packet::ReplayDetected(packet) => self.handle_control_packet(&(*packet).into()), - Packet::UnknownPathSecret(packet) => self.handle_control_packet(&(*packet).into()), + Packet::StaleKey(packet) => self.handle_stale_key(packet, &(*peer).into()), + Packet::ReplayDetected(packet) => self.handle_replay_detected(packet, &(*peer).into()), + Packet::UnknownPathSecret(packet) => { + self.handle_unknown_secret(packet, &(*peer).into()) + } } } @@ -279,10 +414,39 @@ impl Store for State { &self.receiver_shared } - fn send_control_packet(&self, dst: &SocketAddr, buffer: &[u8]) { + fn send_control_packet(&self, dst: &SocketAddr, buffer: &mut [u8]) { match self.control_socket.send_to(buffer, dst) { Ok(_) => { // all done + match control::Packet::decode(s2n_codec::DecoderBufferMut::new(buffer)) + .map(|(t, _)| t) + { + Ok(control::Packet::UnknownPathSecret(packet)) => { + self.subscriber().on_unknown_path_secret_packet_sent( + event::builder::UnknownPathSecretPacketSent { + peer_address: SocketAddress::from(*dst).into_event(), + credential_id: packet.credential_id().into_event(), + }, + ); + } + Ok(control::Packet::StaleKey(packet)) => { + self.subscriber().on_stale_key_packet_sent( + event::builder::StaleKeyPacketSent { + peer_address: SocketAddress::from(*dst).into_event(), + credential_id: packet.credential_id().into_event(), + }, + ); + } + Ok(control::Packet::ReplayDetected(packet)) => { + self.subscriber().on_replay_detected_packet_sent( + event::builder::ReplayDetectedPacketSent { + peer_address: SocketAddress::from(*dst).into_event(), + credential_id: packet.credential_id().into_event(), + }, + ); + } + Err(err) => debug_assert!(false, "decoder error {err:?}"), + } } Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => { // ignore would block -- we're not going to queue up control packet messages. @@ -296,6 +460,66 @@ impl Store for State { fn rehandshake_period(&self) -> Duration { self.rehandshake_period } + + fn check_dedup( + &self, + entry: &Entry, + key_id: s2n_quic_core::varint::VarInt, + ) -> crypto::open::Result { + let creds = &Credentials { + id: *entry.id(), + key_id, + }; + match entry.receiver().post_authentication(creds) { + Ok(()) => Ok(()), + Err(receiver::Error::AlreadyExists) => { + self.send_control_error(entry, creds, receiver::Error::AlreadyExists); + + self.subscriber().on_replay_definitely_detected( + event::builder::ReplayDefinitelyDetected { + credential_id: creds.id.into_event(), + key_id: key_id.into_event(), + }, + ); + + Err(crypto::open::Error::ReplayDefinitelyDetected) + } + Err(receiver::Error::Unknown) => { + self.send_control_error(entry, creds, receiver::Error::Unknown); + + let gap = (*entry.receiver().minimum_unseen_key_id()) + // This should never be negative, but saturate anyway to avoid + // wildly large numbers. + .saturating_sub(*creds.key_id); + + self.subscriber().on_replay_potentially_detected( + event::builder::ReplayPotentiallyDetected { + credential_id: creds.id.into_event(), + key_id: key_id.into_event(), + gap, + }, + ); + + Err(crypto::open::Error::ReplayPotentiallyDetected { gap: Some(gap) }) + } + } + } +} + +impl Drop for State { + fn drop(&mut self) { + if std::thread::panicking() { + return; + } + + self.subscriber().on_path_secret_map_uninitialized( + event::builder::PathSecretMapUninitialized { + capacity: self.secrets_capacity(), + control_socket_port: self.control_socket_port, + entries: self.secrets_len(), + }, + ); + } } #[derive(Default)] diff --git a/dc/s2n-quic-dc/src/path/secret/map/state/tests.rs b/dc/s2n-quic-dc/src/path/secret/map/state/tests.rs index 2e246076c..853627a18 100644 --- a/dc/s2n-quic-dc/src/path/secret/map/state/tests.rs +++ b/dc/s2n-quic-dc/src/path/secret/map/state/tests.rs @@ -2,7 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 use super::*; -use crate::path::secret::{schedule, sender}; +use crate::{ + event::tracing::Subscriber, + path::secret::{schedule, sender}, +}; use s2n_quic_core::dc; use std::{ collections::HashSet, @@ -17,7 +20,7 @@ fn fake_entry(port: u16) -> Arc { #[test] fn cleans_after_delay() { let signer = stateless_reset::Signer::new(b"secret"); - let map = State::new(signer, 50); + let map = State::new(signer, 50, Subscriber::default()); // Stop background processing. We expect to manually invoke clean, and a background worker // might interfere with our state. @@ -45,7 +48,7 @@ fn cleans_after_delay() { #[test] fn thread_shutdown() { let signer = stateless_reset::Signer::new(b"secret"); - let map = State::new(signer, 10); + let map = State::new(signer, 10, Subscriber::default()); let state = Arc::downgrade(&map); drop(map); @@ -113,7 +116,7 @@ enum Invariant { } impl Model { - fn perform(&mut self, operation: Operation, state: &State) { + fn perform(&mut self, operation: Operation, state: &State) { match operation { Operation::Insert { ip, path_secret_id } => { let ip = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from([0, 0, 0, ip]), 0)); @@ -153,7 +156,7 @@ impl Model { } // Evict all stale records *now*. - state.cleaner.clean(&state, 0); + state.cleaner.clean(state, 0); } Operation::ReceiveUnknown { path_secret_id } => { let id = path_secret_id.id(); @@ -165,7 +168,7 @@ impl Model { id, &stateless_reset, ); - state.handle_unknown_secret_packet(&packet); + state.handle_unknown_secret(&packet, &Default::default()); // ReceiveUnknown does not cause any action with respect to our invariants, no // updates required. @@ -173,7 +176,7 @@ impl Model { } } - fn check_invariants(&self, state: &State) { + fn check_invariants(&self, state: &State) { for invariant in self.invariants.iter() { // We avoid assertions for contains() if we're running the small capacity test, since // they are likely broken -- we semi-randomly evict peers in that case. @@ -246,7 +249,7 @@ fn check_invariants() { let mut model = Model::default(); let signer = stateless_reset::Signer::new(b"secret"); - let mut map = State::new(signer, 10_000); + let mut map = State::new(signer, 10_000, Subscriber::default()); // Avoid background work interfering with testing. map.cleaner.stop(); @@ -276,7 +279,7 @@ fn check_invariants_no_overflow() { let mut model = Model::default(); let signer = stateless_reset::Signer::new(b"secret"); - let map = State::new(signer, 10_000); + let map = State::new(signer, 10_000, Subscriber::default()); // Avoid background work interfering with testing. map.cleaner.stop(); @@ -299,7 +302,7 @@ fn check_invariants_no_overflow() { #[ignore = "memory growth takes a long time to run"] fn no_memory_growth() { let signer = stateless_reset::Signer::new(b"secret"); - let map = State::new(signer, 100_000); + let map = State::new(signer, 100_000, Subscriber::default()); map.cleaner.stop(); for idx in 0..500_000 { diff --git a/dc/s2n-quic-dc/src/path/secret/map/status.rs b/dc/s2n-quic-dc/src/path/secret/map/status.rs index 76df63ccf..52ef8790d 100644 --- a/dc/s2n-quic-dc/src/path/secret/map/status.rs +++ b/dc/s2n-quic-dc/src/path/secret/map/status.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use super::{Entry, Map}; -use crate::{credentials::Credentials, crypto, path::secret::receiver}; +use crate::crypto; use core::{ fmt, sync::atomic::{AtomicU64, Ordering}, @@ -73,35 +73,7 @@ impl Dedup { pub fn check(&self) -> crypto::open::Result { *self.cell.get_or_init(|| { match self.init.take() { - Some((entry, key_id, map)) => { - let creds = &Credentials { - id: *entry.id(), - key_id, - }; - match entry.receiver().post_authentication(creds) { - Ok(()) => Ok(()), - Err(receiver::Error::AlreadyExists) => { - map.store.send_control_error( - &entry, - creds, - receiver::Error::AlreadyExists, - ); - Err(crypto::open::Error::ReplayDefinitelyDetected) - } - Err(receiver::Error::Unknown) => { - map.store - .send_control_error(&entry, creds, receiver::Error::Unknown); - Err(crypto::open::Error::ReplayPotentiallyDetected { - gap: Some( - (*entry.receiver().minimum_unseen_key_id()) - // This should never be negative, but saturate anyway to avoid - // wildly large numbers. - .saturating_sub(*creds.key_id), - ), - }) - } - } - } + Some((entry, key_id, map)) => map.store.check_dedup(&entry, key_id), None => { // Dedup has been poisoned! TODO log this Err(crypto::open::Error::ReplayPotentiallyDetected { gap: None }) diff --git a/dc/s2n-quic-dc/src/path/secret/map/store.rs b/dc/s2n-quic-dc/src/path/secret/map/store.rs index 40f15aa45..80ca4b579 100644 --- a/dc/s2n-quic-dc/src/path/secret/map/store.rs +++ b/dc/s2n-quic-dc/src/path/secret/map/store.rs @@ -37,22 +37,29 @@ pub trait Store: 'static + Send + Sync { fn get_by_id(&self, id: &Id) -> Option>>; - fn handle_unexpected_packet(&self, packet: &Packet); + fn handle_unexpected_packet(&self, packet: &Packet, peer: &SocketAddr); - fn handle_control_packet(&self, packet: &control::Packet); + fn handle_control_packet(&self, packet: &control::Packet, peer: &SocketAddr); fn signer(&self) -> &stateless_reset::Signer; fn receiver(&self) -> &Arc; - fn send_control_packet(&self, dst: &SocketAddr, buffer: &[u8]); + fn send_control_packet(&self, dst: &SocketAddr, buffer: &mut [u8]); fn rehandshake_period(&self) -> Duration; + fn check_dedup( + &self, + entry: &Entry, + key_id: s2n_quic_core::varint::VarInt, + ) -> crate::crypto::open::Result; + #[inline] fn send_control_error(&self, entry: &Entry, credentials: &Credentials, error: receiver::Error) { let mut buffer = [0; control::MAX_PACKET_SIZE]; - let buffer = error.to_packet(entry, credentials, &mut buffer); + let len = error.to_packet(entry, credentials, &mut buffer).len(); + let buffer = &mut buffer[..len]; let dst = entry.peer(); self.send_control_packet(dst, buffer); } diff --git a/dc/s2n-quic-dc/src/stream/recv/shared.rs b/dc/s2n-quic-dc/src/stream/recv/shared.rs index b42a7018d..a686eeef7 100644 --- a/dc/s2n-quic-dc/src/stream/recv/shared.rs +++ b/dc/s2n-quic-dc/src/stream/recv/shared.rs @@ -492,7 +492,10 @@ impl Inner { } other => { let kind = other.kind(); - shared.crypto.map().handle_unexpected_packet(other); + shared + .crypto + .map() + .handle_unexpected_packet(other, &shared.read_remote_addr().into()); // if we get a packet we don't expect then it's fatal for streams msg.clear(); @@ -586,7 +589,10 @@ impl Inner { }); } other => { - shared.crypto.map().handle_unexpected_packet(&other); + shared + .crypto + .map() + .handle_unexpected_packet(&other, &shared.read_remote_addr().into()); // TODO if the packet was authentic then close the receiver with an error } diff --git a/dc/s2n-quic-dc/src/stream/send/worker.rs b/dc/s2n-quic-dc/src/stream/send/worker.rs index ec3764372..b08d7461f 100644 --- a/dc/s2n-quic-dc/src/stream/send/worker.rs +++ b/dc/s2n-quic-dc/src/stream/send/worker.rs @@ -335,7 +335,11 @@ where any_valid_packets = true; } } - other => self.shared.crypto.map().handle_unexpected_packet(&other), + other => self + .shared + .crypto + .map() + .handle_unexpected_packet(&other, &self.shared.write_remote_addr().into()), } } } diff --git a/quic/s2n-quic-core/src/event/generated.rs b/quic/s2n-quic-core/src/event/generated.rs index 0382be4e6..805fadd1a 100644 --- a/quic/s2n-quic-core/src/event/generated.rs +++ b/quic/s2n-quic-core/src/event/generated.rs @@ -1757,6 +1757,14 @@ pub mod tracing { Self { client, server } } } + impl Subscriber { + fn parent(&self, meta: &M) -> Option { + match meta.endpoint_type() { + api::EndpointType::Client { .. } => self.client.id(), + api::EndpointType::Server { .. } => self.server.id(), + } + } + } impl super::Subscriber for Subscriber { type ConnectionContext = tracing::Span; fn create_connection_context( @@ -1764,10 +1772,7 @@ pub mod tracing { meta: &api::ConnectionMeta, _info: &api::ConnectionInfo, ) -> Self::ConnectionContext { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); tracing :: span ! (target : "s2n_quic" , parent : parent , tracing :: Level :: DEBUG , "conn" , id = meta . id) } #[inline] @@ -2331,10 +2336,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::VersionInformation, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::VersionInformation { server_versions, client_versions, @@ -2348,10 +2350,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::EndpointPacketSent, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::EndpointPacketSent { packet_header } = event; tracing :: event ! (target : "endpoint_packet_sent" , parent : parent , tracing :: Level :: DEBUG , packet_header = tracing :: field :: debug (packet_header)); } @@ -2361,10 +2360,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::EndpointPacketReceived, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::EndpointPacketReceived { packet_header } = event; tracing :: event ! (target : "endpoint_packet_received" , parent : parent , tracing :: Level :: DEBUG , packet_header = tracing :: field :: debug (packet_header)); } @@ -2374,10 +2370,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::EndpointDatagramSent, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::EndpointDatagramSent { len, gso_offset } = event; tracing :: event ! (target : "endpoint_datagram_sent" , parent : parent , tracing :: Level :: DEBUG , len = tracing :: field :: debug (len) , gso_offset = tracing :: field :: debug (gso_offset)); } @@ -2387,10 +2380,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::EndpointDatagramReceived, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::EndpointDatagramReceived { len } = event; tracing :: event ! (target : "endpoint_datagram_received" , parent : parent , tracing :: Level :: DEBUG , len = tracing :: field :: debug (len)); } @@ -2400,10 +2390,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::EndpointDatagramDropped, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::EndpointDatagramDropped { len, reason } = event; tracing :: event ! (target : "endpoint_datagram_dropped" , parent : parent , tracing :: Level :: DEBUG , len = tracing :: field :: debug (len) , reason = tracing :: field :: debug (reason)); } @@ -2413,19 +2400,13 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::EndpointConnectionAttemptFailed, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::EndpointConnectionAttemptFailed { error } = event; tracing :: event ! (target : "endpoint_connection_attempt_failed" , parent : parent , tracing :: Level :: DEBUG , error = tracing :: field :: debug (error)); } #[inline] fn on_platform_tx(&mut self, meta: &api::EndpointMeta, event: &api::PlatformTx) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::PlatformTx { count, syscalls, @@ -2437,19 +2418,13 @@ pub mod tracing { } #[inline] fn on_platform_tx_error(&mut self, meta: &api::EndpointMeta, event: &api::PlatformTxError) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::PlatformTxError { errno } = event; tracing :: event ! (target : "platform_tx_error" , parent : parent , tracing :: Level :: DEBUG , errno = tracing :: field :: debug (errno)); } #[inline] fn on_platform_rx(&mut self, meta: &api::EndpointMeta, event: &api::PlatformRx) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::PlatformRx { count, syscalls, @@ -2461,10 +2436,7 @@ pub mod tracing { } #[inline] fn on_platform_rx_error(&mut self, meta: &api::EndpointMeta, event: &api::PlatformRxError) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::PlatformRxError { errno } = event; tracing :: event ! (target : "platform_rx_error" , parent : parent , tracing :: Level :: DEBUG , errno = tracing :: field :: debug (errno)); } @@ -2474,10 +2446,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::PlatformFeatureConfigured, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::PlatformFeatureConfigured { configuration } = event; tracing :: event ! (target : "platform_feature_configured" , parent : parent , tracing :: Level :: DEBUG , configuration = tracing :: field :: debug (configuration)); } @@ -2487,10 +2456,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::PlatformEventLoopWakeup, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::PlatformEventLoopWakeup { timeout_expired, rx_ready, @@ -2505,10 +2471,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::PlatformEventLoopSleep, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::PlatformEventLoopSleep { timeout, processing_duration, @@ -2521,10 +2484,7 @@ pub mod tracing { meta: &api::EndpointMeta, event: &api::PlatformEventLoopStarted, ) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => self.client.id(), - api::EndpointType::Server { .. } => self.server.id(), - }; + let parent = self.parent(meta); let api::PlatformEventLoopStarted { local_address } = event; tracing :: event ! (target : "platform_event_loop_started" , parent : parent , tracing :: Level :: DEBUG , local_address = tracing :: field :: debug (local_address)); } diff --git a/quic/s2n-quic-events/src/main.rs b/quic/s2n-quic-events/src/main.rs index 83bddab66..d424eba00 100644 --- a/quic/s2n-quic-events/src/main.rs +++ b/quic/s2n-quic-events/src/main.rs @@ -90,6 +90,13 @@ impl OutputMode { } } + fn trait_constraints(&self) -> TokenStream { + match self { + OutputMode::Ref => quote!('static + Send + Sync), + OutputMode::Mut => quote!('static + Send), + } + } + fn query_mut(&self) -> TokenStream { match self { OutputMode::Ref => quote!(), @@ -307,6 +314,7 @@ struct Output { pub tuple_subscriber: TokenStream, pub tracing_subscriber: TokenStream, pub tracing_subscriber_attr: TokenStream, + pub tracing_subscriber_def: TokenStream, pub builders: TokenStream, pub api: TokenStream, pub testing_fields: TokenStream, @@ -337,6 +345,7 @@ impl ToTokens for Output { tuple_subscriber, tracing_subscriber, tracing_subscriber_attr, + tracing_subscriber_def, builders, api, testing_fields, @@ -366,6 +375,7 @@ impl ToTokens for Output { let supervisor_timeout_tuple = self.mode.supervisor_timeout_tuple(); let query_mut = self.mode.query_mut(); let query_mut_tuple = self.mode.query_mut_tuple(); + let trait_constraints = self.mode.trait_constraints(); tokens.extend(quote!( use super::*; @@ -386,25 +396,7 @@ impl ToTokens for Output { //! This module contains event integration with [`tracing`](https://docs.rs/tracing) use super::api; - /// Emits events with [`tracing`](https://docs.rs/tracing) - #[derive(Clone, Debug)] - pub struct Subscriber { - client: tracing::Span, - server: tracing::Span, - } - - impl Default for Subscriber { - fn default() -> Self { - let root = tracing::span!(target: #target_crate, tracing::Level::DEBUG, #target_crate); - let client = tracing::span!(parent: root.id(), tracing::Level::DEBUG, "client"); - let server = tracing::span!(parent: root.id(), tracing::Level::DEBUG, "server"); - - Self { - client, - server, - } - } - } + #tracing_subscriber_def impl super::Subscriber for Subscriber { type ConnectionContext = tracing::Span; @@ -414,14 +406,7 @@ impl ToTokens for Output { meta: &api::ConnectionMeta, _info: &api::ConnectionInfo ) -> Self::ConnectionContext { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => { - self.client.id() - } - api::EndpointType::Server { .. } => { - self.server.id() - } - }; + let parent = self.parent(meta); tracing::span!(target: #target_crate, parent: parent, tracing::Level::DEBUG, "conn", id = meta.id) } @@ -441,10 +426,11 @@ impl ToTokens for Output { mod traits { use super::*; use core::fmt; - use #s2n_quic_core_path::{query, event::Meta}; + use #s2n_quic_core_path::query; + use crate::event::Meta; /// Allows for events to be subscribed to - pub trait Subscriber: 'static + Send { + pub trait Subscriber: #trait_constraints { /// An application provided type associated with each connection. /// @@ -938,10 +924,42 @@ struct EventInfo<'a> { api: TokenStream, builder: TokenStream, tracing_subscriber_attr: TokenStream, + tracing_subscriber_def: TokenStream, } -fn main() -> Result<()> { - let event_paths = [ +impl EventInfo<'_> { + fn s2n_quic() -> Self { + let tracing_subscriber_def = quote!( + /// Emits events with [`tracing`](https://docs.rs/tracing) + #[derive(Clone, Debug)] + pub struct Subscriber { + client: tracing::Span, + server: tracing::Span, + } + + impl Default for Subscriber { + fn default() -> Self { + let root = tracing::span!(target: "s2n_quic", tracing::Level::DEBUG, "s2n_quic"); + let client = tracing::span!(parent: root.id(), tracing::Level::DEBUG, "client"); + let server = tracing::span!(parent: root.id(), tracing::Level::DEBUG, "server"); + + Self { + client, + server, + } + } + } + + impl Subscriber { + fn parent(&self, meta: &M) -> Option { + match meta.endpoint_type() { + api::EndpointType::Client { .. } => self.client.id(), + api::EndpointType::Server { .. } => self.server.id(), + } + } + } + ); + EventInfo { input_path: concat!( env!("CARGO_MANIFEST_DIR"), @@ -958,7 +976,35 @@ fn main() -> Result<()> { tracing_subscriber_attr: quote! { #[cfg(feature = "event-tracing")] }, - }, + tracing_subscriber_def, + } + } + + fn s2n_quic_dc() -> Self { + let tracing_subscriber_def = quote!( + /// Emits events with [`tracing`](https://docs.rs/tracing) + #[derive(Clone, Debug)] + pub struct Subscriber { + root: tracing::Span, + } + + impl Default for Subscriber { + fn default() -> Self { + let root = tracing::span!(target: "s2n_quic_dc", tracing::Level::DEBUG, "s2n_quic_dc"); + + Self { + root, + } + } + } + + impl Subscriber { + fn parent(&self, _meta: &M) -> Option { + self.root.id() + } + } + ); + EventInfo { input_path: concat!( env!("CARGO_MANIFEST_DIR"), @@ -972,9 +1018,6 @@ fn main() -> Result<()> { s2n_quic_core_path: quote!(s2n_quic_core), api: quote! { pub use s2n_quic_core::event::api::{ - ConnectionMeta, - EndpointMeta, - ConnectionInfo, Subject, EndpointType, SocketAddress, @@ -982,17 +1025,19 @@ fn main() -> Result<()> { }, builder: quote! { pub use s2n_quic_core::event::builder::{ - ConnectionMeta, - EndpointMeta, - ConnectionInfo, Subject, EndpointType, SocketAddress, }; }, tracing_subscriber_attr: quote!(), - }, - ]; + tracing_subscriber_def, + } + } +} + +fn main() -> Result<()> { + let event_paths = [EventInfo::s2n_quic(), EventInfo::s2n_quic_dc()]; for event_info in event_paths { let mut files = vec![]; @@ -1012,6 +1057,7 @@ fn main() -> Result<()> { api: event_info.api, builders: event_info.builder, tracing_subscriber_attr: event_info.tracing_subscriber_attr, + tracing_subscriber_def: event_info.tracing_subscriber_def, ..Default::default() }; diff --git a/quic/s2n-quic-events/src/parser.rs b/quic/s2n-quic-events/src/parser.rs index 13487924f..12317f74a 100644 --- a/quic/s2n-quic-events/src/parser.rs +++ b/quic/s2n-quic-events/src/parser.rs @@ -190,14 +190,7 @@ impl Struct { #[inline] #allow_deprecated fn #function(&#receiver self, meta: &api::EndpointMeta, event: &api::#ident) { - let parent = match meta.endpoint_type { - api::EndpointType::Client { .. } => { - self.client.id() - } - api::EndpointType::Server { .. } => { - self.server.id() - } - }; + let parent = self.parent(meta); let api::#ident { #(#destructure_fields),* } = event; tracing::event!(target: #snake, parent: parent, tracing::Level::DEBUG, #(#destructure_fields = tracing::field::debug(#destructure_fields)),*); }