blob: 5f9e3b453980d8053256e22c0406e2ac703210c6 [file] [log] [blame]
Craig Tiller178edfa2016-02-17 20:54:46 -08001/*
2 *
Craig Tiller9b524122016-02-18 08:23:08 -08003 * Copyright 2016, Google Inc.
Craig Tiller178edfa2016-02-17 20:54:46 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Craig Tiller9533d042016-03-25 17:11:06 -070034#include "src/core/lib/channel/channel_stack_builder.h"
Craig Tiller178edfa2016-02-17 20:54:46 -080035
36#include <string.h>
37
38#include <grpc/support/alloc.h>
Craig Tillerf82ddc42016-04-05 17:15:07 -070039#include <grpc/support/string_util.h>
Craig Tiller178edfa2016-02-17 20:54:46 -080040
Craig Tillerde676262016-02-19 12:28:34 -080041int grpc_trace_channel_stack_builder = 0;
42
Craig Tiller178edfa2016-02-17 20:54:46 -080043typedef struct filter_node {
44 struct filter_node *next;
45 struct filter_node *prev;
46 const grpc_channel_filter *filter;
47 grpc_post_filter_create_init_func init;
48 void *init_arg;
49} filter_node;
50
51struct grpc_channel_stack_builder {
Craig Tiller6fcb64c2016-02-22 16:35:31 -080052 // sentinel nodes for filters that have been added
Craig Tiller178edfa2016-02-17 20:54:46 -080053 filter_node begin;
54 filter_node end;
55 // various set/get-able parameters
Craig Tillerf82ddc42016-04-05 17:15:07 -070056 grpc_channel_args *args;
Craig Tiller178edfa2016-02-17 20:54:46 -080057 grpc_transport *transport;
Craig Tillerf82ddc42016-04-05 17:15:07 -070058 char *target;
Craig Tiller178edfa2016-02-17 20:54:46 -080059 const char *name;
60};
61
62struct grpc_channel_stack_builder_iterator {
63 grpc_channel_stack_builder *builder;
64 filter_node *node;
65};
66
67grpc_channel_stack_builder *grpc_channel_stack_builder_create(void) {
68 grpc_channel_stack_builder *b = gpr_malloc(sizeof(*b));
69 memset(b, 0, sizeof(*b));
70
Craig Tiller6fcb64c2016-02-22 16:35:31 -080071 b->begin.filter = NULL;
72 b->end.filter = NULL;
Craig Tiller178edfa2016-02-17 20:54:46 -080073 b->begin.next = &b->end;
74 b->begin.prev = &b->end;
75 b->end.next = &b->begin;
76 b->end.prev = &b->begin;
77
78 return b;
79}
80
Craig Tillerf82ddc42016-04-05 17:15:07 -070081void grpc_channel_stack_builder_set_target(grpc_channel_stack_builder *b,
82 const char *target) {
83 gpr_free(b->target);
84 b->target = gpr_strdup(target);
85}
86
Craig Tiller0b541632016-04-05 17:21:05 -070087const char *grpc_channel_stack_builder_get_target(
88 grpc_channel_stack_builder *b) {
89 return b->target;
90}
91
Craig Tiller178edfa2016-02-17 20:54:46 -080092static grpc_channel_stack_builder_iterator *create_iterator_at_filter_node(
93 grpc_channel_stack_builder *builder, filter_node *node) {
94 grpc_channel_stack_builder_iterator *it = gpr_malloc(sizeof(*it));
95 it->builder = builder;
96 it->node = node;
97 return it;
98}
99
100void grpc_channel_stack_builder_iterator_destroy(
101 grpc_channel_stack_builder_iterator *it) {
102 gpr_free(it);
103}
104
105grpc_channel_stack_builder_iterator *
106grpc_channel_stack_builder_create_iterator_at_first(
107 grpc_channel_stack_builder *builder) {
108 return create_iterator_at_filter_node(builder, &builder->begin);
109}
110
111grpc_channel_stack_builder_iterator *
112grpc_channel_stack_builder_create_iterator_at_last(
113 grpc_channel_stack_builder *builder) {
114 return create_iterator_at_filter_node(builder, &builder->end);
115}
116
117bool grpc_channel_stack_builder_move_next(
118 grpc_channel_stack_builder_iterator *iterator) {
119 if (iterator->node == &iterator->builder->end) return false;
120 iterator->node = iterator->node->next;
121 return true;
122}
123
124bool grpc_channel_stack_builder_move_prev(
125 grpc_channel_stack_builder_iterator *iterator) {
126 if (iterator->node == &iterator->builder->begin) return false;
127 iterator->node = iterator->node->prev;
128 return true;
129}
130
131bool grpc_channel_stack_builder_move_prev(
132 grpc_channel_stack_builder_iterator *iterator);
133
134void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder,
135 const char *name) {
136 GPR_ASSERT(builder->name == NULL);
137 builder->name = name;
138}
139
140void grpc_channel_stack_builder_set_channel_arguments(
Craig Tillera59c16c2016-10-31 07:25:01 -0700141 grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder,
142 const grpc_channel_args *args) {
Craig Tillerf82ddc42016-04-05 17:15:07 -0700143 if (builder->args != NULL) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700144 grpc_channel_args_destroy(exec_ctx, builder->args);
Craig Tillerf82ddc42016-04-05 17:15:07 -0700145 }
Craig Tiller16c13452016-04-05 20:17:38 -0700146 builder->args = grpc_channel_args_copy(args);
Craig Tiller178edfa2016-02-17 20:54:46 -0800147}
148
149void grpc_channel_stack_builder_set_transport(
150 grpc_channel_stack_builder *builder, grpc_transport *transport) {
151 GPR_ASSERT(builder->transport == NULL);
152 builder->transport = transport;
153}
154
155grpc_transport *grpc_channel_stack_builder_get_transport(
156 grpc_channel_stack_builder *builder) {
157 return builder->transport;
158}
159
160const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments(
161 grpc_channel_stack_builder *builder) {
162 return builder->args;
163}
164
165bool grpc_channel_stack_builder_append_filter(
166 grpc_channel_stack_builder *builder, const grpc_channel_filter *filter,
167 grpc_post_filter_create_init_func post_init_func, void *user_data) {
168 grpc_channel_stack_builder_iterator *it =
169 grpc_channel_stack_builder_create_iterator_at_last(builder);
170 bool ok = grpc_channel_stack_builder_add_filter_before(
171 it, filter, post_init_func, user_data);
172 grpc_channel_stack_builder_iterator_destroy(it);
173 return ok;
174}
175
176bool grpc_channel_stack_builder_prepend_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_first(builder);
181 bool ok = grpc_channel_stack_builder_add_filter_after(
182 it, filter, post_init_func, user_data);
183 grpc_channel_stack_builder_iterator_destroy(it);
184 return ok;
185}
186
187static void add_after(filter_node *before, const grpc_channel_filter *filter,
188 grpc_post_filter_create_init_func post_init_func,
189 void *user_data) {
190 filter_node *new = gpr_malloc(sizeof(*new));
191 new->next = before->next;
192 new->prev = before;
193 new->next->prev = new->prev->next = new;
194 new->filter = filter;
195 new->init = post_init_func;
196 new->init_arg = user_data;
197}
198
199bool grpc_channel_stack_builder_add_filter_before(
200 grpc_channel_stack_builder_iterator *iterator,
201 const grpc_channel_filter *filter,
202 grpc_post_filter_create_init_func post_init_func, void *user_data) {
203 if (iterator->node == &iterator->builder->begin) return false;
204 add_after(iterator->node->prev, filter, post_init_func, user_data);
205 return true;
206}
207
208bool grpc_channel_stack_builder_add_filter_after(
209 grpc_channel_stack_builder_iterator *iterator,
210 const grpc_channel_filter *filter,
211 grpc_post_filter_create_init_func post_init_func, void *user_data) {
212 if (iterator->node == &iterator->builder->end) return false;
213 add_after(iterator->node, filter, post_init_func, user_data);
214 return true;
215}
216
Craig Tillera59c16c2016-10-31 07:25:01 -0700217void grpc_channel_stack_builder_destroy(grpc_exec_ctx *exec_ctx,
218 grpc_channel_stack_builder *builder) {
Craig Tiller178edfa2016-02-17 20:54:46 -0800219 filter_node *p = builder->begin.next;
220 while (p != &builder->end) {
221 filter_node *next = p->next;
222 gpr_free(p);
223 p = next;
224 }
Craig Tillerf82ddc42016-04-05 17:15:07 -0700225 if (builder->args != NULL) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700226 grpc_channel_args_destroy(exec_ctx, builder->args);
Craig Tillerf82ddc42016-04-05 17:15:07 -0700227 }
228 gpr_free(builder->target);
Craig Tiller178edfa2016-02-17 20:54:46 -0800229 gpr_free(builder);
230}
231
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800232grpc_error *grpc_channel_stack_builder_finish(
233 grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder,
234 size_t prefix_bytes, int initial_refs, grpc_iomgr_cb_func destroy,
235 void *destroy_arg, void **result) {
Craig Tiller178edfa2016-02-17 20:54:46 -0800236 // count the number of filters
237 size_t num_filters = 0;
238 for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
239 num_filters++;
240 }
241
242 // create an array of filters
Craig Tillerf6a4d422016-02-18 08:21:21 -0800243 const grpc_channel_filter **filters =
244 gpr_malloc(sizeof(*filters) * num_filters);
Craig Tiller178edfa2016-02-17 20:54:46 -0800245 size_t i = 0;
246 for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
247 filters[i++] = p->filter;
248 }
249
250 // calculate the size of the channel stack
251 size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters);
252
253 // allocate memory, with prefix_bytes followed by channel_stack_size
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800254 *result = gpr_malloc(prefix_bytes + channel_stack_size);
Craig Tiller178edfa2016-02-17 20:54:46 -0800255 // fetch a pointer to the channel stack
256 grpc_channel_stack *channel_stack =
Mark D. Rothe8547762016-11-28 17:42:53 +0000257 (grpc_channel_stack *)((char *)(*result) + prefix_bytes);
Craig Tiller178edfa2016-02-17 20:54:46 -0800258 // and initialize it
Mark D. Rothc1087882016-11-18 10:54:45 -0800259 grpc_error *error = grpc_channel_stack_init(
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800260 exec_ctx, initial_refs, destroy,
261 destroy_arg == NULL ? *result : destroy_arg, filters, num_filters,
262 builder->args, builder->transport, builder->name, channel_stack);
Craig Tiller178edfa2016-02-17 20:54:46 -0800263
Mark D. Rothe62605f2016-11-29 16:31:36 +0000264 if (error != GRPC_ERROR_NONE) {
265 grpc_channel_stack_destroy(exec_ctx, channel_stack);
266 gpr_free(*result);
267 *result = NULL;
268 } else {
269 // run post-initialization functions
270 i = 0;
Mark D. Roth977f5d42016-11-30 14:03:58 -0800271 for (filter_node *p = builder->begin.next; p != &builder->end;
Mark D. Rothe62605f2016-11-29 16:31:36 +0000272 p = p->next) {
273 if (p->init != NULL) {
274 p->init(channel_stack, grpc_channel_stack_element(channel_stack, i),
275 p->init_arg);
276 }
277 i++;
Craig Tillerde676262016-02-19 12:28:34 -0800278 }
Craig Tiller178edfa2016-02-17 20:54:46 -0800279 }
280
Craig Tillera59c16c2016-10-31 07:25:01 -0700281 grpc_channel_stack_builder_destroy(exec_ctx, builder);
Craig Tillerf6a4d422016-02-18 08:21:21 -0800282 gpr_free((grpc_channel_filter **)filters);
Craig Tiller178edfa2016-02-17 20:54:46 -0800283
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800284 return error;
Craig Tiller178edfa2016-02-17 20:54:46 -0800285}