1 // 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 "quiche/quic/core/quic_utils.h"
6
7 #include <algorithm>
8 #include <cstdint>
9 #include <cstring>
10 #include <limits>
11 #include <string>
12
13 #include "absl/base/macros.h"
14 #include "absl/base/optimization.h"
15 #include "absl/numeric/int128.h"
16 #include "absl/strings/string_view.h"
17 #include "openssl/sha.h"
18 #include "quiche/quic/core/quic_connection_id.h"
19 #include "quiche/quic/core/quic_constants.h"
20 #include "quiche/quic/core/quic_types.h"
21 #include "quiche/quic/core/quic_versions.h"
22 #include "quiche/quic/platform/api/quic_bug_tracker.h"
23 #include "quiche/quic/platform/api/quic_flag_utils.h"
24 #include "quiche/quic/platform/api/quic_flags.h"
25 #include "quiche/common/platform/api/quiche_logging.h"
26 #include "quiche/common/platform/api/quiche_mem_slice.h"
27 #include "quiche/common/quiche_endian.h"
28
29 namespace quic {
30 namespace {
31
32 // We know that >= GCC 4.8 and Clang have a __uint128_t intrinsic. Other
33 // compilers don't necessarily, notably MSVC.
34 #if defined(__x86_64__) && \
35 ((defined(__GNUC__) && \
36 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
37 defined(__clang__))
38 #define QUIC_UTIL_HAS_UINT128 1
39 #endif
40
41 #ifdef QUIC_UTIL_HAS_UINT128
IncrementalHashFast(absl::uint128 uhash,absl::string_view data)42 absl::uint128 IncrementalHashFast(absl::uint128 uhash, absl::string_view data) {
43 // This code ends up faster than the naive implementation for 2 reasons:
44 // 1. absl::uint128 is sufficiently complicated that the compiler
45 // cannot transform the multiplication by kPrime into a shift-multiply-add;
46 // it has go through all of the instructions for a 128-bit multiply.
47 // 2. Because there are so fewer instructions (around 13), the hot loop fits
48 // nicely in the instruction queue of many Intel CPUs.
49 // kPrime = 309485009821345068724781371
50 static const absl::uint128 kPrime =
51 (static_cast<absl::uint128>(16777216) << 64) + 315;
52 auto hi = absl::Uint128High64(uhash);
53 auto lo = absl::Uint128Low64(uhash);
54 absl::uint128 xhash = (static_cast<absl::uint128>(hi) << 64) + lo;
55 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
56 for (size_t i = 0; i < data.length(); ++i) {
57 xhash = (xhash ^ static_cast<uint32_t>(octets[i])) * kPrime;
58 }
59 return absl::MakeUint128(absl::Uint128High64(xhash),
60 absl::Uint128Low64(xhash));
61 }
62 #endif
63
64 #ifndef QUIC_UTIL_HAS_UINT128
65 // Slow implementation of IncrementalHash. In practice, only used by Chromium.
IncrementalHashSlow(absl::uint128 hash,absl::string_view data)66 absl::uint128 IncrementalHashSlow(absl::uint128 hash, absl::string_view data) {
67 // kPrime = 309485009821345068724781371
68 static const absl::uint128 kPrime = absl::MakeUint128(16777216, 315);
69 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
70 for (size_t i = 0; i < data.length(); ++i) {
71 hash = hash ^ absl::MakeUint128(0, octets[i]);
72 hash = hash * kPrime;
73 }
74 return hash;
75 }
76 #endif
77
IncrementalHash(absl::uint128 hash,absl::string_view data)78 absl::uint128 IncrementalHash(absl::uint128 hash, absl::string_view data) {
79 #ifdef QUIC_UTIL_HAS_UINT128
80 return IncrementalHashFast(hash, data);
81 #else
82 return IncrementalHashSlow(hash, data);
83 #endif
84 }
85
86 } // namespace
87
88 // static
FNV1a_64_Hash(absl::string_view data)89 uint64_t QuicUtils::FNV1a_64_Hash(absl::string_view data) {
90 static const uint64_t kOffset = UINT64_C(14695981039346656037);
91 static const uint64_t kPrime = UINT64_C(1099511628211);
92
93 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
94
95 uint64_t hash = kOffset;
96
97 for (size_t i = 0; i < data.length(); ++i) {
98 hash = hash ^ octets[i];
99 hash = hash * kPrime;
100 }
101
102 return hash;
103 }
104
105 // static
FNV1a_128_Hash(absl::string_view data)106 absl::uint128 QuicUtils::FNV1a_128_Hash(absl::string_view data) {
107 return FNV1a_128_Hash_Three(data, absl::string_view(), absl::string_view());
108 }
109
110 // static
FNV1a_128_Hash_Two(absl::string_view data1,absl::string_view data2)111 absl::uint128 QuicUtils::FNV1a_128_Hash_Two(absl::string_view data1,
112 absl::string_view data2) {
113 return FNV1a_128_Hash_Three(data1, data2, absl::string_view());
114 }
115
116 // static
FNV1a_128_Hash_Three(absl::string_view data1,absl::string_view data2,absl::string_view data3)117 absl::uint128 QuicUtils::FNV1a_128_Hash_Three(absl::string_view data1,
118 absl::string_view data2,
119 absl::string_view data3) {
120 // The two constants are defined as part of the hash algorithm.
121 // see http://www.isthe.com/chongo/tech/comp/fnv/
122 // kOffset = 144066263297769815596495629667062367629
123 const absl::uint128 kOffset = absl::MakeUint128(
124 UINT64_C(7809847782465536322), UINT64_C(7113472399480571277));
125
126 absl::uint128 hash = IncrementalHash(kOffset, data1);
127 if (data2.empty()) {
128 return hash;
129 }
130
131 hash = IncrementalHash(hash, data2);
132 if (data3.empty()) {
133 return hash;
134 }
135 return IncrementalHash(hash, data3);
136 }
137
138 // static
SerializeUint128Short(absl::uint128 v,uint8_t * out)139 void QuicUtils::SerializeUint128Short(absl::uint128 v, uint8_t* out) {
140 const uint64_t lo = absl::Uint128Low64(v);
141 const uint64_t hi = absl::Uint128High64(v);
142 // This assumes that the system is little-endian.
143 memcpy(out, &lo, sizeof(lo));
144 memcpy(out + sizeof(lo), &hi, sizeof(hi) / 2);
145 }
146
147 #define RETURN_STRING_LITERAL(x) \
148 case x: \
149 return #x;
150
AddressChangeTypeToString(AddressChangeType type)151 std::string QuicUtils::AddressChangeTypeToString(AddressChangeType type) {
152 switch (type) {
153 RETURN_STRING_LITERAL(NO_CHANGE);
154 RETURN_STRING_LITERAL(PORT_CHANGE);
155 RETURN_STRING_LITERAL(IPV4_SUBNET_CHANGE);
156 RETURN_STRING_LITERAL(IPV4_TO_IPV6_CHANGE);
157 RETURN_STRING_LITERAL(IPV6_TO_IPV4_CHANGE);
158 RETURN_STRING_LITERAL(IPV6_TO_IPV6_CHANGE);
159 RETURN_STRING_LITERAL(IPV4_TO_IPV4_CHANGE);
160 }
161 return "INVALID_ADDRESS_CHANGE_TYPE";
162 }
163
SentPacketStateToString(SentPacketState state)164 const char* QuicUtils::SentPacketStateToString(SentPacketState state) {
165 switch (state) {
166 RETURN_STRING_LITERAL(OUTSTANDING);
167 RETURN_STRING_LITERAL(NEVER_SENT);
168 RETURN_STRING_LITERAL(ACKED);
169 RETURN_STRING_LITERAL(UNACKABLE);
170 RETURN_STRING_LITERAL(NEUTERED);
171 RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMITTED);
172 RETURN_STRING_LITERAL(LOST);
173 RETURN_STRING_LITERAL(PTO_RETRANSMITTED);
174 RETURN_STRING_LITERAL(NOT_CONTRIBUTING_RTT);
175 }
176 return "INVALID_SENT_PACKET_STATE";
177 }
178
179 // static
QuicLongHeaderTypetoString(QuicLongHeaderType type)180 const char* QuicUtils::QuicLongHeaderTypetoString(QuicLongHeaderType type) {
181 switch (type) {
182 RETURN_STRING_LITERAL(VERSION_NEGOTIATION);
183 RETURN_STRING_LITERAL(INITIAL);
184 RETURN_STRING_LITERAL(RETRY);
185 RETURN_STRING_LITERAL(HANDSHAKE);
186 RETURN_STRING_LITERAL(ZERO_RTT_PROTECTED);
187 default:
188 return "INVALID_PACKET_TYPE";
189 }
190 }
191
192 // static
AckResultToString(AckResult result)193 const char* QuicUtils::AckResultToString(AckResult result) {
194 switch (result) {
195 RETURN_STRING_LITERAL(PACKETS_NEWLY_ACKED);
196 RETURN_STRING_LITERAL(NO_PACKETS_NEWLY_ACKED);
197 RETURN_STRING_LITERAL(UNSENT_PACKETS_ACKED);
198 RETURN_STRING_LITERAL(UNACKABLE_PACKETS_ACKED);
199 RETURN_STRING_LITERAL(PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE);
200 }
201 return "INVALID_ACK_RESULT";
202 }
203
204 // static
DetermineAddressChangeType(const QuicSocketAddress & old_address,const QuicSocketAddress & new_address)205 AddressChangeType QuicUtils::DetermineAddressChangeType(
206 const QuicSocketAddress& old_address,
207 const QuicSocketAddress& new_address) {
208 if (!old_address.IsInitialized() || !new_address.IsInitialized() ||
209 old_address == new_address) {
210 return NO_CHANGE;
211 }
212
213 if (old_address.host() == new_address.host()) {
214 return PORT_CHANGE;
215 }
216
217 bool old_ip_is_ipv4 = old_address.host().IsIPv4() ? true : false;
218 bool migrating_ip_is_ipv4 = new_address.host().IsIPv4() ? true : false;
219 if (old_ip_is_ipv4 && !migrating_ip_is_ipv4) {
220 return IPV4_TO_IPV6_CHANGE;
221 }
222
223 if (!old_ip_is_ipv4) {
224 return migrating_ip_is_ipv4 ? IPV6_TO_IPV4_CHANGE : IPV6_TO_IPV6_CHANGE;
225 }
226
227 const int kSubnetMaskLength = 24;
228 if (old_address.host().InSameSubnet(new_address.host(), kSubnetMaskLength)) {
229 // Subnet part does not change (here, we use /24), which is considered to be
230 // caused by NATs.
231 return IPV4_SUBNET_CHANGE;
232 }
233
234 return IPV4_TO_IPV4_CHANGE;
235 }
236
237 // static
IsAckable(SentPacketState state)238 bool QuicUtils::IsAckable(SentPacketState state) {
239 return state != NEVER_SENT && state != ACKED && state != UNACKABLE;
240 }
241
242 // static
IsRetransmittableFrame(QuicFrameType type)243 bool QuicUtils::IsRetransmittableFrame(QuicFrameType type) {
244 switch (type) {
245 case ACK_FRAME:
246 case PADDING_FRAME:
247 case STOP_WAITING_FRAME:
248 case MTU_DISCOVERY_FRAME:
249 case PATH_CHALLENGE_FRAME:
250 case PATH_RESPONSE_FRAME:
251 return false;
252 default:
253 return true;
254 }
255 }
256
257 // static
IsHandshakeFrame(const QuicFrame & frame,QuicTransportVersion transport_version)258 bool QuicUtils::IsHandshakeFrame(const QuicFrame& frame,
259 QuicTransportVersion transport_version) {
260 if (!QuicVersionUsesCryptoFrames(transport_version)) {
261 return frame.type == STREAM_FRAME &&
262 frame.stream_frame.stream_id == GetCryptoStreamId(transport_version);
263 } else {
264 return frame.type == CRYPTO_FRAME;
265 }
266 }
267
268 // static
ContainsFrameType(const QuicFrames & frames,QuicFrameType type)269 bool QuicUtils::ContainsFrameType(const QuicFrames& frames,
270 QuicFrameType type) {
271 for (const QuicFrame& frame : frames) {
272 if (frame.type == type) {
273 return true;
274 }
275 }
276 return false;
277 }
278
279 // static
RetransmissionTypeToPacketState(TransmissionType retransmission_type)280 SentPacketState QuicUtils::RetransmissionTypeToPacketState(
281 TransmissionType retransmission_type) {
282 switch (retransmission_type) {
283 case ALL_ZERO_RTT_RETRANSMISSION:
284 return UNACKABLE;
285 case HANDSHAKE_RETRANSMISSION:
286 return HANDSHAKE_RETRANSMITTED;
287 case LOSS_RETRANSMISSION:
288 return LOST;
289 case PTO_RETRANSMISSION:
290 return PTO_RETRANSMITTED;
291 case PATH_RETRANSMISSION:
292 return NOT_CONTRIBUTING_RTT;
293 case ALL_INITIAL_RETRANSMISSION:
294 return UNACKABLE;
295 default:
296 QUIC_BUG(quic_bug_10839_2)
297 << retransmission_type << " is not a retransmission_type";
298 return UNACKABLE;
299 }
300 }
301
302 // static
IsIetfPacketHeader(uint8_t first_byte)303 bool QuicUtils::IsIetfPacketHeader(uint8_t first_byte) {
304 return (first_byte & FLAGS_LONG_HEADER) || (first_byte & FLAGS_FIXED_BIT) ||
305 !(first_byte & FLAGS_DEMULTIPLEXING_BIT);
306 }
307
308 // static
IsIetfPacketShortHeader(uint8_t first_byte)309 bool QuicUtils::IsIetfPacketShortHeader(uint8_t first_byte) {
310 return IsIetfPacketHeader(first_byte) && !(first_byte & FLAGS_LONG_HEADER);
311 }
312
313 // static
GetInvalidStreamId(QuicTransportVersion version)314 QuicStreamId QuicUtils::GetInvalidStreamId(QuicTransportVersion version) {
315 return VersionHasIetfQuicFrames(version)
316 ? std::numeric_limits<QuicStreamId>::max()
317 : 0;
318 }
319
320 // static
GetCryptoStreamId(QuicTransportVersion version)321 QuicStreamId QuicUtils::GetCryptoStreamId(QuicTransportVersion version) {
322 QUIC_BUG_IF(quic_bug_12982_1, QuicVersionUsesCryptoFrames(version))
323 << "CRYPTO data aren't in stream frames; they have no stream ID.";
324 return QuicVersionUsesCryptoFrames(version) ? GetInvalidStreamId(version) : 1;
325 }
326
327 // static
IsCryptoStreamId(QuicTransportVersion version,QuicStreamId stream_id)328 bool QuicUtils::IsCryptoStreamId(QuicTransportVersion version,
329 QuicStreamId stream_id) {
330 if (QuicVersionUsesCryptoFrames(version)) {
331 return false;
332 }
333 return stream_id == GetCryptoStreamId(version);
334 }
335
336 // static
GetHeadersStreamId(QuicTransportVersion version)337 QuicStreamId QuicUtils::GetHeadersStreamId(QuicTransportVersion version) {
338 QUICHE_DCHECK(!VersionUsesHttp3(version));
339 return GetFirstBidirectionalStreamId(version, Perspective::IS_CLIENT);
340 }
341
342 // static
IsClientInitiatedStreamId(QuicTransportVersion version,QuicStreamId id)343 bool QuicUtils::IsClientInitiatedStreamId(QuicTransportVersion version,
344 QuicStreamId id) {
345 if (id == GetInvalidStreamId(version)) {
346 return false;
347 }
348 return VersionHasIetfQuicFrames(version) ? id % 2 == 0 : id % 2 != 0;
349 }
350
351 // static
IsServerInitiatedStreamId(QuicTransportVersion version,QuicStreamId id)352 bool QuicUtils::IsServerInitiatedStreamId(QuicTransportVersion version,
353 QuicStreamId id) {
354 if (id == GetInvalidStreamId(version)) {
355 return false;
356 }
357 return VersionHasIetfQuicFrames(version) ? id % 2 != 0 : id % 2 == 0;
358 }
359
360 // static
IsOutgoingStreamId(ParsedQuicVersion version,QuicStreamId id,Perspective perspective)361 bool QuicUtils::IsOutgoingStreamId(ParsedQuicVersion version, QuicStreamId id,
362 Perspective perspective) {
363 // Streams are outgoing streams, iff:
364 // - we are the server and the stream is server-initiated
365 // - we are the client and the stream is client-initiated.
366 const bool perspective_is_server = perspective == Perspective::IS_SERVER;
367 const bool stream_is_server =
368 QuicUtils::IsServerInitiatedStreamId(version.transport_version, id);
369 return perspective_is_server == stream_is_server;
370 }
371
372 // static
IsBidirectionalStreamId(QuicStreamId id,ParsedQuicVersion version)373 bool QuicUtils::IsBidirectionalStreamId(QuicStreamId id,
374 ParsedQuicVersion version) {
375 QUICHE_DCHECK(version.HasIetfQuicFrames());
376 return id % 4 < 2;
377 }
378
379 // static
GetStreamType(QuicStreamId id,Perspective perspective,bool peer_initiated,ParsedQuicVersion version)380 StreamType QuicUtils::GetStreamType(QuicStreamId id, Perspective perspective,
381 bool peer_initiated,
382 ParsedQuicVersion version) {
383 QUICHE_DCHECK(version.HasIetfQuicFrames());
384 if (IsBidirectionalStreamId(id, version)) {
385 return BIDIRECTIONAL;
386 }
387
388 if (peer_initiated) {
389 if (perspective == Perspective::IS_SERVER) {
390 QUICHE_DCHECK_EQ(2u, id % 4);
391 } else {
392 QUICHE_DCHECK_EQ(Perspective::IS_CLIENT, perspective);
393 QUICHE_DCHECK_EQ(3u, id % 4);
394 }
395 return READ_UNIDIRECTIONAL;
396 }
397
398 if (perspective == Perspective::IS_SERVER) {
399 QUICHE_DCHECK_EQ(3u, id % 4);
400 } else {
401 QUICHE_DCHECK_EQ(Perspective::IS_CLIENT, perspective);
402 QUICHE_DCHECK_EQ(2u, id % 4);
403 }
404 return WRITE_UNIDIRECTIONAL;
405 }
406
407 // static
StreamIdDelta(QuicTransportVersion version)408 QuicStreamId QuicUtils::StreamIdDelta(QuicTransportVersion version) {
409 return VersionHasIetfQuicFrames(version) ? 4 : 2;
410 }
411
412 // static
GetFirstBidirectionalStreamId(QuicTransportVersion version,Perspective perspective)413 QuicStreamId QuicUtils::GetFirstBidirectionalStreamId(
414 QuicTransportVersion version, Perspective perspective) {
415 if (VersionHasIetfQuicFrames(version)) {
416 return perspective == Perspective::IS_CLIENT ? 0 : 1;
417 } else if (QuicVersionUsesCryptoFrames(version)) {
418 return perspective == Perspective::IS_CLIENT ? 1 : 2;
419 }
420 return perspective == Perspective::IS_CLIENT ? 3 : 2;
421 }
422
423 // static
GetFirstUnidirectionalStreamId(QuicTransportVersion version,Perspective perspective)424 QuicStreamId QuicUtils::GetFirstUnidirectionalStreamId(
425 QuicTransportVersion version, Perspective perspective) {
426 if (VersionHasIetfQuicFrames(version)) {
427 return perspective == Perspective::IS_CLIENT ? 2 : 3;
428 } else if (QuicVersionUsesCryptoFrames(version)) {
429 return perspective == Perspective::IS_CLIENT ? 1 : 2;
430 }
431 return perspective == Perspective::IS_CLIENT ? 3 : 2;
432 }
433
434 // static
GetMaxClientInitiatedBidirectionalStreamId(QuicTransportVersion version)435 QuicStreamId QuicUtils::GetMaxClientInitiatedBidirectionalStreamId(
436 QuicTransportVersion version) {
437 if (VersionHasIetfQuicFrames(version)) {
438 // Client initiated bidirectional streams have stream IDs divisible by 4.
439 return std::numeric_limits<QuicStreamId>::max() - 3;
440 }
441
442 // Client initiated bidirectional streams have odd stream IDs.
443 return std::numeric_limits<QuicStreamId>::max();
444 }
445
446 // static
CreateRandomConnectionId()447 QuicConnectionId QuicUtils::CreateRandomConnectionId() {
448 return CreateRandomConnectionId(kQuicDefaultConnectionIdLength,
449 QuicRandom::GetInstance());
450 }
451
452 // static
CreateRandomConnectionId(QuicRandom * random)453 QuicConnectionId QuicUtils::CreateRandomConnectionId(QuicRandom* random) {
454 return CreateRandomConnectionId(kQuicDefaultConnectionIdLength, random);
455 }
456 // static
CreateRandomConnectionId(uint8_t connection_id_length)457 QuicConnectionId QuicUtils::CreateRandomConnectionId(
458 uint8_t connection_id_length) {
459 return CreateRandomConnectionId(connection_id_length,
460 QuicRandom::GetInstance());
461 }
462
463 // static
CreateRandomConnectionId(uint8_t connection_id_length,QuicRandom * random)464 QuicConnectionId QuicUtils::CreateRandomConnectionId(
465 uint8_t connection_id_length, QuicRandom* random) {
466 QuicConnectionId connection_id;
467 connection_id.set_length(connection_id_length);
468 if (connection_id.length() > 0) {
469 random->RandBytes(connection_id.mutable_data(), connection_id.length());
470 }
471 return connection_id;
472 }
473
474 // static
CreateZeroConnectionId(QuicTransportVersion version)475 QuicConnectionId QuicUtils::CreateZeroConnectionId(
476 QuicTransportVersion version) {
477 if (!VersionAllowsVariableLengthConnectionIds(version)) {
478 char connection_id_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
479 return QuicConnectionId(static_cast<char*>(connection_id_bytes),
480 ABSL_ARRAYSIZE(connection_id_bytes));
481 }
482 return EmptyQuicConnectionId();
483 }
484
485 // static
IsConnectionIdLengthValidForVersion(size_t connection_id_length,QuicTransportVersion transport_version)486 bool QuicUtils::IsConnectionIdLengthValidForVersion(
487 size_t connection_id_length, QuicTransportVersion transport_version) {
488 // No version of QUIC can support lengths that do not fit in an uint8_t.
489 if (connection_id_length >
490 static_cast<size_t>(std::numeric_limits<uint8_t>::max())) {
491 return false;
492 }
493
494 if (transport_version == QUIC_VERSION_UNSUPPORTED ||
495 transport_version == QUIC_VERSION_RESERVED_FOR_NEGOTIATION) {
496 // Unknown versions could allow connection ID lengths up to 255.
497 return true;
498 }
499
500 const uint8_t connection_id_length8 =
501 static_cast<uint8_t>(connection_id_length);
502 // Versions that do not support variable lengths only support length 8.
503 if (!VersionAllowsVariableLengthConnectionIds(transport_version)) {
504 return connection_id_length8 == kQuicDefaultConnectionIdLength;
505 }
506 return connection_id_length8 <= kQuicMaxConnectionIdWithLengthPrefixLength;
507 }
508
509 // static
IsConnectionIdValidForVersion(QuicConnectionId connection_id,QuicTransportVersion transport_version)510 bool QuicUtils::IsConnectionIdValidForVersion(
511 QuicConnectionId connection_id, QuicTransportVersion transport_version) {
512 return IsConnectionIdLengthValidForVersion(connection_id.length(),
513 transport_version);
514 }
515
GenerateStatelessResetToken(QuicConnectionId connection_id)516 StatelessResetToken QuicUtils::GenerateStatelessResetToken(
517 QuicConnectionId connection_id) {
518 static_assert(sizeof(absl::uint128) == sizeof(StatelessResetToken),
519 "bad size");
520 static_assert(alignof(absl::uint128) >= alignof(StatelessResetToken),
521 "bad alignment");
522 absl::uint128 hash = FNV1a_128_Hash(
523 absl::string_view(connection_id.data(), connection_id.length()));
524 return *reinterpret_cast<StatelessResetToken*>(&hash);
525 }
526
527 // static
GetMaxStreamCount()528 QuicStreamCount QuicUtils::GetMaxStreamCount() {
529 return (kMaxQuicStreamCount >> 2) + 1;
530 }
531
532 // static
GetPacketNumberSpace(EncryptionLevel encryption_level)533 PacketNumberSpace QuicUtils::GetPacketNumberSpace(
534 EncryptionLevel encryption_level) {
535 switch (encryption_level) {
536 case ENCRYPTION_INITIAL:
537 return INITIAL_DATA;
538 case ENCRYPTION_HANDSHAKE:
539 return HANDSHAKE_DATA;
540 case ENCRYPTION_ZERO_RTT:
541 case ENCRYPTION_FORWARD_SECURE:
542 return APPLICATION_DATA;
543 default:
544 QUIC_BUG(quic_bug_10839_3)
545 << "Try to get packet number space of encryption level: "
546 << encryption_level;
547 return NUM_PACKET_NUMBER_SPACES;
548 }
549 }
550
551 // static
GetEncryptionLevelToSendAckofSpace(PacketNumberSpace packet_number_space)552 EncryptionLevel QuicUtils::GetEncryptionLevelToSendAckofSpace(
553 PacketNumberSpace packet_number_space) {
554 switch (packet_number_space) {
555 case INITIAL_DATA:
556 return ENCRYPTION_INITIAL;
557 case HANDSHAKE_DATA:
558 return ENCRYPTION_HANDSHAKE;
559 case APPLICATION_DATA:
560 return ENCRYPTION_FORWARD_SECURE;
561 default:
562 QUICHE_DCHECK(false);
563 return NUM_ENCRYPTION_LEVELS;
564 }
565 }
566
567 // static
IsProbingFrame(QuicFrameType type)568 bool QuicUtils::IsProbingFrame(QuicFrameType type) {
569 switch (type) {
570 case PATH_CHALLENGE_FRAME:
571 case PATH_RESPONSE_FRAME:
572 case NEW_CONNECTION_ID_FRAME:
573 case PADDING_FRAME:
574 return true;
575 default:
576 return false;
577 }
578 }
579
580 // static
IsAckElicitingFrame(QuicFrameType type)581 bool QuicUtils::IsAckElicitingFrame(QuicFrameType type) {
582 switch (type) {
583 case PADDING_FRAME:
584 case STOP_WAITING_FRAME:
585 case ACK_FRAME:
586 case CONNECTION_CLOSE_FRAME:
587 return false;
588 default:
589 return true;
590 }
591 }
592
593 // static
AreStatelessResetTokensEqual(const StatelessResetToken & token1,const StatelessResetToken & token2)594 bool QuicUtils::AreStatelessResetTokensEqual(
595 const StatelessResetToken& token1, const StatelessResetToken& token2) {
596 char byte = 0;
597 for (size_t i = 0; i < kStatelessResetTokenLength; i++) {
598 // This avoids compiler optimizations that could make us stop comparing
599 // after we find a byte that doesn't match.
600 byte |= (token1[i] ^ token2[i]);
601 }
602 return byte == 0;
603 }
604
IsValidWebTransportSessionId(WebTransportSessionId id,ParsedQuicVersion version)605 bool IsValidWebTransportSessionId(WebTransportSessionId id,
606 ParsedQuicVersion version) {
607 QUICHE_DCHECK(version.UsesHttp3());
608 return (id <= std::numeric_limits<QuicStreamId>::max()) &&
609 QuicUtils::IsBidirectionalStreamId(id, version) &&
610 QuicUtils::IsClientInitiatedStreamId(version.transport_version, id);
611 }
612
MemSliceSpanTotalSize(absl::Span<quiche::QuicheMemSlice> span)613 QuicByteCount MemSliceSpanTotalSize(absl::Span<quiche::QuicheMemSlice> span) {
614 QuicByteCount total = 0;
615 for (const quiche::QuicheMemSlice& slice : span) {
616 total += slice.length();
617 }
618 return total;
619 }
620
RawSha256(absl::string_view input)621 std::string RawSha256(absl::string_view input) {
622 std::string raw_hash;
623 raw_hash.resize(SHA256_DIGEST_LENGTH);
624 SHA256(reinterpret_cast<const uint8_t*>(input.data()), input.size(),
625 reinterpret_cast<uint8_t*>(&raw_hash[0]));
626 return raw_hash;
627 }
628
629 #undef RETURN_STRING_LITERAL // undef for jumbo builds
630 } // namespace quic
631