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