[AuthContext] Introduce an ConnectionContext class to hold arbitrary auth properties types for quick lookup.

PiperOrigin-RevId: 690671976
pull/37932/head
Vignesh Babu 4 months ago committed by Copybara-Service
parent ff7d726a91
commit 5c31076cc9
  1. 53
      CMakeLists.txt
  2. 32
      build_autogenerated.yaml
  3. 11
      src/core/BUILD
  4. 77
      src/core/lib/surface/connection_context.cc
  5. 155
      src/core/lib/surface/connection_context.h
  6. 20
      test/core/surface/BUILD
  7. 78
      test/core/surface/connection_context_test.cc
  8. 24
      tools/run_tests/generated/tests.json

53
CMakeLists.txt generated

@ -1451,6 +1451,7 @@ if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx connected_subchannel_test) add_dependencies(buildtests_cxx connected_subchannel_test)
endif() endif()
add_dependencies(buildtests_cxx connection_context_test)
add_dependencies(buildtests_cxx connection_prefix_bad_client_test) add_dependencies(buildtests_cxx connection_prefix_bad_client_test)
add_dependencies(buildtests_cxx connection_refused_test) add_dependencies(buildtests_cxx connection_refused_test)
add_dependencies(buildtests_cxx connectivity_state_test) add_dependencies(buildtests_cxx connectivity_state_test)
@ -12271,6 +12272,58 @@ endif()
endif() endif()
if(gRPC_BUILD_TESTS) if(gRPC_BUILD_TESTS)
add_executable(connection_context_test
src/core/lib/surface/connection_context.cc
test/core/surface/connection_context_test.cc
test/core/test_util/cmdline.cc
test/core/test_util/fuzzer_util.cc
test/core/test_util/grpc_profiler.cc
test/core/test_util/histogram.cc
test/core/test_util/mock_endpoint.cc
test/core/test_util/parse_hexstring.cc
test/core/test_util/resolve_localhost_ip46.cc
test/core/test_util/slice_splitter.cc
test/core/test_util/tracer_util.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(connection_context_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(connection_context_test PUBLIC cxx_std_14)
target_include_directories(connection_context_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(connection_context_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(connection_prefix_bad_client_test add_executable(connection_prefix_bad_client_test
test/core/bad_client/bad_client.cc test/core/bad_client/bad_client.cc
test/core/bad_client/tests/connection_prefix.cc test/core/bad_client/tests/connection_prefix.cc

@ -8930,6 +8930,38 @@ targets:
- linux - linux
- posix - posix
uses_polling: false uses_polling: false
- name: connection_context_test
gtest: true
build: test
language: c++
headers:
- src/core/lib/surface/connection_context.h
- test/core/test_util/cmdline.h
- test/core/test_util/evaluate_args_test_util.h
- test/core/test_util/fuzzer_util.h
- test/core/test_util/grpc_profiler.h
- test/core/test_util/histogram.h
- test/core/test_util/mock_endpoint.h
- test/core/test_util/parse_hexstring.h
- test/core/test_util/resolve_localhost_ip46.h
- test/core/test_util/slice_splitter.h
- test/core/test_util/tracer_util.h
src:
- src/core/lib/surface/connection_context.cc
- test/core/surface/connection_context_test.cc
- test/core/test_util/cmdline.cc
- test/core/test_util/fuzzer_util.cc
- test/core/test_util/grpc_profiler.cc
- test/core/test_util/histogram.cc
- test/core/test_util/mock_endpoint.cc
- test/core/test_util/parse_hexstring.cc
- test/core/test_util/resolve_localhost_ip46.cc
- test/core/test_util/slice_splitter.cc
- test/core/test_util/tracer_util.cc
deps:
- gtest
- grpc_test_util
uses_polling: false
- name: connection_prefix_bad_client_test - name: connection_prefix_bad_client_test
gtest: true gtest: true
build: test build: test

@ -3668,6 +3668,17 @@ grpc_cc_library(
], ],
) )
grpc_cc_library(
name = "connection_context",
srcs = ["lib/surface/connection_context.cc"],
hdrs = ["lib/surface/connection_context.h"],
deps = [
"//:gpr",
"//:gpr_platform",
"//:orphanable",
],
)
grpc_cc_library( grpc_cc_library(
name = "subchannel_interface", name = "subchannel_interface",
hdrs = ["load_balancing/subchannel_interface.h"], hdrs = ["load_balancing/subchannel_interface.h"],

@ -0,0 +1,77 @@
//
//
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#include "src/core/lib/surface/connection_context.h"
#include <grpc/support/alloc.h>
#include <grpc/support/port_platform.h>
#include <cstddef>
#include "src/core/util/alloc.h"
#include "src/core/util/orphanable.h"
namespace grpc_core {
namespace {
void* ConnectionContextStorage() {
size_t base_size = sizeof(ConnectionContext) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(
connection_context_detail::
BaseConnectionContextPropertiesTraits::Size());
static constexpr size_t alignment =
(GPR_CACHELINE_SIZE > GPR_MAX_ALIGNMENT &&
GPR_CACHELINE_SIZE % GPR_MAX_ALIGNMENT == 0)
? GPR_CACHELINE_SIZE
: GPR_MAX_ALIGNMENT;
return gpr_malloc_aligned(base_size, alignment);
}
} // namespace
OrphanablePtr<ConnectionContext> ConnectionContext::Create() {
void* p = ConnectionContextStorage();
return OrphanablePtr<ConnectionContext>(new (p) ConnectionContext());
}
ConnectionContext::ConnectionContext() {
for (size_t i = 0;
i < connection_context_detail::BaseConnectionContextPropertiesTraits::
NumProperties();
++i) {
registered_properties()[i] = nullptr;
}
}
void ConnectionContext::Orphan() {
this->~ConnectionContext();
gpr_free_aligned(const_cast<ConnectionContext*>(this));
}
ConnectionContext::~ConnectionContext() {
for (size_t i = 0;
i < connection_context_detail::BaseConnectionContextPropertiesTraits::
NumProperties();
++i) {
connection_context_detail::BaseConnectionContextPropertiesTraits::Destroy(
i, registered_properties()[i]);
}
}
} // namespace grpc_core

@ -0,0 +1,155 @@
//
//
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#ifndef GRPC_SRC_CORE_LIB_SURFACE_CONNECTION_CONTEXT_H
#define GRPC_SRC_CORE_LIB_SURFACE_CONNECTION_CONTEXT_H
#include <grpc/support/port_platform.h>
#include <stddef.h>
#include <cstdint>
#include <vector>
#include "src/core/util/orphanable.h"
namespace grpc_core {
class ConnectionContext;
template <typename T>
struct ConnectionContextProperty;
namespace connection_context_detail {
// Tracks all registered/known auth property types (these should only be
// registered via AuthPropertyTraits at static initialization time).
class BaseConnectionContextPropertiesTraits {
public:
// Count of number of registered auth context properties.
static uint16_t NumProperties() {
return static_cast<uint16_t>(RegisteredTraits().size());
}
// Number of bytes required to store pointers of all registered auth context
// properties.
static size_t Size() { return NumProperties() * sizeof(void*); }
// Call the registered destruction function for a context.
static void Destroy(uint16_t id, void* ptr) {
if (ptr == nullptr) return;
RegisteredTraits()[id](ptr);
}
// Allocate a new context id and register the destruction function.
template <typename T>
static uint16_t AllocateId(void (*destroy)(void* ptr)) {
auto& traits = RegisteredTraits();
const uint16_t id = static_cast<uint16_t>(traits.size());
traits.push_back(destroy);
return id;
}
private:
// Allocate a new context id and register the destruction function.
static std::vector<void (*)(void*)>& RegisteredTraits() {
static std::vector<void (*)(void*)> registered_traits;
return registered_traits;
}
};
template <typename T>
class ConnectionContextPropertiesTraits
: public BaseConnectionContextPropertiesTraits {
public:
static uint16_t id() { return id_; }
template <typename... Args>
static T* Construct(Args&&... args) {
return new T(std::forward<Args>(args)...);
}
static void Destruct(void* p) { delete reinterpret_cast<T*>(p); }
protected:
static const uint16_t id_;
};
template <typename T>
const uint16_t ConnectionContextPropertiesTraits<T>::id_ =
BaseConnectionContextPropertiesTraits::AllocateId<T>(
ConnectionContextPropertiesTraits<T>::Destruct);
} // namespace connection_context_detail
class ConnectionContext final : public Orphanable {
public:
static OrphanablePtr<ConnectionContext> Create();
// Sets the value of a registered property if it is not already set. Return
// false if the property is already set. If the property is not already
// set, an object of type Which is created using the passed args
// and stored in the map.
template <typename Which, typename... Args>
bool EmplaceIfUnset(Args&&... args) {
using Traits =
connection_context_detail::ConnectionContextPropertiesTraits<Which>;
Which* value = static_cast<Which*>(registered_properties()[Traits::id()]);
if (value == nullptr) {
registered_properties()[Traits::id()] = Traits::Construct(args...);
return true;
}
return false;
}
// Force updates the value of a registered property. It deletes any previously
// set value.
template <typename Which, typename... Args>
void Update(Args&&... args) {
using Traits =
connection_context_detail::ConnectionContextPropertiesTraits<Which>;
Which* prev = static_cast<Which*>(registered_properties()[Traits::id()]);
if (prev != nullptr) {
Traits::Destroy(Traits::id(), prev);
}
registered_properties()[Traits::id()] = Traits::Construct(args...);
}
// Returns the value of a registered property. If the property is not set,
// returns nullptr.
template <typename Which>
const Which* Get() {
return static_cast<Which*>(
registered_properties()
[connection_context_detail::ConnectionContextPropertiesTraits<
Which>::id()]);
}
void Orphan() override;
~ConnectionContext() override;
private:
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION void** registered_properties() {
return reinterpret_cast<void**>(this + 1);
}
ConnectionContext();
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_SURFACE_CONNECTION_CONTEXT_H

@ -208,3 +208,23 @@ grpc_cc_test(
"//test/core/test_util:grpc_test_util", "//test/core/test_util:grpc_test_util",
], ],
) )
grpc_cc_test(
name = "connection_context_test",
srcs = ["connection_context_test.cc"],
external_deps = [
"absl/log:log",
"gtest",
],
language = "C++",
uses_event_engine = False,
uses_polling = False,
deps = [
"//:gpr",
"//:grpc",
"//:orphanable",
"//src/core:connection_context",
"//test/core/test_util:grpc_test_util",
"//test/core/test_util:grpc_test_util_base",
],
)

@ -0,0 +1,78 @@
//
//
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#include "src/core/lib/surface/connection_context.h"
#include <gtest/gtest.h>
#include "src/core/util/orphanable.h"
#include "test/core/test_util/test_config.h"
namespace grpc_core {
namespace {
class Foo {
public:
explicit Foo(double value) : value_(value) {}
double value() const { return value_; }
private:
double value_;
};
class Bar {
public:
explicit Bar(int value) : value_(value) {}
int value() const { return value_; }
private:
int value_;
};
} // namespace
template <>
struct ConnectionContextProperty<Foo> {};
template <>
struct ConnectionContextProperty<Bar> {};
TEST(ConnectionAuthContextTest, SimpleStaticPropertyAdditionContext) {
OrphanablePtr<ConnectionContext> map = ConnectionContext::Create();
EXPECT_TRUE(map->EmplaceIfUnset<Foo>(3.0));
EXPECT_EQ(map->Get<Foo>()->value(), 3.0);
EXPECT_FALSE(map->EmplaceIfUnset<Foo>(1.0));
EXPECT_EQ(map->Get<Foo>()->value(), 3.0);
map->Update<Foo>(2.0);
EXPECT_EQ(map->Get<Foo>()->value(), 2.0);
EXPECT_TRUE(map->EmplaceIfUnset<Bar>(1));
EXPECT_EQ(map->Get<Bar>()->value(), 1);
EXPECT_FALSE(map->EmplaceIfUnset<Bar>(2));
EXPECT_EQ(map->Get<Bar>()->value(), 1);
map->Update<Bar>(1234);
EXPECT_EQ(map->Get<Bar>()->value(), 1234);
}
} // namespace grpc_core
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(&argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -2455,6 +2455,30 @@
], ],
"uses_polling": false "uses_polling": false
}, },
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "connection_context_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{ {
"args": [], "args": [],
"benchmark": false, "benchmark": false,

Loading…
Cancel
Save