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 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 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 72 const char* grpc_channel_stack_builder_get_target( 73 grpc_channel_stack_builder* b) { 74 return b->target; 75 } 76 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 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* 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* 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 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 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 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 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 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 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 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 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 166 grpc_transport* grpc_channel_stack_builder_get_transport( 167 grpc_channel_stack_builder* builder) { 168 return builder->transport; 169 } 170 171 const grpc_channel_args* grpc_channel_stack_builder_get_channel_arguments( 172 grpc_channel_stack_builder* builder) { 173 return builder->args; 174 } 175 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 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 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 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 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 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 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 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