xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/load_balancer/load_balancer_decoder.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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/load_balancer/load_balancer_decoder.h"
6 
7 #include <cstdint>
8 #include <cstring>
9 #include <optional>
10 
11 #include "absl/types/span.h"
12 #include "quiche/quic/core/quic_connection_id.h"
13 #include "quiche/quic/load_balancer/load_balancer_config.h"
14 #include "quiche/quic/load_balancer/load_balancer_server_id.h"
15 #include "quiche/quic/platform/api/quic_bug_tracker.h"
16 
17 namespace quic {
18 
AddConfig(const LoadBalancerConfig & config)19 bool LoadBalancerDecoder::AddConfig(const LoadBalancerConfig& config) {
20   if (config_[config.config_id()].has_value()) {
21     return false;
22   }
23   config_[config.config_id()] = config;
24   return true;
25 }
26 
DeleteConfig(uint8_t config_id)27 void LoadBalancerDecoder::DeleteConfig(uint8_t config_id) {
28   if (config_id >= kNumLoadBalancerConfigs) {
29     QUIC_BUG(quic_bug_438896865_01)
30         << "Decoder deleting config with invalid config_id "
31         << static_cast<int>(config_id);
32     return;
33   }
34   config_[config_id].reset();
35 }
36 
37 // This is the core logic to extract a server ID given a valid config and
38 // connection ID of sufficient length.
GetServerId(const QuicConnectionId & connection_id,LoadBalancerServerId & server_id) const39 bool LoadBalancerDecoder::GetServerId(const QuicConnectionId& connection_id,
40                                       LoadBalancerServerId& server_id) const {
41   std::optional<uint8_t> config_id = GetConfigId(connection_id);
42   if (!config_id.has_value()) {
43     return false;
44   }
45   std::optional<LoadBalancerConfig> config = config_[*config_id];
46   if (!config.has_value()) {
47     return false;
48   }
49   // Benchmark tests show that minimizing the computation inside
50   // LoadBalancerConfig saves CPU cycles.
51   if (connection_id.length() < config->total_len()) {
52     return false;
53   }
54   const uint8_t* data =
55       reinterpret_cast<const uint8_t*>(connection_id.data()) + 1;
56   uint8_t server_id_len = config->server_id_len();
57   server_id.set_length(server_id_len);
58   if (!config->IsEncrypted()) {
59     memcpy(server_id.mutable_data(), connection_id.data() + 1, server_id_len);
60     return true;
61   }
62   if (config->plaintext_len() == kLoadBalancerBlockSize) {
63     return config->BlockDecrypt(data, server_id.mutable_data());
64   }
65   return config->FourPassDecrypt(
66       absl::MakeConstSpan(data, connection_id.length() - 1), server_id);
67 }
68 
GetConfigId(const QuicConnectionId & connection_id)69 std::optional<uint8_t> LoadBalancerDecoder::GetConfigId(
70     const QuicConnectionId& connection_id) {
71   if (connection_id.IsEmpty()) {
72     return std::optional<uint8_t>();
73   }
74   return GetConfigId(*reinterpret_cast<const uint8_t*>(connection_id.data()));
75 }
76 
GetConfigId(const uint8_t connection_id_first_byte)77 std::optional<uint8_t> LoadBalancerDecoder::GetConfigId(
78     const uint8_t connection_id_first_byte) {
79   uint8_t codepoint = (connection_id_first_byte >> kConnectionIdLengthBits);
80   if (codepoint < kNumLoadBalancerConfigs) {
81     return codepoint;
82   }
83   return std::optional<uint8_t>();
84 }
85 
86 }  // namespace quic
87