• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ngtcp2
3  *
4  * Copyright (c) 2019 ngtcp2 contributors
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "ngtcp2_qlog.h"
26 
27 #include <assert.h>
28 
29 #include "ngtcp2_str.h"
30 #include "ngtcp2_vec.h"
31 #include "ngtcp2_conv.h"
32 #include "ngtcp2_net.h"
33 
ngtcp2_qlog_init(ngtcp2_qlog * qlog,ngtcp2_qlog_write write,ngtcp2_tstamp ts,void * user_data)34 void ngtcp2_qlog_init(ngtcp2_qlog *qlog, ngtcp2_qlog_write write,
35                       ngtcp2_tstamp ts, void *user_data) {
36   qlog->write = write;
37   qlog->ts = qlog->last_ts = ts;
38   qlog->user_data = user_data;
39 }
40 
41 #define write_verbatim(DEST, S) ngtcp2_cpymem((DEST), (S), sizeof(S) - 1)
42 
write_string_impl(uint8_t * p,const uint8_t * data,size_t datalen)43 static uint8_t *write_string_impl(uint8_t *p, const uint8_t *data,
44                                   size_t datalen) {
45   *p++ = '"';
46   if (datalen) {
47     p = ngtcp2_cpymem(p, data, datalen);
48   }
49   *p++ = '"';
50   return p;
51 }
52 
53 #define write_string(DEST, S)                                                  \
54   write_string_impl((DEST), (const uint8_t *)(S), sizeof(S) - 1)
55 
56 #define NGTCP2_LOWER_XDIGITS "0123456789abcdef"
57 
write_hex(uint8_t * p,const uint8_t * data,size_t datalen)58 static uint8_t *write_hex(uint8_t *p, const uint8_t *data, size_t datalen) {
59   const uint8_t *b = data, *end = data + datalen;
60   *p++ = '"';
61   for (; b != end; ++b) {
62     *p++ = (uint8_t)NGTCP2_LOWER_XDIGITS[*b >> 4];
63     *p++ = (uint8_t)NGTCP2_LOWER_XDIGITS[*b & 0xf];
64   }
65   *p++ = '"';
66   return p;
67 }
68 
write_cid(uint8_t * p,const ngtcp2_cid * cid)69 static uint8_t *write_cid(uint8_t *p, const ngtcp2_cid *cid) {
70   return write_hex(p, cid->data, cid->datalen);
71 }
72 
write_number(uint8_t * p,uint64_t n)73 static uint8_t *write_number(uint8_t *p, uint64_t n) {
74   size_t nlen = 0;
75   uint64_t t;
76   uint8_t *res;
77 
78   if (n == 0) {
79     *p++ = '0';
80     return p;
81   }
82   for (t = n; t; t /= 10, ++nlen)
83     ;
84   p += nlen;
85   res = p;
86   for (; n; n /= 10) {
87     *--p = (uint8_t)((n % 10) + '0');
88   }
89   return res;
90 }
91 
write_tstamp(uint8_t * p,ngtcp2_tstamp ts)92 static uint8_t *write_tstamp(uint8_t *p, ngtcp2_tstamp ts) {
93   return write_number(p, ts / NGTCP2_MILLISECONDS);
94 }
95 
write_duration(uint8_t * p,ngtcp2_duration duration)96 static uint8_t *write_duration(uint8_t *p, ngtcp2_duration duration) {
97   return write_number(p, duration / NGTCP2_MILLISECONDS);
98 }
99 
write_bool(uint8_t * p,int b)100 static uint8_t *write_bool(uint8_t *p, int b) {
101   if (b) {
102     return ngtcp2_cpymem(p, "true", sizeof("true") - 1);
103   }
104   return ngtcp2_cpymem(p, "false", sizeof("false") - 1);
105 }
106 
write_pair_impl(uint8_t * p,const uint8_t * name,size_t namelen,const ngtcp2_vec * value)107 static uint8_t *write_pair_impl(uint8_t *p, const uint8_t *name, size_t namelen,
108                                 const ngtcp2_vec *value) {
109   p = write_string_impl(p, name, namelen);
110   *p++ = ':';
111   return write_string_impl(p, value->base, value->len);
112 }
113 
114 #define write_pair(DEST, NAME, VALUE)                                          \
115   write_pair_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1, (VALUE))
116 
write_pair_hex_impl(uint8_t * p,const uint8_t * name,size_t namelen,const uint8_t * value,size_t valuelen)117 static uint8_t *write_pair_hex_impl(uint8_t *p, const uint8_t *name,
118                                     size_t namelen, const uint8_t *value,
119                                     size_t valuelen) {
120   p = write_string_impl(p, name, namelen);
121   *p++ = ':';
122   return write_hex(p, value, valuelen);
123 }
124 
125 #define write_pair_hex(DEST, NAME, VALUE, VALUELEN)                            \
126   write_pair_hex_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,       \
127                       (VALUE), (VALUELEN))
128 
write_pair_number_impl(uint8_t * p,const uint8_t * name,size_t namelen,uint64_t value)129 static uint8_t *write_pair_number_impl(uint8_t *p, const uint8_t *name,
130                                        size_t namelen, uint64_t value) {
131   p = write_string_impl(p, name, namelen);
132   *p++ = ':';
133   return write_number(p, value);
134 }
135 
136 #define write_pair_number(DEST, NAME, VALUE)                                   \
137   write_pair_number_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,    \
138                          (VALUE))
139 
write_pair_duration_impl(uint8_t * p,const uint8_t * name,size_t namelen,ngtcp2_duration duration)140 static uint8_t *write_pair_duration_impl(uint8_t *p, const uint8_t *name,
141                                          size_t namelen,
142                                          ngtcp2_duration duration) {
143   p = write_string_impl(p, name, namelen);
144   *p++ = ':';
145   return write_duration(p, duration);
146 }
147 
148 #define write_pair_duration(DEST, NAME, VALUE)                                 \
149   write_pair_duration_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,  \
150                            (VALUE))
151 
write_pair_tstamp_impl(uint8_t * p,const uint8_t * name,size_t namelen,ngtcp2_tstamp ts)152 static uint8_t *write_pair_tstamp_impl(uint8_t *p, const uint8_t *name,
153                                        size_t namelen, ngtcp2_tstamp ts) {
154   p = write_string_impl(p, name, namelen);
155   *p++ = ':';
156   return write_tstamp(p, ts);
157 }
158 
159 #define write_pair_tstamp(DEST, NAME, VALUE)                                   \
160   write_pair_tstamp_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,    \
161                          (VALUE))
162 
write_pair_bool_impl(uint8_t * p,const uint8_t * name,size_t namelen,int b)163 static uint8_t *write_pair_bool_impl(uint8_t *p, const uint8_t *name,
164                                      size_t namelen, int b) {
165   p = write_string_impl(p, name, namelen);
166   *p++ = ':';
167   return write_bool(p, b);
168 }
169 
170 #define write_pair_bool(DEST, NAME, VALUE)                                     \
171   write_pair_bool_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,      \
172                        (VALUE))
173 
write_pair_cid_impl(uint8_t * p,const uint8_t * name,size_t namelen,const ngtcp2_cid * cid)174 static uint8_t *write_pair_cid_impl(uint8_t *p, const uint8_t *name,
175                                     size_t namelen, const ngtcp2_cid *cid) {
176   p = write_string_impl(p, name, namelen);
177   *p++ = ':';
178   return write_cid(p, cid);
179 }
180 
181 #define write_pair_cid(DEST, NAME, VALUE)                                      \
182   write_pair_cid_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,       \
183                       (VALUE))
184 
185 #define ngtcp2_make_vec_lit(S)                                                 \
186   { (uint8_t *)(S), sizeof((S)) - 1 }
187 
write_common_fields(uint8_t * p,const ngtcp2_cid * odcid)188 static uint8_t *write_common_fields(uint8_t *p, const ngtcp2_cid *odcid) {
189   p = write_verbatim(
190       p, "\"common_fields\":{\"protocol_type\":[\"QUIC\"],\"time_format\":"
191          "\"relative\",\"reference_time\":0,\"group_id\":");
192   p = write_cid(p, odcid);
193   *p++ = '}';
194   return p;
195 }
196 
write_trace(uint8_t * p,int server,const ngtcp2_cid * odcid)197 static uint8_t *write_trace(uint8_t *p, int server, const ngtcp2_cid *odcid) {
198   p = write_verbatim(
199       p, "\"trace\":{\"vantage_point\":{\"name\":\"ngtcp2\",\"type\":");
200   if (server) {
201     p = write_string(p, "server");
202   } else {
203     p = write_string(p, "client");
204   }
205   p = write_verbatim(p, "},");
206   p = write_common_fields(p, odcid);
207   *p++ = '}';
208   return p;
209 }
210 
ngtcp2_qlog_start(ngtcp2_qlog * qlog,const ngtcp2_cid * odcid,int server)211 void ngtcp2_qlog_start(ngtcp2_qlog *qlog, const ngtcp2_cid *odcid, int server) {
212   uint8_t buf[1024];
213   uint8_t *p = buf;
214 
215   if (!qlog->write) {
216     return;
217   }
218 
219   p = write_verbatim(
220       p, "\x1e{\"qlog_format\":\"JSON-SEQ\",\"qlog_version\":\"0.3\",");
221   p = write_trace(p, server, odcid);
222   p = write_verbatim(p, "}\n");
223 
224   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
225               (size_t)(p - buf));
226 }
227 
ngtcp2_qlog_end(ngtcp2_qlog * qlog)228 void ngtcp2_qlog_end(ngtcp2_qlog *qlog) {
229   uint8_t buf[1] = {0};
230 
231   if (!qlog->write) {
232     return;
233   }
234 
235   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_FIN, &buf, 0);
236 }
237 
238 static ngtcp2_vec vec_pkt_type_initial = ngtcp2_make_vec_lit("initial");
239 static ngtcp2_vec vec_pkt_type_handshake = ngtcp2_make_vec_lit("handshake");
240 static ngtcp2_vec vec_pkt_type_0rtt = ngtcp2_make_vec_lit("0RTT");
241 static ngtcp2_vec vec_pkt_type_1rtt = ngtcp2_make_vec_lit("1RTT");
242 static ngtcp2_vec vec_pkt_type_retry = ngtcp2_make_vec_lit("retry");
243 static ngtcp2_vec vec_pkt_type_version_negotiation =
244     ngtcp2_make_vec_lit("version_negotiation");
245 static ngtcp2_vec vec_pkt_type_stateless_reset =
246     ngtcp2_make_vec_lit("stateless_reset");
247 static ngtcp2_vec vec_pkt_type_unknown = ngtcp2_make_vec_lit("unknown");
248 
qlog_pkt_type(const ngtcp2_pkt_hd * hd)249 static const ngtcp2_vec *qlog_pkt_type(const ngtcp2_pkt_hd *hd) {
250   if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
251     switch (hd->type) {
252     case NGTCP2_PKT_INITIAL:
253       return &vec_pkt_type_initial;
254     case NGTCP2_PKT_HANDSHAKE:
255       return &vec_pkt_type_handshake;
256     case NGTCP2_PKT_0RTT:
257       return &vec_pkt_type_0rtt;
258     case NGTCP2_PKT_RETRY:
259       return &vec_pkt_type_retry;
260     default:
261       return &vec_pkt_type_unknown;
262     }
263   }
264 
265   switch (hd->type) {
266   case NGTCP2_PKT_VERSION_NEGOTIATION:
267     return &vec_pkt_type_version_negotiation;
268   case NGTCP2_PKT_STATELESS_RESET:
269     return &vec_pkt_type_stateless_reset;
270   case NGTCP2_PKT_1RTT:
271     return &vec_pkt_type_1rtt;
272   default:
273     return &vec_pkt_type_unknown;
274   }
275 }
276 
write_pkt_hd(uint8_t * p,const ngtcp2_pkt_hd * hd)277 static uint8_t *write_pkt_hd(uint8_t *p, const ngtcp2_pkt_hd *hd) {
278   /*
279    * {"packet_type":"version_negotiation","packet_number":"0000000000000000000","token":{"data":""}}
280    */
281 #define NGTCP2_QLOG_PKT_HD_OVERHEAD 95
282 
283   *p++ = '{';
284   p = write_pair(p, "packet_type", qlog_pkt_type(hd));
285   *p++ = ',';
286   p = write_pair_number(p, "packet_number", (uint64_t)hd->pkt_num);
287   if (hd->type == NGTCP2_PKT_INITIAL && hd->token.len) {
288     p = write_verbatim(p, ",\"token\":{");
289     p = write_pair_hex(p, "data", hd->token.base, hd->token.len);
290     *p++ = '}';
291   }
292   /* TODO Write DCIL and DCID */
293   /* TODO Write SCIL and SCID */
294   *p++ = '}';
295   return p;
296 }
297 
write_padding_frame(uint8_t * p,const ngtcp2_padding * fr)298 static uint8_t *write_padding_frame(uint8_t *p, const ngtcp2_padding *fr) {
299   (void)fr;
300 
301   /* {"frame_type":"padding"} */
302 #define NGTCP2_QLOG_PADDING_FRAME_OVERHEAD 24
303 
304   return write_verbatim(p, "{\"frame_type\":\"padding\"}");
305 }
306 
write_ping_frame(uint8_t * p,const ngtcp2_ping * fr)307 static uint8_t *write_ping_frame(uint8_t *p, const ngtcp2_ping *fr) {
308   (void)fr;
309 
310   /* {"frame_type":"ping"} */
311 #define NGTCP2_QLOG_PING_FRAME_OVERHEAD 21
312 
313   return write_verbatim(p, "{\"frame_type\":\"ping\"}");
314 }
315 
write_ack_frame(uint8_t * p,const ngtcp2_ack * fr)316 static uint8_t *write_ack_frame(uint8_t *p, const ngtcp2_ack *fr) {
317   int64_t largest_ack, min_ack;
318   size_t i;
319   const ngtcp2_ack_blk *blk;
320 
321   /*
322    * {"frame_type":"ack","ack_delay":0000000000000000000,"acked_ranges":[]}
323    *
324    * each range:
325    * [0000000000000000000,0000000000000000000],
326    *
327    * ecn:
328    * ,"ect1":0000000000000000000,"ect0":0000000000000000000,"ce":0000000000000000000
329    */
330 #define NGTCP2_QLOG_ACK_FRAME_BASE_OVERHEAD 70
331 #define NGTCP2_QLOG_ACK_FRAME_RANGE_OVERHEAD 42
332 #define NGTCP2_QLOG_ACK_FRAME_ECN_OVERHEAD 79
333 
334   p = write_verbatim(p, "{\"frame_type\":\"ack\",");
335   p = write_pair_duration(p, "ack_delay", fr->ack_delay_unscaled);
336   p = write_verbatim(p, ",\"acked_ranges\":[");
337 
338   largest_ack = fr->largest_ack;
339   min_ack = fr->largest_ack - (int64_t)fr->first_ack_blklen;
340 
341   *p++ = '[';
342   p = write_number(p, (uint64_t)min_ack);
343   if (largest_ack != min_ack) {
344     *p++ = ',';
345     p = write_number(p, (uint64_t)largest_ack);
346   }
347   *p++ = ']';
348 
349   for (i = 0; i < fr->num_blks; ++i) {
350     blk = &fr->blks[i];
351     largest_ack = min_ack - (int64_t)blk->gap - 2;
352     min_ack = largest_ack - (int64_t)blk->blklen;
353     *p++ = ',';
354     *p++ = '[';
355     p = write_number(p, (uint64_t)min_ack);
356     if (largest_ack != min_ack) {
357       *p++ = ',';
358       p = write_number(p, (uint64_t)largest_ack);
359     }
360     *p++ = ']';
361   }
362 
363   *p++ = ']';
364 
365   if (fr->type == NGTCP2_FRAME_ACK_ECN) {
366     *p++ = ',';
367     p = write_pair_number(p, "ect1", fr->ecn.ect1);
368     *p++ = ',';
369     p = write_pair_number(p, "ect0", fr->ecn.ect0);
370     *p++ = ',';
371     p = write_pair_number(p, "ce", fr->ecn.ce);
372   }
373 
374   *p++ = '}';
375 
376   return p;
377 }
378 
write_reset_stream_frame(uint8_t * p,const ngtcp2_reset_stream * fr)379 static uint8_t *write_reset_stream_frame(uint8_t *p,
380                                          const ngtcp2_reset_stream *fr) {
381   /*
382    * {"frame_type":"reset_stream","stream_id":0000000000000000000,"error_code":0000000000000000000,"final_size":0000000000000000000}
383    */
384 #define NGTCP2_QLOG_RESET_STREAM_FRAME_OVERHEAD 127
385 
386   p = write_verbatim(p, "{\"frame_type\":\"reset_stream\",");
387   p = write_pair_number(p, "stream_id", (uint64_t)fr->stream_id);
388   *p++ = ',';
389   p = write_pair_number(p, "error_code", fr->app_error_code);
390   *p++ = ',';
391   p = write_pair_number(p, "final_size", fr->final_size);
392   *p++ = '}';
393 
394   return p;
395 }
396 
write_stop_sending_frame(uint8_t * p,const ngtcp2_stop_sending * fr)397 static uint8_t *write_stop_sending_frame(uint8_t *p,
398                                          const ngtcp2_stop_sending *fr) {
399   /*
400    * {"frame_type":"stop_sending","stream_id":0000000000000000000,"error_code":0000000000000000000}
401    */
402 #define NGTCP2_QLOG_STOP_SENDING_FRAME_OVERHEAD 94
403 
404   p = write_verbatim(p, "{\"frame_type\":\"stop_sending\",");
405   p = write_pair_number(p, "stream_id", (uint64_t)fr->stream_id);
406   *p++ = ',';
407   p = write_pair_number(p, "error_code", fr->app_error_code);
408   *p++ = '}';
409 
410   return p;
411 }
412 
write_crypto_frame(uint8_t * p,const ngtcp2_crypto * fr)413 static uint8_t *write_crypto_frame(uint8_t *p, const ngtcp2_crypto *fr) {
414   /*
415    * {"frame_type":"crypto","offset":0000000000000000000,"length":0000000000000000000}
416    */
417 #define NGTCP2_QLOG_CRYPTO_FRAME_OVERHEAD 81
418 
419   p = write_verbatim(p, "{\"frame_type\":\"crypto\",");
420   p = write_pair_number(p, "offset", fr->offset);
421   *p++ = ',';
422   p = write_pair_number(p, "length", ngtcp2_vec_len(fr->data, fr->datacnt));
423   *p++ = '}';
424 
425   return p;
426 }
427 
write_new_token_frame(uint8_t * p,const ngtcp2_new_token * fr)428 static uint8_t *write_new_token_frame(uint8_t *p, const ngtcp2_new_token *fr) {
429   /*
430    * {"frame_type":"new_token","length":0000000000000000000,"token":{"data":""}}
431    */
432 #define NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD 75
433 
434   p = write_verbatim(p, "{\"frame_type\":\"new_token\",");
435   p = write_pair_number(p, "length", fr->token.len);
436   p = write_verbatim(p, ",\"token\":{");
437   p = write_pair_hex(p, "data", fr->token.base, fr->token.len);
438   *p++ = '}';
439   *p++ = '}';
440 
441   return p;
442 }
443 
write_stream_frame(uint8_t * p,const ngtcp2_stream * fr)444 static uint8_t *write_stream_frame(uint8_t *p, const ngtcp2_stream *fr) {
445   /*
446    * {"frame_type":"stream","stream_id":0000000000000000000,"offset":0000000000000000000,"length":0000000000000000000,"fin":true}
447    */
448 #define NGTCP2_QLOG_STREAM_FRAME_OVERHEAD 124
449 
450   p = write_verbatim(p, "{\"frame_type\":\"stream\",");
451   p = write_pair_number(p, "stream_id", (uint64_t)fr->stream_id);
452   *p++ = ',';
453   p = write_pair_number(p, "offset", fr->offset);
454   *p++ = ',';
455   p = write_pair_number(p, "length", ngtcp2_vec_len(fr->data, fr->datacnt));
456   if (fr->fin) {
457     *p++ = ',';
458     p = write_pair_bool(p, "fin", 1);
459   }
460   *p++ = '}';
461 
462   return p;
463 }
464 
write_max_data_frame(uint8_t * p,const ngtcp2_max_data * fr)465 static uint8_t *write_max_data_frame(uint8_t *p, const ngtcp2_max_data *fr) {
466   /*
467    * {"frame_type":"max_data","maximum":0000000000000000000}
468    */
469 #define NGTCP2_QLOG_MAX_DATA_FRAME_OVERHEAD 55
470 
471   p = write_verbatim(p, "{\"frame_type\":\"max_data\",");
472   p = write_pair_number(p, "maximum", fr->max_data);
473   *p++ = '}';
474 
475   return p;
476 }
477 
write_max_stream_data_frame(uint8_t * p,const ngtcp2_max_stream_data * fr)478 static uint8_t *write_max_stream_data_frame(uint8_t *p,
479                                             const ngtcp2_max_stream_data *fr) {
480   /*
481    * {"frame_type":"max_stream_data","stream_id":0000000000000000000,"maximum":0000000000000000000}
482    */
483 #define NGTCP2_QLOG_MAX_STREAM_DATA_FRAME_OVERHEAD 94
484 
485   p = write_verbatim(p, "{\"frame_type\":\"max_stream_data\",");
486   p = write_pair_number(p, "stream_id", (uint64_t)fr->stream_id);
487   *p++ = ',';
488   p = write_pair_number(p, "maximum", fr->max_stream_data);
489   *p++ = '}';
490 
491   return p;
492 }
493 
write_max_streams_frame(uint8_t * p,const ngtcp2_max_streams * fr)494 static uint8_t *write_max_streams_frame(uint8_t *p,
495                                         const ngtcp2_max_streams *fr) {
496   /*
497    * {"frame_type":"max_streams","stream_type":"unidirectional","maximum":0000000000000000000}
498    */
499 #define NGTCP2_QLOG_MAX_STREAMS_FRAME_OVERHEAD 89
500 
501   p = write_verbatim(p, "{\"frame_type\":\"max_streams\",\"stream_type\":");
502   if (fr->type == NGTCP2_FRAME_MAX_STREAMS_BIDI) {
503     p = write_string(p, "bidirectional");
504   } else {
505     p = write_string(p, "unidirectional");
506   }
507   *p++ = ',';
508   p = write_pair_number(p, "maximum", fr->max_streams);
509   *p++ = '}';
510 
511   return p;
512 }
513 
write_data_blocked_frame(uint8_t * p,const ngtcp2_data_blocked * fr)514 static uint8_t *write_data_blocked_frame(uint8_t *p,
515                                          const ngtcp2_data_blocked *fr) {
516   (void)fr;
517 
518   /*
519    * {"frame_type":"data_blocked"}
520    */
521 #define NGTCP2_QLOG_DATA_BLOCKED_FRAME_OVERHEAD 29
522 
523   /* TODO log limit */
524 
525   return write_verbatim(p, "{\"frame_type\":\"data_blocked\"}");
526 }
527 
528 static uint8_t *
write_stream_data_blocked_frame(uint8_t * p,const ngtcp2_stream_data_blocked * fr)529 write_stream_data_blocked_frame(uint8_t *p,
530                                 const ngtcp2_stream_data_blocked *fr) {
531   (void)fr;
532 
533   /*
534    * {"frame_type":"stream_data_blocked"}
535    */
536 #define NGTCP2_QLOG_STREAM_DATA_BLOCKED_FRAME_OVERHEAD 36
537 
538   /* TODO log limit */
539 
540   return write_verbatim(p, "{\"frame_type\":\"stream_data_blocked\"}");
541 }
542 
write_streams_blocked_frame(uint8_t * p,const ngtcp2_streams_blocked * fr)543 static uint8_t *write_streams_blocked_frame(uint8_t *p,
544                                             const ngtcp2_streams_blocked *fr) {
545   (void)fr;
546 
547   /*
548    * {"frame_type":"streams_blocked"}
549    */
550 #define NGTCP2_QLOG_STREAMS_BLOCKED_FRAME_OVERHEAD 32
551 
552   /* TODO Log stream_type and limit */
553 
554   return write_verbatim(p, "{\"frame_type\":\"streams_blocked\"}");
555 }
556 
557 static uint8_t *
write_new_connection_id_frame(uint8_t * p,const ngtcp2_new_connection_id * fr)558 write_new_connection_id_frame(uint8_t *p, const ngtcp2_new_connection_id *fr) {
559   /*
560    * {"frame_type":"new_connection_id","sequence_number":0000000000000000000,"retire_prior_to":0000000000000000000,"connection_id_length":0000000000000000000,"connection_id":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","stateless_reset_token":{"data":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}}
561    */
562 #define NGTCP2_QLOG_NEW_CONNECTION_ID_FRAME_OVERHEAD 280
563 
564   p = write_verbatim(p, "{\"frame_type\":\"new_connection_id\",");
565   p = write_pair_number(p, "sequence_number", fr->seq);
566   *p++ = ',';
567   p = write_pair_number(p, "retire_prior_to", fr->retire_prior_to);
568   *p++ = ',';
569   p = write_pair_number(p, "connection_id_length", fr->cid.datalen);
570   *p++ = ',';
571   p = write_pair_cid(p, "connection_id", &fr->cid);
572   p = write_verbatim(p, ",\"stateless_reset_token\":{");
573   p = write_pair_hex(p, "data", fr->stateless_reset_token,
574                      sizeof(fr->stateless_reset_token));
575   *p++ = '}';
576   *p++ = '}';
577 
578   return p;
579 }
580 
581 static uint8_t *
write_retire_connection_id_frame(uint8_t * p,const ngtcp2_retire_connection_id * fr)582 write_retire_connection_id_frame(uint8_t *p,
583                                  const ngtcp2_retire_connection_id *fr) {
584   /*
585    * {"frame_type":"retire_connection_id","sequence_number":0000000000000000000}
586    */
587 #define NGTCP2_QLOG_RETIRE_CONNECTION_ID_FRAME_OVERHEAD 75
588 
589   p = write_verbatim(p, "{\"frame_type\":\"retire_connection_id\",");
590   p = write_pair_number(p, "sequence_number", fr->seq);
591   *p++ = '}';
592 
593   return p;
594 }
595 
write_path_challenge_frame(uint8_t * p,const ngtcp2_path_challenge * fr)596 static uint8_t *write_path_challenge_frame(uint8_t *p,
597                                            const ngtcp2_path_challenge *fr) {
598   /*
599    * {"frame_type":"path_challenge","data":"xxxxxxxxxxxxxxxx"}
600    */
601 #define NGTCP2_QLOG_PATH_CHALLENGE_FRAME_OVERHEAD 57
602 
603   p = write_verbatim(p, "{\"frame_type\":\"path_challenge\",");
604   p = write_pair_hex(p, "data", fr->data, sizeof(fr->data));
605   *p++ = '}';
606 
607   return p;
608 }
609 
write_path_response_frame(uint8_t * p,const ngtcp2_path_response * fr)610 static uint8_t *write_path_response_frame(uint8_t *p,
611                                           const ngtcp2_path_response *fr) {
612   /*
613    * {"frame_type":"path_response","data":"xxxxxxxxxxxxxxxx"}
614    */
615 #define NGTCP2_QLOG_PATH_RESPONSE_FRAME_OVERHEAD 56
616 
617   p = write_verbatim(p, "{\"frame_type\":\"path_response\",");
618   p = write_pair_hex(p, "data", fr->data, sizeof(fr->data));
619   *p++ = '}';
620 
621   return p;
622 }
623 
624 static uint8_t *
write_connection_close_frame(uint8_t * p,const ngtcp2_connection_close * fr)625 write_connection_close_frame(uint8_t *p, const ngtcp2_connection_close *fr) {
626   /*
627    * {"frame_type":"connection_close","error_space":"application","error_code":0000000000000000000,"raw_error_code":0000000000000000000}
628    */
629 #define NGTCP2_QLOG_CONNECTION_CLOSE_FRAME_OVERHEAD 131
630 
631   p = write_verbatim(p,
632                      "{\"frame_type\":\"connection_close\",\"error_space\":");
633   if (fr->type == NGTCP2_FRAME_CONNECTION_CLOSE) {
634     p = write_string(p, "transport");
635   } else {
636     p = write_string(p, "application");
637   }
638   *p++ = ',';
639   p = write_pair_number(p, "error_code", fr->error_code);
640   *p++ = ',';
641   p = write_pair_number(p, "raw_error_code", fr->error_code);
642   /* TODO Write reason by escaping non-printables */
643   /* TODO Write trigger_frame_type */
644   *p++ = '}';
645 
646   return p;
647 }
648 
write_handshake_done_frame(uint8_t * p,const ngtcp2_handshake_done * fr)649 static uint8_t *write_handshake_done_frame(uint8_t *p,
650                                            const ngtcp2_handshake_done *fr) {
651   (void)fr;
652 
653   /*
654    * {"frame_type":"handshake_done"}
655    */
656 #define NGTCP2_QLOG_HANDSHAKE_DONE_FRAME_OVERHEAD 31
657 
658   return write_verbatim(p, "{\"frame_type\":\"handshake_done\"}");
659 }
660 
write_datagram_frame(uint8_t * p,const ngtcp2_datagram * fr)661 static uint8_t *write_datagram_frame(uint8_t *p, const ngtcp2_datagram *fr) {
662   /*
663    * {"frame_type":"datagram","length":0000000000000000000}
664    */
665 #define NGTCP2_QLOG_DATAGRAM_FRAME_OVERHEAD 54
666 
667   p = write_verbatim(p, "{\"frame_type\":\"datagram\",");
668   p = write_pair_number(p, "length", ngtcp2_vec_len(fr->data, fr->datacnt));
669   *p++ = '}';
670 
671   return p;
672 }
673 
qlog_write_time(ngtcp2_qlog * qlog,uint8_t * p)674 static uint8_t *qlog_write_time(ngtcp2_qlog *qlog, uint8_t *p) {
675   return write_pair_tstamp(p, "time", qlog->last_ts - qlog->ts);
676 }
677 
qlog_pkt_write_start(ngtcp2_qlog * qlog,int sent)678 static void qlog_pkt_write_start(ngtcp2_qlog *qlog, int sent) {
679   uint8_t *p;
680 
681   if (!qlog->write) {
682     return;
683   }
684 
685   ngtcp2_buf_reset(&qlog->buf);
686   p = qlog->buf.last;
687 
688   *p++ = '\x1e';
689   *p++ = '{';
690   p = qlog_write_time(qlog, p);
691   p = write_verbatim(p, ",\"name\":");
692   if (sent) {
693     p = write_string(p, "transport:packet_sent");
694   } else {
695     p = write_string(p, "transport:packet_received");
696   }
697   p = write_verbatim(p, ",\"data\":{\"frames\":[");
698   qlog->buf.last = p;
699 }
700 
qlog_pkt_write_end(ngtcp2_qlog * qlog,const ngtcp2_pkt_hd * hd,size_t pktlen)701 static void qlog_pkt_write_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
702                                size_t pktlen) {
703   uint8_t *p = qlog->buf.last;
704 
705   if (!qlog->write) {
706     return;
707   }
708 
709   /*
710    * ],"header":,"raw":{"length":0000000000000000000}}}
711    *
712    * plus, terminating LF
713    */
714 #define NGTCP2_QLOG_PKT_WRITE_END_OVERHEAD                                     \
715   (1 + 50 + NGTCP2_QLOG_PKT_HD_OVERHEAD)
716 
717   if (ngtcp2_buf_left(&qlog->buf) <
718       NGTCP2_QLOG_PKT_WRITE_END_OVERHEAD + hd->token.len * 2) {
719     return;
720   }
721 
722   assert(ngtcp2_buf_len(&qlog->buf));
723 
724   /* Eat last ',' */
725   if (*(p - 1) == ',') {
726     --p;
727   }
728 
729   p = write_verbatim(p, "],\"header\":");
730   p = write_pkt_hd(p, hd);
731   p = write_verbatim(p, ",\"raw\":{\"length\":");
732   p = write_number(p, pktlen);
733   p = write_verbatim(p, "}}}\n");
734 
735   qlog->buf.last = p;
736 
737   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, qlog->buf.pos,
738               ngtcp2_buf_len(&qlog->buf));
739 }
740 
ngtcp2_qlog_write_frame(ngtcp2_qlog * qlog,const ngtcp2_frame * fr)741 void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) {
742   uint8_t *p = qlog->buf.last;
743 
744   if (!qlog->write) {
745     return;
746   }
747 
748   switch (fr->type) {
749   case NGTCP2_FRAME_PADDING:
750     if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_PADDING_FRAME_OVERHEAD + 1) {
751       return;
752     }
753     p = write_padding_frame(p, &fr->padding);
754     break;
755   case NGTCP2_FRAME_PING:
756     if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_PING_FRAME_OVERHEAD + 1) {
757       return;
758     }
759     p = write_ping_frame(p, &fr->ping);
760     break;
761   case NGTCP2_FRAME_ACK:
762   case NGTCP2_FRAME_ACK_ECN:
763     if (ngtcp2_buf_left(&qlog->buf) <
764         NGTCP2_QLOG_ACK_FRAME_BASE_OVERHEAD +
765             (size_t)(fr->type == NGTCP2_FRAME_ACK_ECN
766                          ? NGTCP2_QLOG_ACK_FRAME_ECN_OVERHEAD
767                          : 0) +
768             NGTCP2_QLOG_ACK_FRAME_RANGE_OVERHEAD * (1 + fr->ack.num_blks) + 1) {
769       return;
770     }
771     p = write_ack_frame(p, &fr->ack);
772     break;
773   case NGTCP2_FRAME_RESET_STREAM:
774     if (ngtcp2_buf_left(&qlog->buf) <
775         NGTCP2_QLOG_RESET_STREAM_FRAME_OVERHEAD + 1) {
776       return;
777     }
778     p = write_reset_stream_frame(p, &fr->reset_stream);
779     break;
780   case NGTCP2_FRAME_STOP_SENDING:
781     if (ngtcp2_buf_left(&qlog->buf) <
782         NGTCP2_QLOG_STOP_SENDING_FRAME_OVERHEAD + 1) {
783       return;
784     }
785     p = write_stop_sending_frame(p, &fr->stop_sending);
786     break;
787   case NGTCP2_FRAME_CRYPTO:
788     if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_CRYPTO_FRAME_OVERHEAD + 1) {
789       return;
790     }
791     p = write_crypto_frame(p, &fr->crypto);
792     break;
793   case NGTCP2_FRAME_NEW_TOKEN:
794     if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD +
795                                           fr->new_token.token.len * 2 + 1) {
796       return;
797     }
798     p = write_new_token_frame(p, &fr->new_token);
799     break;
800   case NGTCP2_FRAME_STREAM:
801     if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_STREAM_FRAME_OVERHEAD + 1) {
802       return;
803     }
804     p = write_stream_frame(p, &fr->stream);
805     break;
806   case NGTCP2_FRAME_MAX_DATA:
807     if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_MAX_DATA_FRAME_OVERHEAD + 1) {
808       return;
809     }
810     p = write_max_data_frame(p, &fr->max_data);
811     break;
812   case NGTCP2_FRAME_MAX_STREAM_DATA:
813     if (ngtcp2_buf_left(&qlog->buf) <
814         NGTCP2_QLOG_MAX_STREAM_DATA_FRAME_OVERHEAD + 1) {
815       return;
816     }
817     p = write_max_stream_data_frame(p, &fr->max_stream_data);
818     break;
819   case NGTCP2_FRAME_MAX_STREAMS_BIDI:
820   case NGTCP2_FRAME_MAX_STREAMS_UNI:
821     if (ngtcp2_buf_left(&qlog->buf) <
822         NGTCP2_QLOG_MAX_STREAMS_FRAME_OVERHEAD + 1) {
823       return;
824     }
825     p = write_max_streams_frame(p, &fr->max_streams);
826     break;
827   case NGTCP2_FRAME_DATA_BLOCKED:
828     if (ngtcp2_buf_left(&qlog->buf) <
829         NGTCP2_QLOG_DATA_BLOCKED_FRAME_OVERHEAD + 1) {
830       return;
831     }
832     p = write_data_blocked_frame(p, &fr->data_blocked);
833     break;
834   case NGTCP2_FRAME_STREAM_DATA_BLOCKED:
835     if (ngtcp2_buf_left(&qlog->buf) <
836         NGTCP2_QLOG_STREAM_DATA_BLOCKED_FRAME_OVERHEAD + 1) {
837       return;
838     }
839     p = write_stream_data_blocked_frame(p, &fr->stream_data_blocked);
840     break;
841   case NGTCP2_FRAME_STREAMS_BLOCKED_BIDI:
842   case NGTCP2_FRAME_STREAMS_BLOCKED_UNI:
843     if (ngtcp2_buf_left(&qlog->buf) <
844         NGTCP2_QLOG_STREAMS_BLOCKED_FRAME_OVERHEAD + 1) {
845       return;
846     }
847     p = write_streams_blocked_frame(p, &fr->streams_blocked);
848     break;
849   case NGTCP2_FRAME_NEW_CONNECTION_ID:
850     if (ngtcp2_buf_left(&qlog->buf) <
851         NGTCP2_QLOG_NEW_CONNECTION_ID_FRAME_OVERHEAD + 1) {
852       return;
853     }
854     p = write_new_connection_id_frame(p, &fr->new_connection_id);
855     break;
856   case NGTCP2_FRAME_RETIRE_CONNECTION_ID:
857     if (ngtcp2_buf_left(&qlog->buf) <
858         NGTCP2_QLOG_RETIRE_CONNECTION_ID_FRAME_OVERHEAD + 1) {
859       return;
860     }
861     p = write_retire_connection_id_frame(p, &fr->retire_connection_id);
862     break;
863   case NGTCP2_FRAME_PATH_CHALLENGE:
864     if (ngtcp2_buf_left(&qlog->buf) <
865         NGTCP2_QLOG_PATH_CHALLENGE_FRAME_OVERHEAD + 1) {
866       return;
867     }
868     p = write_path_challenge_frame(p, &fr->path_challenge);
869     break;
870   case NGTCP2_FRAME_PATH_RESPONSE:
871     if (ngtcp2_buf_left(&qlog->buf) <
872         NGTCP2_QLOG_PATH_RESPONSE_FRAME_OVERHEAD + 1) {
873       return;
874     }
875     p = write_path_response_frame(p, &fr->path_response);
876     break;
877   case NGTCP2_FRAME_CONNECTION_CLOSE:
878   case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
879     if (ngtcp2_buf_left(&qlog->buf) <
880         NGTCP2_QLOG_CONNECTION_CLOSE_FRAME_OVERHEAD + 1) {
881       return;
882     }
883     p = write_connection_close_frame(p, &fr->connection_close);
884     break;
885   case NGTCP2_FRAME_HANDSHAKE_DONE:
886     if (ngtcp2_buf_left(&qlog->buf) <
887         NGTCP2_QLOG_HANDSHAKE_DONE_FRAME_OVERHEAD + 1) {
888       return;
889     }
890     p = write_handshake_done_frame(p, &fr->handshake_done);
891     break;
892   case NGTCP2_FRAME_DATAGRAM:
893   case NGTCP2_FRAME_DATAGRAM_LEN:
894     if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_DATAGRAM_FRAME_OVERHEAD + 1) {
895       return;
896     }
897     p = write_datagram_frame(p, &fr->datagram);
898     break;
899   default:
900     assert(0);
901   }
902 
903   *p++ = ',';
904 
905   qlog->buf.last = p;
906 }
907 
ngtcp2_qlog_pkt_received_start(ngtcp2_qlog * qlog)908 void ngtcp2_qlog_pkt_received_start(ngtcp2_qlog *qlog) {
909   qlog_pkt_write_start(qlog, /* sent = */ 0);
910 }
911 
ngtcp2_qlog_pkt_received_end(ngtcp2_qlog * qlog,const ngtcp2_pkt_hd * hd,size_t pktlen)912 void ngtcp2_qlog_pkt_received_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
913                                   size_t pktlen) {
914   qlog_pkt_write_end(qlog, hd, pktlen);
915 }
916 
ngtcp2_qlog_pkt_sent_start(ngtcp2_qlog * qlog)917 void ngtcp2_qlog_pkt_sent_start(ngtcp2_qlog *qlog) {
918   qlog_pkt_write_start(qlog, /* sent = */ 1);
919 }
920 
ngtcp2_qlog_pkt_sent_end(ngtcp2_qlog * qlog,const ngtcp2_pkt_hd * hd,size_t pktlen)921 void ngtcp2_qlog_pkt_sent_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
922                               size_t pktlen) {
923   qlog_pkt_write_end(qlog, hd, pktlen);
924 }
925 
ngtcp2_qlog_parameters_set_transport_params(ngtcp2_qlog * qlog,const ngtcp2_transport_params * params,int server,ngtcp2_qlog_side side)926 void ngtcp2_qlog_parameters_set_transport_params(
927     ngtcp2_qlog *qlog, const ngtcp2_transport_params *params, int server,
928     ngtcp2_qlog_side side) {
929   uint8_t buf[1024];
930   uint8_t *p = buf;
931   const ngtcp2_preferred_addr *paddr;
932 
933   if (!qlog->write) {
934     return;
935   }
936 
937   *p++ = '\x1e';
938   *p++ = '{';
939   p = qlog_write_time(qlog, p);
940   p = write_verbatim(
941       p, ",\"name\":\"transport:parameters_set\",\"data\":{\"owner\":");
942 
943   if (side == NGTCP2_QLOG_SIDE_LOCAL) {
944     p = write_string(p, "local");
945   } else {
946     p = write_string(p, "remote");
947   }
948 
949   *p++ = ',';
950   p = write_pair_cid(p, "initial_source_connection_id", &params->initial_scid);
951   *p++ = ',';
952   if (side == (server ? NGTCP2_QLOG_SIDE_LOCAL : NGTCP2_QLOG_SIDE_REMOTE)) {
953     p = write_pair_cid(p, "original_destination_connection_id",
954                        &params->original_dcid);
955     *p++ = ',';
956   }
957   if (params->retry_scid_present) {
958     p = write_pair_cid(p, "retry_source_connection_id", &params->retry_scid);
959     *p++ = ',';
960   }
961   if (params->stateless_reset_token_present) {
962     p = write_verbatim(p, "\"stateless_reset_token\":{");
963     p = write_pair_hex(p, "data", params->stateless_reset_token,
964                        sizeof(params->stateless_reset_token));
965     *p++ = '}';
966     *p++ = ',';
967   }
968   p = write_pair_bool(p, "disable_active_migration",
969                       params->disable_active_migration);
970   *p++ = ',';
971   p = write_pair_duration(p, "max_idle_timeout", params->max_idle_timeout);
972   *p++ = ',';
973   p = write_pair_number(p, "max_udp_payload_size",
974                         params->max_udp_payload_size);
975   *p++ = ',';
976   p = write_pair_number(p, "ack_delay_exponent", params->ack_delay_exponent);
977   *p++ = ',';
978   p = write_pair_duration(p, "max_ack_delay", params->max_ack_delay);
979   *p++ = ',';
980   p = write_pair_number(p, "active_connection_id_limit",
981                         params->active_connection_id_limit);
982   *p++ = ',';
983   p = write_pair_number(p, "initial_max_data", params->initial_max_data);
984   *p++ = ',';
985   p = write_pair_number(p, "initial_max_stream_data_bidi_local",
986                         params->initial_max_stream_data_bidi_local);
987   *p++ = ',';
988   p = write_pair_number(p, "initial_max_stream_data_bidi_remote",
989                         params->initial_max_stream_data_bidi_remote);
990   *p++ = ',';
991   p = write_pair_number(p, "initial_max_stream_data_uni",
992                         params->initial_max_stream_data_uni);
993   *p++ = ',';
994   p = write_pair_number(p, "initial_max_streams_bidi",
995                         params->initial_max_streams_bidi);
996   *p++ = ',';
997   p = write_pair_number(p, "initial_max_streams_uni",
998                         params->initial_max_streams_uni);
999   if (params->preferred_address_present) {
1000     *p++ = ',';
1001     paddr = &params->preferred_address;
1002     p = write_string(p, "preferred_address");
1003     *p++ = ':';
1004     *p++ = '{';
1005     p = write_pair_hex(p, "ip_v4", paddr->ipv4_addr, sizeof(paddr->ipv4_addr));
1006     *p++ = ',';
1007     p = write_pair_number(p, "port_v4", paddr->ipv4_port);
1008     *p++ = ',';
1009     p = write_pair_hex(p, "ip_v6", paddr->ipv6_addr, sizeof(paddr->ipv6_addr));
1010     *p++ = ',';
1011     p = write_pair_number(p, "port_v6", paddr->ipv6_port);
1012     *p++ = ',';
1013     p = write_pair_cid(p, "connection_id", &paddr->cid);
1014     p = write_verbatim(p, ",\"stateless_reset_token\":{");
1015     p = write_pair_hex(p, "data", paddr->stateless_reset_token,
1016                        sizeof(paddr->stateless_reset_token));
1017     *p++ = '}';
1018     *p++ = '}';
1019   }
1020   *p++ = ',';
1021   p = write_pair_number(p, "max_datagram_frame_size",
1022                         params->max_datagram_frame_size);
1023   *p++ = ',';
1024   p = write_pair_bool(p, "grease_quic_bit", params->grease_quic_bit);
1025   p = write_verbatim(p, "}}\n");
1026 
1027   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
1028               (size_t)(p - buf));
1029 }
1030 
ngtcp2_qlog_metrics_updated(ngtcp2_qlog * qlog,const ngtcp2_conn_stat * cstat)1031 void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog,
1032                                  const ngtcp2_conn_stat *cstat) {
1033   uint8_t buf[1024];
1034   uint8_t *p = buf;
1035 
1036   if (!qlog->write) {
1037     return;
1038   }
1039 
1040   *p++ = '\x1e';
1041   *p++ = '{';
1042   p = qlog_write_time(qlog, p);
1043   p = write_verbatim(p, ",\"name\":\"recovery:metrics_updated\",\"data\":{");
1044 
1045   if (cstat->min_rtt != UINT64_MAX) {
1046     p = write_pair_duration(p, "min_rtt", cstat->min_rtt);
1047     *p++ = ',';
1048   }
1049   p = write_pair_duration(p, "smoothed_rtt", cstat->smoothed_rtt);
1050   *p++ = ',';
1051   p = write_pair_duration(p, "latest_rtt", cstat->latest_rtt);
1052   *p++ = ',';
1053   p = write_pair_duration(p, "rtt_variance", cstat->rttvar);
1054   *p++ = ',';
1055   p = write_pair_number(p, "pto_count", cstat->pto_count);
1056   *p++ = ',';
1057   p = write_pair_number(p, "congestion_window", cstat->cwnd);
1058   *p++ = ',';
1059   p = write_pair_number(p, "bytes_in_flight", cstat->bytes_in_flight);
1060   if (cstat->ssthresh != UINT64_MAX) {
1061     *p++ = ',';
1062     p = write_pair_number(p, "ssthresh", cstat->ssthresh);
1063   }
1064 
1065   p = write_verbatim(p, "}}\n");
1066 
1067   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
1068               (size_t)(p - buf));
1069 }
1070 
ngtcp2_qlog_pkt_lost(ngtcp2_qlog * qlog,ngtcp2_rtb_entry * ent)1071 void ngtcp2_qlog_pkt_lost(ngtcp2_qlog *qlog, ngtcp2_rtb_entry *ent) {
1072   uint8_t buf[256];
1073   uint8_t *p = buf;
1074   ngtcp2_pkt_hd hd = {0};
1075 
1076   if (!qlog->write) {
1077     return;
1078   }
1079 
1080   *p++ = '\x1e';
1081   *p++ = '{';
1082   p = qlog_write_time(qlog, p);
1083   p = write_verbatim(
1084       p, ",\"name\":\"recovery:packet_lost\",\"data\":{\"header\":");
1085 
1086   hd.type = ent->hd.type;
1087   hd.flags = ent->hd.flags;
1088   hd.pkt_num = ent->hd.pkt_num;
1089 
1090   p = write_pkt_hd(p, &hd);
1091   p = write_verbatim(p, "}}\n");
1092 
1093   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
1094               (size_t)(p - buf));
1095 }
1096 
ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog * qlog,const ngtcp2_pkt_hd * hd,const ngtcp2_pkt_retry * retry)1097 void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
1098                                     const ngtcp2_pkt_retry *retry) {
1099   uint8_t rawbuf[1024];
1100   ngtcp2_buf buf;
1101 
1102   if (!qlog->write) {
1103     return;
1104   }
1105 
1106   ngtcp2_buf_init(&buf, rawbuf, sizeof(rawbuf));
1107 
1108   *buf.last++ = '\x1e';
1109   *buf.last++ = '{';
1110   buf.last = qlog_write_time(qlog, buf.last);
1111   buf.last = write_verbatim(
1112       buf.last,
1113       ",\"name\":\"transport:packet_received\",\"data\":{\"header\":");
1114 
1115   if (ngtcp2_buf_left(&buf) <
1116       NGTCP2_QLOG_PKT_HD_OVERHEAD + hd->token.len * 2 +
1117           sizeof(",\"retry_token\":{\"data\":\"\"}}}\n") - 1 +
1118           retry->token.len * 2) {
1119     return;
1120   }
1121 
1122   buf.last = write_pkt_hd(buf.last, hd);
1123   buf.last = write_verbatim(buf.last, ",\"retry_token\":{");
1124   buf.last =
1125       write_pair_hex(buf.last, "data", retry->token.base, retry->token.len);
1126   buf.last = write_verbatim(buf.last, "}}}\n");
1127 
1128   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf.pos,
1129               ngtcp2_buf_len(&buf));
1130 }
1131 
ngtcp2_qlog_stateless_reset_pkt_received(ngtcp2_qlog * qlog,const ngtcp2_pkt_stateless_reset * sr)1132 void ngtcp2_qlog_stateless_reset_pkt_received(
1133     ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset *sr) {
1134   uint8_t buf[256];
1135   uint8_t *p = buf;
1136   ngtcp2_pkt_hd hd = {0};
1137 
1138   if (!qlog->write) {
1139     return;
1140   }
1141 
1142   hd.type = NGTCP2_PKT_STATELESS_RESET;
1143 
1144   *p++ = '\x1e';
1145   *p++ = '{';
1146   p = qlog_write_time(qlog, p);
1147   p = write_verbatim(
1148       p, ",\"name\":\"transport:packet_received\",\"data\":{\"header\":");
1149   p = write_pkt_hd(p, &hd);
1150   *p++ = ',';
1151   p = write_pair_hex(p, "stateless_reset_token", sr->stateless_reset_token,
1152                      NGTCP2_STATELESS_RESET_TOKENLEN);
1153   p = write_verbatim(p, "}}\n");
1154 
1155   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
1156               (size_t)(p - buf));
1157 }
1158 
ngtcp2_qlog_version_negotiation_pkt_received(ngtcp2_qlog * qlog,const ngtcp2_pkt_hd * hd,const uint32_t * sv,size_t nsv)1159 void ngtcp2_qlog_version_negotiation_pkt_received(ngtcp2_qlog *qlog,
1160                                                   const ngtcp2_pkt_hd *hd,
1161                                                   const uint32_t *sv,
1162                                                   size_t nsv) {
1163   uint8_t rawbuf[512];
1164   ngtcp2_buf buf;
1165   size_t i;
1166   uint32_t v;
1167 
1168   if (!qlog->write) {
1169     return;
1170   }
1171 
1172   ngtcp2_buf_init(&buf, rawbuf, sizeof(rawbuf));
1173 
1174   *buf.last++ = '\x1e';
1175   *buf.last++ = '{';
1176   buf.last = qlog_write_time(qlog, buf.last);
1177   buf.last = write_verbatim(
1178       buf.last,
1179       ",\"name\":\"transport:packet_received\",\"data\":{\"header\":");
1180   buf.last = write_pkt_hd(buf.last, hd);
1181   buf.last = write_verbatim(buf.last, ",\"supported_versions\":[");
1182 
1183   if (nsv) {
1184     if (ngtcp2_buf_left(&buf) <
1185         (sizeof("\"xxxxxxxx\",") - 1) * nsv - 1 + sizeof("]}}\n") - 1) {
1186       return;
1187     }
1188 
1189     v = ngtcp2_htonl(sv[0]);
1190     buf.last = write_hex(buf.last, (const uint8_t *)&v, sizeof(v));
1191 
1192     for (i = 1; i < nsv; ++i) {
1193       *buf.last++ = ',';
1194       v = ngtcp2_htonl(sv[i]);
1195       buf.last = write_hex(buf.last, (const uint8_t *)&v, sizeof(v));
1196     }
1197   }
1198 
1199   buf.last = write_verbatim(buf.last, "]}}\n");
1200 
1201   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf.pos,
1202               ngtcp2_buf_len(&buf));
1203 }
1204