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