blob: 8057a7d1fb74e6d1aa47d436c135cb835ddefc7b [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"
QUICHE teama6ef0a62019-03-07 20:34:33 -050016#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
dschinazi8eb45e92019-05-10 11:36:15 -070017#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050018#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"
bnc4e9283d2019-12-17 07:08:57 -080021#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
QUICHE team173c48f2019-11-19 16:34:44 -080022#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h"
dmcardlecf0bfcf2019-12-13 08:08:21 -080023#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050024
25namespace quic {
26namespace {
27
28// We know that >= GCC 4.8 and Clang have a __uint128_t intrinsic. Other
29// compilers don't necessarily, notably MSVC.
30#if defined(__x86_64__) && \
31 ((defined(__GNUC__) && \
32 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
33 defined(__clang__))
34#define QUIC_UTIL_HAS_UINT128 1
35#endif
36
37#ifdef QUIC_UTIL_HAS_UINT128
dmcardlecf0bfcf2019-12-13 08:08:21 -080038QuicUint128 IncrementalHashFast(QuicUint128 uhash,
39 quiche::QuicheStringPiece data) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050040 // This code ends up faster than the naive implementation for 2 reasons:
41 // 1. QuicUint128 is sufficiently complicated that the compiler
42 // cannot transform the multiplication by kPrime into a shift-multiply-add;
43 // it has go through all of the instructions for a 128-bit multiply.
44 // 2. Because there are so fewer instructions (around 13), the hot loop fits
45 // nicely in the instruction queue of many Intel CPUs.
46 // kPrime = 309485009821345068724781371
47 static const QuicUint128 kPrime =
48 (static_cast<QuicUint128>(16777216) << 64) + 315;
49 auto hi = QuicUint128High64(uhash);
50 auto lo = QuicUint128Low64(uhash);
51 QuicUint128 xhash = (static_cast<QuicUint128>(hi) << 64) + lo;
52 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
53 for (size_t i = 0; i < data.length(); ++i) {
54 xhash = (xhash ^ static_cast<uint32_t>(octets[i])) * kPrime;
55 }
56 return MakeQuicUint128(QuicUint128High64(xhash), QuicUint128Low64(xhash));
57}
58#endif
59
60#ifndef QUIC_UTIL_HAS_UINT128
61// Slow implementation of IncrementalHash. In practice, only used by Chromium.
dmcardlecf0bfcf2019-12-13 08:08:21 -080062QuicUint128 IncrementalHashSlow(QuicUint128 hash,
63 quiche::QuicheStringPiece data) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050064 // kPrime = 309485009821345068724781371
65 static const QuicUint128 kPrime = MakeQuicUint128(16777216, 315);
66 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
67 for (size_t i = 0; i < data.length(); ++i) {
68 hash = hash ^ MakeQuicUint128(0, octets[i]);
69 hash = hash * kPrime;
70 }
71 return hash;
72}
73#endif
74
dmcardlecf0bfcf2019-12-13 08:08:21 -080075QuicUint128 IncrementalHash(QuicUint128 hash, quiche::QuicheStringPiece data) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050076#ifdef QUIC_UTIL_HAS_UINT128
77 return IncrementalHashFast(hash, data);
78#else
79 return IncrementalHashSlow(hash, data);
80#endif
81}
82
83} // namespace
84
85// static
dmcardlecf0bfcf2019-12-13 08:08:21 -080086uint64_t QuicUtils::FNV1a_64_Hash(quiche::QuicheStringPiece data) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 static const uint64_t kOffset = UINT64_C(14695981039346656037);
88 static const uint64_t kPrime = UINT64_C(1099511628211);
89
90 const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data());
91
92 uint64_t hash = kOffset;
93
94 for (size_t i = 0; i < data.length(); ++i) {
95 hash = hash ^ octets[i];
96 hash = hash * kPrime;
97 }
98
99 return hash;
100}
101
102// static
dmcardlecf0bfcf2019-12-13 08:08:21 -0800103QuicUint128 QuicUtils::FNV1a_128_Hash(quiche::QuicheStringPiece data) {
104 return FNV1a_128_Hash_Three(data, quiche::QuicheStringPiece(),
105 quiche::QuicheStringPiece());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500106}
107
108// static
dmcardlecf0bfcf2019-12-13 08:08:21 -0800109QuicUint128 QuicUtils::FNV1a_128_Hash_Two(quiche::QuicheStringPiece data1,
110 quiche::QuicheStringPiece data2) {
111 return FNV1a_128_Hash_Three(data1, data2, quiche::QuicheStringPiece());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112}
113
114// static
dmcardlecf0bfcf2019-12-13 08:08:21 -0800115QuicUint128 QuicUtils::FNV1a_128_Hash_Three(quiche::QuicheStringPiece data1,
116 quiche::QuicheStringPiece data2,
117 quiche::QuicheStringPiece data3) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500118 // The two constants are defined as part of the hash algorithm.
119 // see http://www.isthe.com/chongo/tech/comp/fnv/
120 // kOffset = 144066263297769815596495629667062367629
121 const QuicUint128 kOffset = MakeQuicUint128(UINT64_C(7809847782465536322),
122 UINT64_C(7113472399480571277));
123
124 QuicUint128 hash = IncrementalHash(kOffset, data1);
125 if (data2.empty()) {
126 return hash;
127 }
128
129 hash = IncrementalHash(hash, data2);
130 if (data3.empty()) {
131 return hash;
132 }
133 return IncrementalHash(hash, data3);
134}
135
136// static
137void QuicUtils::SerializeUint128Short(QuicUint128 v, uint8_t* out) {
138 const uint64_t lo = QuicUint128Low64(v);
139 const uint64_t hi = QuicUint128High64(v);
140 // This assumes that the system is little-endian.
141 memcpy(out, &lo, sizeof(lo));
142 memcpy(out + sizeof(lo), &hi, sizeof(hi) / 2);
143}
144
145#define RETURN_STRING_LITERAL(x) \
146 case x: \
147 return #x;
148
vasilvvc48c8712019-03-11 13:38:16 -0700149std::string QuicUtils::AddressChangeTypeToString(AddressChangeType type) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500150 switch (type) {
151 RETURN_STRING_LITERAL(NO_CHANGE);
152 RETURN_STRING_LITERAL(PORT_CHANGE);
153 RETURN_STRING_LITERAL(IPV4_SUBNET_CHANGE);
154 RETURN_STRING_LITERAL(IPV4_TO_IPV6_CHANGE);
155 RETURN_STRING_LITERAL(IPV6_TO_IPV4_CHANGE);
156 RETURN_STRING_LITERAL(IPV6_TO_IPV6_CHANGE);
157 RETURN_STRING_LITERAL(IPV4_TO_IPV4_CHANGE);
158 }
159 return "INVALID_ADDRESS_CHANGE_TYPE";
160}
161
162const char* QuicUtils::SentPacketStateToString(SentPacketState state) {
163 switch (state) {
164 RETURN_STRING_LITERAL(OUTSTANDING);
165 RETURN_STRING_LITERAL(NEVER_SENT);
166 RETURN_STRING_LITERAL(ACKED);
167 RETURN_STRING_LITERAL(UNACKABLE);
fayang93c83942019-11-07 10:41:16 -0800168 RETURN_STRING_LITERAL(NEUTERED);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500169 RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMITTED);
170 RETURN_STRING_LITERAL(LOST);
171 RETURN_STRING_LITERAL(TLP_RETRANSMITTED);
172 RETURN_STRING_LITERAL(RTO_RETRANSMITTED);
fayang73d0ac42019-10-31 12:45:31 -0700173 RETURN_STRING_LITERAL(PTO_RETRANSMITTED);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500174 RETURN_STRING_LITERAL(PROBE_RETRANSMITTED);
175 }
176 return "INVALID_SENT_PACKET_STATE";
177}
178
179// static
180const 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
fayang3eb82212019-04-16 12:05:46 -0700193const 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
QUICHE teama6ef0a62019-03-07 20:34:33 -0500205AddressChangeType 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
238void QuicUtils::CopyToBuffer(const struct iovec* iov,
239 int iov_count,
240 size_t iov_offset,
241 size_t buffer_length,
242 char* buffer) {
243 int iovnum = 0;
244 while (iovnum < iov_count && iov_offset >= iov[iovnum].iov_len) {
245 iov_offset -= iov[iovnum].iov_len;
246 ++iovnum;
247 }
248 DCHECK_LE(iovnum, iov_count);
249 DCHECK_LE(iov_offset, iov[iovnum].iov_len);
250 if (iovnum >= iov_count || buffer_length == 0) {
251 return;
252 }
253
254 // Unroll the first iteration that handles iov_offset.
255 const size_t iov_available = iov[iovnum].iov_len - iov_offset;
256 size_t copy_len = std::min(buffer_length, iov_available);
257
258 // Try to prefetch the next iov if there is at least one more after the
259 // current. Otherwise, it looks like an irregular access that the hardware
260 // prefetcher won't speculatively prefetch. Only prefetch one iov because
261 // generally, the iov_offset is not 0, input iov consists of 2K buffers and
262 // the output buffer is ~1.4K.
263 if (copy_len == iov_available && iovnum + 1 < iov_count) {
264 char* next_base = static_cast<char*>(iov[iovnum + 1].iov_base);
265 // Prefetch 2 cachelines worth of data to get the prefetcher started; leave
266 // it to the hardware prefetcher after that.
267 QuicPrefetchT0(next_base);
268 if (iov[iovnum + 1].iov_len >= 64) {
269 QuicPrefetchT0(next_base + QUIC_CACHELINE_SIZE);
270 }
271 }
272
273 const char* src = static_cast<char*>(iov[iovnum].iov_base) + iov_offset;
274 while (true) {
275 memcpy(buffer, src, copy_len);
276 buffer_length -= copy_len;
277 buffer += copy_len;
278 if (buffer_length == 0 || ++iovnum >= iov_count) {
279 break;
280 }
281 src = static_cast<char*>(iov[iovnum].iov_base);
282 copy_len = std::min(buffer_length, iov[iovnum].iov_len);
283 }
284 QUIC_BUG_IF(buffer_length > 0) << "Failed to copy entire length to buffer.";
285}
286
287// static
dmcardlecf0bfcf2019-12-13 08:08:21 -0800288struct iovec QuicUtils::MakeIovec(quiche::QuicheStringPiece data) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500289 struct iovec iov = {const_cast<char*>(data.data()),
290 static_cast<size_t>(data.size())};
291 return iov;
292}
293
294// static
295bool QuicUtils::IsAckable(SentPacketState state) {
296 return state != NEVER_SENT && state != ACKED && state != UNACKABLE;
297}
298
299// static
300bool QuicUtils::IsRetransmittableFrame(QuicFrameType type) {
301 switch (type) {
302 case ACK_FRAME:
303 case PADDING_FRAME:
304 case STOP_WAITING_FRAME:
305 case MTU_DISCOVERY_FRAME:
306 return false;
307 default:
308 return true;
309 }
310}
311
312// static
313bool QuicUtils::IsHandshakeFrame(const QuicFrame& frame,
314 QuicTransportVersion transport_version) {
QUICHE teamea740082019-03-11 17:58:43 -0700315 if (!QuicVersionUsesCryptoFrames(transport_version)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500316 return frame.type == STREAM_FRAME &&
317 frame.stream_frame.stream_id == GetCryptoStreamId(transport_version);
318 } else {
319 return frame.type == CRYPTO_FRAME;
320 }
321}
322
323// static
wubf6ed10e2020-01-31 13:22:02 -0800324bool QuicUtils::ContainsFrameType(const QuicFrames& frames,
325 QuicFrameType type) {
326 for (const QuicFrame& frame : frames) {
327 if (frame.type == type) {
328 return true;
329 }
330 }
331 return false;
332}
333
334// static
QUICHE teama6ef0a62019-03-07 20:34:33 -0500335SentPacketState QuicUtils::RetransmissionTypeToPacketState(
336 TransmissionType retransmission_type) {
337 switch (retransmission_type) {
338 case ALL_UNACKED_RETRANSMISSION:
339 case ALL_INITIAL_RETRANSMISSION:
340 return UNACKABLE;
341 case HANDSHAKE_RETRANSMISSION:
342 return HANDSHAKE_RETRANSMITTED;
343 case LOSS_RETRANSMISSION:
344 return LOST;
345 case TLP_RETRANSMISSION:
346 return TLP_RETRANSMITTED;
347 case RTO_RETRANSMISSION:
348 return RTO_RETRANSMITTED;
fayang73d0ac42019-10-31 12:45:31 -0700349 case PTO_RETRANSMISSION:
350 return PTO_RETRANSMITTED;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500351 case PROBING_RETRANSMISSION:
352 return PROBE_RETRANSMITTED;
353 default:
dschinazief79a5f2019-10-04 10:32:54 -0700354 QUIC_BUG << TransmissionTypeToString(retransmission_type)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500355 << " is not a retransmission_type";
356 return UNACKABLE;
357 }
358}
359
360// static
361bool QuicUtils::IsIetfPacketHeader(uint8_t first_byte) {
362 return (first_byte & FLAGS_LONG_HEADER) || (first_byte & FLAGS_FIXED_BIT) ||
363 !(first_byte & FLAGS_DEMULTIPLEXING_BIT);
364}
365
366// static
367bool QuicUtils::IsIetfPacketShortHeader(uint8_t first_byte) {
368 return IsIetfPacketHeader(first_byte) && !(first_byte & FLAGS_LONG_HEADER);
369}
370
371// static
372QuicStreamId QuicUtils::GetInvalidStreamId(QuicTransportVersion version) {
fkastenholz305e1732019-06-18 05:01:22 -0700373 return VersionHasIetfQuicFrames(version)
374 ? std::numeric_limits<QuicStreamId>::max()
375 : 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500376}
377
378// static
379QuicStreamId QuicUtils::GetCryptoStreamId(QuicTransportVersion version) {
nharper46833c32019-05-15 21:33:05 -0700380 QUIC_BUG_IF(QuicVersionUsesCryptoFrames(version))
381 << "CRYPTO data aren't in stream frames; they have no stream ID.";
382 return QuicVersionUsesCryptoFrames(version) ? GetInvalidStreamId(version) : 1;
383}
384
385// static
386bool QuicUtils::IsCryptoStreamId(QuicTransportVersion version,
387 QuicStreamId stream_id) {
388 if (QuicVersionUsesCryptoFrames(version)) {
389 return false;
390 }
391 return stream_id == GetCryptoStreamId(version);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500392}
393
394// static
395QuicStreamId QuicUtils::GetHeadersStreamId(QuicTransportVersion version) {
renjietanga29a96a2019-10-10 12:47:50 -0700396 DCHECK(!VersionUsesHttp3(version));
nharpercd820e02019-05-16 15:12:07 -0700397 return GetFirstBidirectionalStreamId(version, Perspective::IS_CLIENT);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500398}
399
400// static
401bool QuicUtils::IsClientInitiatedStreamId(QuicTransportVersion version,
402 QuicStreamId id) {
403 if (id == GetInvalidStreamId(version)) {
404 return false;
405 }
fkastenholz305e1732019-06-18 05:01:22 -0700406 return VersionHasIetfQuicFrames(version) ? id % 2 == 0 : id % 2 != 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500407}
408
409// static
410bool QuicUtils::IsServerInitiatedStreamId(QuicTransportVersion version,
411 QuicStreamId id) {
412 if (id == GetInvalidStreamId(version)) {
413 return false;
414 }
fkastenholz305e1732019-06-18 05:01:22 -0700415 return VersionHasIetfQuicFrames(version) ? id % 2 != 0 : id % 2 == 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500416}
417
418// static
dschinazi18cdf132019-10-09 16:08:18 -0700419bool QuicUtils::IsOutgoingStreamId(ParsedQuicVersion version,
420 QuicStreamId id,
421 Perspective perspective) {
422 // Streams are outgoing streams, iff:
423 // - we are the server and the stream is server-initiated
424 // - we are the client and the stream is client-initiated.
425 const bool perspective_is_server = perspective == Perspective::IS_SERVER;
426 const bool stream_is_server =
427 QuicUtils::IsServerInitiatedStreamId(version.transport_version, id);
428 return perspective_is_server == stream_is_server;
429}
430
431// static
QUICHE teama6ef0a62019-03-07 20:34:33 -0500432bool QuicUtils::IsBidirectionalStreamId(QuicStreamId id) {
433 return id % 4 < 2;
434}
435
436// static
437StreamType QuicUtils::GetStreamType(QuicStreamId id,
438 Perspective perspective,
439 bool peer_initiated) {
440 if (IsBidirectionalStreamId(id)) {
441 return BIDIRECTIONAL;
442 }
443
444 if (peer_initiated) {
445 if (perspective == Perspective::IS_SERVER) {
446 DCHECK_EQ(2u, id % 4);
447 } else {
448 DCHECK_EQ(Perspective::IS_CLIENT, perspective);
449 DCHECK_EQ(3u, id % 4);
450 }
451 return READ_UNIDIRECTIONAL;
452 }
453
454 if (perspective == Perspective::IS_SERVER) {
455 DCHECK_EQ(3u, id % 4);
456 } else {
457 DCHECK_EQ(Perspective::IS_CLIENT, perspective);
458 DCHECK_EQ(2u, id % 4);
459 }
460 return WRITE_UNIDIRECTIONAL;
461}
462
463// static
464QuicStreamId QuicUtils::StreamIdDelta(QuicTransportVersion version) {
fkastenholz305e1732019-06-18 05:01:22 -0700465 return VersionHasIetfQuicFrames(version) ? 4 : 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500466}
467
468// static
469QuicStreamId QuicUtils::GetFirstBidirectionalStreamId(
470 QuicTransportVersion version,
471 Perspective perspective) {
fkastenholz305e1732019-06-18 05:01:22 -0700472 if (VersionHasIetfQuicFrames(version)) {
nharpercd820e02019-05-16 15:12:07 -0700473 return perspective == Perspective::IS_CLIENT ? 0 : 1;
474 } else if (QuicVersionUsesCryptoFrames(version)) {
475 return perspective == Perspective::IS_CLIENT ? 1 : 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500476 }
nharpercd820e02019-05-16 15:12:07 -0700477 return perspective == Perspective::IS_CLIENT ? 3 : 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500478}
479
480// static
481QuicStreamId QuicUtils::GetFirstUnidirectionalStreamId(
482 QuicTransportVersion version,
483 Perspective perspective) {
fkastenholz305e1732019-06-18 05:01:22 -0700484 if (VersionHasIetfQuicFrames(version)) {
nharpercd820e02019-05-16 15:12:07 -0700485 return perspective == Perspective::IS_CLIENT ? 2 : 3;
486 } else if (QuicVersionUsesCryptoFrames(version)) {
487 return perspective == Perspective::IS_CLIENT ? 1 : 2;
488 }
489 return perspective == Perspective::IS_CLIENT ? 3 : 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500490}
491
492// static
dschinaziadc75072019-08-19 10:54:45 -0700493QuicConnectionId QuicUtils::CreateReplacementConnectionId(
494 QuicConnectionId connection_id) {
495 const uint64_t connection_id_hash = FNV1a_64_Hash(
dmcardlecf0bfcf2019-12-13 08:08:21 -0800496 quiche::QuicheStringPiece(connection_id.data(), connection_id.length()));
dschinaziadc75072019-08-19 10:54:45 -0700497 return QuicConnectionId(reinterpret_cast<const char*>(&connection_id_hash),
498 sizeof(connection_id_hash));
499}
500
501// static
QUICHE teama6ef0a62019-03-07 20:34:33 -0500502QuicConnectionId QuicUtils::CreateRandomConnectionId() {
QUICHE teamc65d1d12019-03-19 20:58:04 -0700503 return CreateRandomConnectionId(kQuicDefaultConnectionIdLength,
504 QuicRandom::GetInstance());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500505}
506
507// static
508QuicConnectionId QuicUtils::CreateRandomConnectionId(QuicRandom* random) {
QUICHE teamc65d1d12019-03-19 20:58:04 -0700509 return CreateRandomConnectionId(kQuicDefaultConnectionIdLength, random);
510}
511// static
512QuicConnectionId QuicUtils::CreateRandomConnectionId(
513 uint8_t connection_id_length) {
514 return CreateRandomConnectionId(connection_id_length,
515 QuicRandom::GetInstance());
516}
517
518// static
519QuicConnectionId QuicUtils::CreateRandomConnectionId(
520 uint8_t connection_id_length,
521 QuicRandom* random) {
dschinazib953d022019-08-01 18:05:58 -0700522 QuicConnectionId connection_id;
523 connection_id.set_length(connection_id_length);
524 if (connection_id.length() > 0) {
525 random->RandBytes(connection_id.mutable_data(), connection_id.length());
QUICHE teamc65d1d12019-03-19 20:58:04 -0700526 }
dschinazib953d022019-08-01 18:05:58 -0700527 return connection_id;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500528}
529
530// static
QUICHE teama6ef0a62019-03-07 20:34:33 -0500531QuicConnectionId QuicUtils::CreateZeroConnectionId(
532 QuicTransportVersion version) {
dschinazi97da52b2020-01-13 15:44:43 -0800533 if (!VersionAllowsVariableLengthConnectionIds(version)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500534 char connection_id_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
535 return QuicConnectionId(static_cast<char*>(connection_id_bytes),
bnc4e9283d2019-12-17 07:08:57 -0800536 QUICHE_ARRAYSIZE(connection_id_bytes));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500537 }
538 return EmptyQuicConnectionId();
539}
540
541// static
dschinazi6c84c142019-07-31 09:11:49 -0700542bool QuicUtils::IsConnectionIdLengthValidForVersion(
543 size_t connection_id_length,
544 QuicTransportVersion transport_version) {
545 // No version of QUIC can support lengths that do not fit in an uint8_t.
546 if (connection_id_length >
547 static_cast<size_t>(std::numeric_limits<uint8_t>::max())) {
548 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500549 }
dschinaziffa83552019-12-17 11:00:23 -0800550
dschinazi161bb492020-02-05 09:59:38 -0800551 if (transport_version == QUIC_VERSION_UNSUPPORTED ||
552 transport_version == QUIC_VERSION_RESERVED_FOR_NEGOTIATION) {
553 // Unknown versions could allow connection ID lengths up to 255.
554 return true;
dschinaziffa83552019-12-17 11:00:23 -0800555 }
556
dschinazi6c84c142019-07-31 09:11:49 -0700557 const uint8_t connection_id_length8 =
558 static_cast<uint8_t>(connection_id_length);
559 // Versions that do not support variable lengths only support length 8.
dschinazi97da52b2020-01-13 15:44:43 -0800560 if (!VersionAllowsVariableLengthConnectionIds(transport_version)) {
dschinazi6c84c142019-07-31 09:11:49 -0700561 return connection_id_length8 == kQuicDefaultConnectionIdLength;
562 }
dschinazib953d022019-08-01 18:05:58 -0700563 // Versions that do support variable length but do not have length-prefixed
564 // connection IDs use the 4-bit connection ID length encoding which can
565 // only encode values 0 and 4-18.
566 if (!VersionHasLengthPrefixedConnectionIds(transport_version)) {
567 return connection_id_length8 == 0 ||
568 (connection_id_length8 >= 4 &&
dschinazib012d212019-08-01 18:07:26 -0700569 connection_id_length8 <= kQuicMaxConnectionId4BitLength);
dschinazib953d022019-08-01 18:05:58 -0700570 }
dschinazib012d212019-08-01 18:07:26 -0700571 return connection_id_length8 <= kQuicMaxConnectionIdWithLengthPrefixLength;
dschinazi6c84c142019-07-31 09:11:49 -0700572}
573
574// static
575bool QuicUtils::IsConnectionIdValidForVersion(
576 QuicConnectionId connection_id,
577 QuicTransportVersion transport_version) {
578 return IsConnectionIdLengthValidForVersion(connection_id.length(),
579 transport_version);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500580}
581
582QuicUint128 QuicUtils::GenerateStatelessResetToken(
583 QuicConnectionId connection_id) {
dschinazi9a910e32019-08-19 18:05:04 -0700584 return FNV1a_128_Hash(
dmcardlecf0bfcf2019-12-13 08:08:21 -0800585 quiche::QuicheStringPiece(connection_id.data(), connection_id.length()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500586}
587
fkastenholz3c4eabf2019-04-22 07:49:59 -0700588// static
589QuicStreamCount QuicUtils::GetMaxStreamCount(bool unidirectional,
590 Perspective perspective) {
ianswett22781cb2019-12-12 06:45:08 -0800591 // gQUIC uses one client initiated bidi stream for the crypto stream.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700592 if (!unidirectional && perspective == Perspective::IS_CLIENT) {
593 return kMaxQuicStreamCount >> 2;
594 }
595 return (kMaxQuicStreamCount >> 2) + 1;
596}
597
QUICHE team10b22a12019-03-21 15:31:42 -0700598// static
599PacketNumberSpace QuicUtils::GetPacketNumberSpace(
600 EncryptionLevel encryption_level) {
601 switch (encryption_level) {
602 case ENCRYPTION_INITIAL:
603 return INITIAL_DATA;
604 case ENCRYPTION_HANDSHAKE:
605 return HANDSHAKE_DATA;
606 case ENCRYPTION_ZERO_RTT:
607 case ENCRYPTION_FORWARD_SECURE:
608 return APPLICATION_DATA;
609 default:
610 QUIC_BUG << "Try to get packet number space of encryption level: "
611 << EncryptionLevelToString(encryption_level);
612 return NUM_PACKET_NUMBER_SPACES;
613 }
614}
615
QUICHE team1dfa46b2019-03-22 10:39:10 -0700616// static
617EncryptionLevel QuicUtils::GetEncryptionLevel(
618 PacketNumberSpace packet_number_space) {
619 switch (packet_number_space) {
620 case INITIAL_DATA:
621 return ENCRYPTION_INITIAL;
622 case HANDSHAKE_DATA:
623 return ENCRYPTION_HANDSHAKE;
624 case APPLICATION_DATA:
625 return ENCRYPTION_FORWARD_SECURE;
626 default:
627 DCHECK(false);
628 return NUM_ENCRYPTION_LEVELS;
629 }
630}
631
QUICHE teama6ef0a62019-03-07 20:34:33 -0500632#undef RETURN_STRING_LITERAL // undef for jumbo builds
633} // namespace quic