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