Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/ssl/quic/qlog_event_helpers.c
48266 views
1
/*
2
* Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.
3
*
4
* Licensed under the Apache License 2.0 (the "License"). You may not use
5
* this file except in compliance with the License. You can obtain a copy
6
* in the file LICENSE in the source distribution or at
7
* https://www.openssl.org/source/license.html
8
*/
9
10
#include "internal/qlog_event_helpers.h"
11
#include "internal/common.h"
12
#include "internal/packet.h"
13
#include "internal/quic_channel.h"
14
#include "internal/quic_error.h"
15
16
void ossl_qlog_event_connectivity_connection_started(QLOG *qlog,
17
const QUIC_CONN_ID *init_dcid)
18
{
19
#ifndef OPENSSL_NO_QLOG
20
QLOG_EVENT_BEGIN(qlog, connectivity, connection_started)
21
QLOG_STR("protocol", "quic");
22
QLOG_CID("dst_cid", init_dcid);
23
QLOG_EVENT_END()
24
#endif
25
}
26
27
#ifndef OPENSSL_NO_QLOG
28
static const char *map_state_to_qlog(uint32_t state,
29
int handshake_complete,
30
int handshake_confirmed)
31
{
32
switch (state) {
33
default:
34
case QUIC_CHANNEL_STATE_IDLE:
35
return NULL;
36
37
case QUIC_CHANNEL_STATE_ACTIVE:
38
if (handshake_confirmed)
39
return "handshake_confirmed";
40
else if (handshake_complete)
41
return "handshake_complete";
42
else
43
return "attempted";
44
45
case QUIC_CHANNEL_STATE_TERMINATING_CLOSING:
46
return "closing";
47
48
case QUIC_CHANNEL_STATE_TERMINATING_DRAINING:
49
return "draining";
50
51
case QUIC_CHANNEL_STATE_TERMINATED:
52
return "closed";
53
}
54
}
55
#endif
56
57
void ossl_qlog_event_connectivity_connection_state_updated(QLOG *qlog,
58
uint32_t old_state,
59
uint32_t new_state,
60
int handshake_complete,
61
int handshake_confirmed)
62
{
63
#ifndef OPENSSL_NO_QLOG
64
const char *state_s;
65
66
QLOG_EVENT_BEGIN(qlog, connectivity, connection_state_updated)
67
state_s = map_state_to_qlog(new_state,
68
handshake_complete,
69
handshake_confirmed);
70
71
if (state_s != NULL)
72
QLOG_STR("state", state_s);
73
QLOG_EVENT_END()
74
#endif
75
}
76
77
#ifndef OPENSSL_NO_QLOG
78
static const char *quic_err_to_qlog(uint64_t error_code)
79
{
80
switch (error_code) {
81
case OSSL_QUIC_ERR_INTERNAL_ERROR:
82
return "internal_error";
83
case OSSL_QUIC_ERR_CONNECTION_REFUSED:
84
return "connection_refused";
85
case OSSL_QUIC_ERR_FLOW_CONTROL_ERROR:
86
return "flow_control_error";
87
case OSSL_QUIC_ERR_STREAM_LIMIT_ERROR:
88
return "stream_limit_error";
89
case OSSL_QUIC_ERR_STREAM_STATE_ERROR:
90
return "stream_state_error";
91
case OSSL_QUIC_ERR_FINAL_SIZE_ERROR:
92
return "final_size_error";
93
case OSSL_QUIC_ERR_FRAME_ENCODING_ERROR:
94
return "frame_encoding_error";
95
case OSSL_QUIC_ERR_TRANSPORT_PARAMETER_ERROR:
96
return "transport_parameter_error";
97
case OSSL_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR:
98
return "connection_id_limit_error";
99
case OSSL_QUIC_ERR_PROTOCOL_VIOLATION:
100
return "protocol_violation";
101
case OSSL_QUIC_ERR_INVALID_TOKEN:
102
return "invalid_token";
103
case OSSL_QUIC_ERR_APPLICATION_ERROR:
104
return "application_error";
105
case OSSL_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED:
106
return "crypto_buffer_exceeded";
107
case OSSL_QUIC_ERR_KEY_UPDATE_ERROR:
108
return "key_update_error";
109
case OSSL_QUIC_ERR_AEAD_LIMIT_REACHED:
110
return "aead_limit_reached";
111
case OSSL_QUIC_ERR_NO_VIABLE_PATH:
112
return "no_viable_path";
113
default:
114
return NULL;
115
}
116
}
117
#endif
118
119
void ossl_qlog_event_connectivity_connection_closed(QLOG *qlog,
120
const QUIC_TERMINATE_CAUSE *tcause)
121
{
122
#ifndef OPENSSL_NO_QLOG
123
QLOG_EVENT_BEGIN(qlog, connectivity, connection_closed)
124
QLOG_STR("owner", tcause->remote ? "remote" : "local");
125
if (tcause->app) {
126
QLOG_U64("application_code", tcause->error_code);
127
} else {
128
const char *m = quic_err_to_qlog(tcause->error_code);
129
char ce[32];
130
131
if (tcause->error_code >= OSSL_QUIC_ERR_CRYPTO_ERR_BEGIN
132
&& tcause->error_code <= OSSL_QUIC_ERR_CRYPTO_ERR_END) {
133
BIO_snprintf(ce, sizeof(ce), "crypto_error_0x%03llx",
134
(unsigned long long)tcause->error_code);
135
m = ce;
136
}
137
/* TODO(QLOG FUTURE): Consider adding ERR information in the output. */
138
139
if (m != NULL)
140
QLOG_STR("connection_code", m);
141
else
142
QLOG_U64("connection_code", tcause->error_code);
143
}
144
145
QLOG_STR_LEN("reason", tcause->reason, tcause->reason_len);
146
QLOG_EVENT_END()
147
#endif
148
}
149
150
#ifndef OPENSSL_NO_QLOG
151
static const char *quic_pkt_type_to_qlog(uint32_t pkt_type)
152
{
153
switch (pkt_type) {
154
case QUIC_PKT_TYPE_INITIAL:
155
return "initial";
156
case QUIC_PKT_TYPE_HANDSHAKE:
157
return "handshake";
158
case QUIC_PKT_TYPE_0RTT:
159
return "0RTT";
160
case QUIC_PKT_TYPE_1RTT:
161
return "1RTT";
162
case QUIC_PKT_TYPE_VERSION_NEG:
163
return "version_negotiation";
164
case QUIC_PKT_TYPE_RETRY:
165
return "retry";
166
default:
167
return "unknown";
168
}
169
}
170
#endif
171
172
void ossl_qlog_event_recovery_packet_lost(QLOG *qlog,
173
const QUIC_TXPIM_PKT *tpkt)
174
{
175
#ifndef OPENSSL_NO_QLOG
176
QLOG_EVENT_BEGIN(qlog, recovery, packet_lost)
177
QLOG_BEGIN("header")
178
QLOG_STR("packet_type", quic_pkt_type_to_qlog(tpkt->pkt_type));
179
if (ossl_quic_pkt_type_has_pn(tpkt->pkt_type))
180
QLOG_U64("packet_number", tpkt->ackm_pkt.pkt_num);
181
QLOG_END()
182
QLOG_EVENT_END()
183
#endif
184
}
185
186
#ifndef OPENSSL_NO_QLOG
187
# define MAX_ACK_RANGES 32
188
189
static void ignore_res(int x) {}
190
191
/*
192
* For logging received packets, we need to parse all the frames in the packet
193
* to log them. We should do this separately to the RXDP code because we want to
194
* log the packet and its contents before we start to actually process it in
195
* case it causes an error. We also in general don't want to do other
196
* non-logging related work in the middle of an event logging transaction.
197
* Reparsing packet data allows us to meet these needs while avoiding the need
198
* to keep around bookkeeping data on what frames were in a packet, etc.
199
*
200
* For logging transmitted packets, we actually reuse the same code and reparse
201
* the outgoing packet's payload. This again has the advantage that we only log
202
* a packet when it is actually queued for transmission (and not if something
203
* goes wrong before then) while avoiding the need to keep around bookkeeping
204
* data on what frames it contained.
205
*/
206
static int log_frame_actual(QLOG *qlog_instance, PACKET *pkt,
207
size_t *need_skip)
208
{
209
uint64_t frame_type;
210
OSSL_QUIC_FRAME_ACK ack;
211
OSSL_QUIC_ACK_RANGE ack_ranges[MAX_ACK_RANGES];
212
uint64_t num_ranges, total_ranges;
213
size_t i;
214
PACKET orig_pkt = *pkt;
215
216
if (!ossl_quic_wire_peek_frame_header(pkt, &frame_type, NULL)) {
217
*need_skip = SIZE_MAX;
218
return 0;
219
}
220
221
/*
222
* If something goes wrong decoding a frame we cannot log it as that frame
223
* as we need to know how to decode it in order to be able to do so, but in
224
* that case we log it as an unknown frame to assist with diagnosis.
225
*/
226
switch (frame_type) {
227
case OSSL_QUIC_FRAME_TYPE_PADDING:
228
QLOG_STR("frame_type", "padding");
229
QLOG_U64("payload_length",
230
ossl_quic_wire_decode_padding(pkt));
231
break;
232
case OSSL_QUIC_FRAME_TYPE_PING:
233
if (!ossl_quic_wire_decode_frame_ping(pkt))
234
goto unknown;
235
236
QLOG_STR("frame_type", "ping");
237
break;
238
case OSSL_QUIC_FRAME_TYPE_ACK_WITHOUT_ECN:
239
case OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN:
240
if (!ossl_quic_wire_peek_frame_ack_num_ranges(pkt, &num_ranges))
241
goto unknown;
242
243
ack.ack_ranges = ack_ranges;
244
ack.num_ack_ranges = OSSL_NELEM(ack_ranges);
245
if (!ossl_quic_wire_decode_frame_ack(pkt, 3, &ack, &total_ranges))
246
goto unknown;
247
248
QLOG_STR("frame_type", "ack");
249
QLOG_U64("ack_delay", ossl_time2ms(ack.delay_time));
250
if (ack.ecn_present) {
251
QLOG_U64("ect1", ack.ect0);
252
QLOG_U64("ect0", ack.ect1);
253
QLOG_U64("ce", ack.ecnce);
254
}
255
QLOG_BEGIN_ARRAY("acked_ranges");
256
for (i = 0; i < ack.num_ack_ranges; ++i) {
257
QLOG_BEGIN_ARRAY(NULL)
258
QLOG_U64(NULL, ack.ack_ranges[i].start);
259
if (ack.ack_ranges[i].end != ack.ack_ranges[i].start)
260
QLOG_U64(NULL, ack.ack_ranges[i].end);
261
QLOG_END_ARRAY()
262
}
263
QLOG_END_ARRAY()
264
break;
265
case OSSL_QUIC_FRAME_TYPE_RESET_STREAM:
266
{
267
OSSL_QUIC_FRAME_RESET_STREAM f;
268
269
if (!ossl_quic_wire_decode_frame_reset_stream(pkt, &f))
270
goto unknown;
271
272
QLOG_STR("frame_type", "reset_stream");
273
QLOG_U64("stream_id", f.stream_id);
274
QLOG_U64("error_code", f.app_error_code);
275
QLOG_U64("final_size", f.final_size);
276
}
277
break;
278
case OSSL_QUIC_FRAME_TYPE_STOP_SENDING:
279
{
280
OSSL_QUIC_FRAME_STOP_SENDING f;
281
282
if (!ossl_quic_wire_decode_frame_stop_sending(pkt, &f))
283
goto unknown;
284
285
QLOG_STR("frame_type", "stop_sending");
286
QLOG_U64("stream_id", f.stream_id);
287
QLOG_U64("error_code", f.app_error_code);
288
}
289
break;
290
case OSSL_QUIC_FRAME_TYPE_CRYPTO:
291
{
292
OSSL_QUIC_FRAME_CRYPTO f;
293
294
if (!ossl_quic_wire_decode_frame_crypto(pkt, 1, &f))
295
goto unknown;
296
297
QLOG_STR("frame_type", "crypto");
298
QLOG_U64("offset", f.offset);
299
QLOG_U64("payload_length", f.len);
300
*need_skip += (size_t)f.len;
301
}
302
break;
303
case OSSL_QUIC_FRAME_TYPE_STREAM:
304
case OSSL_QUIC_FRAME_TYPE_STREAM_FIN:
305
case OSSL_QUIC_FRAME_TYPE_STREAM_LEN:
306
case OSSL_QUIC_FRAME_TYPE_STREAM_LEN_FIN:
307
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF:
308
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_FIN:
309
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN:
310
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN_FIN:
311
{
312
OSSL_QUIC_FRAME_STREAM f;
313
314
if (!ossl_quic_wire_decode_frame_stream(pkt, 1, &f))
315
goto unknown;
316
317
QLOG_STR("frame_type", "stream");
318
QLOG_U64("stream_id", f.stream_id);
319
QLOG_U64("offset", f.offset);
320
QLOG_U64("payload_length", f.len);
321
QLOG_BOOL("explicit_length", f.has_explicit_len);
322
if (f.is_fin)
323
QLOG_BOOL("fin", 1);
324
*need_skip = f.has_explicit_len
325
? *need_skip + (size_t)f.len : SIZE_MAX;
326
}
327
break;
328
case OSSL_QUIC_FRAME_TYPE_MAX_DATA:
329
{
330
uint64_t x;
331
332
if (!ossl_quic_wire_decode_frame_max_data(pkt, &x))
333
goto unknown;
334
335
QLOG_STR("frame_type", "max_data");
336
QLOG_U64("maximum", x);
337
}
338
break;
339
case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI:
340
case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI:
341
{
342
uint64_t x;
343
344
if (!ossl_quic_wire_decode_frame_max_streams(pkt, &x))
345
goto unknown;
346
347
QLOG_STR("frame_type", "max_streams");
348
QLOG_STR("stream_type",
349
frame_type == OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI
350
? "bidirectional" : "unidirectional");
351
QLOG_U64("maximum", x);
352
}
353
break;
354
case OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA:
355
{
356
uint64_t stream_id, max_data;
357
358
if (!ossl_quic_wire_decode_frame_max_stream_data(pkt, &stream_id,
359
&max_data))
360
goto unknown;
361
362
QLOG_STR("frame_type", "max_stream_data");
363
QLOG_U64("stream_id", stream_id);
364
QLOG_U64("maximum", max_data);
365
}
366
break;
367
case OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE:
368
{
369
uint64_t challenge;
370
371
if (!ossl_quic_wire_decode_frame_path_challenge(pkt, &challenge))
372
goto unknown;
373
374
QLOG_STR("frame_type", "path_challenge");
375
}
376
break;
377
case OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE:
378
{
379
uint64_t challenge;
380
381
if (!ossl_quic_wire_decode_frame_path_response(pkt, &challenge))
382
goto unknown;
383
384
QLOG_STR("frame_type", "path_response");
385
}
386
break;
387
case OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP:
388
case OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_TRANSPORT:
389
{
390
OSSL_QUIC_FRAME_CONN_CLOSE f;
391
392
if (!ossl_quic_wire_decode_frame_conn_close(pkt, &f))
393
goto unknown;
394
395
QLOG_STR("frame_type", "connection_close");
396
QLOG_STR("error_space", f.is_app ? "application" : "transport");
397
QLOG_U64("error_code_value", f.error_code);
398
if (f.is_app)
399
QLOG_U64("error_code", f.error_code);
400
if (!f.is_app && f.frame_type != 0)
401
QLOG_U64("trigger_frame_type", f.frame_type);
402
QLOG_STR_LEN("reason", f.reason, f.reason_len);
403
}
404
break;
405
case OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE:
406
{
407
if (!ossl_quic_wire_decode_frame_handshake_done(pkt))
408
goto unknown;
409
410
QLOG_STR("frame_type", "handshake_done");
411
}
412
break;
413
case OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID:
414
{
415
OSSL_QUIC_FRAME_NEW_CONN_ID f;
416
417
if (!ossl_quic_wire_decode_frame_new_conn_id(pkt, &f))
418
goto unknown;
419
420
QLOG_STR("frame_type", "new_connection_id");
421
QLOG_U64("sequence_number", f.seq_num);
422
QLOG_U64("retire_prior_to", f.retire_prior_to);
423
QLOG_CID("connection_id", &f.conn_id);
424
QLOG_BIN("stateless_reset_token",
425
f.stateless_reset.token,
426
sizeof(f.stateless_reset.token));
427
}
428
break;
429
case OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID:
430
{
431
uint64_t seq_num;
432
433
if (!ossl_quic_wire_decode_frame_retire_conn_id(pkt, &seq_num))
434
goto unknown;
435
436
QLOG_STR("frame_type", "retire_connection_id");
437
QLOG_U64("sequence_number", seq_num);
438
}
439
break;
440
case OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED:
441
{
442
uint64_t x;
443
444
if (!ossl_quic_wire_decode_frame_data_blocked(pkt, &x))
445
goto unknown;
446
447
QLOG_STR("frame_type", "data_blocked");
448
QLOG_U64("limit", x);
449
}
450
break;
451
case OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED:
452
{
453
uint64_t stream_id, x;
454
455
if (!ossl_quic_wire_decode_frame_stream_data_blocked(pkt,
456
&stream_id,
457
&x))
458
goto unknown;
459
460
QLOG_STR("frame_type", "stream_data_blocked");
461
QLOG_U64("stream_id", stream_id);
462
QLOG_U64("limit", x);
463
}
464
break;
465
case OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI:
466
case OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI:
467
{
468
uint64_t x;
469
470
if (!ossl_quic_wire_decode_frame_streams_blocked(pkt, &x))
471
goto unknown;
472
473
QLOG_STR("frame_type", "streams_blocked");
474
QLOG_STR("stream_type",
475
frame_type == OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI
476
? "bidirectional" : "unidirectional");
477
QLOG_U64("limit", x);
478
}
479
break;
480
case OSSL_QUIC_FRAME_TYPE_NEW_TOKEN:
481
{
482
const unsigned char *token;
483
size_t token_len;
484
485
if (!ossl_quic_wire_decode_frame_new_token(pkt, &token, &token_len))
486
goto unknown;
487
488
QLOG_STR("frame_type", "new_token");
489
QLOG_BEGIN("token");
490
QLOG_BEGIN("raw");
491
QLOG_BIN("data", token, token_len);
492
QLOG_END();
493
QLOG_END();
494
}
495
break;
496
default:
497
unknown:
498
QLOG_STR("frame_type", "unknown");
499
QLOG_U64("frame_type_value", frame_type);
500
501
/*
502
* Can't continue scanning for frames in this case as the frame length
503
* is unknown. We log the entire body of the rest of the packet payload
504
* as the raw data of the frame.
505
*/
506
QLOG_BEGIN("raw");
507
QLOG_BIN("data", PACKET_data(&orig_pkt),
508
PACKET_remaining(&orig_pkt));
509
QLOG_END();
510
ignore_res(PACKET_forward(pkt, PACKET_remaining(pkt)));
511
break;
512
}
513
514
return 1;
515
}
516
517
static void log_frame(QLOG *qlog_instance, PACKET *pkt,
518
size_t *need_skip)
519
{
520
size_t rem_before, rem_after;
521
522
rem_before = PACKET_remaining(pkt);
523
524
if (!log_frame_actual(qlog_instance, pkt, need_skip))
525
return;
526
527
rem_after = PACKET_remaining(pkt);
528
QLOG_U64("length", rem_before - rem_after);
529
}
530
531
static int log_frames(QLOG *qlog_instance,
532
const OSSL_QTX_IOVEC *iovec,
533
size_t num_iovec)
534
{
535
size_t i;
536
PACKET pkt;
537
size_t need_skip = 0;
538
539
for (i = 0; i < num_iovec; ++i) {
540
if (!PACKET_buf_init(&pkt, iovec[i].buf, iovec[i].buf_len))
541
return 0;
542
543
while (PACKET_remaining(&pkt) > 0) {
544
if (need_skip > 0) {
545
size_t adv = need_skip;
546
547
if (adv > PACKET_remaining(&pkt))
548
adv = PACKET_remaining(&pkt);
549
550
if (!PACKET_forward(&pkt, adv))
551
return 0;
552
553
need_skip -= adv;
554
continue;
555
}
556
557
QLOG_BEGIN(NULL)
558
{
559
log_frame(qlog_instance, &pkt, &need_skip);
560
}
561
QLOG_END()
562
}
563
}
564
565
return 1;
566
}
567
568
static void log_packet(QLOG *qlog_instance,
569
const QUIC_PKT_HDR *hdr,
570
QUIC_PN pn,
571
const OSSL_QTX_IOVEC *iovec,
572
size_t num_iovec,
573
uint64_t datagram_id)
574
{
575
const char *type_s;
576
577
QLOG_BEGIN("header")
578
type_s = quic_pkt_type_to_qlog(hdr->type);
579
if (type_s == NULL)
580
type_s = "unknown";
581
582
QLOG_STR("packet_type", type_s);
583
if (ossl_quic_pkt_type_has_pn(hdr->type))
584
QLOG_U64("packet_number", pn);
585
586
QLOG_CID("dcid", &hdr->dst_conn_id);
587
if (ossl_quic_pkt_type_has_scid(hdr->type))
588
QLOG_CID("scid", &hdr->src_conn_id);
589
590
if (hdr->token_len > 0) {
591
QLOG_BEGIN("token")
592
QLOG_BEGIN("raw")
593
QLOG_BIN("data", hdr->token, hdr->token_len);
594
QLOG_END()
595
QLOG_END()
596
}
597
/* TODO(QLOG FUTURE): flags, length */
598
QLOG_END()
599
QLOG_U64("datagram_id", datagram_id);
600
601
if (ossl_quic_pkt_type_is_encrypted(hdr->type)) {
602
QLOG_BEGIN_ARRAY("frames")
603
log_frames(qlog_instance, iovec, num_iovec);
604
QLOG_END_ARRAY()
605
}
606
}
607
608
#endif
609
610
void ossl_qlog_event_transport_packet_sent(QLOG *qlog,
611
const QUIC_PKT_HDR *hdr,
612
QUIC_PN pn,
613
const OSSL_QTX_IOVEC *iovec,
614
size_t num_iovec,
615
uint64_t datagram_id)
616
{
617
#ifndef OPENSSL_NO_QLOG
618
QLOG_EVENT_BEGIN(qlog, transport, packet_sent)
619
log_packet(qlog, hdr, pn, iovec, num_iovec, datagram_id);
620
QLOG_EVENT_END()
621
#endif
622
}
623
624
void ossl_qlog_event_transport_packet_received(QLOG *qlog,
625
const QUIC_PKT_HDR *hdr,
626
QUIC_PN pn,
627
const OSSL_QTX_IOVEC *iovec,
628
size_t num_iovec,
629
uint64_t datagram_id)
630
{
631
#ifndef OPENSSL_NO_QLOG
632
QLOG_EVENT_BEGIN(qlog, transport, packet_received)
633
log_packet(qlog, hdr, pn, iovec, num_iovec, datagram_id);
634
QLOG_EVENT_END()
635
#endif
636
}
637
638