Home | History | Annotate | Download | only in channel
      1 /*
      2  *
      3  * Copyright 2015 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 <limits.h>
     22 #include <string.h>
     23 
     24 #include <grpc/compression.h>
     25 #include <grpc/grpc.h>
     26 #include <grpc/support/alloc.h>
     27 #include <grpc/support/log.h>
     28 #include <grpc/support/string_util.h>
     29 
     30 #include "src/core/lib/channel/channel_args.h"
     31 #include "src/core/lib/gpr/string.h"
     32 #include "src/core/lib/gpr/useful.h"
     33 
     34 static grpc_arg copy_arg(const grpc_arg* src) {
     35   grpc_arg dst;
     36   dst.type = src->type;
     37   dst.key = gpr_strdup(src->key);
     38   switch (dst.type) {
     39     case GRPC_ARG_STRING:
     40       dst.value.string = gpr_strdup(src->value.string);
     41       break;
     42     case GRPC_ARG_INTEGER:
     43       dst.value.integer = src->value.integer;
     44       break;
     45     case GRPC_ARG_POINTER:
     46       dst.value.pointer = src->value.pointer;
     47       dst.value.pointer.p =
     48           src->value.pointer.vtable->copy(src->value.pointer.p);
     49       break;
     50   }
     51   return dst;
     52 }
     53 
     54 grpc_channel_args* grpc_channel_args_copy_and_add(const grpc_channel_args* src,
     55                                                   const grpc_arg* to_add,
     56                                                   size_t num_to_add) {
     57   return grpc_channel_args_copy_and_add_and_remove(src, nullptr, 0, to_add,
     58                                                    num_to_add);
     59 }
     60 
     61 grpc_channel_args* grpc_channel_args_copy_and_remove(
     62     const grpc_channel_args* src, const char** to_remove,
     63     size_t num_to_remove) {
     64   return grpc_channel_args_copy_and_add_and_remove(src, to_remove,
     65                                                    num_to_remove, nullptr, 0);
     66 }
     67 
     68 static bool should_remove_arg(const grpc_arg* arg, const char** to_remove,
     69                               size_t num_to_remove) {
     70   for (size_t i = 0; i < num_to_remove; ++i) {
     71     if (strcmp(arg->key, to_remove[i]) == 0) return true;
     72   }
     73   return false;
     74 }
     75 
     76 grpc_channel_args* grpc_channel_args_copy_and_add_and_remove(
     77     const grpc_channel_args* src, const char** to_remove, size_t num_to_remove,
     78     const grpc_arg* to_add, size_t num_to_add) {
     79   // Figure out how many args we'll be copying.
     80   size_t num_args_to_copy = 0;
     81   if (src != nullptr) {
     82     for (size_t i = 0; i < src->num_args; ++i) {
     83       if (!should_remove_arg(&src->args[i], to_remove, num_to_remove)) {
     84         ++num_args_to_copy;
     85       }
     86     }
     87   }
     88   // Create result.
     89   grpc_channel_args* dst =
     90       static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
     91   dst->num_args = num_args_to_copy + num_to_add;
     92   if (dst->num_args == 0) {
     93     dst->args = nullptr;
     94     return dst;
     95   }
     96   dst->args =
     97       static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * dst->num_args));
     98   // Copy args from src that are not being removed.
     99   size_t dst_idx = 0;
    100   if (src != nullptr) {
    101     for (size_t i = 0; i < src->num_args; ++i) {
    102       if (!should_remove_arg(&src->args[i], to_remove, num_to_remove)) {
    103         dst->args[dst_idx++] = copy_arg(&src->args[i]);
    104       }
    105     }
    106   }
    107   // Add args from to_add.
    108   for (size_t i = 0; i < num_to_add; ++i) {
    109     dst->args[dst_idx++] = copy_arg(&to_add[i]);
    110   }
    111   GPR_ASSERT(dst_idx == dst->num_args);
    112   return dst;
    113 }
    114 
    115 grpc_channel_args* grpc_channel_args_copy(const grpc_channel_args* src) {
    116   return grpc_channel_args_copy_and_add(src, nullptr, 0);
    117 }
    118 
    119 grpc_channel_args* grpc_channel_args_union(const grpc_channel_args* a,
    120                                            const grpc_channel_args* b) {
    121   const size_t max_out = (a->num_args + b->num_args);
    122   grpc_arg* uniques =
    123       static_cast<grpc_arg*>(gpr_malloc(sizeof(*uniques) * max_out));
    124   for (size_t i = 0; i < a->num_args; ++i) uniques[i] = a->args[i];
    125 
    126   size_t uniques_idx = a->num_args;
    127   for (size_t i = 0; i < b->num_args; ++i) {
    128     const char* b_key = b->args[i].key;
    129     if (grpc_channel_args_find(a, b_key) == nullptr) {  // not found
    130       uniques[uniques_idx++] = b->args[i];
    131     }
    132   }
    133   grpc_channel_args* result =
    134       grpc_channel_args_copy_and_add(nullptr, uniques, uniques_idx);
    135   gpr_free(uniques);
    136   return result;
    137 }
    138 
    139 static int cmp_arg(const grpc_arg* a, const grpc_arg* b) {
    140   int c = GPR_ICMP(a->type, b->type);
    141   if (c != 0) return c;
    142   c = strcmp(a->key, b->key);
    143   if (c != 0) return c;
    144   switch (a->type) {
    145     case GRPC_ARG_STRING:
    146       return strcmp(a->value.string, b->value.string);
    147     case GRPC_ARG_INTEGER:
    148       return GPR_ICMP(a->value.integer, b->value.integer);
    149     case GRPC_ARG_POINTER:
    150       c = GPR_ICMP(a->value.pointer.p, b->value.pointer.p);
    151       if (c != 0) {
    152         c = GPR_ICMP(a->value.pointer.vtable, b->value.pointer.vtable);
    153         if (c == 0) {
    154           c = a->value.pointer.vtable->cmp(a->value.pointer.p,
    155                                            b->value.pointer.p);
    156         }
    157       }
    158       return c;
    159   }
    160   GPR_UNREACHABLE_CODE(return 0);
    161 }
    162 
    163 /* stabilizing comparison function: since channel_args ordering matters for
    164  * keys with the same name, we need to preserve that ordering */
    165 static int cmp_key_stable(const void* ap, const void* bp) {
    166   const grpc_arg* const* a = static_cast<const grpc_arg* const*>(ap);
    167   const grpc_arg* const* b = static_cast<const grpc_arg* const*>(bp);
    168   int c = strcmp((*a)->key, (*b)->key);
    169   if (c == 0) c = GPR_ICMP(*a, *b);
    170   return c;
    171 }
    172 
    173 grpc_channel_args* grpc_channel_args_normalize(const grpc_channel_args* a) {
    174   grpc_arg** args =
    175       static_cast<grpc_arg**>(gpr_malloc(sizeof(grpc_arg*) * a->num_args));
    176   for (size_t i = 0; i < a->num_args; i++) {
    177     args[i] = &a->args[i];
    178   }
    179   if (a->num_args > 1)
    180     qsort(args, a->num_args, sizeof(grpc_arg*), cmp_key_stable);
    181 
    182   grpc_channel_args* b =
    183       static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
    184   b->num_args = a->num_args;
    185   b->args = static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * b->num_args));
    186   for (size_t i = 0; i < a->num_args; i++) {
    187     b->args[i] = copy_arg(args[i]);
    188   }
    189 
    190   gpr_free(args);
    191   return b;
    192 }
    193 
    194 void grpc_channel_args_destroy(grpc_channel_args* a) {
    195   size_t i;
    196   if (!a) return;
    197   for (i = 0; i < a->num_args; i++) {
    198     switch (a->args[i].type) {
    199       case GRPC_ARG_STRING:
    200         gpr_free(a->args[i].value.string);
    201         break;
    202       case GRPC_ARG_INTEGER:
    203         break;
    204       case GRPC_ARG_POINTER:
    205         a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p);
    206         break;
    207     }
    208     gpr_free(a->args[i].key);
    209   }
    210   gpr_free(a->args);
    211   gpr_free(a);
    212 }
    213 
    214 grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
    215     const grpc_channel_args* a) {
    216   size_t i;
    217   if (a == nullptr) return GRPC_COMPRESS_NONE;
    218   for (i = 0; i < a->num_args; ++i) {
    219     if (a->args[i].type == GRPC_ARG_INTEGER &&
    220         !strcmp(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, a->args[i].key)) {
    221       return static_cast<grpc_compression_algorithm>(a->args[i].value.integer);
    222       break;
    223     }
    224   }
    225   return GRPC_COMPRESS_NONE;
    226 }
    227 
    228 grpc_channel_args* grpc_channel_args_set_compression_algorithm(
    229     grpc_channel_args* a, grpc_compression_algorithm algorithm) {
    230   GPR_ASSERT(algorithm < GRPC_COMPRESS_ALGORITHMS_COUNT);
    231   grpc_arg tmp;
    232   tmp.type = GRPC_ARG_INTEGER;
    233   tmp.key = (char*)GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM;
    234   tmp.value.integer = algorithm;
    235   return grpc_channel_args_copy_and_add(a, &tmp, 1);
    236 }
    237 
    238 /** Returns 1 if the argument for compression algorithm's enabled states bitset
    239  * was found in \a a, returning the arg's value in \a states. Otherwise, returns
    240  * 0. */
    241 static int find_compression_algorithm_states_bitset(const grpc_channel_args* a,
    242                                                     int** states_arg) {
    243   if (a != nullptr) {
    244     size_t i;
    245     for (i = 0; i < a->num_args; ++i) {
    246       if (a->args[i].type == GRPC_ARG_INTEGER &&
    247           !strcmp(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
    248                   a->args[i].key)) {
    249         *states_arg = &a->args[i].value.integer;
    250         **states_arg |= 0x1; /* forcefully enable support for no compression */
    251         return 1;
    252       }
    253     }
    254   }
    255   return 0; /* GPR_FALSE */
    256 }
    257 
    258 grpc_channel_args* grpc_channel_args_compression_algorithm_set_state(
    259     grpc_channel_args** a, grpc_compression_algorithm algorithm, int state) {
    260   int* states_arg = nullptr;
    261   grpc_channel_args* result = *a;
    262   const int states_arg_found =
    263       find_compression_algorithm_states_bitset(*a, &states_arg);
    264 
    265   if (grpc_channel_args_get_compression_algorithm(*a) == algorithm &&
    266       state == 0) {
    267     const char* algo_name = nullptr;
    268     GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algo_name) != 0);
    269     gpr_log(GPR_ERROR,
    270             "Tried to disable default compression algorithm '%s'. The "
    271             "operation has been ignored.",
    272             algo_name);
    273   } else if (states_arg_found) {
    274     if (state != 0) {
    275       GPR_BITSET((unsigned*)states_arg, algorithm);
    276     } else if (algorithm != GRPC_COMPRESS_NONE) {
    277       GPR_BITCLEAR((unsigned*)states_arg, algorithm);
    278     }
    279   } else {
    280     /* create a new arg */
    281     grpc_arg tmp;
    282     tmp.type = GRPC_ARG_INTEGER;
    283     tmp.key = (char*)GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET;
    284     /* all enabled by default */
    285     tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
    286     if (state != 0) {
    287       GPR_BITSET((unsigned*)&tmp.value.integer, algorithm);
    288     } else if (algorithm != GRPC_COMPRESS_NONE) {
    289       GPR_BITCLEAR((unsigned*)&tmp.value.integer, algorithm);
    290     }
    291     result = grpc_channel_args_copy_and_add(*a, &tmp, 1);
    292     grpc_channel_args_destroy(*a);
    293     *a = result;
    294   }
    295   return result;
    296 }
    297 
    298 uint32_t grpc_channel_args_compression_algorithm_get_states(
    299     const grpc_channel_args* a) {
    300   int* states_arg;
    301   if (find_compression_algorithm_states_bitset(a, &states_arg)) {
    302     return static_cast<uint32_t>(*states_arg);
    303   } else {
    304     return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */
    305   }
    306 }
    307 
    308 grpc_channel_args* grpc_channel_args_set_socket_mutator(
    309     grpc_channel_args* a, grpc_socket_mutator* mutator) {
    310   grpc_arg tmp = grpc_socket_mutator_to_arg(mutator);
    311   return grpc_channel_args_copy_and_add(a, &tmp, 1);
    312 }
    313 
    314 int grpc_channel_args_compare(const grpc_channel_args* a,
    315                               const grpc_channel_args* b) {
    316   int c = GPR_ICMP(a->num_args, b->num_args);
    317   if (c != 0) return c;
    318   for (size_t i = 0; i < a->num_args; i++) {
    319     c = cmp_arg(&a->args[i], &b->args[i]);
    320     if (c != 0) return c;
    321   }
    322   return 0;
    323 }
    324 
    325 const grpc_arg* grpc_channel_args_find(const grpc_channel_args* args,
    326                                        const char* name) {
    327   if (args != nullptr) {
    328     for (size_t i = 0; i < args->num_args; ++i) {
    329       if (strcmp(args->args[i].key, name) == 0) {
    330         return &args->args[i];
    331       }
    332     }
    333   }
    334   return nullptr;
    335 }
    336 
    337 int grpc_channel_arg_get_integer(const grpc_arg* arg,
    338                                  const grpc_integer_options options) {
    339   if (arg == nullptr) return options.default_value;
    340   if (arg->type != GRPC_ARG_INTEGER) {
    341     gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
    342     return options.default_value;
    343   }
    344   if (arg->value.integer < options.min_value) {
    345     gpr_log(GPR_ERROR, "%s ignored: it must be >= %d", arg->key,
    346             options.min_value);
    347     return options.default_value;
    348   }
    349   if (arg->value.integer > options.max_value) {
    350     gpr_log(GPR_ERROR, "%s ignored: it must be <= %d", arg->key,
    351             options.max_value);
    352     return options.default_value;
    353   }
    354   return arg->value.integer;
    355 }
    356 
    357 char* grpc_channel_arg_get_string(const grpc_arg* arg) {
    358   if (arg == nullptr) return nullptr;
    359   if (arg->type != GRPC_ARG_STRING) {
    360     gpr_log(GPR_ERROR, "%s ignored: it must be an string", arg->key);
    361     return nullptr;
    362   }
    363   return arg->value.string;
    364 }
    365 
    366 bool grpc_channel_arg_get_bool(const grpc_arg* arg, bool default_value) {
    367   if (arg == nullptr) return default_value;
    368   if (arg->type != GRPC_ARG_INTEGER) {
    369     gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
    370     return default_value;
    371   }
    372   switch (arg->value.integer) {
    373     case 0:
    374       return false;
    375     case 1:
    376       return true;
    377     default:
    378       gpr_log(GPR_ERROR, "%s treated as bool but set to %d (assuming true)",
    379               arg->key, arg->value.integer);
    380       return true;
    381   }
    382 }
    383 
    384 bool grpc_channel_args_want_minimal_stack(const grpc_channel_args* args) {
    385   return grpc_channel_arg_get_bool(
    386       grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK), false);
    387 }
    388 
    389 grpc_arg grpc_channel_arg_string_create(char* name, char* value) {
    390   grpc_arg arg;
    391   arg.type = GRPC_ARG_STRING;
    392   arg.key = name;
    393   arg.value.string = value;
    394   return arg;
    395 }
    396 
    397 grpc_arg grpc_channel_arg_integer_create(char* name, int value) {
    398   grpc_arg arg;
    399   arg.type = GRPC_ARG_INTEGER;
    400   arg.key = name;
    401   arg.value.integer = value;
    402   return arg;
    403 }
    404 
    405 grpc_arg grpc_channel_arg_pointer_create(
    406     char* name, void* value, const grpc_arg_pointer_vtable* vtable) {
    407   grpc_arg arg;
    408   arg.type = GRPC_ARG_POINTER;
    409   arg.key = name;
    410   arg.value.pointer.p = value;
    411   arg.value.pointer.vtable = vtable;
    412   return arg;
    413 }
    414 
    415 char* grpc_channel_args_string(const grpc_channel_args* args) {
    416   if (args == nullptr) return nullptr;
    417   gpr_strvec v;
    418   gpr_strvec_init(&v);
    419   for (size_t i = 0; i < args->num_args; ++i) {
    420     const grpc_arg& arg = args->args[i];
    421     char* s;
    422     switch (arg.type) {
    423       case GRPC_ARG_INTEGER:
    424         gpr_asprintf(&s, "%s=%d", arg.key, arg.value.integer);
    425         break;
    426       case GRPC_ARG_STRING:
    427         gpr_asprintf(&s, "%s=%s", arg.key, arg.value.string);
    428         break;
    429       case GRPC_ARG_POINTER:
    430         gpr_asprintf(&s, "%s=%p", arg.key, arg.value.pointer.p);
    431         break;
    432       default:
    433         gpr_asprintf(&s, "arg with unknown type");
    434     }
    435     gpr_strvec_add(&v, s);
    436   }
    437   char* result =
    438       gpr_strjoin_sep(const_cast<const char**>(v.strs), v.count, ", ", nullptr);
    439   gpr_strvec_destroy(&v);
    440   return result;
    441 }
    442