blob: da2cb1a699caca498da6acefc2884aea1a5c9d87 [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"
renjietang118c8ac2019-07-30 11:43:59 -070014#include "net/third_party/quiche/src/quic/core/quic_versions.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050015#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
dschinazi8eb45e92019-05-10 11:36:15 -070019#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050020#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
21#include "net/third_party/quiche/src/quic/platform/api/quic_prefetch.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h"
23
24namespace quic {
25namespace {
26
27// We know that >= GCC 4.8 and Clang have a __uint128_t intrinsic. Other
28// compilers don't necessarily, notably MSVC.
29#if defined(__x86_64__) && \
30 ((defined(__GNUC__) && \
31 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
32 defined(__clang__))
33#define QUIC_UTIL_HAS_UINT128 1
34#endif
35
36#ifdef QUIC_UTIL_HAS_UINT128
37QuicUint128 IncrementalHashFast(QuicUint128 uhash, QuicStringPiece data) {
38 // This code ends up faster than the naive implementation for 2 reasons:
39 // 1. QuicUint128 is sufficiently complicated that the compiler
40 // cannot transform the multiplication by kPrime into a shift-multiply-add;
41 // it has go through all of the instructions for a 128-bit multiply.
42 // 2. Because there are so fewer instructions (around 13), the hot loop fits
43 // nicely in the instruction queue of many Intel CPUs.
44 // kPrime = 309485009821345068724781371
45 static const QuicUint128 kPrime =
46 (static_cast<QuicUint128>(16777216) << 64) + 315;
47 auto hi = QuicUint128High64(uhash);
48 auto lo = QuicUint128Low64(uhash);
49 QuicUint128 xhash = (static_cast<QuicUint128>(hi) << 64) + lo;
50 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
51 for (size_t i = 0; i < data.length(); ++i) {
52 xhash = (xhash ^ static_cast<uint32_t>(octets[i])) * kPrime;
53 }
54 return MakeQuicUint128(QuicUint128High64(xhash), QuicUint128Low64(xhash));
55}
56#endif
57
58#ifndef QUIC_UTIL_HAS_UINT128
59// Slow implementation of IncrementalHash. In practice, only used by Chromium.
60QuicUint128 IncrementalHashSlow(QuicUint128 hash, QuicStringPiece data) {
61 // kPrime = 309485009821345068724781371
62 static const QuicUint128 kPrime = MakeQuicUint128(16777216, 315);
63 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
64 for (size_t i = 0; i < data.length(); ++i) {
65 hash = hash ^ MakeQuicUint128(0, octets[i]);
66 hash = hash * kPrime;
67 }
68 return hash;
69}
70#endif
71
72QuicUint128 IncrementalHash(QuicUint128 hash, QuicStringPiece data) {
73#ifdef QUIC_UTIL_HAS_UINT128
74 return IncrementalHashFast(hash, data);
75#else
76 return IncrementalHashSlow(hash, data);
77#endif
78}
79
80} // namespace
81
82// static
83uint64_t QuicUtils::FNV1a_64_Hash(QuicStringPiece data) {
84 static const uint64_t kOffset = UINT64_C(14695981039346656037);
85 static const uint64_t kPrime = UINT64_C(1099511628211);
86
87 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
88
89 uint64_t hash = kOffset;
90
91 for (size_t i = 0; i < data.length(); ++i) {
92 hash = hash ^ octets[i];
93 hash = hash * kPrime;
94 }
95
96 return hash;
97}
98
99// static
100QuicUint128 QuicUtils::FNV1a_128_Hash(QuicStringPiece data) {
101 return FNV1a_128_Hash_Three(data, QuicStringPiece(), QuicStringPiece());
102}
103
104// static
105QuicUint128 QuicUtils::FNV1a_128_Hash_Two(QuicStringPiece data1,
106 QuicStringPiece data2) {
107 return FNV1a_128_Hash_Three(data1, data2, QuicStringPiece());
108}
109
110// static
111QuicUint128 QuicUtils::FNV1a_128_Hash_Three(QuicStringPiece data1,
112 QuicStringPiece data2,
113 QuicStringPiece data3) {
114 // The two constants are defined as part of the hash algorithm.
115 // see http://www.isthe.com/chongo/tech/comp/fnv/
116 // kOffset = 144066263297769815596495629667062367629
117 const QuicUint128 kOffset = MakeQuicUint128(UINT64_C(7809847782465536322),
118 UINT64_C(7113472399480571277));
119
120 QuicUint128 hash = IncrementalHash(kOffset, data1);
121 if (data2.empty()) {
122 return hash;
123 }
124
125 hash = IncrementalHash(hash, data2);
126 if (data3.empty()) {
127 return hash;
128 }
129 return IncrementalHash(hash, data3);
130}
131
132// static
133void QuicUtils::SerializeUint128Short(QuicUint128 v, uint8_t* out) {
134 const uint64_t lo = QuicUint128Low64(v);
135 const uint64_t hi = QuicUint128High64(v);
136 // This assumes that the system is little-endian.
137 memcpy(out, &lo, sizeof(lo));
138 memcpy(out + sizeof(lo), &hi, sizeof(hi) / 2);
139}
140
141#define RETURN_STRING_LITERAL(x) \
142 case x: \
143 return #x;
144
145// static
146const char* QuicUtils::EncryptionLevelToString(EncryptionLevel level) {
147 switch (level) {
QUICHE team6987b4a2019-03-15 16:23:04 -0700148 RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
QUICHE team88ea0082019-03-15 10:05:26 -0700149 RETURN_STRING_LITERAL(ENCRYPTION_HANDSHAKE);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500150 RETURN_STRING_LITERAL(ENCRYPTION_ZERO_RTT);
151 RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE);
152 RETURN_STRING_LITERAL(NUM_ENCRYPTION_LEVELS);
153 }
154 return "INVALID_ENCRYPTION_LEVEL";
155}
156
157// static
158const char* QuicUtils::TransmissionTypeToString(TransmissionType type) {
159 switch (type) {
160 RETURN_STRING_LITERAL(NOT_RETRANSMISSION);
161 RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMISSION);
162 RETURN_STRING_LITERAL(LOSS_RETRANSMISSION);
163 RETURN_STRING_LITERAL(ALL_UNACKED_RETRANSMISSION);
164 RETURN_STRING_LITERAL(ALL_INITIAL_RETRANSMISSION);
165 RETURN_STRING_LITERAL(RTO_RETRANSMISSION);
166 RETURN_STRING_LITERAL(TLP_RETRANSMISSION);
167 RETURN_STRING_LITERAL(PROBING_RETRANSMISSION);
168 }
169 return "INVALID_TRANSMISSION_TYPE";
170}
171
vasilvvc48c8712019-03-11 13:38:16 -0700172std::string QuicUtils::AddressChangeTypeToString(AddressChangeType type) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500173 switch (type) {
174 RETURN_STRING_LITERAL(NO_CHANGE);
175 RETURN_STRING_LITERAL(PORT_CHANGE);
176 RETURN_STRING_LITERAL(IPV4_SUBNET_CHANGE);
177 RETURN_STRING_LITERAL(IPV4_TO_IPV6_CHANGE);
178 RETURN_STRING_LITERAL(IPV6_TO_IPV4_CHANGE);
179 RETURN_STRING_LITERAL(IPV6_TO_IPV6_CHANGE);
180 RETURN_STRING_LITERAL(IPV4_TO_IPV4_CHANGE);
181 }
182 return "INVALID_ADDRESS_CHANGE_TYPE";
183}
184
185const char* QuicUtils::SentPacketStateToString(SentPacketState state) {
186 switch (state) {
187 RETURN_STRING_LITERAL(OUTSTANDING);
188 RETURN_STRING_LITERAL(NEVER_SENT);
189 RETURN_STRING_LITERAL(ACKED);
190 RETURN_STRING_LITERAL(UNACKABLE);
191 RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMITTED);
192 RETURN_STRING_LITERAL(LOST);
193 RETURN_STRING_LITERAL(TLP_RETRANSMITTED);
194 RETURN_STRING_LITERAL(RTO_RETRANSMITTED);
195 RETURN_STRING_LITERAL(PROBE_RETRANSMITTED);
196 }
197 return "INVALID_SENT_PACKET_STATE";
198}
199
200// static
201const char* QuicUtils::QuicLongHeaderTypetoString(QuicLongHeaderType type) {
202 switch (type) {
203 RETURN_STRING_LITERAL(VERSION_NEGOTIATION);
204 RETURN_STRING_LITERAL(INITIAL);
205 RETURN_STRING_LITERAL(RETRY);
206 RETURN_STRING_LITERAL(HANDSHAKE);
207 RETURN_STRING_LITERAL(ZERO_RTT_PROTECTED);
208 default:
209 return "INVALID_PACKET_TYPE";
210 }
211}
212
213// static
fayang3eb82212019-04-16 12:05:46 -0700214const char* QuicUtils::AckResultToString(AckResult result) {
215 switch (result) {
216 RETURN_STRING_LITERAL(PACKETS_NEWLY_ACKED);
217 RETURN_STRING_LITERAL(NO_PACKETS_NEWLY_ACKED);
218 RETURN_STRING_LITERAL(UNSENT_PACKETS_ACKED);
219 RETURN_STRING_LITERAL(UNACKABLE_PACKETS_ACKED);
220 RETURN_STRING_LITERAL(PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE);
221 }
222 return "INVALID_ACK_RESULT";
223}
224
225// static
QUICHE teama6ef0a62019-03-07 20:34:33 -0500226AddressChangeType QuicUtils::DetermineAddressChangeType(
227 const QuicSocketAddress& old_address,
228 const QuicSocketAddress& new_address) {
229 if (!old_address.IsInitialized() || !new_address.IsInitialized() ||
230 old_address == new_address) {
231 return NO_CHANGE;
232 }
233
234 if (old_address.host() == new_address.host()) {
235 return PORT_CHANGE;
236 }
237
238 bool old_ip_is_ipv4 = old_address.host().IsIPv4() ? true : false;
239 bool migrating_ip_is_ipv4 = new_address.host().IsIPv4() ? true : false;
240 if (old_ip_is_ipv4 && !migrating_ip_is_ipv4) {
241 return IPV4_TO_IPV6_CHANGE;
242 }
243
244 if (!old_ip_is_ipv4) {
245 return migrating_ip_is_ipv4 ? IPV6_TO_IPV4_CHANGE : IPV6_TO_IPV6_CHANGE;
246 }
247
248 const int kSubnetMaskLength = 24;
249 if (old_address.host().InSameSubnet(new_address.host(), kSubnetMaskLength)) {
250 // Subnet part does not change (here, we use /24), which is considered to be
251 // caused by NATs.
252 return IPV4_SUBNET_CHANGE;
253 }
254
255 return IPV4_TO_IPV4_CHANGE;
256}
257
258// static
259void QuicUtils::CopyToBuffer(const struct iovec* iov,
260 int iov_count,
261 size_t iov_offset,
262 size_t buffer_length,
263 char* buffer) {
264 int iovnum = 0;
265 while (iovnum < iov_count && iov_offset >= iov[iovnum].iov_len) {
266 iov_offset -= iov[iovnum].iov_len;
267 ++iovnum;
268 }
269 DCHECK_LE(iovnum, iov_count);
270 DCHECK_LE(iov_offset, iov[iovnum].iov_len);
271 if (iovnum >= iov_count || buffer_length == 0) {
272 return;
273 }
274
275 // Unroll the first iteration that handles iov_offset.
276 const size_t iov_available = iov[iovnum].iov_len - iov_offset;
277 size_t copy_len = std::min(buffer_length, iov_available);
278
279 // Try to prefetch the next iov if there is at least one more after the
280 // current. Otherwise, it looks like an irregular access that the hardware
281 // prefetcher won't speculatively prefetch. Only prefetch one iov because
282 // generally, the iov_offset is not 0, input iov consists of 2K buffers and
283 // the output buffer is ~1.4K.
284 if (copy_len == iov_available && iovnum + 1 < iov_count) {
285 char* next_base = static_cast<char*>(iov[iovnum + 1].iov_base);
286 // Prefetch 2 cachelines worth of data to get the prefetcher started; leave
287 // it to the hardware prefetcher after that.
288 QuicPrefetchT0(next_base);
289 if (iov[iovnum + 1].iov_len >= 64) {
290 QuicPrefetchT0(next_base + QUIC_CACHELINE_SIZE);
291 }
292 }
293
294 const char* src = static_cast<char*>(iov[iovnum].iov_base) + iov_offset;
295 while (true) {
296 memcpy(buffer, src, copy_len);
297 buffer_length -= copy_len;
298 buffer += copy_len;
299 if (buffer_length == 0 || ++iovnum >= iov_count) {
300 break;
301 }
302 src = static_cast<char*>(iov[iovnum].iov_base);
303 copy_len = std::min(buffer_length, iov[iovnum].iov_len);
304 }
305 QUIC_BUG_IF(buffer_length > 0) << "Failed to copy entire length to buffer.";
306}
307
308// static
309struct iovec QuicUtils::MakeIovec(QuicStringPiece data) {
310 struct iovec iov = {const_cast<char*>(data.data()),
311 static_cast<size_t>(data.size())};
312 return iov;
313}
314
315// static
316bool QuicUtils::IsAckable(SentPacketState state) {
317 return state != NEVER_SENT && state != ACKED && state != UNACKABLE;
318}
319
320// static
321bool QuicUtils::IsRetransmittableFrame(QuicFrameType type) {
322 switch (type) {
323 case ACK_FRAME:
324 case PADDING_FRAME:
325 case STOP_WAITING_FRAME:
326 case MTU_DISCOVERY_FRAME:
327 return false;
328 default:
329 return true;
330 }
331}
332
333// static
334bool QuicUtils::IsHandshakeFrame(const QuicFrame& frame,
335 QuicTransportVersion transport_version) {
QUICHE teamea740082019-03-11 17:58:43 -0700336 if (!QuicVersionUsesCryptoFrames(transport_version)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500337 return frame.type == STREAM_FRAME &&
338 frame.stream_frame.stream_id == GetCryptoStreamId(transport_version);
339 } else {
340 return frame.type == CRYPTO_FRAME;
341 }
342}
343
344// static
345SentPacketState QuicUtils::RetransmissionTypeToPacketState(
346 TransmissionType retransmission_type) {
347 switch (retransmission_type) {
348 case ALL_UNACKED_RETRANSMISSION:
349 case ALL_INITIAL_RETRANSMISSION:
350 return UNACKABLE;
351 case HANDSHAKE_RETRANSMISSION:
352 return HANDSHAKE_RETRANSMITTED;
353 case LOSS_RETRANSMISSION:
354 return LOST;
355 case TLP_RETRANSMISSION:
356 return TLP_RETRANSMITTED;
357 case RTO_RETRANSMISSION:
358 return RTO_RETRANSMITTED;
359 case PROBING_RETRANSMISSION:
360 return PROBE_RETRANSMITTED;
361 default:
362 QUIC_BUG << QuicUtils::TransmissionTypeToString(retransmission_type)
363 << " is not a retransmission_type";
364 return UNACKABLE;
365 }
366}
367
368// static
369bool QuicUtils::IsIetfPacketHeader(uint8_t first_byte) {
370 return (first_byte & FLAGS_LONG_HEADER) || (first_byte & FLAGS_FIXED_BIT) ||
371 !(first_byte & FLAGS_DEMULTIPLEXING_BIT);
372}
373
374// static
375bool QuicUtils::IsIetfPacketShortHeader(uint8_t first_byte) {
376 return IsIetfPacketHeader(first_byte) && !(first_byte & FLAGS_LONG_HEADER);
377}
378
379// static
380QuicStreamId QuicUtils::GetInvalidStreamId(QuicTransportVersion version) {
fkastenholz305e1732019-06-18 05:01:22 -0700381 return VersionHasIetfQuicFrames(version)
382 ? std::numeric_limits<QuicStreamId>::max()
383 : 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500384}
385
386// static
387QuicStreamId QuicUtils::GetCryptoStreamId(QuicTransportVersion version) {
nharper46833c32019-05-15 21:33:05 -0700388 QUIC_BUG_IF(QuicVersionUsesCryptoFrames(version))
389 << "CRYPTO data aren't in stream frames; they have no stream ID.";
390 return QuicVersionUsesCryptoFrames(version) ? GetInvalidStreamId(version) : 1;
391}
392
393// static
394bool QuicUtils::IsCryptoStreamId(QuicTransportVersion version,
395 QuicStreamId stream_id) {
396 if (QuicVersionUsesCryptoFrames(version)) {
397 return false;
398 }
399 return stream_id == GetCryptoStreamId(version);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500400}
401
402// static
403QuicStreamId QuicUtils::GetHeadersStreamId(QuicTransportVersion version) {
renjietang940a5322019-08-02 16:17:51 -0700404 DCHECK(!VersionUsesQpack(version));
nharpercd820e02019-05-16 15:12:07 -0700405 return GetFirstBidirectionalStreamId(version, Perspective::IS_CLIENT);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500406}
407
408// static
409bool QuicUtils::IsClientInitiatedStreamId(QuicTransportVersion version,
410 QuicStreamId id) {
411 if (id == GetInvalidStreamId(version)) {
412 return false;
413 }
fkastenholz305e1732019-06-18 05:01:22 -0700414 return VersionHasIetfQuicFrames(version) ? id % 2 == 0 : id % 2 != 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500415}
416
417// static
418bool QuicUtils::IsServerInitiatedStreamId(QuicTransportVersion version,
419 QuicStreamId id) {
420 if (id == GetInvalidStreamId(version)) {
421 return false;
422 }
fkastenholz305e1732019-06-18 05:01:22 -0700423 return VersionHasIetfQuicFrames(version) ? id % 2 != 0 : id % 2 == 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500424}
425
426// static
427bool QuicUtils::IsBidirectionalStreamId(QuicStreamId id) {
428 return id % 4 < 2;
429}
430
431// static
432StreamType QuicUtils::GetStreamType(QuicStreamId id,
433 Perspective perspective,
434 bool peer_initiated) {
435 if (IsBidirectionalStreamId(id)) {
436 return BIDIRECTIONAL;
437 }
438
439 if (peer_initiated) {
440 if (perspective == Perspective::IS_SERVER) {
441 DCHECK_EQ(2u, id % 4);
442 } else {
443 DCHECK_EQ(Perspective::IS_CLIENT, perspective);
444 DCHECK_EQ(3u, id % 4);
445 }
446 return READ_UNIDIRECTIONAL;
447 }
448
449 if (perspective == Perspective::IS_SERVER) {
450 DCHECK_EQ(3u, id % 4);
451 } else {
452 DCHECK_EQ(Perspective::IS_CLIENT, perspective);
453 DCHECK_EQ(2u, id % 4);
454 }
455 return WRITE_UNIDIRECTIONAL;
456}
457
458// static
459QuicStreamId QuicUtils::StreamIdDelta(QuicTransportVersion version) {
fkastenholz305e1732019-06-18 05:01:22 -0700460 return VersionHasIetfQuicFrames(version) ? 4 : 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500461}
462
463// static
464QuicStreamId QuicUtils::GetFirstBidirectionalStreamId(
465 QuicTransportVersion version,
466 Perspective perspective) {
fkastenholz305e1732019-06-18 05:01:22 -0700467 if (VersionHasIetfQuicFrames(version)) {
nharpercd820e02019-05-16 15:12:07 -0700468 return perspective == Perspective::IS_CLIENT ? 0 : 1;
469 } else if (QuicVersionUsesCryptoFrames(version)) {
470 return perspective == Perspective::IS_CLIENT ? 1 : 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500471 }
nharpercd820e02019-05-16 15:12:07 -0700472 return perspective == Perspective::IS_CLIENT ? 3 : 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500473}
474
475// static
476QuicStreamId QuicUtils::GetFirstUnidirectionalStreamId(
477 QuicTransportVersion version,
478 Perspective perspective) {
fkastenholz305e1732019-06-18 05:01:22 -0700479 if (VersionHasIetfQuicFrames(version)) {
nharpercd820e02019-05-16 15:12:07 -0700480 return perspective == Perspective::IS_CLIENT ? 2 : 3;
481 } else if (QuicVersionUsesCryptoFrames(version)) {
482 return perspective == Perspective::IS_CLIENT ? 1 : 2;
483 }
484 return perspective == Perspective::IS_CLIENT ? 3 : 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500485}
486
487// static
dschinaziadc75072019-08-19 10:54:45 -0700488QuicConnectionId QuicUtils::CreateReplacementConnectionId(
489 QuicConnectionId connection_id) {
490 const uint64_t connection_id_hash = FNV1a_64_Hash(
491 QuicStringPiece(connection_id.data(), connection_id.length()));
492 return QuicConnectionId(reinterpret_cast<const char*>(&connection_id_hash),
493 sizeof(connection_id_hash));
494}
495
496// static
QUICHE teama6ef0a62019-03-07 20:34:33 -0500497QuicConnectionId QuicUtils::CreateRandomConnectionId() {
QUICHE teamc65d1d12019-03-19 20:58:04 -0700498 return CreateRandomConnectionId(kQuicDefaultConnectionIdLength,
499 QuicRandom::GetInstance());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500500}
501
502// static
503QuicConnectionId QuicUtils::CreateRandomConnectionId(QuicRandom* random) {
QUICHE teamc65d1d12019-03-19 20:58:04 -0700504 return CreateRandomConnectionId(kQuicDefaultConnectionIdLength, random);
505}
506// static
507QuicConnectionId QuicUtils::CreateRandomConnectionId(
508 uint8_t connection_id_length) {
509 return CreateRandomConnectionId(connection_id_length,
510 QuicRandom::GetInstance());
511}
512
513// static
514QuicConnectionId QuicUtils::CreateRandomConnectionId(
515 uint8_t connection_id_length,
516 QuicRandom* random) {
dschinazib953d022019-08-01 18:05:58 -0700517 QuicConnectionId connection_id;
518 connection_id.set_length(connection_id_length);
519 if (connection_id.length() > 0) {
520 random->RandBytes(connection_id.mutable_data(), connection_id.length());
QUICHE teamc65d1d12019-03-19 20:58:04 -0700521 }
dschinazib953d022019-08-01 18:05:58 -0700522 return connection_id;
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
dschinazi6c84c142019-07-31 09:11:49 -0700546bool QuicUtils::IsConnectionIdLengthValidForVersion(
547 size_t connection_id_length,
548 QuicTransportVersion transport_version) {
549 // No version of QUIC can support lengths that do not fit in an uint8_t.
550 if (connection_id_length >
551 static_cast<size_t>(std::numeric_limits<uint8_t>::max())) {
552 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500553 }
dschinazi6c84c142019-07-31 09:11:49 -0700554 const uint8_t connection_id_length8 =
555 static_cast<uint8_t>(connection_id_length);
556 // Versions that do not support variable lengths only support length 8.
557 if (!VariableLengthConnectionIdAllowedForVersion(transport_version)) {
558 return connection_id_length8 == kQuicDefaultConnectionIdLength;
559 }
dschinazib953d022019-08-01 18:05:58 -0700560 // Versions that do support variable length but do not have length-prefixed
561 // connection IDs use the 4-bit connection ID length encoding which can
562 // only encode values 0 and 4-18.
563 if (!VersionHasLengthPrefixedConnectionIds(transport_version)) {
564 return connection_id_length8 == 0 ||
565 (connection_id_length8 >= 4 &&
dschinazib012d212019-08-01 18:07:26 -0700566 connection_id_length8 <= kQuicMaxConnectionId4BitLength);
dschinazib953d022019-08-01 18:05:58 -0700567 }
dschinazib012d212019-08-01 18:07:26 -0700568 return connection_id_length8 <= kQuicMaxConnectionIdWithLengthPrefixLength;
dschinazi6c84c142019-07-31 09:11:49 -0700569}
570
571// static
572bool QuicUtils::IsConnectionIdValidForVersion(
573 QuicConnectionId connection_id,
574 QuicTransportVersion transport_version) {
575 return IsConnectionIdLengthValidForVersion(connection_id.length(),
576 transport_version);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500577}
578
579QuicUint128 QuicUtils::GenerateStatelessResetToken(
580 QuicConnectionId connection_id) {
dschinazi9a910e32019-08-19 18:05:04 -0700581 if (!GetQuicRestartFlag(quic_use_hashed_stateless_reset_tokens)) {
582 uint64_t data_bytes[3] = {0, 0, 0};
583 static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdAllVersionsLength,
584 "kQuicMaxConnectionIdAllVersionsLength changed");
585 memcpy(data_bytes, connection_id.data(), connection_id.length());
586 // This is designed so that the common case of 64bit connection IDs
587 // produces a stateless reset token that is equal to the connection ID
588 // interpreted as a 64bit unsigned integer, to facilitate debugging.
589 return MakeQuicUint128(
590 QuicEndian::NetToHost64(sizeof(uint64_t) ^ connection_id.length() ^
591 data_bytes[1] ^ data_bytes[2]),
592 QuicEndian::NetToHost64(data_bytes[0]));
593 }
594 QUIC_RESTART_FLAG_COUNT(quic_use_hashed_stateless_reset_tokens);
595 return FNV1a_128_Hash(
596 QuicStringPiece(connection_id.data(), connection_id.length()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500597}
598
fkastenholz3c4eabf2019-04-22 07:49:59 -0700599// Returns the maximum value that a stream count may have, taking into account
600// the fact that bidirectional, client initiated, streams have one fewer stream
601// available than the others. This is because the old crypto streams, with ID ==
602// 0 are not included in the count.
603// The version is not included in the call, nor does the method take the version
604// into account, because this is called only from code used for IETF QUIC.
605// TODO(fkastenholz): Remove this method and replace calls to it with direct
606// references to kMaxQuicStreamIdCount when streamid 0 becomes a normal stream
607// id.
608// static
609QuicStreamCount QuicUtils::GetMaxStreamCount(bool unidirectional,
610 Perspective perspective) {
611 if (!unidirectional && perspective == Perspective::IS_CLIENT) {
612 return kMaxQuicStreamCount >> 2;
613 }
614 return (kMaxQuicStreamCount >> 2) + 1;
615}
616
QUICHE team10b22a12019-03-21 15:31:42 -0700617// static
618PacketNumberSpace QuicUtils::GetPacketNumberSpace(
619 EncryptionLevel encryption_level) {
620 switch (encryption_level) {
621 case ENCRYPTION_INITIAL:
622 return INITIAL_DATA;
623 case ENCRYPTION_HANDSHAKE:
624 return HANDSHAKE_DATA;
625 case ENCRYPTION_ZERO_RTT:
626 case ENCRYPTION_FORWARD_SECURE:
627 return APPLICATION_DATA;
628 default:
629 QUIC_BUG << "Try to get packet number space of encryption level: "
630 << EncryptionLevelToString(encryption_level);
631 return NUM_PACKET_NUMBER_SPACES;
632 }
633}
634
QUICHE team1dfa46b2019-03-22 10:39:10 -0700635// static
636EncryptionLevel QuicUtils::GetEncryptionLevel(
637 PacketNumberSpace packet_number_space) {
638 switch (packet_number_space) {
639 case INITIAL_DATA:
640 return ENCRYPTION_INITIAL;
641 case HANDSHAKE_DATA:
642 return ENCRYPTION_HANDSHAKE;
643 case APPLICATION_DATA:
644 return ENCRYPTION_FORWARD_SECURE;
645 default:
646 DCHECK(false);
647 return NUM_ENCRYPTION_LEVELS;
648 }
649}
650
QUICHE teama6ef0a62019-03-07 20:34:33 -0500651#undef RETURN_STRING_LITERAL // undef for jumbo builds
652} // namespace quic