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
copy_arg(const grpc_arg * src)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
grpc_channel_args_copy_and_add(const grpc_channel_args * src,const grpc_arg * to_add,size_t num_to_add)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
grpc_channel_args_copy_and_remove(const grpc_channel_args * src,const char ** to_remove,size_t num_to_remove)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
should_remove_arg(const grpc_arg * arg,const char ** to_remove,size_t num_to_remove)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
grpc_channel_args_copy_and_add_and_remove(const grpc_channel_args * src,const char ** to_remove,size_t num_to_remove,const grpc_arg * to_add,size_t num_to_add)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
grpc_channel_args_copy(const grpc_channel_args * src)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
grpc_channel_args_union(const grpc_channel_args * a,const grpc_channel_args * b)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
cmp_arg(const grpc_arg * a,const grpc_arg * b)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 */
cmp_key_stable(const void * ap,const void * bp)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
grpc_channel_args_normalize(const grpc_channel_args * a)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
grpc_channel_args_destroy(grpc_channel_args * a)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
grpc_channel_args_get_compression_algorithm(const grpc_channel_args * a)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
grpc_channel_args_set_compression_algorithm(grpc_channel_args * a,grpc_compression_algorithm algorithm)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. */
find_compression_algorithm_states_bitset(const grpc_channel_args * a,int ** states_arg)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
grpc_channel_args_compression_algorithm_set_state(grpc_channel_args ** a,grpc_compression_algorithm algorithm,int state)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
grpc_channel_args_compression_algorithm_get_states(const grpc_channel_args * a)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
grpc_channel_args_set_socket_mutator(grpc_channel_args * a,grpc_socket_mutator * mutator)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
grpc_channel_args_compare(const grpc_channel_args * a,const grpc_channel_args * b)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
grpc_channel_args_find(const grpc_channel_args * args,const char * name)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
grpc_channel_arg_get_integer(const grpc_arg * arg,const grpc_integer_options options)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
grpc_channel_arg_get_string(const grpc_arg * arg)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
grpc_channel_arg_get_bool(const grpc_arg * arg,bool default_value)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
grpc_channel_args_want_minimal_stack(const grpc_channel_args * args)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
grpc_channel_arg_string_create(char * name,char * value)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
grpc_channel_arg_integer_create(char * name,int value)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
grpc_channel_arg_pointer_create(char * name,void * value,const grpc_arg_pointer_vtable * vtable)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
grpc_channel_args_string(const grpc_channel_args * args)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