• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2016 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/lib/channel/channel_stack_builder.h"
22 
23 #include <string.h>
24 
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/string_util.h>
27 
28 typedef struct filter_node {
29   struct filter_node* next;
30   struct filter_node* prev;
31   const grpc_channel_filter* filter;
32   grpc_post_filter_create_init_func init;
33   void* init_arg;
34 } filter_node;
35 
36 struct grpc_channel_stack_builder {
37   // sentinel nodes for filters that have been added
38   filter_node begin;
39   filter_node end;
40   // various set/get-able parameters
41   grpc_channel_args* args;
42   grpc_transport* transport;
43   char* target;
44   const char* name;
45 };
46 
47 struct grpc_channel_stack_builder_iterator {
48   grpc_channel_stack_builder* builder;
49   filter_node* node;
50 };
51 
grpc_channel_stack_builder_create(void)52 grpc_channel_stack_builder* grpc_channel_stack_builder_create(void) {
53   grpc_channel_stack_builder* b =
54       static_cast<grpc_channel_stack_builder*>(gpr_zalloc(sizeof(*b)));
55 
56   b->begin.filter = nullptr;
57   b->end.filter = nullptr;
58   b->begin.next = &b->end;
59   b->begin.prev = &b->end;
60   b->end.next = &b->begin;
61   b->end.prev = &b->begin;
62 
63   return b;
64 }
65 
grpc_channel_stack_builder_set_target(grpc_channel_stack_builder * b,const char * target)66 void grpc_channel_stack_builder_set_target(grpc_channel_stack_builder* b,
67                                            const char* target) {
68   gpr_free(b->target);
69   b->target = gpr_strdup(target);
70 }
71 
grpc_channel_stack_builder_get_target(grpc_channel_stack_builder * b)72 const char* grpc_channel_stack_builder_get_target(
73     grpc_channel_stack_builder* b) {
74   return b->target;
75 }
76 
create_iterator_at_filter_node(grpc_channel_stack_builder * builder,filter_node * node)77 static grpc_channel_stack_builder_iterator* create_iterator_at_filter_node(
78     grpc_channel_stack_builder* builder, filter_node* node) {
79   grpc_channel_stack_builder_iterator* it =
80       static_cast<grpc_channel_stack_builder_iterator*>(
81           gpr_malloc(sizeof(*it)));
82   it->builder = builder;
83   it->node = node;
84   return it;
85 }
86 
grpc_channel_stack_builder_iterator_destroy(grpc_channel_stack_builder_iterator * it)87 void grpc_channel_stack_builder_iterator_destroy(
88     grpc_channel_stack_builder_iterator* it) {
89   gpr_free(it);
90 }
91 
92 grpc_channel_stack_builder_iterator*
grpc_channel_stack_builder_create_iterator_at_first(grpc_channel_stack_builder * builder)93 grpc_channel_stack_builder_create_iterator_at_first(
94     grpc_channel_stack_builder* builder) {
95   return create_iterator_at_filter_node(builder, &builder->begin);
96 }
97 
98 grpc_channel_stack_builder_iterator*
grpc_channel_stack_builder_create_iterator_at_last(grpc_channel_stack_builder * builder)99 grpc_channel_stack_builder_create_iterator_at_last(
100     grpc_channel_stack_builder* builder) {
101   return create_iterator_at_filter_node(builder, &builder->end);
102 }
103 
grpc_channel_stack_builder_iterator_is_end(grpc_channel_stack_builder_iterator * iterator)104 bool grpc_channel_stack_builder_iterator_is_end(
105     grpc_channel_stack_builder_iterator* iterator) {
106   return iterator->node == &iterator->builder->end;
107 }
108 
grpc_channel_stack_builder_iterator_filter_name(grpc_channel_stack_builder_iterator * iterator)109 const char* grpc_channel_stack_builder_iterator_filter_name(
110     grpc_channel_stack_builder_iterator* iterator) {
111   if (iterator->node->filter == nullptr) return nullptr;
112   return iterator->node->filter->name;
113 }
114 
grpc_channel_stack_builder_move_next(grpc_channel_stack_builder_iterator * iterator)115 bool grpc_channel_stack_builder_move_next(
116     grpc_channel_stack_builder_iterator* iterator) {
117   if (iterator->node == &iterator->builder->end) return false;
118   iterator->node = iterator->node->next;
119   return true;
120 }
121 
grpc_channel_stack_builder_move_prev(grpc_channel_stack_builder_iterator * iterator)122 bool grpc_channel_stack_builder_move_prev(
123     grpc_channel_stack_builder_iterator* iterator) {
124   if (iterator->node == &iterator->builder->begin) return false;
125   iterator->node = iterator->node->prev;
126   return true;
127 }
128 
grpc_channel_stack_builder_iterator_find(grpc_channel_stack_builder * builder,const char * filter_name)129 grpc_channel_stack_builder_iterator* grpc_channel_stack_builder_iterator_find(
130     grpc_channel_stack_builder* builder, const char* filter_name) {
131   GPR_ASSERT(filter_name != nullptr);
132   grpc_channel_stack_builder_iterator* it =
133       grpc_channel_stack_builder_create_iterator_at_first(builder);
134   while (grpc_channel_stack_builder_move_next(it)) {
135     if (grpc_channel_stack_builder_iterator_is_end(it)) break;
136     const char* filter_name_at_it =
137         grpc_channel_stack_builder_iterator_filter_name(it);
138     if (strcmp(filter_name, filter_name_at_it) == 0) break;
139   }
140   return it;
141 }
142 
143 bool grpc_channel_stack_builder_move_prev(
144     grpc_channel_stack_builder_iterator* iterator);
145 
grpc_channel_stack_builder_set_name(grpc_channel_stack_builder * builder,const char * name)146 void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder* builder,
147                                          const char* name) {
148   GPR_ASSERT(builder->name == nullptr);
149   builder->name = name;
150 }
151 
grpc_channel_stack_builder_set_channel_arguments(grpc_channel_stack_builder * builder,const grpc_channel_args * args)152 void grpc_channel_stack_builder_set_channel_arguments(
153     grpc_channel_stack_builder* builder, const grpc_channel_args* args) {
154   if (builder->args != nullptr) {
155     grpc_channel_args_destroy(builder->args);
156   }
157   builder->args = grpc_channel_args_copy(args);
158 }
159 
grpc_channel_stack_builder_set_transport(grpc_channel_stack_builder * builder,grpc_transport * transport)160 void grpc_channel_stack_builder_set_transport(
161     grpc_channel_stack_builder* builder, grpc_transport* transport) {
162   GPR_ASSERT(builder->transport == nullptr);
163   builder->transport = transport;
164 }
165 
grpc_channel_stack_builder_get_transport(grpc_channel_stack_builder * builder)166 grpc_transport* grpc_channel_stack_builder_get_transport(
167     grpc_channel_stack_builder* builder) {
168   return builder->transport;
169 }
170 
grpc_channel_stack_builder_get_channel_arguments(grpc_channel_stack_builder * builder)171 const grpc_channel_args* grpc_channel_stack_builder_get_channel_arguments(
172     grpc_channel_stack_builder* builder) {
173   return builder->args;
174 }
175 
grpc_channel_stack_builder_append_filter(grpc_channel_stack_builder * builder,const grpc_channel_filter * filter,grpc_post_filter_create_init_func post_init_func,void * user_data)176 bool grpc_channel_stack_builder_append_filter(
177     grpc_channel_stack_builder* builder, const grpc_channel_filter* filter,
178     grpc_post_filter_create_init_func post_init_func, void* user_data) {
179   grpc_channel_stack_builder_iterator* it =
180       grpc_channel_stack_builder_create_iterator_at_last(builder);
181   bool ok = grpc_channel_stack_builder_add_filter_before(
182       it, filter, post_init_func, user_data);
183   grpc_channel_stack_builder_iterator_destroy(it);
184   return ok;
185 }
186 
grpc_channel_stack_builder_remove_filter(grpc_channel_stack_builder * builder,const char * filter_name)187 bool grpc_channel_stack_builder_remove_filter(
188     grpc_channel_stack_builder* builder, const char* filter_name) {
189   grpc_channel_stack_builder_iterator* it =
190       grpc_channel_stack_builder_iterator_find(builder, filter_name);
191   if (grpc_channel_stack_builder_iterator_is_end(it)) {
192     grpc_channel_stack_builder_iterator_destroy(it);
193     return false;
194   }
195   it->node->prev->next = it->node->next;
196   it->node->next->prev = it->node->prev;
197   gpr_free(it->node);
198   grpc_channel_stack_builder_iterator_destroy(it);
199   return true;
200 }
201 
grpc_channel_stack_builder_prepend_filter(grpc_channel_stack_builder * builder,const grpc_channel_filter * filter,grpc_post_filter_create_init_func post_init_func,void * user_data)202 bool grpc_channel_stack_builder_prepend_filter(
203     grpc_channel_stack_builder* builder, const grpc_channel_filter* filter,
204     grpc_post_filter_create_init_func post_init_func, void* user_data) {
205   grpc_channel_stack_builder_iterator* it =
206       grpc_channel_stack_builder_create_iterator_at_first(builder);
207   bool ok = grpc_channel_stack_builder_add_filter_after(
208       it, filter, post_init_func, user_data);
209   grpc_channel_stack_builder_iterator_destroy(it);
210   return ok;
211 }
212 
add_after(filter_node * before,const grpc_channel_filter * filter,grpc_post_filter_create_init_func post_init_func,void * user_data)213 static void add_after(filter_node* before, const grpc_channel_filter* filter,
214                       grpc_post_filter_create_init_func post_init_func,
215                       void* user_data) {
216   filter_node* new_node =
217       static_cast<filter_node*>(gpr_malloc(sizeof(*new_node)));
218   new_node->next = before->next;
219   new_node->prev = before;
220   new_node->next->prev = new_node->prev->next = new_node;
221   new_node->filter = filter;
222   new_node->init = post_init_func;
223   new_node->init_arg = user_data;
224 }
225 
grpc_channel_stack_builder_add_filter_before(grpc_channel_stack_builder_iterator * iterator,const grpc_channel_filter * filter,grpc_post_filter_create_init_func post_init_func,void * user_data)226 bool grpc_channel_stack_builder_add_filter_before(
227     grpc_channel_stack_builder_iterator* iterator,
228     const grpc_channel_filter* filter,
229     grpc_post_filter_create_init_func post_init_func, void* user_data) {
230   if (iterator->node == &iterator->builder->begin) return false;
231   add_after(iterator->node->prev, filter, post_init_func, user_data);
232   return true;
233 }
234 
grpc_channel_stack_builder_add_filter_after(grpc_channel_stack_builder_iterator * iterator,const grpc_channel_filter * filter,grpc_post_filter_create_init_func post_init_func,void * user_data)235 bool grpc_channel_stack_builder_add_filter_after(
236     grpc_channel_stack_builder_iterator* iterator,
237     const grpc_channel_filter* filter,
238     grpc_post_filter_create_init_func post_init_func, void* user_data) {
239   if (iterator->node == &iterator->builder->end) return false;
240   add_after(iterator->node, filter, post_init_func, user_data);
241   return true;
242 }
243 
grpc_channel_stack_builder_destroy(grpc_channel_stack_builder * builder)244 void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder* builder) {
245   filter_node* p = builder->begin.next;
246   while (p != &builder->end) {
247     filter_node* next = p->next;
248     gpr_free(p);
249     p = next;
250   }
251   if (builder->args != nullptr) {
252     grpc_channel_args_destroy(builder->args);
253   }
254   gpr_free(builder->target);
255   gpr_free(builder);
256 }
257 
grpc_channel_stack_builder_finish(grpc_channel_stack_builder * builder,size_t prefix_bytes,int initial_refs,grpc_iomgr_cb_func destroy,void * destroy_arg,void ** result)258 grpc_error* grpc_channel_stack_builder_finish(
259     grpc_channel_stack_builder* builder, size_t prefix_bytes, int initial_refs,
260     grpc_iomgr_cb_func destroy, void* destroy_arg, void** result) {
261   // count the number of filters
262   size_t num_filters = 0;
263   for (filter_node* p = builder->begin.next; p != &builder->end; p = p->next) {
264     num_filters++;
265   }
266 
267   // create an array of filters
268   const grpc_channel_filter** filters =
269       static_cast<const grpc_channel_filter**>(
270           gpr_malloc(sizeof(*filters) * num_filters));
271   size_t i = 0;
272   for (filter_node* p = builder->begin.next; p != &builder->end; p = p->next) {
273     filters[i++] = p->filter;
274   }
275 
276   // calculate the size of the channel stack
277   size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters);
278 
279   // allocate memory, with prefix_bytes followed by channel_stack_size
280   *result = gpr_zalloc(prefix_bytes + channel_stack_size);
281   // fetch a pointer to the channel stack
282   grpc_channel_stack* channel_stack = reinterpret_cast<grpc_channel_stack*>(
283       static_cast<char*>(*result) + prefix_bytes);
284   // and initialize it
285   grpc_error* error = grpc_channel_stack_init(
286       initial_refs, destroy, destroy_arg == nullptr ? *result : destroy_arg,
287       filters, num_filters, builder->args, builder->transport, builder->name,
288       channel_stack);
289 
290   if (error != GRPC_ERROR_NONE) {
291     grpc_channel_stack_destroy(channel_stack);
292     gpr_free(*result);
293     *result = nullptr;
294   } else {
295     // run post-initialization functions
296     i = 0;
297     for (filter_node* p = builder->begin.next; p != &builder->end;
298          p = p->next) {
299       if (p->init != nullptr) {
300         p->init(channel_stack, grpc_channel_stack_element(channel_stack, i),
301                 p->init_arg);
302       }
303       i++;
304     }
305   }
306 
307   grpc_channel_stack_builder_destroy(builder);
308   gpr_free(const_cast<grpc_channel_filter**>(filters));
309 
310   return error;
311 }
312