Skip to main content

qlog/events/
quic.rs

1// Copyright (C) 2021, Cloudflare, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//
11//     * Redistributions in binary form must reproduce the above copyright
12//       notice, this list of conditions and the following disclaimer in the
13//       documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27use serde::Deserialize;
28use serde::Serialize;
29
30use smallvec::SmallVec;
31
32use super::connectivity::TransportOwner;
33use super::Bytes;
34use super::DataRecipient;
35use super::ExData;
36use super::RawInfo;
37use super::Token;
38use crate::HexSlice;
39use crate::StatelessResetToken;
40
41#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
42#[serde(rename_all = "snake_case")]
43pub enum PacketType {
44    Initial,
45    Handshake,
46
47    #[serde(rename = "0RTT")]
48    ZeroRtt,
49
50    #[serde(rename = "1RTT")]
51    OneRtt,
52
53    Retry,
54    VersionNegotiation,
55    #[default]
56    Unknown,
57}
58
59#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
60#[serde(rename_all = "snake_case")]
61pub enum PacketNumberSpace {
62    Initial,
63    Handshake,
64    ApplicationData,
65}
66
67#[serde_with::skip_serializing_none]
68#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, Default)]
69pub struct PacketHeader {
70    pub packet_type: PacketType,
71    pub packet_number: Option<u64>,
72
73    pub flags: Option<u8>,
74    pub token: Option<Token>,
75
76    pub length: Option<u16>,
77
78    pub version: Option<Bytes>,
79
80    pub scil: Option<u8>,
81    pub dcil: Option<u8>,
82    pub scid: Option<Bytes>,
83    pub dcid: Option<Bytes>,
84}
85
86impl PacketHeader {
87    #[allow(clippy::too_many_arguments)]
88    /// Creates a new PacketHeader.
89    pub fn new(
90        packet_type: PacketType, packet_number: Option<u64>, flags: Option<u8>,
91        token: Option<Token>, length: Option<u16>, version: Option<u32>,
92        scid: Option<&[u8]>, dcid: Option<&[u8]>,
93    ) -> Self {
94        let (scil, scid) = match scid {
95            Some(cid) => (
96                Some(cid.len() as u8),
97                Some(format!("{}", HexSlice::new(&cid))),
98            ),
99
100            None => (None, None),
101        };
102
103        let (dcil, dcid) = match dcid {
104            Some(cid) => (
105                Some(cid.len() as u8),
106                Some(format!("{}", HexSlice::new(&cid))),
107            ),
108
109            None => (None, None),
110        };
111
112        let version = version.map(|v| format!("{v:x?}"));
113
114        PacketHeader {
115            packet_type,
116            packet_number,
117            flags,
118            token,
119            length,
120            version,
121            scil,
122            dcil,
123            scid,
124            dcid,
125        }
126    }
127
128    /// Creates a new PacketHeader.
129    ///
130    /// Once a QUIC connection has formed, version, dcid and scid are stable, so
131    /// there are space benefits to not logging them in every packet, especially
132    /// PacketType::OneRtt.
133    pub fn with_type(
134        ty: PacketType, packet_number: Option<u64>, version: Option<u32>,
135        scid: Option<&[u8]>, dcid: Option<&[u8]>,
136    ) -> Self {
137        match ty {
138            PacketType::OneRtt => PacketHeader::new(
139                ty,
140                packet_number,
141                None,
142                None,
143                None,
144                None,
145                None,
146                None,
147            ),
148
149            _ => PacketHeader::new(
150                ty,
151                packet_number,
152                None,
153                None,
154                None,
155                version,
156                scid,
157                dcid,
158            ),
159        }
160    }
161}
162
163#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
164#[serde(rename_all = "snake_case")]
165pub enum StreamType {
166    Bidirectional,
167    Unidirectional,
168}
169
170#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
171#[serde(rename_all = "snake_case")]
172pub enum StreamSide {
173    Sending,
174    Receiving,
175}
176
177#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
178#[serde(rename_all = "snake_case")]
179pub enum StreamState {
180    // bidirectional stream states, draft-23 3.4.
181    Idle,
182    Open,
183    HalfClosedLocal,
184    HalfClosedRemote,
185    Closed,
186
187    // sending-side stream states, draft-23 3.1.
188    Ready,
189    Send,
190    DataSent,
191    ResetSent,
192    ResetReceived,
193
194    // receive-side stream states, draft-23 3.2.
195    Receive,
196    SizeKnown,
197    DataRead,
198    ResetRead,
199
200    // both-side states
201    DataReceived,
202
203    // qlog-defined
204    Destroyed,
205}
206
207#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
208#[serde(rename_all = "snake_case")]
209pub enum ErrorSpace {
210    TransportError,
211    ApplicationError,
212}
213
214#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
215#[serde(rename_all = "snake_case")]
216pub enum TransportError {
217    NoError,
218    InternalError,
219    ConnectionRefused,
220    FlowControlError,
221    StreamLimitError,
222    StreamStateError,
223    FinalSizeError,
224    FrameEncodingError,
225    TransportParameterError,
226    ConnectionIdLimitError,
227    ProtocolViolation,
228    InvalidToken,
229    ApplicationError,
230    CryptoBufferExceeded,
231    KeyUpdateError,
232    AeadLimitReached,
233    NoViablePath,
234}
235
236#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
237#[serde(rename_all = "snake_case")]
238pub enum TransportEventType {
239    VersionInformation,
240    AlpnInformation,
241
242    ParametersSet,
243    ParametersRestored,
244
245    DatagramsSent,
246    DatagramsReceived,
247    DatagramDropped,
248
249    PacketSent,
250    PacketReceived,
251    PacketDropped,
252    PacketBuffered,
253    PacketsAcked,
254
255    FramesProcessed,
256
257    StreamStateUpdated,
258
259    DataMoved,
260}
261
262#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
263#[serde(rename_all = "snake_case")]
264pub enum PacketSentTrigger {
265    RetransmitReordered,
266    RetransmitTimeout,
267    PtoProbe,
268    RetransmitCrypto,
269    CcBandwidthProbe,
270}
271
272#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
273#[serde(rename_all = "snake_case")]
274pub enum PacketReceivedTrigger {
275    KeysUnavailable,
276}
277
278#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
279#[serde(rename_all = "snake_case")]
280pub enum PacketDroppedTrigger {
281    InternalError,
282    Rejected,
283    Unsupported,
284    Invalid,
285    ConnectionUnknown,
286    DecryptionFailure,
287    General,
288}
289
290#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
291#[serde(rename_all = "snake_case")]
292pub enum PacketBufferedTrigger {
293    Backpressure,
294    KeysUnavailable,
295}
296
297#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
298#[serde(rename_all = "snake_case")]
299pub enum SecurityEventType {
300    KeyUpdated,
301    KeyDiscarded,
302}
303
304#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
305#[serde(rename_all = "snake_case")]
306pub enum RecoveryEventType {
307    ParametersSet,
308    MetricsUpdated,
309    CongestionStateUpdated,
310    LossTimerUpdated,
311    PacketLost,
312    MarkedForRetransmit,
313}
314
315#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
316#[serde(rename_all = "snake_case")]
317pub enum CongestionStateUpdatedTrigger {
318    PersistentCongestion,
319    Ecn,
320}
321
322#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)]
323#[serde(rename_all = "snake_case")]
324pub enum PacketLostTrigger {
325    ReorderingThreshold,
326    TimeThreshold,
327    PtoExpired,
328}
329
330#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
331#[serde(rename_all = "snake_case")]
332pub enum LossTimerEventType {
333    Set,
334    Expired,
335    Cancelled,
336}
337
338#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
339#[serde(rename_all = "snake_case")]
340pub enum TimerType {
341    Ack,
342    Pto,
343}
344
345#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
346#[serde(untagged)]
347pub enum AckedRanges {
348    Single(Vec<Vec<u64>>),
349    Double(Vec<(u64, u64)>),
350}
351
352#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
353#[serde(rename_all = "snake_case")]
354pub enum QuicFrameTypeName {
355    Padding,
356    Ping,
357    Ack,
358    ResetStream,
359    StopSending,
360    Crypto,
361    NewToken,
362    Stream,
363    MaxData,
364    MaxStreamData,
365    MaxStreams,
366    DataBlocked,
367    StreamDataBlocked,
368    StreamsBlocked,
369    NewConnectionId,
370    RetireConnectionId,
371    PathChallenge,
372    PathResponse,
373    ConnectionClose,
374    ApplicationClose,
375    HandshakeDone,
376    Datagram,
377    #[default]
378    Unknown,
379}
380
381#[serde_with::skip_serializing_none]
382#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
383#[serde(tag = "frame_type")]
384#[serde(rename_all = "snake_case")]
385// Strictly, the qlog spec says that all these frame types have a frame_type
386// field. But instead of making that a rust object property, just use serde to
387// ensure it goes out on the wire. This means that deserialization of frames
388// also works automatically.
389pub enum QuicFrame {
390    Padding {
391        length: Option<u32>,
392        payload_length: u32,
393    },
394
395    Ping {
396        length: Option<u32>,
397        payload_length: Option<u32>,
398    },
399
400    Ack {
401        ack_delay: Option<f32>,
402        acked_ranges: Option<AckedRanges>,
403
404        ect1: Option<u64>,
405        ect0: Option<u64>,
406        ce: Option<u64>,
407
408        length: Option<u32>,
409        payload_length: Option<u32>,
410    },
411
412    ResetStream {
413        stream_id: u64,
414        error_code: u64,
415        final_size: u64,
416
417        length: Option<u32>,
418        payload_length: Option<u32>,
419    },
420
421    StopSending {
422        stream_id: u64,
423        error_code: u64,
424
425        length: Option<u32>,
426        payload_length: Option<u32>,
427    },
428
429    Crypto {
430        offset: u64,
431        length: u64,
432    },
433
434    NewToken {
435        token: Token,
436    },
437
438    Stream {
439        stream_id: u64,
440        offset: u64,
441        length: u64,
442        fin: Option<bool>,
443
444        raw: Option<RawInfo>,
445    },
446
447    MaxData {
448        maximum: u64,
449    },
450
451    MaxStreamData {
452        stream_id: u64,
453        maximum: u64,
454    },
455
456    MaxStreams {
457        stream_type: StreamType,
458        maximum: u64,
459    },
460
461    DataBlocked {
462        limit: u64,
463    },
464
465    StreamDataBlocked {
466        stream_id: u64,
467        limit: u64,
468    },
469
470    StreamsBlocked {
471        stream_type: StreamType,
472        limit: u64,
473    },
474
475    NewConnectionId {
476        sequence_number: u32,
477        retire_prior_to: u32,
478        connection_id_length: Option<u8>,
479        connection_id: Bytes,
480        stateless_reset_token: Option<StatelessResetToken>,
481    },
482
483    RetireConnectionId {
484        sequence_number: u32,
485    },
486
487    PathChallenge {
488        data: Option<Bytes>,
489    },
490
491    PathResponse {
492        data: Option<Bytes>,
493    },
494
495    ConnectionClose {
496        error_space: Option<ErrorSpace>,
497        error_code: Option<u64>,
498        error_code_value: Option<u64>,
499        reason: Option<String>,
500
501        trigger_frame_type: Option<u64>,
502    },
503
504    HandshakeDone,
505
506    Datagram {
507        length: u64,
508
509        raw: Option<Bytes>,
510    },
511
512    Unknown {
513        raw_frame_type: u64,
514        frame_type_value: Option<u64>,
515        raw: Option<RawInfo>,
516    },
517}
518
519#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
520pub struct PreferredAddress {
521    pub ip_v4: String,
522    pub ip_v6: String,
523
524    pub port_v4: u16,
525    pub port_v6: u16,
526
527    pub connection_id: Bytes,
528    pub stateless_reset_token: StatelessResetToken,
529}
530
531#[serde_with::skip_serializing_none]
532#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
533pub struct VersionInformation {
534    pub server_versions: Option<Vec<Bytes>>,
535    pub client_versions: Option<Vec<Bytes>>,
536    pub chosen_version: Option<Bytes>,
537}
538
539#[serde_with::skip_serializing_none]
540#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
541pub struct AlpnInformation {
542    pub server_alpns: Option<Vec<Bytes>>,
543    pub client_alpns: Option<Vec<Bytes>>,
544    pub chosen_alpn: Option<Bytes>,
545}
546
547#[serde_with::skip_serializing_none]
548#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
549pub struct TransportParametersSet {
550    pub owner: Option<TransportOwner>,
551
552    pub resumption_allowed: Option<bool>,
553    pub early_data_enabled: Option<bool>,
554    pub tls_cipher: Option<String>,
555    pub aead_tag_length: Option<u8>,
556
557    pub original_destination_connection_id: Option<Bytes>,
558    pub initial_source_connection_id: Option<Bytes>,
559    pub retry_source_connection_id: Option<Bytes>,
560    pub stateless_reset_token: Option<StatelessResetToken>,
561    pub disable_active_migration: Option<bool>,
562
563    pub max_idle_timeout: Option<u64>,
564    pub max_udp_payload_size: Option<u32>,
565    pub ack_delay_exponent: Option<u16>,
566    pub max_ack_delay: Option<u16>,
567    pub active_connection_id_limit: Option<u32>,
568
569    pub initial_max_data: Option<u64>,
570    pub initial_max_stream_data_bidi_local: Option<u64>,
571    pub initial_max_stream_data_bidi_remote: Option<u64>,
572    pub initial_max_stream_data_uni: Option<u64>,
573    pub initial_max_streams_bidi: Option<u64>,
574    pub initial_max_streams_uni: Option<u64>,
575
576    pub preferred_address: Option<PreferredAddress>,
577
578    pub unknown_parameters: Vec<UnknownTransportParameter>,
579}
580
581#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
582pub struct UnknownTransportParameter {
583    pub id: u64,
584    pub value: Bytes,
585}
586
587#[serde_with::skip_serializing_none]
588#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
589pub struct TransportParametersRestored {
590    pub disable_active_migration: Option<bool>,
591
592    pub max_idle_timeout: Option<u64>,
593    pub max_udp_payload_size: Option<u32>,
594    pub active_connection_id_limit: Option<u32>,
595
596    pub initial_max_data: Option<u64>,
597    pub initial_max_stream_data_bidi_local: Option<u64>,
598    pub initial_max_stream_data_bidi_remote: Option<u64>,
599    pub initial_max_stream_data_uni: Option<u64>,
600    pub initial_max_streams_bidi: Option<u64>,
601    pub initial_max_streams_uni: Option<u64>,
602}
603
604#[serde_with::skip_serializing_none]
605#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
606pub struct DatagramsReceived {
607    pub count: Option<u16>,
608
609    pub raw: Option<Vec<RawInfo>>,
610
611    pub datagram_ids: Option<Vec<u32>>,
612}
613
614#[serde_with::skip_serializing_none]
615#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
616pub struct DatagramsSent {
617    pub count: Option<u16>,
618
619    pub raw: Option<Vec<RawInfo>>,
620
621    pub datagram_ids: Option<Vec<u32>>,
622}
623
624#[serde_with::skip_serializing_none]
625#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
626pub struct DatagramDropped {
627    pub raw: Option<RawInfo>,
628}
629
630#[serde_with::skip_serializing_none]
631#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)]
632pub struct PacketReceived {
633    pub header: PacketHeader,
634    // `frames` is defined here in the QLog schema specification. However,
635    // our streaming serializer requires serde to put the object at the end,
636    // so we define it there and depend on serde's preserve_order feature.
637    pub is_coalesced: Option<bool>,
638
639    pub retry_token: Option<Token>,
640
641    pub stateless_reset_token: Option<StatelessResetToken>,
642
643    pub supported_versions: Option<Vec<Bytes>>,
644
645    pub raw: Option<RawInfo>,
646    pub datagram_id: Option<u32>,
647
648    pub trigger: Option<PacketReceivedTrigger>,
649
650    pub frames: Option<Vec<QuicFrame>>,
651}
652
653#[serde_with::skip_serializing_none]
654#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)]
655pub struct PacketSent {
656    pub header: PacketHeader,
657    // `frames` is defined here in the QLog schema specification. However,
658    // our streaming serializer requires serde to put the object at the end,
659    // so we define it there and depend on serde's preserve_order feature.
660    pub is_coalesced: Option<bool>,
661
662    pub retry_token: Option<Token>,
663
664    pub stateless_reset_token: Option<StatelessResetToken>,
665
666    pub supported_versions: Option<Vec<Bytes>>,
667
668    pub raw: Option<RawInfo>,
669    pub datagram_id: Option<u32>,
670
671    pub trigger: Option<PacketSentTrigger>,
672
673    pub send_at_time: Option<f32>,
674
675    pub frames: Option<SmallVec<[QuicFrame; 1]>>,
676}
677
678#[serde_with::skip_serializing_none]
679#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
680pub struct PacketDropped {
681    pub header: Option<PacketHeader>,
682
683    pub raw: Option<RawInfo>,
684    pub datagram_id: Option<u32>,
685
686    pub details: Option<String>,
687
688    pub trigger: Option<PacketDroppedTrigger>,
689}
690
691#[serde_with::skip_serializing_none]
692#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
693pub struct PacketBuffered {
694    pub header: Option<PacketHeader>,
695
696    pub raw: Option<RawInfo>,
697    pub datagram_id: Option<u32>,
698
699    pub trigger: Option<PacketBufferedTrigger>,
700}
701
702#[serde_with::skip_serializing_none]
703#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
704pub struct PacketsAcked {
705    pub packet_number_space: Option<PacketNumberSpace>,
706    pub packet_numbers: Option<Vec<u64>>,
707}
708
709#[serde_with::skip_serializing_none]
710#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
711pub struct StreamStateUpdated {
712    pub stream_id: u64,
713    pub stream_type: Option<StreamType>,
714
715    pub old: Option<StreamState>,
716    pub new: StreamState,
717
718    pub stream_side: Option<StreamSide>,
719}
720
721#[serde_with::skip_serializing_none]
722#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)]
723pub struct FramesProcessed {
724    pub frames: Vec<QuicFrame>,
725
726    pub packet_number: Option<u64>,
727}
728
729#[serde_with::skip_serializing_none]
730#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
731pub struct DataMoved {
732    pub stream_id: Option<u64>,
733    pub offset: Option<u64>,
734    pub length: Option<u64>,
735
736    pub from: Option<DataRecipient>,
737    pub to: Option<DataRecipient>,
738
739    pub raw: Option<RawInfo>,
740}
741
742#[serde_with::skip_serializing_none]
743#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)]
744pub struct RecoveryParametersSet {
745    pub reordering_threshold: Option<u16>,
746    pub time_threshold: Option<f32>,
747    pub timer_granularity: Option<u16>,
748    pub initial_rtt: Option<f32>,
749
750    pub max_datagram_size: Option<u32>,
751    pub initial_congestion_window: Option<u64>,
752    pub minimum_congestion_window: Option<u32>,
753    pub loss_reduction_factor: Option<f32>,
754    pub persistent_congestion_threshold: Option<u16>,
755}
756
757#[serde_with::skip_serializing_none]
758#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)]
759pub struct MetricsUpdated {
760    /// Extension data for non-standard fields. `flatten` causes these fields to
761    /// be serialized into the `data` field of a qlog event. On deserialize,
762    /// unknown fields are collected into `ex_data`.
763    #[serde(flatten)]
764    pub ex_data: ExData,
765
766    pub min_rtt: Option<f32>,
767    pub smoothed_rtt: Option<f32>,
768    pub latest_rtt: Option<f32>,
769    pub rtt_variance: Option<f32>,
770
771    pub pto_count: Option<u16>,
772
773    pub congestion_window: Option<u64>,
774    pub bytes_in_flight: Option<u64>,
775
776    pub ssthresh: Option<u64>,
777
778    // qlog defined
779    pub packets_in_flight: Option<u64>,
780
781    pub pacing_rate: Option<u64>,
782}
783
784#[serde_with::skip_serializing_none]
785#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Default)]
786pub struct CongestionStateUpdated {
787    pub old: Option<String>,
788    pub new: String,
789
790    pub trigger: Option<CongestionStateUpdatedTrigger>,
791}
792
793#[serde_with::skip_serializing_none]
794#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
795pub struct LossTimerUpdated {
796    pub timer_type: Option<TimerType>,
797    pub packet_number_space: Option<PacketNumberSpace>,
798
799    pub event_type: LossTimerEventType,
800
801    pub delta: Option<f32>,
802}
803
804#[serde_with::skip_serializing_none]
805#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)]
806pub struct PacketLost {
807    pub header: Option<PacketHeader>,
808
809    pub frames: Option<Vec<QuicFrame>>,
810
811    pub trigger: Option<PacketLostTrigger>,
812}
813
814#[serde_with::skip_serializing_none]
815#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)]
816pub struct MarkedForRetransmit {
817    pub frames: Vec<QuicFrame>,
818}