blob: e1caf8954a211f9350daac4e54dde327c5d9f263 [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_utils.h"
6
7#include <algorithm>
8#include <cstdint>
vasilvv872e7a32019-03-12 16:42:44 -07009#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050010
QUICHE teamc65d1d12019-03-19 20:58:04 -070011#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050012#include "net/third_party/quiche/src/quic/core/quic_constants.h"
13#include "net/third_party/quiche/src/quic/core/quic_types.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_prefetch.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050020#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h"
21
22namespace quic {
23namespace {
24
25// We know that >= GCC 4.8 and Clang have a __uint128_t intrinsic. Other
26// compilers don't necessarily, notably MSVC.
27#if defined(__x86_64__) && \
28 ((defined(__GNUC__) && \
29 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
30 defined(__clang__))
31#define QUIC_UTIL_HAS_UINT128 1
32#endif
33
34#ifdef QUIC_UTIL_HAS_UINT128
35QuicUint128 IncrementalHashFast(QuicUint128 uhash, QuicStringPiece data) {
36 // This code ends up faster than the naive implementation for 2 reasons:
37 // 1. QuicUint128 is sufficiently complicated that the compiler
38 // cannot transform the multiplication by kPrime into a shift-multiply-add;
39 // it has go through all of the instructions for a 128-bit multiply.
40 // 2. Because there are so fewer instructions (around 13), the hot loop fits
41 // nicely in the instruction queue of many Intel CPUs.
42 // kPrime = 309485009821345068724781371
43 static const QuicUint128 kPrime =
44 (static_cast<QuicUint128>(16777216) << 64) + 315;
45 auto hi = QuicUint128High64(uhash);
46 auto lo = QuicUint128Low64(uhash);
47 QuicUint128 xhash = (static_cast<QuicUint128>(hi) << 64) + lo;
48 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
49 for (size_t i = 0; i < data.length(); ++i) {
50 xhash = (xhash ^ static_cast<uint32_t>(octets[i])) * kPrime;
51 }
52 return MakeQuicUint128(QuicUint128High64(xhash), QuicUint128Low64(xhash));
53}
54#endif
55
56#ifndef QUIC_UTIL_HAS_UINT128
57// Slow implementation of IncrementalHash. In practice, only used by Chromium.
58QuicUint128 IncrementalHashSlow(QuicUint128 hash, QuicStringPiece data) {
59 // kPrime = 309485009821345068724781371
60 static const QuicUint128 kPrime = MakeQuicUint128(16777216, 315);
61 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
62 for (size_t i = 0; i < data.length(); ++i) {
63 hash = hash ^ MakeQuicUint128(0, octets[i]);
64 hash = hash * kPrime;
65 }
66 return hash;
67}
68#endif
69
70QuicUint128 IncrementalHash(QuicUint128 hash, QuicStringPiece data) {
71#ifdef QUIC_UTIL_HAS_UINT128
72 return IncrementalHashFast(hash, data);
73#else
74 return IncrementalHashSlow(hash, data);
75#endif
76}
77
78} // namespace
79
80// static
81uint64_t QuicUtils::FNV1a_64_Hash(QuicStringPiece data) {
82 static const uint64_t kOffset = UINT64_C(14695981039346656037);
83 static const uint64_t kPrime = UINT64_C(1099511628211);
84
85 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
86
87 uint64_t hash = kOffset;
88
89 for (size_t i = 0; i < data.length(); ++i) {
90 hash = hash ^ octets[i];
91 hash = hash * kPrime;
92 }
93
94 return hash;
95}
96
97// static
98QuicUint128 QuicUtils::FNV1a_128_Hash(QuicStringPiece data) {
99 return FNV1a_128_Hash_Three(data, QuicStringPiece(), QuicStringPiece());
100}
101
102// static
103QuicUint128 QuicUtils::FNV1a_128_Hash_Two(QuicStringPiece data1,
104 QuicStringPiece data2) {
105 return FNV1a_128_Hash_Three(data1, data2, QuicStringPiece());
106}
107
108// static
109QuicUint128 QuicUtils::FNV1a_128_Hash_Three(QuicStringPiece data1,
110 QuicStringPiece data2,
111 QuicStringPiece data3) {
112 // The two constants are defined as part of the hash algorithm.
113 // see http://www.isthe.com/chongo/tech/comp/fnv/
114 // kOffset = 144066263297769815596495629667062367629
115 const QuicUint128 kOffset = MakeQuicUint128(UINT64_C(7809847782465536322),
116 UINT64_C(7113472399480571277));
117
118 QuicUint128 hash = IncrementalHash(kOffset, data1);
119 if (data2.empty()) {
120 return hash;
121 }
122
123 hash = IncrementalHash(hash, data2);
124 if (data3.empty()) {
125 return hash;
126 }
127 return IncrementalHash(hash, data3);
128}
129
130// static
131void QuicUtils::SerializeUint128Short(QuicUint128 v, uint8_t* out) {
132 const uint64_t lo = QuicUint128Low64(v);
133 const uint64_t hi = QuicUint128High64(v);
134 // This assumes that the system is little-endian.
135 memcpy(out, &lo, sizeof(lo));
136 memcpy(out + sizeof(lo), &hi, sizeof(hi) / 2);
137}
138
139#define RETURN_STRING_LITERAL(x) \
140 case x: \
141 return #x;
142
143// static
144const char* QuicUtils::EncryptionLevelToString(EncryptionLevel level) {
145 switch (level) {
QUICHE team6987b4a2019-03-15 16:23:04 -0700146 RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
QUICHE team88ea0082019-03-15 10:05:26 -0700147 RETURN_STRING_LITERAL(ENCRYPTION_HANDSHAKE);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500148 RETURN_STRING_LITERAL(ENCRYPTION_ZERO_RTT);
149 RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE);
150 RETURN_STRING_LITERAL(NUM_ENCRYPTION_LEVELS);
151 }
152 return "INVALID_ENCRYPTION_LEVEL";
153}
154
155// static
156const char* QuicUtils::TransmissionTypeToString(TransmissionType type) {
157 switch (type) {
158 RETURN_STRING_LITERAL(NOT_RETRANSMISSION);
159 RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMISSION);
160 RETURN_STRING_LITERAL(LOSS_RETRANSMISSION);
161 RETURN_STRING_LITERAL(ALL_UNACKED_RETRANSMISSION);
162 RETURN_STRING_LITERAL(ALL_INITIAL_RETRANSMISSION);
163 RETURN_STRING_LITERAL(RTO_RETRANSMISSION);
164 RETURN_STRING_LITERAL(TLP_RETRANSMISSION);
165 RETURN_STRING_LITERAL(PROBING_RETRANSMISSION);
166 }
167 return "INVALID_TRANSMISSION_TYPE";
168}
169
vasilvvc48c8712019-03-11 13:38:16 -0700170std::string QuicUtils::AddressChangeTypeToString(AddressChangeType type) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500171 switch (type) {
172 RETURN_STRING_LITERAL(NO_CHANGE);
173 RETURN_STRING_LITERAL(PORT_CHANGE);
174 RETURN_STRING_LITERAL(IPV4_SUBNET_CHANGE);
175 RETURN_STRING_LITERAL(IPV4_TO_IPV6_CHANGE);
176 RETURN_STRING_LITERAL(IPV6_TO_IPV4_CHANGE);
177 RETURN_STRING_LITERAL(IPV6_TO_IPV6_CHANGE);
178 RETURN_STRING_LITERAL(IPV4_TO_IPV4_CHANGE);
179 }
180 return "INVALID_ADDRESS_CHANGE_TYPE";
181}
182
183const char* QuicUtils::SentPacketStateToString(SentPacketState state) {
184 switch (state) {
185 RETURN_STRING_LITERAL(OUTSTANDING);
186 RETURN_STRING_LITERAL(NEVER_SENT);
187 RETURN_STRING_LITERAL(ACKED);
188 RETURN_STRING_LITERAL(UNACKABLE);
189 RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMITTED);
190 RETURN_STRING_LITERAL(LOST);
191 RETURN_STRING_LITERAL(TLP_RETRANSMITTED);
192 RETURN_STRING_LITERAL(RTO_RETRANSMITTED);
193 RETURN_STRING_LITERAL(PROBE_RETRANSMITTED);
194 }
195 return "INVALID_SENT_PACKET_STATE";
196}
197
198// static
199const char* QuicUtils::QuicLongHeaderTypetoString(QuicLongHeaderType type) {
200 switch (type) {
201 RETURN_STRING_LITERAL(VERSION_NEGOTIATION);
202 RETURN_STRING_LITERAL(INITIAL);
203 RETURN_STRING_LITERAL(RETRY);
204 RETURN_STRING_LITERAL(HANDSHAKE);
205 RETURN_STRING_LITERAL(ZERO_RTT_PROTECTED);
206 default:
207 return "INVALID_PACKET_TYPE";
208 }
209}
210
211// static
fayang3eb82212019-04-16 12:05:46 -0700212const char* QuicUtils::AckResultToString(AckResult result) {
213 switch (result) {
214 RETURN_STRING_LITERAL(PACKETS_NEWLY_ACKED);
215 RETURN_STRING_LITERAL(NO_PACKETS_NEWLY_ACKED);
216 RETURN_STRING_LITERAL(UNSENT_PACKETS_ACKED);
217 RETURN_STRING_LITERAL(UNACKABLE_PACKETS_ACKED);
218 RETURN_STRING_LITERAL(PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE);
219 }
220 return "INVALID_ACK_RESULT";
221}
222
223// static
QUICHE teama6ef0a62019-03-07 20:34:33 -0500224AddressChangeType QuicUtils::DetermineAddressChangeType(
225 const QuicSocketAddress& old_address,
226 const QuicSocketAddress& new_address) {
227 if (!old_address.IsInitialized() || !new_address.IsInitialized() ||
228 old_address == new_address) {
229 return NO_CHANGE;
230 }
231
232 if (old_address.host() == new_address.host()) {
233 return PORT_CHANGE;
234 }
235
236 bool old_ip_is_ipv4 = old_address.host().IsIPv4() ? true : false;
237 bool migrating_ip_is_ipv4 = new_address.host().IsIPv4() ? true : false;
238 if (old_ip_is_ipv4 && !migrating_ip_is_ipv4) {
239 return IPV4_TO_IPV6_CHANGE;
240 }
241
242 if (!old_ip_is_ipv4) {
243 return migrating_ip_is_ipv4 ? IPV6_TO_IPV4_CHANGE : IPV6_TO_IPV6_CHANGE;
244 }
245
246 const int kSubnetMaskLength = 24;
247 if (old_address.host().InSameSubnet(new_address.host(), kSubnetMaskLength)) {
248 // Subnet part does not change (here, we use /24), which is considered to be
249 // caused by NATs.
250 return IPV4_SUBNET_CHANGE;
251 }
252
253 return IPV4_TO_IPV4_CHANGE;
254}
255
256// static
257void QuicUtils::CopyToBuffer(const struct iovec* iov,
258 int iov_count,
259 size_t iov_offset,
260 size_t buffer_length,
261 char* buffer) {
262 int iovnum = 0;
263 while (iovnum < iov_count && iov_offset >= iov[iovnum].iov_len) {
264 iov_offset -= iov[iovnum].iov_len;
265 ++iovnum;
266 }
267 DCHECK_LE(iovnum, iov_count);
268 DCHECK_LE(iov_offset, iov[iovnum].iov_len);
269 if (iovnum >= iov_count || buffer_length == 0) {
270 return;
271 }
272
273 // Unroll the first iteration that handles iov_offset.
274 const size_t iov_available = iov[iovnum].iov_len - iov_offset;
275 size_t copy_len = std::min(buffer_length, iov_available);
276
277 // Try to prefetch the next iov if there is at least one more after the
278 // current. Otherwise, it looks like an irregular access that the hardware
279 // prefetcher won't speculatively prefetch. Only prefetch one iov because
280 // generally, the iov_offset is not 0, input iov consists of 2K buffers and
281 // the output buffer is ~1.4K.
282 if (copy_len == iov_available && iovnum + 1 < iov_count) {
283 char* next_base = static_cast<char*>(iov[iovnum + 1].iov_base);
284 // Prefetch 2 cachelines worth of data to get the prefetcher started; leave
285 // it to the hardware prefetcher after that.
286 QuicPrefetchT0(next_base);
287 if (iov[iovnum + 1].iov_len >= 64) {
288 QuicPrefetchT0(next_base + QUIC_CACHELINE_SIZE);
289 }
290 }
291
292 const char* src = static_cast<char*>(iov[iovnum].iov_base) + iov_offset;
293 while (true) {
294 memcpy(buffer, src, copy_len);
295 buffer_length -= copy_len;
296 buffer += copy_len;
297 if (buffer_length == 0 || ++iovnum >= iov_count) {
298 break;
299 }
300 src = static_cast<char*>(iov[iovnum].iov_base);
301 copy_len = std::min(buffer_length, iov[iovnum].iov_len);
302 }
303 QUIC_BUG_IF(buffer_length > 0) << "Failed to copy entire length to buffer.";
304}
305
306// static
307struct iovec QuicUtils::MakeIovec(QuicStringPiece data) {
308 struct iovec iov = {const_cast<char*>(data.data()),
309 static_cast<size_t>(data.size())};
310 return iov;
311}
312
313// static
314bool QuicUtils::IsAckable(SentPacketState state) {
315 return state != NEVER_SENT && state != ACKED && state != UNACKABLE;
316}
317
318// static
319bool QuicUtils::IsRetransmittableFrame(QuicFrameType type) {
320 switch (type) {
321 case ACK_FRAME:
322 case PADDING_FRAME:
323 case STOP_WAITING_FRAME:
324 case MTU_DISCOVERY_FRAME:
325 return false;
326 default:
327 return true;
328 }
329}
330
331// static
332bool QuicUtils::IsHandshakeFrame(const QuicFrame& frame,
333 QuicTransportVersion transport_version) {
QUICHE teamea740082019-03-11 17:58:43 -0700334 if (!QuicVersionUsesCryptoFrames(transport_version)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500335 return frame.type == STREAM_FRAME &&
336 frame.stream_frame.stream_id == GetCryptoStreamId(transport_version);
337 } else {
338 return frame.type == CRYPTO_FRAME;
339 }
340}
341
342// static
343SentPacketState QuicUtils::RetransmissionTypeToPacketState(
344 TransmissionType retransmission_type) {
345 switch (retransmission_type) {
346 case ALL_UNACKED_RETRANSMISSION:
347 case ALL_INITIAL_RETRANSMISSION:
348 return UNACKABLE;
349 case HANDSHAKE_RETRANSMISSION:
350 return HANDSHAKE_RETRANSMITTED;
351 case LOSS_RETRANSMISSION:
352 return LOST;
353 case TLP_RETRANSMISSION:
354 return TLP_RETRANSMITTED;
355 case RTO_RETRANSMISSION:
356 return RTO_RETRANSMITTED;
357 case PROBING_RETRANSMISSION:
358 return PROBE_RETRANSMITTED;
359 default:
360 QUIC_BUG << QuicUtils::TransmissionTypeToString(retransmission_type)
361 << " is not a retransmission_type";
362 return UNACKABLE;
363 }
364}
365
366// static
367bool QuicUtils::IsIetfPacketHeader(uint8_t first_byte) {
368 return (first_byte & FLAGS_LONG_HEADER) || (first_byte & FLAGS_FIXED_BIT) ||
369 !(first_byte & FLAGS_DEMULTIPLEXING_BIT);
370}
371
372// static
373bool QuicUtils::IsIetfPacketShortHeader(uint8_t first_byte) {
374 return IsIetfPacketHeader(first_byte) && !(first_byte & FLAGS_LONG_HEADER);
375}
376
377// static
378QuicStreamId QuicUtils::GetInvalidStreamId(QuicTransportVersion version) {
379 return version == QUIC_VERSION_99 ? std::numeric_limits<QuicStreamId>::max()
380 : 0;
381}
382
383// static
384QuicStreamId QuicUtils::GetCryptoStreamId(QuicTransportVersion version) {
385 // TODO(nharper): Change this to return GetInvalidStreamId for version 47 or
386 // greater. Currently, too many things break with that change.
387 return version == QUIC_VERSION_99 ? 0 : 1;
388}
389
390// static
391QuicStreamId QuicUtils::GetHeadersStreamId(QuicTransportVersion version) {
392 return version == QUIC_VERSION_99 ? 4 : 3;
393}
394
395// static
396bool QuicUtils::IsClientInitiatedStreamId(QuicTransportVersion version,
397 QuicStreamId id) {
398 if (id == GetInvalidStreamId(version)) {
399 return false;
400 }
401 return version == QUIC_VERSION_99 ? id % 2 == 0 : id % 2 != 0;
402}
403
404// static
405bool QuicUtils::IsServerInitiatedStreamId(QuicTransportVersion version,
406 QuicStreamId id) {
407 if (id == GetInvalidStreamId(version)) {
408 return false;
409 }
410 return version == QUIC_VERSION_99 ? id % 2 != 0 : id % 2 == 0;
411}
412
413// static
414bool QuicUtils::IsBidirectionalStreamId(QuicStreamId id) {
415 return id % 4 < 2;
416}
417
418// static
419StreamType QuicUtils::GetStreamType(QuicStreamId id,
420 Perspective perspective,
421 bool peer_initiated) {
422 if (IsBidirectionalStreamId(id)) {
423 return BIDIRECTIONAL;
424 }
425
426 if (peer_initiated) {
427 if (perspective == Perspective::IS_SERVER) {
428 DCHECK_EQ(2u, id % 4);
429 } else {
430 DCHECK_EQ(Perspective::IS_CLIENT, perspective);
431 DCHECK_EQ(3u, id % 4);
432 }
433 return READ_UNIDIRECTIONAL;
434 }
435
436 if (perspective == Perspective::IS_SERVER) {
437 DCHECK_EQ(3u, id % 4);
438 } else {
439 DCHECK_EQ(Perspective::IS_CLIENT, perspective);
440 DCHECK_EQ(2u, id % 4);
441 }
442 return WRITE_UNIDIRECTIONAL;
443}
444
445// static
446QuicStreamId QuicUtils::StreamIdDelta(QuicTransportVersion version) {
447 return version == QUIC_VERSION_99 ? 4 : 2;
448}
449
450// static
451QuicStreamId QuicUtils::GetFirstBidirectionalStreamId(
452 QuicTransportVersion version,
453 Perspective perspective) {
454 if (perspective == Perspective::IS_CLIENT) {
455 return version == QUIC_VERSION_99 ? 4 : 3;
456 }
457 return version == QUIC_VERSION_99 ? 1 : 2;
458}
459
460// static
461QuicStreamId QuicUtils::GetFirstUnidirectionalStreamId(
462 QuicTransportVersion version,
463 Perspective perspective) {
464 if (perspective == Perspective::IS_CLIENT) {
465 return version == QUIC_VERSION_99 ? 2 : 3;
466 }
467 return version == QUIC_VERSION_99 ? 3 : 2;
468}
469
470// static
471QuicConnectionId QuicUtils::CreateRandomConnectionId() {
QUICHE teamc65d1d12019-03-19 20:58:04 -0700472 return CreateRandomConnectionId(kQuicDefaultConnectionIdLength,
473 QuicRandom::GetInstance());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500474}
475
476// static
477QuicConnectionId QuicUtils::CreateRandomConnectionId(QuicRandom* random) {
QUICHE teamc65d1d12019-03-19 20:58:04 -0700478 return CreateRandomConnectionId(kQuicDefaultConnectionIdLength, random);
479}
480// static
481QuicConnectionId QuicUtils::CreateRandomConnectionId(
482 uint8_t connection_id_length) {
483 return CreateRandomConnectionId(connection_id_length,
484 QuicRandom::GetInstance());
485}
486
487// static
488QuicConnectionId QuicUtils::CreateRandomConnectionId(
489 uint8_t connection_id_length,
490 QuicRandom* random) {
491 if (connection_id_length == 0) {
492 return EmptyQuicConnectionId();
493 }
494 if (connection_id_length > kQuicMaxConnectionIdLength) {
495 QUIC_BUG << "Tried to CreateRandomConnectionId of invalid length "
496 << static_cast<int>(connection_id_length);
497 connection_id_length = kQuicMaxConnectionIdLength;
498 }
499 char connection_id_bytes[kQuicMaxConnectionIdLength];
500 random->RandBytes(connection_id_bytes, connection_id_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500501 return QuicConnectionId(static_cast<char*>(connection_id_bytes),
QUICHE teamc65d1d12019-03-19 20:58:04 -0700502 connection_id_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500503}
504
505// static
506bool QuicUtils::VariableLengthConnectionIdAllowedForVersion(
507 QuicTransportVersion version) {
QUICHE team9b41c972019-03-21 11:22:48 -0700508 return version >= QUIC_VERSION_47;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500509}
510
511// static
512QuicConnectionId QuicUtils::CreateZeroConnectionId(
513 QuicTransportVersion version) {
514 if (!VariableLengthConnectionIdAllowedForVersion(version)) {
515 char connection_id_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
516 return QuicConnectionId(static_cast<char*>(connection_id_bytes),
517 QUIC_ARRAYSIZE(connection_id_bytes));
518 }
519 return EmptyQuicConnectionId();
520}
521
522// static
523bool QuicUtils::IsConnectionIdValidForVersion(QuicConnectionId connection_id,
524 QuicTransportVersion version) {
525 if (VariableLengthConnectionIdAllowedForVersion(version)) {
526 return true;
527 }
528 return connection_id.length() == kQuicDefaultConnectionIdLength;
529}
530
531QuicUint128 QuicUtils::GenerateStatelessResetToken(
532 QuicConnectionId connection_id) {
533 uint64_t data_bytes[3] = {0, 0, 0};
534 static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdLength,
535 "kQuicMaxConnectionIdLength changed");
536 memcpy(data_bytes, connection_id.data(), connection_id.length());
537 // This is designed so that the common case of 64bit connection IDs
538 // produces a stateless reset token that is equal to the connection ID
539 // interpreted as a 64bit unsigned integer, to facilitate debugging.
540 return MakeQuicUint128(
541 QuicEndian::NetToHost64(sizeof(uint64_t) ^ connection_id.length() ^
542 data_bytes[1] ^ data_bytes[2]),
543 QuicEndian::NetToHost64(data_bytes[0]));
544}
545
fkastenholz3c4eabf2019-04-22 07:49:59 -0700546// Returns the maximum value that a stream count may have, taking into account
547// the fact that bidirectional, client initiated, streams have one fewer stream
548// available than the others. This is because the old crypto streams, with ID ==
549// 0 are not included in the count.
550// The version is not included in the call, nor does the method take the version
551// into account, because this is called only from code used for IETF QUIC.
552// TODO(fkastenholz): Remove this method and replace calls to it with direct
553// references to kMaxQuicStreamIdCount when streamid 0 becomes a normal stream
554// id.
555// static
556QuicStreamCount QuicUtils::GetMaxStreamCount(bool unidirectional,
557 Perspective perspective) {
558 if (!unidirectional && perspective == Perspective::IS_CLIENT) {
559 return kMaxQuicStreamCount >> 2;
560 }
561 return (kMaxQuicStreamCount >> 2) + 1;
562}
563
QUICHE team10b22a12019-03-21 15:31:42 -0700564// static
565PacketNumberSpace QuicUtils::GetPacketNumberSpace(
566 EncryptionLevel encryption_level) {
567 switch (encryption_level) {
568 case ENCRYPTION_INITIAL:
569 return INITIAL_DATA;
570 case ENCRYPTION_HANDSHAKE:
571 return HANDSHAKE_DATA;
572 case ENCRYPTION_ZERO_RTT:
573 case ENCRYPTION_FORWARD_SECURE:
574 return APPLICATION_DATA;
575 default:
576 QUIC_BUG << "Try to get packet number space of encryption level: "
577 << EncryptionLevelToString(encryption_level);
578 return NUM_PACKET_NUMBER_SPACES;
579 }
580}
581
QUICHE team1dfa46b2019-03-22 10:39:10 -0700582// static
583EncryptionLevel QuicUtils::GetEncryptionLevel(
584 PacketNumberSpace packet_number_space) {
585 switch (packet_number_space) {
586 case INITIAL_DATA:
587 return ENCRYPTION_INITIAL;
588 case HANDSHAKE_DATA:
589 return ENCRYPTION_HANDSHAKE;
590 case APPLICATION_DATA:
591 return ENCRYPTION_FORWARD_SECURE;
592 default:
593 DCHECK(false);
594 return NUM_ENCRYPTION_LEVELS;
595 }
596}
597
QUICHE teama6ef0a62019-03-07 20:34:33 -0500598#undef RETURN_STRING_LITERAL // undef for jumbo builds
599} // namespace quic