blob: 1ce0c4e07ff09128af28befdf6668a8b7a9f586f [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>
39
Craig Tillerde676262016-02-19 12:28:34 -080040int grpc_trace_channel_stack_builder = 0;
41
Craig Tiller178edfa2016-02-17 20:54:46 -080042typedef struct filter_node {
43 struct filter_node *next;
44 struct filter_node *prev;
45 const grpc_channel_filter *filter;
46 grpc_post_filter_create_init_func init;
47 void *init_arg;
48} filter_node;
49
50struct grpc_channel_stack_builder {
Craig Tiller6fcb64c2016-02-22 16:35:31 -080051 // sentinel nodes for filters that have been added
Craig Tiller178edfa2016-02-17 20:54:46 -080052 filter_node begin;
53 filter_node end;
54 // various set/get-able parameters
55 const grpc_channel_args *args;
56 grpc_transport *transport;
57 const char *name;
58};
59
60struct grpc_channel_stack_builder_iterator {
61 grpc_channel_stack_builder *builder;
62 filter_node *node;
63};
64
65grpc_channel_stack_builder *grpc_channel_stack_builder_create(void) {
66 grpc_channel_stack_builder *b = gpr_malloc(sizeof(*b));
67 memset(b, 0, sizeof(*b));
68
Craig Tiller6fcb64c2016-02-22 16:35:31 -080069 b->begin.filter = NULL;
70 b->end.filter = NULL;
Craig Tiller178edfa2016-02-17 20:54:46 -080071 b->begin.next = &b->end;
72 b->begin.prev = &b->end;
73 b->end.next = &b->begin;
74 b->end.prev = &b->begin;
75
76 return b;
77}
78
79static grpc_channel_stack_builder_iterator *create_iterator_at_filter_node(
80 grpc_channel_stack_builder *builder, filter_node *node) {
81 grpc_channel_stack_builder_iterator *it = gpr_malloc(sizeof(*it));
82 it->builder = builder;
83 it->node = node;
84 return it;
85}
86
87void grpc_channel_stack_builder_iterator_destroy(
88 grpc_channel_stack_builder_iterator *it) {
89 gpr_free(it);
90}
91
92grpc_channel_stack_builder_iterator *
93grpc_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
98grpc_channel_stack_builder_iterator *
99grpc_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
104bool grpc_channel_stack_builder_move_next(
105 grpc_channel_stack_builder_iterator *iterator) {
106 if (iterator->node == &iterator->builder->end) return false;
107 iterator->node = iterator->node->next;
108 return true;
109}
110
111bool grpc_channel_stack_builder_move_prev(
112 grpc_channel_stack_builder_iterator *iterator) {
113 if (iterator->node == &iterator->builder->begin) return false;
114 iterator->node = iterator->node->prev;
115 return true;
116}
117
118bool grpc_channel_stack_builder_move_prev(
119 grpc_channel_stack_builder_iterator *iterator);
120
121void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder,
122 const char *name) {
123 GPR_ASSERT(builder->name == NULL);
124 builder->name = name;
125}
126
127void grpc_channel_stack_builder_set_channel_arguments(
128 grpc_channel_stack_builder *builder, const grpc_channel_args *args) {
129 GPR_ASSERT(builder->args == NULL);
130 builder->args = args;
131}
132
133void grpc_channel_stack_builder_set_transport(
134 grpc_channel_stack_builder *builder, grpc_transport *transport) {
135 GPR_ASSERT(builder->transport == NULL);
136 builder->transport = transport;
137}
138
139grpc_transport *grpc_channel_stack_builder_get_transport(
140 grpc_channel_stack_builder *builder) {
141 return builder->transport;
142}
143
144const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments(
145 grpc_channel_stack_builder *builder) {
146 return builder->args;
147}
148
149bool grpc_channel_stack_builder_append_filter(
150 grpc_channel_stack_builder *builder, const grpc_channel_filter *filter,
151 grpc_post_filter_create_init_func post_init_func, void *user_data) {
152 grpc_channel_stack_builder_iterator *it =
153 grpc_channel_stack_builder_create_iterator_at_last(builder);
154 bool ok = grpc_channel_stack_builder_add_filter_before(
155 it, filter, post_init_func, user_data);
156 grpc_channel_stack_builder_iterator_destroy(it);
157 return ok;
158}
159
160bool grpc_channel_stack_builder_prepend_filter(
161 grpc_channel_stack_builder *builder, const grpc_channel_filter *filter,
162 grpc_post_filter_create_init_func post_init_func, void *user_data) {
163 grpc_channel_stack_builder_iterator *it =
164 grpc_channel_stack_builder_create_iterator_at_first(builder);
165 bool ok = grpc_channel_stack_builder_add_filter_after(
166 it, filter, post_init_func, user_data);
167 grpc_channel_stack_builder_iterator_destroy(it);
168 return ok;
169}
170
171static void add_after(filter_node *before, const grpc_channel_filter *filter,
172 grpc_post_filter_create_init_func post_init_func,
173 void *user_data) {
174 filter_node *new = gpr_malloc(sizeof(*new));
175 new->next = before->next;
176 new->prev = before;
177 new->next->prev = new->prev->next = new;
178 new->filter = filter;
179 new->init = post_init_func;
180 new->init_arg = user_data;
181}
182
183bool grpc_channel_stack_builder_add_filter_before(
184 grpc_channel_stack_builder_iterator *iterator,
185 const grpc_channel_filter *filter,
186 grpc_post_filter_create_init_func post_init_func, void *user_data) {
187 if (iterator->node == &iterator->builder->begin) return false;
188 add_after(iterator->node->prev, filter, post_init_func, user_data);
189 return true;
190}
191
192bool grpc_channel_stack_builder_add_filter_after(
193 grpc_channel_stack_builder_iterator *iterator,
194 const grpc_channel_filter *filter,
195 grpc_post_filter_create_init_func post_init_func, void *user_data) {
196 if (iterator->node == &iterator->builder->end) return false;
197 add_after(iterator->node, filter, post_init_func, user_data);
198 return true;
199}
200
201void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder) {
202 filter_node *p = builder->begin.next;
203 while (p != &builder->end) {
204 filter_node *next = p->next;
205 gpr_free(p);
206 p = next;
207 }
208 gpr_free(builder);
209}
210
211void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx,
212 grpc_channel_stack_builder *builder,
213 size_t prefix_bytes, int initial_refs,
214 grpc_iomgr_cb_func destroy,
215 void *destroy_arg) {
216 // count the number of filters
217 size_t num_filters = 0;
218 for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
219 num_filters++;
220 }
221
222 // create an array of filters
Craig Tillerf6a4d422016-02-18 08:21:21 -0800223 const grpc_channel_filter **filters =
224 gpr_malloc(sizeof(*filters) * num_filters);
Craig Tiller178edfa2016-02-17 20:54:46 -0800225 size_t i = 0;
226 for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
227 filters[i++] = p->filter;
228 }
229
230 // calculate the size of the channel stack
231 size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters);
232
233 // allocate memory, with prefix_bytes followed by channel_stack_size
234 char *result = gpr_malloc(prefix_bytes + channel_stack_size);
235 // fetch a pointer to the channel stack
236 grpc_channel_stack *channel_stack =
237 (grpc_channel_stack *)(result + prefix_bytes);
238 // and initialize it
239 grpc_channel_stack_init(exec_ctx, initial_refs, destroy,
240 destroy_arg == NULL ? result : destroy_arg, filters,
241 num_filters, builder->args, builder->name,
242 channel_stack);
243
244 // run post-initialization functions
245 i = 0;
246 for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
Craig Tillerde676262016-02-19 12:28:34 -0800247 if (p->init != NULL) {
Craig Tiller178edfa2016-02-17 20:54:46 -0800248 p->init(channel_stack, grpc_channel_stack_element(channel_stack, i),
249 p->init_arg);
Craig Tillerde676262016-02-19 12:28:34 -0800250 }
Craig Tiller178edfa2016-02-17 20:54:46 -0800251 i++;
252 }
253
254 grpc_channel_stack_builder_destroy(builder);
Craig Tillerf6a4d422016-02-18 08:21:21 -0800255 gpr_free((grpc_channel_filter **)filters);
Craig Tiller178edfa2016-02-17 20:54:46 -0800256
257 return result;
258}