• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2022 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 "quiche/quic/core/deterministic_connection_id_generator.h"
6 
7 #include "quiche/quic/core/quic_utils.h"
8 #include "quiche/quic/platform/api/quic_bug_tracker.h"
9 #include "quiche/quic/platform/api/quic_logging.h"
10 
11 namespace quic {
12 
DeterministicConnectionIdGenerator(uint8_t expected_connection_id_length)13 DeterministicConnectionIdGenerator::DeterministicConnectionIdGenerator(
14     uint8_t expected_connection_id_length)
15     : expected_connection_id_length_(expected_connection_id_length) {
16   if (expected_connection_id_length_ >
17       kQuicMaxConnectionIdWithLengthPrefixLength) {
18     QUIC_BUG(quic_bug_465151159_01)
19         << "Issuing connection IDs longer than allowed in RFC9000";
20   }
21 }
22 
23 absl::optional<QuicConnectionId>
GenerateNextConnectionId(const QuicConnectionId & original)24 DeterministicConnectionIdGenerator::GenerateNextConnectionId(
25     const QuicConnectionId& original) {
26   if (expected_connection_id_length_ == 0) {
27     return EmptyQuicConnectionId();
28   }
29   const uint64_t connection_id_hash64 = QuicUtils::FNV1a_64_Hash(
30       absl::string_view(original.data(), original.length()));
31   if (expected_connection_id_length_ <= sizeof(uint64_t)) {
32     return QuicConnectionId(
33         reinterpret_cast<const char*>(&connection_id_hash64),
34         expected_connection_id_length_);
35   }
36   char new_connection_id_data[255] = {};
37   const absl::uint128 connection_id_hash128 = QuicUtils::FNV1a_128_Hash(
38       absl::string_view(original.data(), original.length()));
39   static_assert(sizeof(connection_id_hash64) + sizeof(connection_id_hash128) <=
40                     sizeof(new_connection_id_data),
41                 "bad size");
42   memcpy(new_connection_id_data, &connection_id_hash64,
43          sizeof(connection_id_hash64));
44   // TODO(martinduke): We don't have any test coverage of the line below. In
45   // particular, if the memcpy somehow misses a byte, a test could check if one
46   // byte position in generated connection IDs is always the same.
47   memcpy(new_connection_id_data + sizeof(connection_id_hash64),
48          &connection_id_hash128, sizeof(connection_id_hash128));
49   return QuicConnectionId(new_connection_id_data,
50                           expected_connection_id_length_);
51 }
52 
53 absl::optional<QuicConnectionId>
MaybeReplaceConnectionId(const QuicConnectionId & original,const ParsedQuicVersion & version)54 DeterministicConnectionIdGenerator::MaybeReplaceConnectionId(
55     const QuicConnectionId& original, const ParsedQuicVersion& version) {
56   if (original.length() == expected_connection_id_length_) {
57     return absl::optional<QuicConnectionId>();
58   }
59   QUICHE_DCHECK(version.AllowsVariableLengthConnectionIds());
60   absl::optional<QuicConnectionId> new_connection_id =
61       GenerateNextConnectionId(original);
62   // Verify that ReplaceShortServerConnectionId is deterministic.
63   QUICHE_DCHECK(new_connection_id.has_value());
64   QUICHE_DCHECK_EQ(
65       *new_connection_id,
66       static_cast<QuicConnectionId>(*GenerateNextConnectionId(original)));
67   QUICHE_DCHECK_EQ(expected_connection_id_length_, new_connection_id->length());
68   QUIC_DLOG(INFO) << "Replacing incoming connection ID " << original << " with "
69                   << new_connection_id.value();
70   return new_connection_id;
71 }
72 
73 }  // namespace quic
74