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