• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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