7f7cf75328b5ea0bd2db476a8d9542945fd9b1bc
[platform/upstream/grpc.git] / src / core / lib / channel / channel_stack_builder.cc
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
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
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
73 const char* grpc_channel_stack_builder_get_target(
74     grpc_channel_stack_builder* b) {
75   return b->target;
76 }
77
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
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*
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*
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
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
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
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
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
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
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
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
161 const grpc_channel_args* grpc_channel_stack_builder_get_channel_arguments(
162     grpc_channel_stack_builder* builder) {
163   return builder->args;
164 }
165
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
172 grpc_transport* grpc_channel_stack_builder_get_transport(
173     grpc_channel_stack_builder* builder) {
174   return builder->transport;
175 }
176
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
183 grpc_resource_user* grpc_channel_stack_builder_get_resource_user(
184     grpc_channel_stack_builder* builder) {
185   return builder->resource_user;
186 }
187
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
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
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
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
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
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
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
270 grpc_error_handle 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_handle 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 }