blob: e0382fa0d9a202689a16542c19421606bfa418bf [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller19482442016-01-25 09:59:20 -08003 * Copyright 2015-2016, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080034#include "src/core/channel/channel_args.h"
Craig Tillerf40df232016-03-25 13:38:14 -070035#include <grpc/grpc.h>
Craig Tiller485d7762015-01-23 12:54:05 -080036#include "src/core/support/string.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080037
Bogdan Drutu441499a2016-01-26 19:16:04 -080038#include <grpc/census.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080039#include <grpc/support/alloc.h>
Craig Tiller7e5a9cf2016-02-02 09:28:22 -080040#include <grpc/support/log.h>
Masood Malekghassemi701af602015-06-03 15:01:17 -070041#include <grpc/support/string_util.h>
David Garcia Quintasa4c4f022015-08-21 00:05:42 -070042#include <grpc/support/useful.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080043
44#include <string.h>
45
Craig Tillera82950e2015-09-22 12:33:20 -070046static grpc_arg copy_arg(const grpc_arg *src) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080047 grpc_arg dst;
48 dst.type = src->type;
Craig Tillera82950e2015-09-22 12:33:20 -070049 dst.key = gpr_strdup(src->key);
50 switch (dst.type) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080051 case GRPC_ARG_STRING:
Craig Tillera82950e2015-09-22 12:33:20 -070052 dst.value.string = gpr_strdup(src->value.string);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080053 break;
54 case GRPC_ARG_INTEGER:
55 dst.value.integer = src->value.integer;
56 break;
57 case GRPC_ARG_POINTER:
58 dst.value.pointer = src->value.pointer;
Craig Tiller5de79ee2016-01-25 08:16:02 -080059 dst.value.pointer.p =
60 src->value.pointer.vtable->copy(src->value.pointer.p);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080061 break;
Craig Tillera82950e2015-09-22 12:33:20 -070062 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080063 return dst;
64}
65
Craig Tillera82950e2015-09-22 12:33:20 -070066grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
67 const grpc_arg *to_add,
68 size_t num_to_add) {
69 grpc_channel_args *dst = gpr_malloc(sizeof(grpc_channel_args));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080070 size_t i;
71 size_t src_num_args = (src == NULL) ? 0 : src->num_args;
Craig Tillera82950e2015-09-22 12:33:20 -070072 if (!src && !to_add) {
73 dst->num_args = 0;
74 dst->args = NULL;
75 return dst;
76 }
Craig Tillerd9a50882015-06-29 15:57:36 -070077 dst->num_args = src_num_args + num_to_add;
Craig Tillera82950e2015-09-22 12:33:20 -070078 dst->args = gpr_malloc(sizeof(grpc_arg) * dst->num_args);
79 for (i = 0; i < src_num_args; i++) {
80 dst->args[i] = copy_arg(&src->args[i]);
81 }
82 for (i = 0; i < num_to_add; i++) {
83 dst->args[i + src_num_args] = copy_arg(&to_add[i]);
84 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080085 return dst;
86}
87
Craig Tillera82950e2015-09-22 12:33:20 -070088grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src) {
89 return grpc_channel_args_copy_and_add(src, NULL, 0);
Craig Tillerd9a50882015-06-29 15:57:36 -070090}
91
Craig Tillera82950e2015-09-22 12:33:20 -070092grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a,
93 const grpc_channel_args *b) {
94 return grpc_channel_args_copy_and_add(a, b->args, b->num_args);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080095}
96
Craig Tilleredc2fff2016-01-13 06:54:27 -080097static int cmp_arg(const grpc_arg *a, const grpc_arg *b) {
Craig Tiller19482442016-01-25 09:59:20 -080098 int c = GPR_ICMP(a->type, b->type);
Craig Tilleredc2fff2016-01-13 06:54:27 -080099 if (c != 0) return c;
100 c = strcmp(a->key, b->key);
101 if (c != 0) return c;
102 switch (a->type) {
103 case GRPC_ARG_STRING:
Craig Tiller7e5a9cf2016-02-02 09:28:22 -0800104 return strcmp(a->value.string, b->value.string);
Craig Tilleredc2fff2016-01-13 06:54:27 -0800105 case GRPC_ARG_INTEGER:
Craig Tiller7e5a9cf2016-02-02 09:28:22 -0800106 return GPR_ICMP(a->value.integer, b->value.integer);
Craig Tilleredc2fff2016-01-13 06:54:27 -0800107 case GRPC_ARG_POINTER:
Craig Tiller5de79ee2016-01-25 08:16:02 -0800108 c = GPR_ICMP(a->value.pointer.p, b->value.pointer.p);
Craig Tilleredc2fff2016-01-13 06:54:27 -0800109 if (c != 0) {
Craig Tiller5de79ee2016-01-25 08:16:02 -0800110 c = GPR_ICMP(a->value.pointer.vtable, b->value.pointer.vtable);
Craig Tilleredc2fff2016-01-13 06:54:27 -0800111 if (c == 0) {
112 c = a->value.pointer.vtable->cmp(a->value.pointer.p,
113 b->value.pointer.p);
114 }
115 }
Craig Tiller7e5a9cf2016-02-02 09:28:22 -0800116 return c;
Craig Tilleredc2fff2016-01-13 06:54:27 -0800117 }
Craig Tiller7e5a9cf2016-02-02 09:28:22 -0800118 GPR_UNREACHABLE_CODE(return 0);
Craig Tilleredc2fff2016-01-13 06:54:27 -0800119}
120
Craig Tiller24e274b2016-02-11 08:54:49 -0800121/* stabilizing comparison function: since channel_args ordering matters for
122 * keys with the same name, we need to preserve that ordering */
Craig Tilleredc2fff2016-01-13 06:54:27 -0800123static int cmp_key_stable(const void *ap, const void *bp) {
124 const grpc_arg *const *a = ap;
125 const grpc_arg *const *b = bp;
126 int c = strcmp((*a)->key, (*b)->key);
127 if (c == 0) c = GPR_ICMP(*a, *b);
128 return c;
129}
130
131grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a) {
Craig Tiller5de79ee2016-01-25 08:16:02 -0800132 grpc_arg **args = gpr_malloc(sizeof(grpc_arg *) * a->num_args);
Craig Tilleredc2fff2016-01-13 06:54:27 -0800133 for (size_t i = 0; i < a->num_args; i++) {
134 args[i] = &a->args[i];
135 }
Craig Tiller5de79ee2016-01-25 08:16:02 -0800136 qsort(args, a->num_args, sizeof(grpc_arg *), cmp_key_stable);
Craig Tilleredc2fff2016-01-13 06:54:27 -0800137
138 grpc_channel_args *b = gpr_malloc(sizeof(grpc_channel_args));
139 b->num_args = a->num_args;
140 b->args = gpr_malloc(sizeof(grpc_arg) * b->num_args);
141 for (size_t i = 0; i < a->num_args; i++) {
142 b->args[i] = copy_arg(args[i]);
143 }
144
145 gpr_free(args);
146 return b;
147}
148
Craig Tillera82950e2015-09-22 12:33:20 -0700149void grpc_channel_args_destroy(grpc_channel_args *a) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800150 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700151 for (i = 0; i < a->num_args; i++) {
152 switch (a->args[i].type) {
153 case GRPC_ARG_STRING:
154 gpr_free(a->args[i].value.string);
155 break;
156 case GRPC_ARG_INTEGER:
157 break;
158 case GRPC_ARG_POINTER:
Craig Tilleredc2fff2016-01-13 06:54:27 -0800159 a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p);
Craig Tillera82950e2015-09-22 12:33:20 -0700160 break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800161 }
Craig Tillera82950e2015-09-22 12:33:20 -0700162 gpr_free(a->args[i].key);
163 }
164 gpr_free(a->args);
165 gpr_free(a);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800166}
167
Craig Tillera82950e2015-09-22 12:33:20 -0700168int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) {
David Garcia Quintas20afd462015-07-06 23:01:39 -0700169 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700170 if (a == NULL) return 0;
171 for (i = 0; i < a->num_args; i++) {
172 if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_CENSUS)) {
Bogdan Drutu441499a2016-01-26 19:16:04 -0800173 return a->args[i].value.integer != 0 && census_enabled();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800174 }
Craig Tillera82950e2015-09-22 12:33:20 -0700175 }
Bogdan Drutu441499a2016-01-26 19:16:04 -0800176 return census_enabled();
Craig Tiller190d3602015-02-18 09:23:38 -0800177}
David Garcia Quintascc6c43c2015-06-16 11:35:41 -0700178
Craig Tillera82950e2015-09-22 12:33:20 -0700179grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
180 const grpc_channel_args *a) {
David Garcia Quintascc6c43c2015-06-16 11:35:41 -0700181 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700182 if (a == NULL) return 0;
183 for (i = 0; i < a->num_args; ++i) {
184 if (a->args[i].type == GRPC_ARG_INTEGER &&
185 !strcmp(GRPC_COMPRESSION_ALGORITHM_ARG, a->args[i].key)) {
186 return (grpc_compression_algorithm)a->args[i].value.integer;
187 break;
David Garcia Quintascc6c43c2015-06-16 11:35:41 -0700188 }
Craig Tillera82950e2015-09-22 12:33:20 -0700189 }
David Garcia Quintascadbf222015-07-17 15:33:13 -0700190 return GRPC_COMPRESS_NONE;
David Garcia Quintascc6c43c2015-06-16 11:35:41 -0700191}
192
Craig Tillera82950e2015-09-22 12:33:20 -0700193grpc_channel_args *grpc_channel_args_set_compression_algorithm(
194 grpc_channel_args *a, grpc_compression_algorithm algorithm) {
David Garcia Quintascc6c43c2015-06-16 11:35:41 -0700195 grpc_arg tmp;
196 tmp.type = GRPC_ARG_INTEGER;
David Garcia Quintascadbf222015-07-17 15:33:13 -0700197 tmp.key = GRPC_COMPRESSION_ALGORITHM_ARG;
198 tmp.value.integer = algorithm;
Craig Tillera82950e2015-09-22 12:33:20 -0700199 return grpc_channel_args_copy_and_add(a, &tmp, 1);
David Garcia Quintascc6c43c2015-06-16 11:35:41 -0700200}
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700201
202/** Returns 1 if the argument for compression algorithm's enabled states bitset
203 * was found in \a a, returning the arg's value in \a states. Otherwise, returns
204 * 0. */
Craig Tillera82950e2015-09-22 12:33:20 -0700205static int find_compression_algorithm_states_bitset(const grpc_channel_args *a,
206 int **states_arg) {
207 if (a != NULL) {
208 size_t i;
209 for (i = 0; i < a->num_args; ++i) {
210 if (a->args[i].type == GRPC_ARG_INTEGER &&
211 !strcmp(GRPC_COMPRESSION_ALGORITHM_STATE_ARG, a->args[i].key)) {
212 *states_arg = &a->args[i].value.integer;
213 return 1; /* GPR_TRUE */
214 }
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700215 }
Craig Tillera82950e2015-09-22 12:33:20 -0700216 }
217 return 0; /* GPR_FALSE */
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700218}
219
Craig Tillera82950e2015-09-22 12:33:20 -0700220grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
221 grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) {
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700222 int *states_arg;
David Garcia Quintasfe5f2542015-08-24 12:33:05 -0700223 grpc_channel_args *result = *a;
Craig Tillera82950e2015-09-22 12:33:20 -0700224 const int states_arg_found =
225 find_compression_algorithm_states_bitset(*a, &states_arg);
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700226
Craig Tillera82950e2015-09-22 12:33:20 -0700227 if (states_arg_found) {
228 if (state != 0) {
229 GPR_BITSET((unsigned *)states_arg, algorithm);
230 } else {
231 GPR_BITCLEAR((unsigned *)states_arg, algorithm);
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700232 }
Craig Tillera82950e2015-09-22 12:33:20 -0700233 } else {
234 /* create a new arg */
235 grpc_arg tmp;
236 tmp.type = GRPC_ARG_INTEGER;
237 tmp.key = GRPC_COMPRESSION_ALGORITHM_STATE_ARG;
238 /* all enabled by default */
239 tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
240 if (state != 0) {
241 GPR_BITSET((unsigned *)&tmp.value.integer, algorithm);
242 } else {
243 GPR_BITCLEAR((unsigned *)&tmp.value.integer, algorithm);
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700244 }
Craig Tillera82950e2015-09-22 12:33:20 -0700245 result = grpc_channel_args_copy_and_add(*a, &tmp, 1);
246 grpc_channel_args_destroy(*a);
247 *a = result;
248 }
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700249 return result;
250}
251
Craig Tillera82950e2015-09-22 12:33:20 -0700252int grpc_channel_args_compression_algorithm_get_states(
253 const grpc_channel_args *a) {
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700254 int *states_arg;
Craig Tillera82950e2015-09-22 12:33:20 -0700255 if (find_compression_algorithm_states_bitset(a, &states_arg)) {
256 return *states_arg;
257 } else {
258 return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */
259 }
David Garcia Quintasa4c4f022015-08-21 00:05:42 -0700260}
Craig Tilleredc2fff2016-01-13 06:54:27 -0800261
Craig Tiller5de79ee2016-01-25 08:16:02 -0800262int grpc_channel_args_compare(const grpc_channel_args *a,
Craig Tilleredc2fff2016-01-13 06:54:27 -0800263 const grpc_channel_args *b) {
264 int c = GPR_ICMP(a->num_args, b->num_args);
265 if (c != 0) return c;
266 for (size_t i = 0; i < a->num_args; i++) {
267 c = cmp_arg(&a->args[i], &b->args[i]);
268 if (c != 0) return c;
269 }
270 return 0;
271}