1 /** @file
2  *
3  *  A brief file description
4  *
5  *  @section license License
6  *
7  *  Licensed to the Apache Software Foundation (ASF) under one
8  *  or more contributor license agreements.  See the NOTICE file
9  *  distributed with this work for additional information
10  *  regarding copyright ownership.  The ASF licenses this file
11  *  to you under the Apache License, Version 2.0 (the
12  *  "License"); you may not use this file except in compliance
13  *  with the License.  You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  *  Unless required by applicable law or agreed to in writing, software
18  *  distributed under the License is distributed on an "AS IS" BASIS,
19  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  *  See the License for the specific language governing permissions and
21  *  limitations under the License.
22  */
23 
24 #pragma once
25 
26 #include <string>
27 #include <yaml-cpp/yaml.h>
28 
29 #include "QUICTypes.h"
30 #include "QLogEvent.h"
31 #include "QLogFrame.h"
32 
33 namespace QLog
34 {
35 class QLogEvent
36 {
37 public:
~QLogEvent()38   virtual ~QLogEvent() {}
39 
40   virtual std::string category() const = 0;
41   virtual std::string event() const    = 0;
42   virtual void encode(YAML::Node &)    = 0;
43 
44   virtual ink_hrtime
get_time()45   get_time() const
46   {
47     return this->_time;
48   };
49 
50 protected:
51   ink_hrtime _time = Thread::get_hrtime();
52 };
53 
54 using QLogEventUPtr = std::unique_ptr<QLogEvent>;
55 
56 #define SET(field, type) \
57   void set_##field(type v) { this->_node[#field] = v; }
58 
59 // enum class PacketType : uint8_t { initial, handshake, zerortt, onertt, retry, version_negotiation, unknown };
60 using PacketType = std::string;
61 
62 struct PacketHeader {
63   std::string packet_number;
64   uint64_t packet_size;
65   uint64_t payload_length;
66 
67   // only if present in the header
68   // if correctly using NEW_CONNECTION_ID events,
69   // dcid can be skipped for 1RTT packets
70   std::string version;
71   std::string scil;
72   std::string dcil;
73   std::string scid;
74   std::string dcid;
75 
76   // Note: short vs long header is implicit through PacketType
77   void
encodePacketHeader78   encode(YAML::Node &node) const
79   {
80     node["packet_number"]  = packet_number;
81     node["packet_size"]    = packet_size;
82     node["payload_length"] = payload_length;
83     node["version"]        = version;
84     node["scil"]           = scil;
85     node["dcil"]           = dcil;
86     node["scid"]           = scid;
87     node["dcid"]           = dcid;
88   }
89 };
90 
91 #define SET_FUNC(cla, field, type) \
92 public:                            \
93   cla &set_##field(const type &v)  \
94   {                                \
95     this->_##field = v;            \
96     return *this;                  \
97   }                                \
98                                    \
99 private:                           \
100   type _##field;
101 
102 #define APPEND_FUNC(cla, field, type) \
103 public:                               \
104   cla &append_##field(type v)         \
105   {                                   \
106     this->_##field.push_back(v);      \
107     return *this;                     \
108   }                                   \
109                                       \
110 private:                              \
111   std::vector<type> _##field;
112 
113 #define APPEND_FRAME_FUNC(cla)             \
114 public:                                    \
115   cla &append_frames(QLogFrameUPtr v)      \
116   {                                        \
117     this->_frames.push_back(std::move(v)); \
118     return *this;                          \
119   }                                        \
120                                            \
121 private:                                   \
122   std::vector<QLogFrameUPtr> _frames;
123 
124 //
125 // connectivity
126 //
127 namespace Connectivity
128 {
129   class ConnectivityEvent : public QLogEvent
130   {
131   public:
132     std::string
category()133     category() const override
134     {
135       return "connectivity";
136     }
137   };
138 
139   class ServerListening : public ConnectivityEvent
140   {
141   public:
142     ServerListening(int port, bool v6 = false)
143     {
144       if (v6) {
145         set_port_v6(port);
146       } else {
147         set_port_v4(port);
148       }
149     }
150 
151 #define _SET(a, b) SET_FUNC(ServerListening, a, b)
152 #define _APPEND(a, b) APPEND_FUNC(ServerListening, a, b)
153     _SET(port_v4, int)
154     _SET(port_v6, int)
155     _SET(ip_v4, std::string)
156     _SET(ip_v6, std::string)
157     _SET(stateless_reset_required, bool)
158     _APPEND(quic_version, std::string)
159     _APPEND(alpn_values, std::string)
160 
161 #undef _SET
162 #undef _APPEND
163 
164     void encode(YAML::Node &) override;
165 
166     std::string
event()167     event() const override
168     {
169       return "server_listening";
170     }
171   };
172 
173   class ConnectionStarted : public ConnectivityEvent
174   {
175   public:
176     ConnectionStarted(const std::string &version, const std::string &sip, const std::string &dip, int sport, int dport,
177                       const std::string &protocol = "QUIC")
178     {
179       set_ip_version(version);
180       set_protocol(protocol);
181       set_src_ip(sip);
182       set_dst_ip(dip);
183       set_src_port(sport);
184       set_dst_port(dport);
185     }
186 
187 #define _SET(a, b) SET_FUNC(ConnectionStarted, a, b)
188 #define _APPEND(a, b) APPEND_FUNC(ConnectionStarted, a, b)
189     _SET(quic_version, std::string);
190     _SET(src_cid, std::string);
191     _SET(dst_cid, std::string);
192     _SET(protocol, std::string);
193     _SET(ip_version, std::string)
194     _SET(src_ip, std::string)
195     _SET(dst_ip, std::string)
196     _SET(src_port, int)
197     _SET(dst_port, int)
198     _APPEND(alpn_values, std::string)
199 
200 #undef _SET
201 #undef _APPEND
202 
203     void encode(YAML::Node &) override;
204 
205     std::string
event()206     event() const override
207     {
208       return "connection_started";
209     }
210   };
211 
212   class ConnectionIdUpdated : public ConnectivityEvent
213   {
214   public:
215     ConnectionIdUpdated(const std::string &old, const std::string &n, bool peer = false)
216     {
217       if (peer) {
218         set_dst_old(old);
219         set_dst_new(n);
220       } else {
221         set_src_old(old);
222         set_src_new(n);
223       }
224     }
225 
226 #define _SET(a, b) SET_FUNC(ConnectionIdUpdated, a, b)
227 #define _APPEND(a, b) APPEND_FUNC(ConnectionIdUpdated, a, b)
228 
229     _SET(src_old, std::string);
230     _SET(src_new, std::string);
231     _SET(dst_old, std::string);
232     _SET(dst_new, std::string);
233 
234 #undef _SET
235 #undef _APPEND
236 
237     void encode(YAML::Node &) override;
238 
239     std::string
event()240     event() const override
241     {
242       return "connection_id_updated";
243     }
244   };
245 
246   class SpinBitUpdated : public ConnectivityEvent
247   {
248   public:
SpinBitUpdated(bool state)249     SpinBitUpdated(bool state) { set_state(state); }
250 
251 #define _SET(a, b) SET_FUNC(SpinBitUpdated, a, b)
252     _SET(state, bool);
253 #undef _SET
254 
255     void encode(YAML::Node &) override;
256 
257     std::string
event()258     event() const override
259     {
260       return "spin_bit_updated";
261     }
262   };
263 
264   class ConnectionStateUpdated : public ConnectivityEvent
265   {
266   public:
267     enum class ConnectionState : uint8_t {
268       attempted, // client initial sent
269       reset,     // stateless reset sent
270       handshake, // handshake in progress
271       active,    // handshake successful, data exchange
272       keepalive, // no data for a longer period
273       draining,  // CONNECTION_CLOSE sent
274       closed     // connection actually fully closed, memory freed
275     };
276 
277     enum class Triggered : uint8_t {
278       unknown,
279       error,      // when closing because of an unexpected event
280       clean,      // when closing normally
281       application // e.g., HTTP/3's GOAWAY frame
282     };
283 
284     ConnectionStateUpdated(ConnectionState n, Triggered tr = Triggered::unknown)
285     {
286       set_new(n);
287       set_trigger(tr);
288     }
289 
290 #define _SET(a, b) SET_FUNC(ConnectionStateUpdated, a, b)
291     _SET(new, ConnectionState);
292     _SET(old, ConnectionState);
293     _SET(trigger, Triggered)
294 
295 #undef _SET
296 
297     void encode(YAML::Node &) override;
298 
299     static const char *
trigger_name(Triggered trigger)300     trigger_name(Triggered trigger)
301     {
302       switch (trigger) {
303       case Triggered::error:
304         return "error";
305       case Triggered::clean:
306         return "clean";
307       case Triggered::application:
308         return "application";
309       default:
310         return nullptr;
311       }
312     }
313 
314     std::string
event()315     event() const override
316     {
317       return "connection_state_updated";
318     }
319   };
320 
321 } // namespace Connectivity
322 
323 namespace Security
324 {
325   class KeyEvent : public QLogEvent
326   {
327   public:
328     enum class KeyType : uint8_t {
329       server_initial_secret,
330       client_initial_secret,
331 
332       server_handshake_secret,
333       client_handshake_secret,
334 
335       server_0rtt_secret,
336       client_0rtt_secret,
337 
338       server_1rtt_secret,
339       client_1rtt_secret
340     };
341 
342     enum class Triggered : uint8_t {
343       unknown,
344       remote_update,
345       local_update,
346       tls,
347     };
348 
349     KeyEvent(KeyType ty, const std::string &n, int generation, Triggered triggered = Triggered::unknown)
350     {
351       set_key_type(ty);
352       set_new(n);
353       set_generation(generation);
354       set_trigger(triggered);
355     }
356 
357 #define _SET(a, b) SET_FUNC(KeyEvent, a, b)
358     _SET(key_type, KeyType);
359     _SET(new, std::string)
360     _SET(old, std::string);
361     _SET(generation, int)
362     _SET(trigger, Triggered)
363 #undef _SET
364 
365     void encode(YAML::Node &) override;
366 
367     const char *
trigger_name(Triggered triggered)368     trigger_name(Triggered triggered)
369     {
370       switch (triggered) {
371       case Triggered::remote_update:
372         return "remote_update";
373       case Triggered::local_update:
374         return "local_update";
375       case Triggered::tls:
376         return "tls";
377       default:
378         return nullptr;
379       }
380     }
381 
382     std::string
category()383     category() const override
384     {
385       return "security";
386     }
387   };
388 
389   class KeyUpdated : public KeyEvent
390   {
391   public:
392     KeyUpdated(KeyType ty, const std::string &n, int generation, Triggered triggered = KeyEvent::Triggered::unknown)
KeyEvent(ty,n,generation,triggered)393       : KeyEvent(ty, n, generation, triggered)
394     {
395     }
396 
397     std::string
event()398     event() const override
399     {
400       return "key_updated";
401     }
402   };
403 
404   class KeyRetired : public KeyEvent
405   {
406   public:
407     KeyRetired(KeyType ty, const std::string &n, int generation, Triggered triggered = KeyEvent::Triggered::unknown)
KeyEvent(ty,n,generation,triggered)408       : KeyEvent(ty, n, generation, triggered)
409     {
410     }
411 
412     std::string
event()413     event() const override
414     {
415       return "key_retired";
416     }
417   };
418 
419 } // namespace Security
420 
421 //
422 // transport event
423 //
424 namespace Transport
425 {
426   class TransportEvent : public QLogEvent
427   {
428   public:
429     std::string
category()430     category() const override
431     {
432       return "transport";
433     }
434   };
435 
436   class ParametersSet : public TransportEvent
437   {
438   public:
439     struct PreferredAddress {
440       std::string ip;
441       int port;
442       std::string connection_id;
443       std::string stateless_reset_token;
444       bool ipv4 = true;
445     };
446 
ParametersSet(bool owner)447     ParametersSet(bool owner) : _owner(owner) {}
448 
449     std::string
event()450     event() const override
451     {
452       return "parameters_set";
453     }
454 
455 #define _SET(a, b) SET_FUNC(ParametersSet, a, b)
456     _SET(resumption_allowed, bool); // early data extension was enabled on the TLS layer
457     _SET(early_data_enabled, bool); // early data extension was enabled on the TLS layer
458     _SET(alpn, std::string);
459     _SET(version, std::string);                // hex (e.g. 0x);
460     _SET(tls_cipher, std::string);             // (e.g. AES_128_GCM_SHA256);
461     _SET(original_connection_id, std::string); // hex
462     _SET(stateless_reset_token, std::string);  // hex
463     _SET(disable_active_migration, bool);
464     _SET(idle_timeout, int);
465     _SET(max_packet_size, int);
466     _SET(ack_delay_exponent, int);
467     _SET(max_ack_delay, int);
468     _SET(active_connection_id_limit, int);
469     _SET(initial_max_data, std::string);
470     _SET(initial_max_stream_data_bidi_local, std::string);
471     _SET(initial_max_stream_data_bidi_remote, std::string);
472     _SET(initial_max_stream_data_uni, std::string);
473     _SET(initial_max_streams_bidi, std::string);
474     _SET(initial_max_streams_uni, std::string);
475     _SET(max_idle_timeout, int64_t)
476     _SET(max_udp_payload_size, size_t)
477     _SET(preferred_address, PreferredAddress)
478 #undef _SET
479 
480     void encode(YAML::Node &) override;
481 
482   private:
483     bool _owner = false;
484   };
485 
486   class PacketEvent : public TransportEvent
487   {
488   public:
489     enum class Triggered : uint8_t {
490       unknown,
491       keys_available,       // if packet was buffered because it couldn't be decrypted before
492       retransmit_reordered, // draft-23 5.1.1
493       retransmit_timeout,   // draft-23 5.1.2
494       pto_probe,            // draft-23 5.3.1
495       retransmit_crypto,    // draft-19 6.2
496       cc_bandwidth_probe,   // needed for some CCs to figure out bandwidth allocations when there are no normal sends
497     };
498 
499     PacketEvent(const PacketType &type, PacketHeader h, Triggered tr = Triggered::unknown)
500     {
501       set_packet_type(type).set_header(h).set_trigger(tr);
502     }
503 
504 #define _SET(a, b) SET_FUNC(PacketEvent, a, b)
505 #define _APPEND(a, b) APPEND_FUNC(PacketEvent, a, b)
506     _SET(packet_type, PacketType)
507     _SET(header, PacketHeader)
508     _SET(is_coalesced, bool);
509     _SET(raw_encrypted, std::string);
510     _SET(raw_decrypted, std::string);
511     _SET(stateless_reset_token, std::string);
512     _SET(trigger, Triggered);
513     _APPEND(supported_version, std::string);
514 
515 #undef _SET
516 #undef _APPEND
517     APPEND_FRAME_FUNC(PacketEvent)
518 
519     void encode(YAML::Node &) override;
520 
521     static const char *
trigger_name(Triggered triggered)522     trigger_name(Triggered triggered)
523     {
524       switch (triggered) {
525       case Triggered::retransmit_reordered:
526         return "retransmit_reordered";
527       case Triggered::retransmit_timeout:
528         return "retransmit_timeout";
529       case Triggered::pto_probe:
530         return "pto_probe";
531       case Triggered::retransmit_crypto:
532         return "retransmit_crypto";
533       case Triggered::cc_bandwidth_probe:
534         return "cc_bandwidth_probe";
535         break;
536       case Triggered::keys_available:
537         return "keys_available";
538       default:
539         return nullptr;
540       }
541     }
542   };
543 
544   class PacketSent : public PacketEvent
545   {
546   public:
PacketEvent(type,h,tr)547     PacketSent(const PacketType &type, const PacketHeader &h, Triggered tr = Triggered::unknown) : PacketEvent(type, h, tr) {}
548     std::string
event()549     event() const override
550     {
551       return "packet_sent";
552     }
553   };
554 
555   class PacketReceived : public PacketEvent
556   {
557   public:
PacketEvent(type,h,tr)558     PacketReceived(const PacketType &type, const PacketHeader &h, Triggered tr = Triggered::unknown) : PacketEvent(type, h, tr) {}
559     std::string
event()560     event() const override
561     {
562       return "packet_received";
563     }
564   };
565 
566   class PacketDropped : public TransportEvent
567   {
568   public:
569     enum class Triggered : uint8_t {
570       unknown,
571       key_unavailable,
572       unknown_connection_id,
573       header_decrypt_error,
574       payload_decrypt_error,
575       protocol_violation,
576       dos_prevention,
577       unsupported_version,
578       unexpected_packet,
579       unexpected_source_connection_id,
580       unexpected_version,
581     };
582 
583     PacketDropped(Triggered tr = Triggered::unknown) { set_trigger(tr); }
584 
585 #define _SET(a, b) SET_FUNC(PacketDropped, a, b)
586     _SET(packet_size, int);
587     _SET(raw, std::string);
588     _SET(trigger, Triggered);
589     _SET(packet_type, PacketType)
590 #undef _SET
591 
592     void encode(YAML::Node &) override;
593 
594     std::string
event()595     event() const override
596     {
597       return "packet_dropped";
598     }
599 
600     static const char *
trigger_name(Triggered tr)601     trigger_name(Triggered tr)
602     {
603       switch (tr) {
604       case Triggered::key_unavailable:
605         return "key_unavailable";
606       case Triggered::unknown_connection_id:
607         return "unknown_connection_id";
608       case Triggered::header_decrypt_error:
609         return "header_decrypt_error";
610       case Triggered::payload_decrypt_error:
611         return "payload_decrypt_error";
612       case Triggered::protocol_violation:
613         return "protocol_violation";
614       case Triggered::dos_prevention:
615         return "dos_prevention";
616       case Triggered::unsupported_version:
617         return "unsupported_version";
618       case Triggered::unexpected_packet:
619         return "unexpected_packet";
620       case Triggered::unexpected_source_connection_id:
621         return "unexpected_source_connection_id";
622       case Triggered::unexpected_version:
623         return "unexpected_version";
624       default:
625         return nullptr;
626       }
627     }
628   };
629 
630   class PacketBuffered : public TransportEvent
631   {
632   public:
633     enum class Triggered : uint8_t {
634       unknown,
635       backpressure,
636       keys_unavailable,
637     };
638 
639     PacketBuffered(Triggered tr = Triggered::unknown) { set_trigger(tr); }
640 
641 #define _SET(a, b) SET_FUNC(PacketBuffered, a, b)
642     _SET(trigger, Triggered);
643     _SET(packet_type, PacketType)
644     _SET(packet_number, std::string)
645 #undef _SET
646 
647     void encode(YAML::Node &) override;
648 
649     std::string
event()650     event() const override
651     {
652       return "packet_buffered";
653     }
654 
655     static const char *
trigger_name(Triggered tr)656     trigger_name(Triggered tr)
657     {
658       switch (tr) {
659       case Triggered::backpressure:
660         return "backpressure";
661       case Triggered::keys_unavailable:
662         return "keys_unavailable";
663       default:
664         return nullptr;
665       }
666     }
667   };
668 
669   class DatagramsEvent : public TransportEvent
670   {
671   public:
672 #define _SET(a, b) SET_FUNC(DatagramsEvent, a, b)
673     _SET(count, int);
674     _SET(byte_length, int);
675 #undef _SET
676     void encode(YAML::Node &) override;
677   };
678 
679   class DatagramsSent : public DatagramsEvent
680   {
681   public:
682     std::string
event()683     event() const override
684     {
685       return "datagrams_sent";
686     }
687   };
688   class DatagramReceived : public DatagramsEvent
689   {
690   public:
691     std::string
event()692     event() const override
693     {
694       return "datagrams_received";
695     }
696   };
697 
698   class DatagramsDropped : public TransportEvent
699   {
700   public:
701 #define _SET(a, b) SET_FUNC(DatagramsDropped, a, b)
702     _SET(byte_length, int);
703 #undef _SET
704 
705     void encode(YAML::Node &) override;
706 
707     std::string
event()708     event() const override
709     {
710       return "datagrams_dropped";
711     }
712   };
713 
714   class StreamStateUpdated : public TransportEvent
715   {
716     enum class StreamState {
717       // bidirectional stream states, draft-23 3.4.
718       idle,
719       open,
720       half_closed_local,
721       half_closed_remote,
722       closed,
723 
724       // sending-side stream states, draft-23 3.1.
725       ready,
726       send,
727       data_sent,
728       reset_sent,
729       reset_received,
730 
731       // receive-side stream states, draft-23 3.2.
732       receive,
733       size_known,
734       data_read,
735       reset_read,
736 
737       // both-side states
738       data_received,
739 
740       // qlog-defined
741       destroyed // memory actually freed
742     };
743 
StreamStateUpdated(std::string stream_id,StreamState n)744     StreamStateUpdated(std::string stream_id, StreamState n) { set_new(n).set_stream_id(stream_id); }
745 
746     void encode(YAML::Node &) override;
747 
748 #define _SET(a, b) SET_FUNC(StreamStateUpdated, a, b)
749     _SET(new, StreamState);
750     _SET(old, StreamState);
751     _SET(stream_id, std::string);
752     _SET(bidi, bool);
753 #undef _SET
754 
755     std::string
event()756     event() const override
757     {
758       return "stream_state_updated";
759     }
760   };
761 
762   class FrameProcessed : public TransportEvent
763   {
764   public:
765     APPEND_FRAME_FUNC(FrameProcessed)
766 
767     void encode(YAML::Node &) override;
768 
769     std::string
event()770     event() const override
771     {
772       return "frame_processed";
773     }
774   };
775 
776 } // namespace Transport
777 
778 namespace Recovery
779 {
780   class RecoveryEvent : public QLogEvent
781   {
782   public:
783     std::string
category()784     category() const override
785     {
786       return "recovery";
787     }
788   };
789 
790   class ParametersSet : public RecoveryEvent
791   {
792   public:
793 #define _SET(a, b) SET_FUNC(ParametersSet, a, b)
794     _SET(reordering_threshold, int);
795     _SET(time_threshold, int);
796     _SET(timer_granularity, int);
797     _SET(initial_rtt, int);
798     _SET(max_datagram_size, int);
799     _SET(initial_congestion_window, int);
800     _SET(minimum_congestion_window, int);
801     _SET(loss_reduction_factor, int);
802     _SET(persistent_congestion_threshold, int);
803 #undef _SET
804     void encode(YAML::Node &) override;
805 
806     std::string
event()807     event() const override
808     {
809       return "parameters_set";
810     }
811   };
812 
813   class MetricsUpdated : public RecoveryEvent
814   {
815   public:
816 #define _SET(a, b) SET_FUNC(MetricsUpdated, a, b)
817     _SET(min_rtt, int);
818     _SET(smoothed_rtt, int);
819     _SET(latest_rtt, int);
820     _SET(rtt_variance, int);
821     _SET(max_ack_delay, int);
822     _SET(pto_count, int);
823     _SET(congestion_window, int);
824     _SET(bytes_in_flight, int);
825     _SET(ssthresh, int);
826     _SET(packets_in_flight, int);
827     _SET(in_recovery, int);
828     _SET(pacing_rate, int);
829 #undef _SET
830     void encode(YAML::Node &) override;
831 
832     std::string
event()833     event() const override
834     {
835       return "metrics_updated";
836     }
837   };
838 
839   class CongestionStateUpdated : public RecoveryEvent
840   {
841   public:
842     enum class State : uint8_t {
843       slow_start,
844       congestion_avoidance,
845       application_limited,
846       recovery,
847     };
848 
849     enum class Triggered : uint8_t {
850       unknown,
851       persistent_congestion,
852       ECN,
853     };
854 
855     CongestionStateUpdated(State n, Triggered tr = Triggered::unknown) { set_trigger(tr).set_new(n); }
856 
857 #define _SET(a, b) SET_FUNC(CongestionStateUpdated, a, b)
858     _SET(trigger, Triggered)
859     _SET(new, State)
860     _SET(old, State)
861 #undef _SET
862 
863     void encode(YAML::Node &) override;
864 
865     std::string
event()866     event() const override
867     {
868       return "congestion_state_updated";
869     }
870 
871     static const char *
trigger_name(Triggered tr)872     trigger_name(Triggered tr)
873     {
874       switch (tr) {
875       case Triggered::persistent_congestion:
876         return "persistent_congestion";
877       case Triggered::ECN:
878         return "ECN";
879       default:
880         return nullptr;
881       }
882     }
883 
884     static const char *
state_to_string(State s)885     state_to_string(State s)
886     {
887       switch (s) {
888       case State::slow_start:
889         return "slow_start";
890       case State::congestion_avoidance:
891         return "congestion_avoidance";
892       case State::application_limited:
893         return "application_limited";
894       case State::recovery:
895         return "recovery";
896       default:
897         break;
898       }
899 
900       return nullptr;
901     }
902   };
903 
904   class LossTimerUpdated : public RecoveryEvent
905   {
906   public:
907     enum class EventType : uint8_t {
908       set,
909       expired,
910       cancelled,
911     };
912 
913     void
set_timer_type(bool ack)914     set_timer_type(bool ack)
915     {
916       this->_timer_type_ack = ack;
917     }
918 
919     void encode(YAML::Node &) override;
920 
921 #define _SET(a, b) SET_FUNC(LossTimerUpdated, a, b)
922     _SET(event_type, EventType)
923     _SET(packet_number_space, int);
924     _SET(delta, int);
925 #undef _SET
926 
927     std::string
event()928     event() const override
929     {
930       return "loss_timer_updated";
931     }
932 
933     static const char *
event_type_name(EventType et)934     event_type_name(EventType et)
935     {
936       switch (et) {
937       case EventType::set:
938         return "set";
939       case EventType::expired:
940         return "expired";
941       case EventType::cancelled:
942         return "cancelled";
943       default:
944         break;
945       }
946       return nullptr;
947     }
948 
949   private:
950     bool _timer_type_ack = false;
951   };
952 
953   class PacketLost : public RecoveryEvent
954   {
955   public:
956     enum class Triggered : uint8_t {
957       unknown,
958       reordering_threshold,
959       time_threshold,
960       pto_expired,
961     };
962 
963     PacketLost(PacketType pt, uint64_t pn, Triggered tr = Triggered::unknown)
964     {
965       set_trigger(tr).set_packet_type(pt).set_packet_number(pn);
966     }
967 
968 #define _SET(a, b) SET_FUNC(PacketLost, a, b)
969     _SET(header, PacketHeader)
970     _SET(packet_number, uint64_t);
971     _SET(packet_type, PacketType);
972     _SET(trigger, Triggered)
973     APPEND_FRAME_FUNC(PacketLost)
974 #undef _SET
975 
976     void encode(YAML::Node &) override;
977 
978     std::string
event()979     event() const override
980     {
981       return "packet_lost";
982     }
983 
984     static const char *
trigger_name(Triggered tr)985     trigger_name(Triggered tr)
986     {
987       switch (tr) {
988       case Triggered::pto_expired:
989         return "pto_expired";
990       case Triggered::reordering_threshold:
991         return "reordering_threshold";
992       case Triggered::time_threshold:
993         return "time_threshold";
994       default:
995         return nullptr;
996       }
997     }
998   };
999 
1000   class MarkedForRetransmit : public RecoveryEvent
1001   {
1002   public:
1003     APPEND_FRAME_FUNC(MarkedForRetransmit)
1004     void encode(YAML::Node &) override;
1005     std::string
event()1006     event() const override
1007     {
1008       return "marked_for_retransmit";
1009     }
1010   };
1011 
1012 } // namespace Recovery
1013 
1014 } // namespace QLog
1015