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