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