1 // 2 // 3 // Copyright 2024 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // 17 // 18 19 #ifndef GRPC_SRC_CORE_LIB_SURFACE_CONNECTION_CONTEXT_H 20 #define GRPC_SRC_CORE_LIB_SURFACE_CONNECTION_CONTEXT_H 21 22 #include <grpc/support/port_platform.h> 23 #include <stddef.h> 24 25 #include <cstdint> 26 #include <vector> 27 28 #include "src/core/util/no_destruct.h" 29 #include "src/core/util/orphanable.h" 30 31 namespace grpc_core { 32 33 class ConnectionContext; 34 35 template <typename T> 36 struct ConnectionContextProperty; 37 38 namespace connection_context_detail { 39 40 // Tracks all registered/known auth property types (these should only be 41 // registered via AuthPropertyTraits at static initialization time). 42 class BaseConnectionContextPropertiesTraits { 43 public: 44 // Count of number of registered auth context properties. NumProperties()45 static uint16_t NumProperties() { 46 return static_cast<uint16_t>(RegisteredTraits().size()); 47 } 48 49 // Number of bytes required to store pointers of all registered auth context 50 // properties. Size()51 static size_t Size() { return NumProperties() * sizeof(void*); } 52 53 // Call the registered destruction function for a context. Destroy(uint16_t id,void * ptr)54 static void Destroy(uint16_t id, void* ptr) { 55 if (ptr == nullptr) return; 56 RegisteredTraits()[id](ptr); 57 } 58 59 // Allocate a new context id and register the destruction function. 60 template <typename T> AllocateId(void (* destroy)(void * ptr))61 static uint16_t AllocateId(void (*destroy)(void* ptr)) { 62 auto& traits = RegisteredTraits(); 63 const uint16_t id = static_cast<uint16_t>(traits.size()); 64 traits.push_back(destroy); 65 return id; 66 } 67 68 private: 69 // Allocate a new context id and register the destruction function. 70 RegisteredTraits()71 static std::vector<void (*)(void*)>& RegisteredTraits() { 72 static NoDestruct<std::vector<void (*)(void*)>> registered_traits; 73 return *registered_traits; 74 } 75 }; 76 77 template <typename T> 78 class ConnectionContextPropertiesTraits 79 : public BaseConnectionContextPropertiesTraits { 80 public: id()81 static uint16_t id() { return id_; } 82 template <typename... Args> Construct(Args &&...args)83 static T* Construct(Args&&... args) { 84 return new T(std::forward<Args>(args)...); 85 } Destruct(void * p)86 static void Destruct(void* p) { delete reinterpret_cast<T*>(p); } 87 88 protected: 89 static const uint16_t id_; 90 }; 91 92 template <typename T> 93 const uint16_t ConnectionContextPropertiesTraits<T>::id_ = 94 BaseConnectionContextPropertiesTraits::AllocateId<T>( 95 ConnectionContextPropertiesTraits<T>::Destruct); 96 97 } // namespace connection_context_detail 98 99 class ConnectionContext final : public Orphanable { 100 public: 101 static OrphanablePtr<ConnectionContext> Create(); 102 103 // Sets the value of a registered property if it is not already set. Return 104 // false if the property is already set. If the property is not already 105 // set, an object of type Which is created using the passed args 106 // and stored in the map. 107 template <typename Which, typename... Args> EmplaceIfUnset(Args &&...args)108 bool EmplaceIfUnset(Args&&... args) { 109 using Traits = 110 connection_context_detail::ConnectionContextPropertiesTraits<Which>; 111 Which* value = static_cast<Which*>(registered_properties()[Traits::id()]); 112 if (value == nullptr) { 113 registered_properties()[Traits::id()] = Traits::Construct(args...); 114 return true; 115 } 116 return false; 117 } 118 119 // Force updates the value of a registered property. It deletes any previously 120 // set value. 121 template <typename Which, typename... Args> Update(Args &&...args)122 void Update(Args&&... args) { 123 using Traits = 124 connection_context_detail::ConnectionContextPropertiesTraits<Which>; 125 Which* prev = static_cast<Which*>(registered_properties()[Traits::id()]); 126 if (prev != nullptr) { 127 Traits::Destroy(Traits::id(), prev); 128 } 129 registered_properties()[Traits::id()] = Traits::Construct(args...); 130 } 131 132 // Returns the value of a registered property. If the property is not set, 133 // returns nullptr. 134 template <typename Which> Get()135 const Which* Get() { 136 return static_cast<Which*>( 137 registered_properties() 138 [connection_context_detail::ConnectionContextPropertiesTraits< 139 Which>::id()]); 140 } 141 142 void Orphan() override; 143 144 ~ConnectionContext() override; 145 146 private: registered_properties()147 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION void** registered_properties() { 148 return reinterpret_cast<void**>(this + 1); 149 } 150 151 ConnectionContext(); 152 }; 153 154 } // namespace grpc_core 155 156 #endif // GRPC_SRC_CORE_LIB_SURFACE_CONNECTION_CONTEXT_H 157