Home | History | Annotate | Download | only in channel
      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