Line data Source code
1 : #pragma GCC diagnostic ignored "-Wtype-limits"
2 :
3 : #include "templ/fd_quic_pretty_print.h"
4 : #include "templ/fd_quic_templ.h"
5 : #include "templ/fd_quic_frames_templ.h"
6 : #include "templ/fd_quic_undefs.h"
7 : #include "fd_quic_private.h"
8 : #include "fd_quic_pretty_print.h"
9 :
10 : /* Generate frame pretty-print */
11 :
12 : #define FD_TEMPL_DEF_STRUCT_BEGIN(NAME) \
13 : static ulong fd_quic_pretty_print_frame_##NAME( \
14 : fd_quic_##NAME##_t * frame, \
15 : char ** out_buf, \
16 : ulong * out_buf_sz, \
17 : uchar const * const buf, \
18 : ulong const buf_sz \
19 0 : ) { \
20 0 : uchar const * p0 = buf; \
21 0 : uchar const * const p1 = buf+buf_sz; \
22 0 : ulong rc; \
23 0 : \
24 0 : rc = fd_quic_decode_##NAME( frame, p0, (ulong)(p1-p0) ); \
25 0 : if( FD_UNLIKELY( rc==FD_QUIC_PARSE_FAIL ) ) return FD_QUIC_PARSE_FAIL; \
26 0 : p0 += rc; \
27 0 : \
28 0 : fd_quic_pretty_print_struct_##NAME( out_buf, out_buf_sz, frame ); \
29 0 : \
30 0 : return (ulong)(p0-buf); \
31 0 : }
32 : #include "templ/fd_quic_dft.h"
33 : #include "templ/fd_quic_frames_templ.h"
34 : #include "templ/fd_quic_undefs.h"
35 :
36 : #include "templ/fd_quic_frame.h"
37 :
38 :
39 : #define safe_snprintf( out, sz, ... ) \
40 0 : (__extension__({ \
41 0 : int rtn = snprintf( (out), (sz), __VA_ARGS__ ); \
42 0 : if( rtn < 0 ) rtn = 0; \
43 0 : if( rtn > (int)(sz) ) rtn = (int)(sz); \
44 0 : (ulong)rtn; }))
45 :
46 : ulong
47 : fd_quic_pretty_print_frame( char ** out_buf,
48 : ulong * out_buf_sz,
49 : uchar const * buf,
50 0 : ulong buf_sz ) {
51 0 : if( FD_UNLIKELY( buf_sz<1UL ) ) return FD_QUIC_PARSE_FAIL;
52 :
53 0 : uchar const * cur_buf = buf;
54 0 : uchar const * buf_end = buf + buf_sz;
55 :
56 0 : if( cur_buf[0] == 0x00 ) { /* handle padding separately */
57 0 : ulong padding_cnt = 0;
58 0 : while( cur_buf < buf_end && *cur_buf == 0x00 ) {
59 0 : padding_cnt++;
60 0 : cur_buf++;
61 0 : }
62 :
63 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"frame_type\": \"0-padding\", \"count\": %lu, ", padding_cnt );
64 0 : *out_buf += sz;
65 0 : *out_buf_sz -= sz;
66 :
67 0 : if( FD_UNLIKELY( cur_buf == buf_end ) ) return (ulong)( cur_buf - buf );
68 0 : }
69 :
70 : /* Frame ID is technically a varint but it's sufficient to look at the
71 : first byte. */
72 0 : uint id = cur_buf[0];
73 0 : if( FD_UNLIKELY( id >= FD_QUIC_FRAME_TYPE_CNT ) ) {
74 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"frame_type\": \"%x-unknown\", ...", (uint)id );
75 0 : *out_buf += sz;
76 0 : *out_buf_sz -= sz;
77 :
78 0 : return FD_QUIC_PARSE_FAIL;
79 0 : }
80 :
81 0 : ulong consumed = 0UL;
82 :
83 0 : union {
84 0 : #define FD_TEMPL_DEF_STRUCT_BEGIN(NAME) fd_quic_##NAME##_t NAME;
85 0 : #include "templ/fd_quic_dft.h"
86 0 : #include "templ/fd_quic_frames_templ.h"
87 0 : #include "templ/fd_quic_undefs.h"
88 0 : } data;
89 :
90 0 : memset( &data, 0, sizeof( data ) );
91 :
92 : /* tail call to frame handler */
93 0 : switch( id ) {
94 :
95 0 : # define F(T,MID,NAME,...) \
96 0 : case T: { \
97 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"frame_type\": \"%u\", ", (uint)id ); \
98 0 : *out_buf += sz; \
99 0 : *out_buf_sz -= sz; \
100 0 : consumed = fd_quic_pretty_print_frame_##NAME##_frame( &data.NAME##_frame, out_buf, out_buf_sz, cur_buf, (ulong)( buf_end - cur_buf ) ); \
101 0 : break; \
102 0 : }
103 0 : FD_QUIC_FRAME_TYPES(F)
104 0 : # undef F
105 :
106 0 : default:
107 : /* we're unable to consume more bytes, since this is invalid */
108 : /* TODO put error key in json */
109 0 : return FD_QUIC_PARSE_FAIL;
110 0 : }
111 :
112 0 : if( consumed == FD_QUIC_PARSE_FAIL ) return FD_QUIC_PARSE_FAIL;
113 :
114 : /* handle repeating blocks, etc. */
115 0 : cur_buf += consumed;
116 :
117 0 : switch( id ) {
118 0 : case 0x02:
119 0 : case 0x03:
120 0 : {
121 0 : ulong ack_range_count = data.ack_frame.ack_range_count;
122 :
123 : /* skip ack ranges */
124 0 : for( ulong j = 0UL; j < ack_range_count; ++j ) {
125 0 : fd_quic_ack_range_frag_t ack_range[1];
126 0 : ulong rc = fd_quic_decode_ack_range_frag( ack_range, cur_buf, (ulong)( buf_end - cur_buf ) );
127 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
128 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"parse-ack-ranges\"" );
129 0 : *out_buf += out_sz;
130 0 : *out_buf_sz -= out_sz;
131 0 : return FD_QUIC_PARSE_FAIL;
132 0 : }
133 :
134 0 : fd_quic_pretty_print_struct_ack_range_frag( out_buf, out_buf_sz, ack_range );
135 0 : }
136 :
137 0 : if( data.ack_frame.type & 1U ) {
138 0 : fd_quic_ecn_counts_frag_t ecn_counts[1] = {0};
139 0 : ulong rc = fd_quic_decode_ecn_counts_frag( ecn_counts, cur_buf, (ulong)( buf_end - cur_buf ) );
140 0 : if( rc == FD_QUIC_PARSE_FAIL ) {
141 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"parse-ecn-counts\"" );
142 0 : *out_buf += out_sz;
143 0 : *out_buf_sz -= out_sz;
144 0 : return FD_QUIC_PARSE_FAIL;
145 0 : }
146 :
147 0 : cur_buf += rc;
148 0 : }
149 :
150 0 : break;
151 0 : }
152 :
153 0 : case 0x06:
154 0 : {
155 0 : ulong out_sz = 0;
156 0 : ulong remain = (ulong)( buf_end - cur_buf );
157 0 : ulong data_sz = data.crypto_frame.length;
158 0 : if( data_sz > remain ) {
159 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
160 0 : *out_buf += out_sz;
161 0 : *out_buf_sz -= out_sz;
162 :
163 0 : return FD_QUIC_PARSE_FAIL;
164 0 : }
165 :
166 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"data\": [ " );
167 0 : *out_buf += out_sz;
168 0 : *out_buf_sz -= out_sz;
169 :
170 0 : for( ulong j = 0; j < data_sz; ++j ) {
171 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "0x%02x, ", cur_buf[j] );
172 0 : *out_buf += out_sz;
173 0 : *out_buf_sz -= out_sz;
174 0 : }
175 :
176 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "], " );
177 0 : *out_buf += out_sz;
178 0 : *out_buf_sz -= out_sz;
179 :
180 0 : cur_buf += data_sz;
181 :
182 0 : break;
183 0 : }
184 :
185 0 : case 0x08:
186 0 : case 0x09:
187 0 : case 0x0a:
188 0 : case 0x0b:
189 0 : case 0x0c:
190 0 : case 0x0d:
191 0 : case 0x0e:
192 0 : case 0x0f:
193 0 : {
194 0 : ulong remain = (ulong)( buf_end - cur_buf );
195 :
196 : /* stream */
197 : /* optional fields decoding */
198 0 : ulong offset = 0;
199 0 : ulong stream_id = 0;
200 0 : ulong data_sz = remain;
201 0 : ulong fin = 0;
202 :
203 0 : switch( id ) {
204 0 : # define _0(ELSE,...) ELSE
205 0 : # define _1(ELSE,...) __VA_ARGS__
206 0 : # define _CASE(OFF,LEN,FIN,NAME) \
207 0 : case 8 + OFF(0,4) + LEN(0,2) + FIN(0,1): \
208 0 : OFF(,offset = data.NAME.offset;) \
209 0 : LEN(,data_sz = data.NAME.length;) \
210 0 : FIN(,fin = 1;) \
211 0 : stream_id = data.NAME.stream_id; \
212 0 : break;
213 0 : _CASE(_0,_0,_0,stream_8_frame)
214 0 : _CASE(_0,_0,_1,stream_8_frame)
215 0 : _CASE(_0,_1,_0,stream_a_frame)
216 0 : _CASE(_0,_1,_1,stream_a_frame)
217 0 : _CASE(_1,_0,_0,stream_c_frame)
218 0 : _CASE(_1,_0,_1,stream_c_frame)
219 0 : _CASE(_1,_1,_0,stream_e_frame)
220 0 : _CASE(_1,_1,_1,stream_e_frame)
221 0 : # undef _CASE
222 0 : # undef _1
223 0 : # undef _0
224 0 : }
225 :
226 0 : ulong stream_type = stream_id & 3UL;
227 :
228 0 : ulong out_sz = safe_snprintf(
229 0 : *out_buf,
230 0 : *out_buf_sz,
231 0 : "\"stream_type\": %u, \"offset\": %lu, \"length\": %lu, \"fin\": %lu, ",
232 0 : (uint)stream_type, offset, data_sz, fin );
233 0 : *out_buf += out_sz;
234 0 : *out_buf_sz -= out_sz;
235 :
236 0 : if( data_sz > remain ) {
237 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
238 0 : *out_buf += out_sz;
239 0 : *out_buf_sz -= out_sz;
240 :
241 0 : return FD_QUIC_PARSE_FAIL;
242 0 : }
243 :
244 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"data\": [ " );
245 0 : *out_buf += out_sz;
246 0 : *out_buf_sz -= out_sz;
247 :
248 0 : for( ulong j = 0; j < data_sz; ++j ) {
249 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "0x%02x, ", cur_buf[j] );
250 0 : *out_buf += out_sz;
251 0 : *out_buf_sz -= out_sz;
252 0 : }
253 :
254 0 : out_sz = safe_snprintf( *out_buf, *out_buf_sz, "], " );
255 0 : *out_buf += out_sz;
256 0 : *out_buf_sz -= out_sz;
257 :
258 0 : cur_buf += data_sz;
259 :
260 0 : break;
261 0 : }
262 :
263 0 : case 0x1c: /* connection close */
264 0 : {
265 : /* the conn_close_1_frame structure is different to conn_close_0_frame */
266 0 : ulong reason_phrase_length = data.conn_close_0_frame.reason_phrase_length;
267 0 : ulong remain = (ulong)( buf_end - cur_buf );
268 0 : if( FD_UNLIKELY( reason_phrase_length > remain ) ) {
269 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
270 0 : *out_buf += out_sz;
271 0 : *out_buf_sz -= out_sz;
272 :
273 0 : return FD_QUIC_PARSE_FAIL;
274 0 : }
275 :
276 : /* TODO pretty print the reason phrase */
277 :
278 0 : cur_buf += reason_phrase_length;
279 :
280 0 : break;
281 0 : }
282 :
283 0 : case 0x1d: /* connection close */
284 0 : {
285 : /* the conn_close_1_frame structure is different to conn_close_0_frame */
286 0 : ulong reason_phrase_length = data.conn_close_1_frame.reason_phrase_length;
287 0 : ulong remain = (ulong)( buf_end - cur_buf );
288 0 : if( FD_UNLIKELY( reason_phrase_length > remain ) ) {
289 0 : ulong out_sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"overflow\", " );
290 0 : *out_buf += out_sz;
291 0 : *out_buf_sz -= out_sz;
292 :
293 0 : return FD_QUIC_PARSE_FAIL;
294 0 : }
295 :
296 : /* TODO pretty print the reason phrase */
297 :
298 0 : cur_buf += reason_phrase_length;
299 :
300 0 : break;
301 0 : }
302 0 : }
303 :
304 0 : return (ulong)( cur_buf - buf );
305 :
306 0 : }
307 :
308 : ulong
309 : fd_quic_pretty_print_frames( char ** out_buf,
310 : ulong * out_buf_sz,
311 : uchar const * buf,
312 : ulong buf_sz );
313 :
314 :
315 : ulong
316 : fd_quic_pretty_print_quic_hdr_initial( char ** out_buf,
317 : ulong * out_buf_sz,
318 : uchar const ** frame_ptr,
319 : ulong * frame_sz,
320 : uchar const * buf,
321 0 : ulong buf_sz ) {
322 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"hdr_type\": \"initial\", " );
323 0 : *out_buf += sz;
324 0 : *out_buf_sz -= sz;
325 :
326 0 : fd_quic_initial_t initial[1] = {0};
327 0 : ulong rc = fd_quic_decode_initial( initial, buf, buf_sz );
328 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
329 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"hdr_parse_failed\", " );
330 0 : *out_buf += sz;
331 0 : *out_buf_sz -= sz;
332 :
333 0 : FD_LOG_HEXDUMP_ERR(( "hdr_parse_failed", buf, fd_ulong_min( 16, buf_sz ) ));
334 :
335 0 : return FD_QUIC_PARSE_FAIL;
336 0 : }
337 :
338 0 : ulong body_sz = initial->len; /* not a protected field */
339 0 : ulong pn_offset = initial->pkt_num_pnoff;
340 0 : ulong pkt_number_sz = fd_quic_h0_pkt_num_len( buf[0] ) + 1u;
341 0 : ulong payload_off = pn_offset + pkt_number_sz;
342 :
343 : /* now we have decrypted packet number */
344 0 : ulong pkt_number = fd_quic_pktnum_decode( buf+pn_offset, pkt_number_sz );
345 :
346 : /* write pkt_number_sz into initial, for tracing */
347 : /* note this is the raw packet number, which may have been truncated */
348 0 : initial->pkt_num = pkt_number;
349 :
350 0 : *frame_ptr = buf + payload_off;
351 0 : *frame_sz = body_sz - pkt_number_sz - FD_QUIC_CRYPTO_TAG_SZ; /* total size of all frames in packet */
352 :
353 0 : fd_quic_pretty_print_struct_initial( out_buf, out_buf_sz, initial );
354 :
355 0 : return payload_off;
356 0 : }
357 :
358 :
359 : ulong
360 : fd_quic_pretty_print_quic_hdr_handshake( char ** out_buf,
361 : ulong * out_buf_sz,
362 : uchar const ** frame_ptr,
363 : ulong * frame_sz,
364 : uchar const * buf,
365 0 : ulong buf_sz ) {
366 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"hdr_type\": \"handshake\", " );
367 0 : *out_buf += sz;
368 0 : *out_buf_sz -= sz;
369 :
370 0 : fd_quic_handshake_t handshake[1] = {0};
371 0 : ulong rc = fd_quic_decode_handshake( handshake, buf, buf_sz );
372 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
373 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"hdr_parse_failed\", " );
374 0 : *out_buf += sz;
375 0 : *out_buf_sz -= sz;
376 :
377 0 : FD_LOG_HEXDUMP_ERR(( "hdr_parse_failed", buf, fd_ulong_min( 16, buf_sz ) ));
378 :
379 0 : return FD_QUIC_PARSE_FAIL;
380 0 : }
381 :
382 0 : ulong body_sz = handshake->len; /* not a protected field */
383 0 : ulong pn_offset = handshake->pkt_num_pnoff;
384 0 : ulong pkt_number_sz = fd_quic_h0_pkt_num_len( buf[0] ) + 1u;
385 0 : ulong payload_off = pn_offset + pkt_number_sz;
386 :
387 : /* now we have decrypted packet number */
388 0 : ulong pkt_number = fd_quic_pktnum_decode( buf+pn_offset, pkt_number_sz );
389 :
390 : /* write pkt_number_sz into handshake, for tracing */
391 : /* note this is the raw packet number, which may have been truncated */
392 0 : handshake->pkt_num = pkt_number;
393 :
394 0 : *frame_ptr = buf + payload_off;
395 0 : *frame_sz = body_sz - pkt_number_sz - FD_QUIC_CRYPTO_TAG_SZ; /* total size of all frames in packet */
396 :
397 0 : fd_quic_pretty_print_struct_handshake( out_buf, out_buf_sz, handshake );
398 :
399 0 : return payload_off;
400 0 : }
401 :
402 :
403 : ulong
404 : fd_quic_pretty_print_quic_hdr_one_rtt( char ** out_buf,
405 : ulong * out_buf_sz,
406 : uchar const ** frame_ptr,
407 : ulong * frame_sz,
408 : uchar const * buf,
409 0 : ulong buf_sz ) {
410 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"hdr_type\": \"1-rtt\", " );
411 0 : *out_buf += sz;
412 0 : *out_buf_sz -= sz;
413 :
414 0 : fd_quic_one_rtt_t one_rtt[1] = {0};
415 :
416 : /* hidden field needed by decode function */
417 0 : one_rtt->dst_conn_id_len = 8;
418 :
419 0 : ulong rc = fd_quic_decode_one_rtt( one_rtt, buf, buf_sz );
420 0 : if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
421 0 : ulong sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"hdr_parse_failed\", " );
422 0 : *out_buf += sz;
423 0 : *out_buf_sz -= sz;
424 :
425 0 : FD_LOG_HEXDUMP_ERR(( "hdr_parse_failed", buf, fd_ulong_min( 16, buf_sz ) ));
426 :
427 0 : return FD_QUIC_PARSE_FAIL;
428 0 : }
429 :
430 0 : ulong pn_offset = one_rtt->pkt_num_pnoff;
431 0 : ulong pkt_number_sz = fd_quic_h0_pkt_num_len( buf[0] ) + 1u;
432 0 : ulong payload_off = pn_offset + pkt_number_sz;
433 0 : ulong payload_sz = buf_sz - pn_offset - pkt_number_sz; /* includes auth tag */
434 :
435 : /* now we have decrypted packet number */
436 0 : ulong pkt_number = fd_quic_pktnum_decode( buf+pn_offset, pkt_number_sz );
437 :
438 : /* write pkt_number_sz into one_rtt, for tracing */
439 : /* note this is the raw packet number, which may have been truncated */
440 0 : one_rtt->pkt_num = pkt_number;
441 :
442 0 : *frame_ptr = buf + payload_off;
443 0 : *frame_sz = payload_sz - FD_QUIC_CRYPTO_TAG_SZ; /* total size of all frames in packet */
444 :
445 0 : fd_quic_pretty_print_struct_one_rtt( out_buf, out_buf_sz, one_rtt );
446 :
447 0 : return payload_off;
448 0 : }
449 :
450 :
451 : ulong
452 : fd_quic_pretty_print_quic_hdr( char ** out_buf,
453 : ulong * out_buf_sz,
454 : uchar const ** frame_ptr,
455 : ulong * frame_sz,
456 : uchar const * buf,
457 0 : ulong buf_sz ) {
458 0 : ulong sz;
459 :
460 0 : uint first = (uint)buf[0];
461 0 : uint is_long = first >> 7u;
462 :
463 0 : if( !is_long ) {
464 0 : return fd_quic_pretty_print_quic_hdr_one_rtt( out_buf, out_buf_sz, frame_ptr, frame_sz, buf, buf_sz );
465 0 : }
466 :
467 0 : uint long_type = ( first >> 4u ) & 0x03u;
468 :
469 0 : switch( long_type ) {
470 0 : case 0x00: /* initial */
471 0 : return fd_quic_pretty_print_quic_hdr_initial( out_buf, out_buf_sz, frame_ptr, frame_sz, buf, buf_sz );
472 0 : case 0x01: /* 0-rtt - unused */
473 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"0-rtt\", " );
474 0 : *out_buf += sz;
475 0 : *out_buf_sz -= sz;
476 0 : return FD_QUIC_PARSE_FAIL;
477 0 : case 0x02: /* handshake */
478 0 : return fd_quic_pretty_print_quic_hdr_handshake( out_buf, out_buf_sz, frame_ptr, frame_sz, buf, buf_sz );
479 0 : case 0x03:
480 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"not-implemented-retry\", " );
481 0 : *out_buf += sz;
482 0 : *out_buf_sz -= sz;
483 0 : return FD_QUIC_PARSE_FAIL;
484 0 : }
485 :
486 : /* long type is uint & 0x03u - yet gcc thinks this is reachable */
487 0 : return FD_QUIC_PARSE_FAIL;
488 0 : }
489 :
490 :
491 : /* 16 bytes allows for: xxx.xxx.xxx.xxx\0 */
492 0 : #define IP4_TO_STR_BUF_SZ 16
493 : static
494 : char const *
495 0 : ip4_to_str( char buf[IP4_TO_STR_BUF_SZ], uint ip4_addr ) {
496 : /* can't use sizeof(buf) here, as technically typeof(buf) is char* */
497 0 : ulong sz = safe_snprintf( buf, IP4_TO_STR_BUF_SZ, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( ip4_addr ) );
498 : /* should not be possible */
499 0 : if( FD_UNLIKELY( sz >= IP4_TO_STR_BUF_SZ ) ) buf[IP4_TO_STR_BUF_SZ-1] = '\0';
500 0 : return buf;
501 0 : }
502 :
503 :
504 : ulong
505 : fd_quic_pretty_print_quic_pkt( fd_quic_pretty_print_t * pretty_print,
506 : ulong now,
507 : uchar const * buf,
508 : ulong buf_sz,
509 : char const * flow,
510 : uint ip4_saddr,
511 0 : ushort udp_sport ) {
512 0 : (void)pretty_print;
513 0 : (void)now;
514 :
515 0 : char tmp_buf[16];
516 :
517 0 : if( buf == NULL ) return FD_QUIC_PARSE_FAIL;
518 :
519 0 : static FD_TL char pretty_print_buf[16384];
520 :
521 0 : memset( pretty_print_buf, 0, sizeof( pretty_print_buf ) );
522 :
523 0 : char * out_buf = &pretty_print_buf[0];
524 0 : ulong out_buf_sz = sizeof( pretty_print_buf ) - 1UL;
525 :
526 0 : uchar const * frame_ptr = NULL;
527 0 : ulong frame_sz = 0;
528 :
529 0 : ulong sz = safe_snprintf( out_buf, out_buf_sz, "{ \"type\": \"packet\", \"flow\": \"%s\", ", flow );
530 0 : out_buf += sz;
531 0 : out_buf_sz -= sz;
532 :
533 0 : /* */ sz = safe_snprintf( out_buf, out_buf_sz, "\"src_ip_addr\": \"%s\", \"src_udp_port\": \"%u\", ",
534 0 : ip4_to_str( tmp_buf, ip4_saddr ), fd_ushort_bswap( udp_sport ) );
535 0 : out_buf += sz;
536 0 : out_buf_sz -= sz;
537 :
538 0 : ulong hdr_rc = fd_quic_pretty_print_quic_hdr( &out_buf,
539 0 : &out_buf_sz,
540 0 : &frame_ptr,
541 0 : &frame_sz,
542 0 : buf,
543 0 : buf_sz );
544 0 : if( hdr_rc == FD_QUIC_PARSE_FAIL ) {
545 0 : sz = safe_snprintf( out_buf, out_buf_sz, "\"err\": \"parse_fail\" } " );
546 0 : out_buf += sz;
547 0 : out_buf_sz -= sz;
548 :
549 0 : return FD_QUIC_PARSE_FAIL;
550 0 : }
551 :
552 0 : sz = safe_snprintf( out_buf, out_buf_sz, "\"frames\": [ " );
553 0 : out_buf += sz;
554 0 : out_buf_sz -= sz;
555 :
556 0 : ulong rc = fd_quic_pretty_print_frames( &out_buf,
557 0 : &out_buf_sz,
558 0 : frame_ptr,
559 0 : frame_sz );
560 0 : if( rc == FD_QUIC_PARSE_FAIL ) {
561 0 : sz = safe_snprintf( out_buf, out_buf_sz, "], \"err\": \"parse_fail\" }, " );
562 0 : out_buf += sz;
563 0 : out_buf_sz -= sz;
564 0 : printf( "\nTRACE: %s\n", pretty_print_buf );
565 0 : fflush( stdout );
566 0 : return FD_QUIC_PARSE_FAIL;
567 0 : }
568 :
569 0 : sz = safe_snprintf( out_buf, out_buf_sz, "] }, " );
570 0 : out_buf += sz;
571 0 : out_buf_sz -= sz;
572 :
573 0 : for( ulong j = 0; j < (ulong)( out_buf - pretty_print_buf); ++j ) {
574 0 : if( pretty_print_buf[j] == '\0' ) pretty_print_buf[j] = '*';
575 0 : }
576 :
577 0 : printf( "TRACE: [ %s ]\n", pretty_print_buf );
578 :
579 0 : return rc;
580 0 : }
581 :
582 : ulong
583 : fd_quic_pretty_print_frames( char ** out_buf,
584 : ulong * out_buf_sz,
585 : uchar const * buf,
586 0 : ulong buf_sz ) {
587 0 : uchar const * orig_buf = buf;
588 0 : ulong sz;
589 :
590 0 : while( buf_sz > 0 ) {
591 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "{ \"type\": \"frame\", " );
592 0 : *out_buf += sz;
593 0 : *out_buf_sz -= sz;
594 :
595 0 : ulong rc = fd_quic_pretty_print_frame( out_buf, out_buf_sz, buf, buf_sz );
596 0 : if( rc == FD_QUIC_PARSE_FAIL ) {
597 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, "\"err\": \"parse_fail\" }, " );
598 0 : *out_buf += sz;
599 0 : *out_buf_sz -= sz;
600 0 : break;
601 0 : }
602 :
603 0 : sz = safe_snprintf( *out_buf, *out_buf_sz, " }, " );
604 0 : *out_buf += sz;
605 0 : *out_buf_sz -= sz;
606 :
607 0 : if( rc >= buf_sz ) break;
608 :
609 0 : buf += rc;
610 0 : buf_sz -= rc;
611 0 : }
612 :
613 0 : return (ulong)( buf - orig_buf );
614 0 : }
|