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