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)19bool 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)27void 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) const39bool 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)69std::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)77std::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