1 //
2 //
3 // Copyright 2021 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 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/ext/xds/xds_channel_stack_modifier.h"
22 
23 #include "src/core/lib/config/core_configuration.h"
24 #include "src/core/lib/surface/channel_init.h"
25 
26 namespace grpc_core {
27 namespace {
28 
XdsChannelStackModifierArgCopy(void * p)29 void* XdsChannelStackModifierArgCopy(void* p) {
30   XdsChannelStackModifier* arg = static_cast<XdsChannelStackModifier*>(p);
31   return arg->Ref().release();
32 }
33 
XdsChannelStackModifierArgDestroy(void * p)34 void XdsChannelStackModifierArgDestroy(void* p) {
35   XdsChannelStackModifier* arg = static_cast<XdsChannelStackModifier*>(p);
36   arg->Unref();
37 }
38 
XdsChannelStackModifierArgCmp(void * p,void * q)39 int XdsChannelStackModifierArgCmp(void* p, void* q) {
40   return QsortCompare(p, q);
41 }
42 
43 const grpc_arg_pointer_vtable kChannelArgVtable = {
44     XdsChannelStackModifierArgCopy, XdsChannelStackModifierArgDestroy,
45     XdsChannelStackModifierArgCmp};
46 
47 const char* kXdsChannelStackModifierChannelArgName =
48     "grpc.internal.xds_channel_stack_modifier";
49 
50 }  // namespace
51 
ModifyChannelStack(grpc_channel_stack_builder * builder)52 bool XdsChannelStackModifier::ModifyChannelStack(
53     grpc_channel_stack_builder* builder) {
54   // Insert the filters after the census filter if present.
55   grpc_channel_stack_builder_iterator* it =
56       grpc_channel_stack_builder_create_iterator_at_first(builder);
57   while (grpc_channel_stack_builder_move_next(it)) {
58     if (grpc_channel_stack_builder_iterator_is_end(it)) break;
59     const char* filter_name_at_it =
60         grpc_channel_stack_builder_iterator_filter_name(it);
61     if (strcmp("census_server", filter_name_at_it) == 0 ||
62         strcmp("opencensus_server", filter_name_at_it) == 0) {
63       break;
64     }
65   }
66   if (grpc_channel_stack_builder_iterator_is_end(it)) {
67     // No census filter found. Reset iterator to the beginning. This will result
68     // in prepending the list of xDS HTTP filters to the current stack. Note
69     // that this stage is run before the stage that adds the top server filter,
70     // resulting in these filters being finally placed after the `server`
71     // filter.
72     grpc_channel_stack_builder_iterator_destroy(it);
73     it = grpc_channel_stack_builder_create_iterator_at_first(builder);
74   }
75   GPR_ASSERT(grpc_channel_stack_builder_move_next(it));
76   for (const grpc_channel_filter* filter : filters_) {
77     GPR_ASSERT(grpc_channel_stack_builder_add_filter_before(it, filter, nullptr,
78                                                             nullptr));
79   }
80   grpc_channel_stack_builder_iterator_destroy(it);
81   return true;
82 }
83 
MakeChannelArg() const84 grpc_arg XdsChannelStackModifier::MakeChannelArg() const {
85   return grpc_channel_arg_pointer_create(
86       const_cast<char*>(kXdsChannelStackModifierChannelArgName),
87       const_cast<XdsChannelStackModifier*>(this), &kChannelArgVtable);
88 }
89 
90 RefCountedPtr<XdsChannelStackModifier>
GetFromChannelArgs(const grpc_channel_args & args)91 XdsChannelStackModifier::GetFromChannelArgs(const grpc_channel_args& args) {
92   XdsChannelStackModifier* config_selector_provider =
93       grpc_channel_args_find_pointer<XdsChannelStackModifier>(
94           &args, kXdsChannelStackModifierChannelArgName);
95   return config_selector_provider != nullptr ? config_selector_provider->Ref()
96                                              : nullptr;
97 }
98 
RegisterXdsChannelStackModifier(CoreConfiguration::Builder * builder)99 void RegisterXdsChannelStackModifier(CoreConfiguration::Builder* builder) {
100   builder->channel_init()->RegisterStage(
101       GRPC_SERVER_CHANNEL, INT_MAX, [](grpc_channel_stack_builder* builder) {
102         grpc_core::RefCountedPtr<XdsChannelStackModifier>
103             channel_stack_modifier =
104                 XdsChannelStackModifier::GetFromChannelArgs(
105                     *grpc_channel_stack_builder_get_channel_arguments(builder));
106         if (channel_stack_modifier != nullptr) {
107           return channel_stack_modifier->ModifyChannelStack(builder);
108         }
109         return true;
110       });
111 }
112 
113 }  // namespace grpc_core
114