3 * Copyright 2016 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/support/port_platform.h>
21 #include "src/core/lib/channel/channel_stack_builder.h"
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/string_util.h>
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;
36 struct grpc_channel_stack_builder {
37 // sentinel nodes for filters that have been added
40 // various set/get-able parameters
41 grpc_channel_args* args;
42 grpc_transport* transport;
43 grpc_resource_user* resource_user;
48 struct grpc_channel_stack_builder_iterator {
49 grpc_channel_stack_builder* builder;
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)));
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;
67 void grpc_channel_stack_builder_set_target(grpc_channel_stack_builder* b,
70 b->target = gpr_strdup(target);
73 const char* grpc_channel_stack_builder_get_target(
74 grpc_channel_stack_builder* b) {
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;
88 void grpc_channel_stack_builder_iterator_destroy(
89 grpc_channel_stack_builder_iterator* it) {
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);
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);
105 bool grpc_channel_stack_builder_iterator_is_end(
106 grpc_channel_stack_builder_iterator* iterator) {
107 return iterator->node == &iterator->builder->end;
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;
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;
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;
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;
144 bool grpc_channel_stack_builder_move_prev(
145 grpc_channel_stack_builder_iterator* iterator);
147 void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder* builder,
149 GPR_ASSERT(builder->name == nullptr);
150 builder->name = name;
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);
158 builder->args = grpc_channel_args_copy(args);
161 const grpc_channel_args* grpc_channel_stack_builder_get_channel_arguments(
162 grpc_channel_stack_builder* builder) {
163 return builder->args;
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;
172 grpc_transport* grpc_channel_stack_builder_get_transport(
173 grpc_channel_stack_builder* builder) {
174 return builder->transport;
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;
183 grpc_resource_user* grpc_channel_stack_builder_get_resource_user(
184 grpc_channel_stack_builder* builder) {
185 return builder->resource_user;
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);
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);
207 it->node->prev->next = it->node->next;
208 it->node->next->prev = it->node->prev;
210 grpc_channel_stack_builder_iterator_destroy(it);
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);
225 static void add_after(filter_node* before, const grpc_channel_filter* filter,
226 grpc_post_filter_create_init_func post_init_func,
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;
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);
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);
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;
263 if (builder->args != nullptr) {
264 grpc_channel_args_destroy(builder->args);
266 gpr_free(builder->target);
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) {
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));
284 for (filter_node* p = builder->begin.next; p != &builder->end; p = p->next) {
285 filters[i++] = p->filter;
288 // calculate the size of the channel stack
289 size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters);
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);
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,
302 if (error != GRPC_ERROR_NONE) {
303 grpc_channel_stack_destroy(channel_stack);
307 // run post-initialization functions
309 for (filter_node* p = builder->begin.next; p != &builder->end;
311 if (p->init != nullptr) {
312 p->init(channel_stack, grpc_channel_stack_element(channel_stack, i),
319 grpc_channel_stack_builder_destroy(builder);
320 gpr_free(const_cast<grpc_channel_filter**>(filters));