blob: 2d6d0c92a6d87c67ce61e11ea7a6c54b2174da05 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/quic/core/quic_packets.h"
6
7#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
8#include "net/third_party/quiche/src/quic/core/quic_types.h"
9#include "net/third_party/quiche/src/quic/core/quic_utils.h"
10#include "net/third_party/quiche/src/quic/core/quic_versions.h"
rchf0a9f372019-05-15 21:36:43 -070011#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050012#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
fayang1ed1f762019-06-24 11:40:04 -070016#include "net/third_party/quiche/src/quic/platform/api/quic_string_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
18
19namespace quic {
20
QUICHE team2252b702019-05-14 23:55:14 -040021QuicConnectionId GetServerConnectionIdAsRecipient(
22 const QuicPacketHeader& header,
23 Perspective perspective) {
dschinazi5e1a7b22019-07-31 12:23:21 -070024 if (perspective == Perspective::IS_SERVER) {
QUICHE team2252b702019-05-14 23:55:14 -040025 return header.destination_connection_id;
26 }
27 return header.source_connection_id;
28}
29
dschinaziac6805d2019-05-30 09:44:27 -070030QuicConnectionId GetClientConnectionIdAsRecipient(
31 const QuicPacketHeader& header,
32 Perspective perspective) {
dschinaziac6805d2019-05-30 09:44:27 -070033 if (perspective == Perspective::IS_CLIENT) {
34 return header.destination_connection_id;
35 }
36 return header.source_connection_id;
37}
38
QUICHE team2252b702019-05-14 23:55:14 -040039QuicConnectionId GetServerConnectionIdAsSender(const QuicPacketHeader& header,
40 Perspective perspective) {
dschinazi5e1a7b22019-07-31 12:23:21 -070041 if (perspective == Perspective::IS_CLIENT) {
QUICHE team2252b702019-05-14 23:55:14 -040042 return header.destination_connection_id;
43 }
QUICHE team2252b702019-05-14 23:55:14 -040044 return header.source_connection_id;
45}
46
47QuicConnectionIdIncluded GetServerConnectionIdIncludedAsSender(
48 const QuicPacketHeader& header,
49 Perspective perspective) {
dschinazi5e1a7b22019-07-31 12:23:21 -070050 if (perspective == Perspective::IS_CLIENT) {
QUICHE team2252b702019-05-14 23:55:14 -040051 return header.destination_connection_id_included;
52 }
QUICHE team2252b702019-05-14 23:55:14 -040053 return header.source_connection_id_included;
54}
55
dschinaziac6805d2019-05-30 09:44:27 -070056QuicConnectionId GetClientConnectionIdAsSender(const QuicPacketHeader& header,
57 Perspective perspective) {
dschinazi5e1a7b22019-07-31 12:23:21 -070058 if (perspective == Perspective::IS_CLIENT) {
dschinaziac6805d2019-05-30 09:44:27 -070059 return header.source_connection_id;
60 }
dschinaziac6805d2019-05-30 09:44:27 -070061 return header.destination_connection_id;
62}
63
QUICHE team2252b702019-05-14 23:55:14 -040064QuicConnectionIdIncluded GetClientConnectionIdIncludedAsSender(
65 const QuicPacketHeader& header,
66 Perspective perspective) {
dschinazi5e1a7b22019-07-31 12:23:21 -070067 if (perspective == Perspective::IS_CLIENT) {
QUICHE team2252b702019-05-14 23:55:14 -040068 return header.source_connection_id_included;
69 }
70 return header.destination_connection_id_included;
71}
72
QUICHE teama6ef0a62019-03-07 20:34:33 -050073QuicConnectionIdLength GetIncludedConnectionIdLength(
74 QuicConnectionId connection_id,
75 QuicConnectionIdIncluded connection_id_included) {
76 DCHECK(connection_id_included == CONNECTION_ID_PRESENT ||
77 connection_id_included == CONNECTION_ID_ABSENT);
78 return connection_id_included == CONNECTION_ID_PRESENT
79 ? static_cast<QuicConnectionIdLength>(connection_id.length())
80 : PACKET_0BYTE_CONNECTION_ID;
81}
82
83QuicConnectionIdLength GetIncludedDestinationConnectionIdLength(
84 const QuicPacketHeader& header) {
85 return GetIncludedConnectionIdLength(
86 header.destination_connection_id,
87 header.destination_connection_id_included);
88}
89
90QuicConnectionIdLength GetIncludedSourceConnectionIdLength(
91 const QuicPacketHeader& header) {
92 return GetIncludedConnectionIdLength(header.source_connection_id,
93 header.source_connection_id_included);
94}
95
96size_t GetPacketHeaderSize(QuicTransportVersion version,
97 const QuicPacketHeader& header) {
98 return GetPacketHeaderSize(
99 version, GetIncludedDestinationConnectionIdLength(header),
100 GetIncludedSourceConnectionIdLength(header), header.version_flag,
101 header.nonce != nullptr, header.packet_number_length,
102 header.retry_token_length_length, header.retry_token.length(),
103 header.length_length);
104}
105
106size_t GetPacketHeaderSize(
107 QuicTransportVersion version,
108 QuicConnectionIdLength destination_connection_id_length,
109 QuicConnectionIdLength source_connection_id_length,
110 bool include_version,
111 bool include_diversification_nonce,
112 QuicPacketNumberLength packet_number_length,
113 QuicVariableLengthIntegerLength retry_token_length_length,
114 QuicByteCount retry_token_length,
115 QuicVariableLengthIntegerLength length_length) {
fayangd4291e42019-05-30 10:31:21 -0700116 if (VersionHasIetfInvariantHeader(version)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117 if (include_version) {
118 // Long header.
nharperd43f1d62019-07-01 15:18:20 -0700119 size_t size = kPacketHeaderTypeSize + kConnectionIdLengthSize +
120 destination_connection_id_length +
fayang36825da2019-08-21 14:01:27 -0700121 source_connection_id_length + packet_number_length +
nharperd43f1d62019-07-01 15:18:20 -0700122 kQuicVersionSize;
123 if (include_diversification_nonce) {
124 size += kDiversificationNonceSize;
125 }
dschinazi48ac9192019-07-31 00:07:26 -0700126 if (VersionHasLengthPrefixedConnectionIds(version)) {
127 size += kConnectionIdLengthSize;
128 }
nharperd43f1d62019-07-01 15:18:20 -0700129 DCHECK(QuicVersionHasLongHeaderLengths(version) ||
nharper2f6632d2019-07-01 18:01:22 -0700130 !GetQuicReloadableFlag(quic_fix_get_packet_header_size) ||
nharperd43f1d62019-07-01 15:18:20 -0700131 retry_token_length_length + retry_token_length + length_length ==
132 0);
133 if (QuicVersionHasLongHeaderLengths(version) ||
134 !GetQuicReloadableFlag(quic_fix_get_packet_header_size)) {
135 QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_get_packet_header_size, 1, 3);
136 size += retry_token_length_length + retry_token_length + length_length;
137 }
138 return size;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500139 }
140 // Short header.
141 return kPacketHeaderTypeSize + destination_connection_id_length +
142 packet_number_length;
143 }
QUICHE team2252b702019-05-14 23:55:14 -0400144 // Google QUIC versions <= 43 can only carry one connection ID.
145 DCHECK(destination_connection_id_length == 0 ||
146 source_connection_id_length == 0);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500147 return kPublicFlagsSize + destination_connection_id_length +
QUICHE team2252b702019-05-14 23:55:14 -0400148 source_connection_id_length +
QUICHE teama6ef0a62019-03-07 20:34:33 -0500149 (include_version ? kQuicVersionSize : 0) + packet_number_length +
150 (include_diversification_nonce ? kDiversificationNonceSize : 0);
151}
152
153size_t GetStartOfEncryptedData(QuicTransportVersion version,
154 const QuicPacketHeader& header) {
155 return GetPacketHeaderSize(version, header);
156}
157
158size_t GetStartOfEncryptedData(
159 QuicTransportVersion version,
160 QuicConnectionIdLength destination_connection_id_length,
161 QuicConnectionIdLength source_connection_id_length,
162 bool include_version,
163 bool include_diversification_nonce,
164 QuicPacketNumberLength packet_number_length,
165 QuicVariableLengthIntegerLength retry_token_length_length,
166 QuicByteCount retry_token_length,
167 QuicVariableLengthIntegerLength length_length) {
168 // Encryption starts before private flags.
169 return GetPacketHeaderSize(
170 version, destination_connection_id_length, source_connection_id_length,
171 include_version, include_diversification_nonce, packet_number_length,
172 retry_token_length_length, retry_token_length, length_length);
173}
174
175QuicPacketHeader::QuicPacketHeader()
176 : destination_connection_id(EmptyQuicConnectionId()),
177 destination_connection_id_included(CONNECTION_ID_PRESENT),
178 source_connection_id(EmptyQuicConnectionId()),
179 source_connection_id_included(CONNECTION_ID_ABSENT),
180 reset_flag(false),
181 version_flag(false),
182 has_possible_stateless_reset_token(false),
183 packet_number_length(PACKET_4BYTE_PACKET_NUMBER),
184 version(UnsupportedQuicVersion()),
185 nonce(nullptr),
186 form(GOOGLE_QUIC_PACKET),
187 long_packet_type(INITIAL),
188 possible_stateless_reset_token(0),
189 retry_token_length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0),
190 retry_token(QuicStringPiece()),
191 length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0),
192 remaining_packet_length(0) {}
193
194QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default;
195
196QuicPacketHeader::~QuicPacketHeader() {}
197
198QuicPublicResetPacket::QuicPublicResetPacket()
199 : connection_id(EmptyQuicConnectionId()), nonce_proof(0) {}
200
201QuicPublicResetPacket::QuicPublicResetPacket(QuicConnectionId connection_id)
202 : connection_id(connection_id), nonce_proof(0) {}
203
204QuicVersionNegotiationPacket::QuicVersionNegotiationPacket()
205 : connection_id(EmptyQuicConnectionId()) {}
206
207QuicVersionNegotiationPacket::QuicVersionNegotiationPacket(
208 QuicConnectionId connection_id)
209 : connection_id(connection_id) {}
210
211QuicVersionNegotiationPacket::QuicVersionNegotiationPacket(
212 const QuicVersionNegotiationPacket& other) = default;
213
214QuicVersionNegotiationPacket::~QuicVersionNegotiationPacket() {}
215
216QuicIetfStatelessResetPacket::QuicIetfStatelessResetPacket()
217 : stateless_reset_token(0) {}
218
219QuicIetfStatelessResetPacket::QuicIetfStatelessResetPacket(
220 const QuicPacketHeader& header,
221 QuicUint128 token)
222 : header(header), stateless_reset_token(token) {}
223
224QuicIetfStatelessResetPacket::QuicIetfStatelessResetPacket(
225 const QuicIetfStatelessResetPacket& other) = default;
226
227QuicIetfStatelessResetPacket::~QuicIetfStatelessResetPacket() {}
228
229std::ostream& operator<<(std::ostream& os, const QuicPacketHeader& header) {
230 os << "{ destination_connection_id: " << header.destination_connection_id
231 << " ("
232 << (header.destination_connection_id_included == CONNECTION_ID_PRESENT
233 ? "present"
234 : "absent")
235 << "), source_connection_id: " << header.source_connection_id << " ("
236 << (header.source_connection_id_included == CONNECTION_ID_PRESENT
237 ? "present"
238 : "absent")
239 << "), packet_number_length: " << header.packet_number_length
240 << ", reset_flag: " << header.reset_flag
241 << ", version_flag: " << header.version_flag;
242 if (header.version_flag) {
243 os << ", version: " << ParsedQuicVersionToString(header.version);
244 if (header.long_packet_type != INVALID_PACKET_TYPE) {
245 os << ", long_packet_type: "
246 << QuicUtils::QuicLongHeaderTypetoString(header.long_packet_type);
247 }
248 if (header.retry_token_length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) {
249 os << ", retry_token_length_length: "
250 << static_cast<int>(header.retry_token_length_length);
251 }
252 if (header.retry_token.length() != 0) {
253 os << ", retry_token_length: " << header.retry_token.length();
254 }
255 if (header.length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) {
256 os << ", length_length: " << static_cast<int>(header.length_length);
257 }
258 if (header.remaining_packet_length != 0) {
259 os << ", remaining_packet_length: " << header.remaining_packet_length;
260 }
261 }
262 if (header.nonce != nullptr) {
263 os << ", diversification_nonce: "
264 << QuicTextUtils::HexEncode(
265 QuicStringPiece(header.nonce->data(), header.nonce->size()));
266 }
267 os << ", packet_number: " << header.packet_number << " }\n";
268 return os;
269}
270
271QuicData::QuicData(const char* buffer, size_t length)
272 : buffer_(buffer), length_(length), owns_buffer_(false) {}
273
274QuicData::QuicData(const char* buffer, size_t length, bool owns_buffer)
275 : buffer_(buffer), length_(length), owns_buffer_(owns_buffer) {}
276
dschinazi4b5a68a2019-08-15 15:45:36 -0700277QuicData::QuicData(QuicStringPiece packet_data)
278 : buffer_(packet_data.data()),
279 length_(packet_data.length()),
280 owns_buffer_(false) {}
281
QUICHE teama6ef0a62019-03-07 20:34:33 -0500282QuicData::~QuicData() {
283 if (owns_buffer_) {
284 delete[] const_cast<char*>(buffer_);
285 }
286}
287
288QuicPacket::QuicPacket(
289 char* buffer,
290 size_t length,
291 bool owns_buffer,
292 QuicConnectionIdLength destination_connection_id_length,
293 QuicConnectionIdLength source_connection_id_length,
294 bool includes_version,
295 bool includes_diversification_nonce,
296 QuicPacketNumberLength packet_number_length,
297 QuicVariableLengthIntegerLength retry_token_length_length,
298 QuicByteCount retry_token_length,
299 QuicVariableLengthIntegerLength length_length)
300 : QuicData(buffer, length, owns_buffer),
301 buffer_(buffer),
302 destination_connection_id_length_(destination_connection_id_length),
303 source_connection_id_length_(source_connection_id_length),
304 includes_version_(includes_version),
305 includes_diversification_nonce_(includes_diversification_nonce),
306 packet_number_length_(packet_number_length),
307 retry_token_length_length_(retry_token_length_length),
308 retry_token_length_(retry_token_length),
309 length_length_(length_length) {}
310
dschinazi17d42422019-06-18 16:35:07 -0700311QuicPacket::QuicPacket(QuicTransportVersion /*version*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500312 char* buffer,
313 size_t length,
314 bool owns_buffer,
315 const QuicPacketHeader& header)
316 : QuicPacket(buffer,
317 length,
318 owns_buffer,
319 GetIncludedDestinationConnectionIdLength(header),
320 GetIncludedSourceConnectionIdLength(header),
321 header.version_flag,
322 header.nonce != nullptr,
323 header.packet_number_length,
324 header.retry_token_length_length,
325 header.retry_token.length(),
326 header.length_length) {}
327
328QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer, size_t length)
329 : QuicData(buffer, length) {}
330
331QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer,
332 size_t length,
333 bool owns_buffer)
334 : QuicData(buffer, length, owns_buffer) {}
335
dschinazi4b5a68a2019-08-15 15:45:36 -0700336QuicEncryptedPacket::QuicEncryptedPacket(QuicStringPiece data)
337 : QuicData(data) {}
338
QUICHE teama6ef0a62019-03-07 20:34:33 -0500339std::unique_ptr<QuicEncryptedPacket> QuicEncryptedPacket::Clone() const {
340 char* buffer = new char[this->length()];
341 memcpy(buffer, this->data(), this->length());
342 return QuicMakeUnique<QuicEncryptedPacket>(buffer, this->length(), true);
343}
344
345std::ostream& operator<<(std::ostream& os, const QuicEncryptedPacket& s) {
346 os << s.length() << "-byte data";
347 return os;
348}
349
350QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
351 size_t length,
352 QuicTime receipt_time)
353 : QuicReceivedPacket(buffer,
354 length,
355 receipt_time,
356 false /* owns_buffer */) {}
357
358QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
359 size_t length,
360 QuicTime receipt_time,
361 bool owns_buffer)
362 : QuicReceivedPacket(buffer,
363 length,
364 receipt_time,
365 owns_buffer,
366 0 /* ttl */,
367 true /* ttl_valid */) {}
368
369QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
370 size_t length,
371 QuicTime receipt_time,
372 bool owns_buffer,
373 int ttl,
374 bool ttl_valid)
375 : quic::QuicReceivedPacket(buffer,
376 length,
377 receipt_time,
378 owns_buffer,
379 ttl,
380 ttl_valid,
381 nullptr /* packet_headers */,
382 0 /* headers_length */,
383 false /* owns_header_buffer */) {}
384
385QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
386 size_t length,
387 QuicTime receipt_time,
388 bool owns_buffer,
389 int ttl,
390 bool ttl_valid,
391 char* packet_headers,
392 size_t headers_length,
393 bool owns_header_buffer)
394 : QuicEncryptedPacket(buffer, length, owns_buffer),
395 receipt_time_(receipt_time),
396 ttl_(ttl_valid ? ttl : -1),
397 packet_headers_(packet_headers),
398 headers_length_(headers_length),
399 owns_header_buffer_(owns_header_buffer) {}
400
401QuicReceivedPacket::~QuicReceivedPacket() {
402 if (owns_header_buffer_) {
403 delete[] static_cast<char*>(packet_headers_);
404 }
405}
406
407std::unique_ptr<QuicReceivedPacket> QuicReceivedPacket::Clone() const {
408 char* buffer = new char[this->length()];
409 memcpy(buffer, this->data(), this->length());
410 if (this->packet_headers()) {
411 char* headers_buffer = new char[this->headers_length()];
412 memcpy(headers_buffer, this->packet_headers(), this->headers_length());
413 return QuicMakeUnique<QuicReceivedPacket>(
414 buffer, this->length(), receipt_time(), true, ttl(), ttl() >= 0,
415 headers_buffer, this->headers_length(), true);
416 }
417
418 return QuicMakeUnique<QuicReceivedPacket>(
419 buffer, this->length(), receipt_time(), true, ttl(), ttl() >= 0);
420}
421
422std::ostream& operator<<(std::ostream& os, const QuicReceivedPacket& s) {
423 os << s.length() << "-byte data";
424 return os;
425}
426
427QuicStringPiece QuicPacket::AssociatedData(QuicTransportVersion version) const {
428 return QuicStringPiece(
429 data(),
430 GetStartOfEncryptedData(version, destination_connection_id_length_,
431 source_connection_id_length_, includes_version_,
432 includes_diversification_nonce_,
433 packet_number_length_, retry_token_length_length_,
434 retry_token_length_, length_length_));
435}
436
437QuicStringPiece QuicPacket::Plaintext(QuicTransportVersion version) const {
438 const size_t start_of_encrypted_data = GetStartOfEncryptedData(
439 version, destination_connection_id_length_, source_connection_id_length_,
440 includes_version_, includes_diversification_nonce_, packet_number_length_,
441 retry_token_length_length_, retry_token_length_, length_length_);
442 return QuicStringPiece(data() + start_of_encrypted_data,
443 length() - start_of_encrypted_data);
444}
445
446SerializedPacket::SerializedPacket(QuicPacketNumber packet_number,
447 QuicPacketNumberLength packet_number_length,
448 const char* encrypted_buffer,
449 QuicPacketLength encrypted_length,
450 bool has_ack,
451 bool has_stop_waiting)
452 : encrypted_buffer(encrypted_buffer),
453 encrypted_length(encrypted_length),
454 has_crypto_handshake(NOT_HANDSHAKE),
455 num_padding_bytes(0),
456 packet_number(packet_number),
457 packet_number_length(packet_number_length),
QUICHE team6987b4a2019-03-15 16:23:04 -0700458 encryption_level(ENCRYPTION_INITIAL),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500459 has_ack(has_ack),
460 has_stop_waiting(has_stop_waiting),
461 transmission_type(NOT_RETRANSMISSION) {}
462
463SerializedPacket::SerializedPacket(const SerializedPacket& other) = default;
464
465SerializedPacket& SerializedPacket::operator=(const SerializedPacket& other) =
466 default;
467
468SerializedPacket::SerializedPacket(SerializedPacket&& other)
469 : encrypted_buffer(other.encrypted_buffer),
470 encrypted_length(other.encrypted_length),
471 has_crypto_handshake(other.has_crypto_handshake),
472 num_padding_bytes(other.num_padding_bytes),
473 packet_number(other.packet_number),
474 packet_number_length(other.packet_number_length),
475 encryption_level(other.encryption_level),
476 has_ack(other.has_ack),
477 has_stop_waiting(other.has_stop_waiting),
478 transmission_type(other.transmission_type),
479 original_packet_number(other.original_packet_number),
480 largest_acked(other.largest_acked) {
481 retransmittable_frames.swap(other.retransmittable_frames);
482}
483
484SerializedPacket::~SerializedPacket() {}
485
486void ClearSerializedPacket(SerializedPacket* serialized_packet) {
487 if (!serialized_packet->retransmittable_frames.empty()) {
488 DeleteFrames(&serialized_packet->retransmittable_frames);
489 }
490 serialized_packet->encrypted_buffer = nullptr;
491 serialized_packet->encrypted_length = 0;
492 serialized_packet->largest_acked.Clear();
493}
494
495char* CopyBuffer(const SerializedPacket& packet) {
496 char* dst_buffer = new char[packet.encrypted_length];
497 memcpy(dst_buffer, packet.encrypted_buffer, packet.encrypted_length);
498 return dst_buffer;
499}
500
fayang1ed1f762019-06-24 11:40:04 -0700501ReceivedPacketInfo::ReceivedPacketInfo(const QuicSocketAddress& self_address,
502 const QuicSocketAddress& peer_address,
503 const QuicReceivedPacket& packet)
504 : self_address(self_address),
505 peer_address(peer_address),
506 packet(packet),
507 form(GOOGLE_QUIC_PACKET),
508 version_flag(false),
dschinazi48ac9192019-07-31 00:07:26 -0700509 use_length_prefix(false),
fayang1ed1f762019-06-24 11:40:04 -0700510 version_label(0),
511 version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
512 destination_connection_id(EmptyQuicConnectionId()),
513 source_connection_id(EmptyQuicConnectionId()) {}
514
515ReceivedPacketInfo::~ReceivedPacketInfo() {}
516
517std::string ReceivedPacketInfo::ToString() const {
518 std::string output =
519 QuicStrCat("{ self_address: ", self_address.ToString(),
520 ", peer_address: ", peer_address.ToString(),
521 ", packet_length: ", packet.length(),
522 ", header_format: ", form, ", version_flag: ", version_flag);
523 if (version_flag) {
524 QuicStrAppend(&output, ", version: ", ParsedQuicVersionToString(version));
525 }
526 QuicStrAppend(
527 &output,
528 ", destination_connection_id: ", destination_connection_id.ToString(),
529 ", source_connection_id: ", source_connection_id.ToString(), " }\n");
530 return output;
531}
532
533std::ostream& operator<<(std::ostream& os,
534 const ReceivedPacketInfo& packet_info) {
535 os << packet_info.ToString();
536 return os;
537}
538
QUICHE teama6ef0a62019-03-07 20:34:33 -0500539} // namespace quic