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", ¶ms->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 ¶ms->original_dcid);
956 *p++ = ',';
957 }
958 if (params->retry_scid_present) {
959 p = write_pair_cid(p, "retry_source_connection_id", ¶ms->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 = ¶ms->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