• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <vector>
25 
26 #include "absl/strings/str_format.h"
27 #include "absl/strings/str_join.h"
28 
29 #include <grpc/grpc.h>
30 #include <grpc/impl/codegen/grpc_types.h>
31 #include <grpc/impl/codegen/log.h>
32 #include <grpc/support/alloc.h>
33 #include <grpc/support/log.h>
34 #include <grpc/support/string_util.h>
35 
36 #include "src/core/lib/channel/channel_args.h"
37 #include "src/core/lib/gpr/string.h"
38 #include "src/core/lib/gpr/useful.h"
39 
copy_arg(const grpc_arg * src)40 static grpc_arg copy_arg(const grpc_arg* src) {
41   grpc_arg dst;
42   dst.type = src->type;
43   dst.key = gpr_strdup(src->key);
44   switch (dst.type) {
45     case GRPC_ARG_STRING:
46       dst.value.string = gpr_strdup(src->value.string);
47       break;
48     case GRPC_ARG_INTEGER:
49       dst.value.integer = src->value.integer;
50       break;
51     case GRPC_ARG_POINTER:
52       dst.value.pointer = src->value.pointer;
53       dst.value.pointer.p =
54           src->value.pointer.vtable->copy(src->value.pointer.p);
55       break;
56   }
57   return dst;
58 }
59 
grpc_channel_args_copy_and_add(const grpc_channel_args * src,const grpc_arg * to_add,size_t num_to_add)60 grpc_channel_args* grpc_channel_args_copy_and_add(const grpc_channel_args* src,
61                                                   const grpc_arg* to_add,
62                                                   size_t num_to_add) {
63   return grpc_channel_args_copy_and_add_and_remove(src, nullptr, 0, to_add,
64                                                    num_to_add);
65 }
66 
grpc_channel_args_copy_and_remove(const grpc_channel_args * src,const char ** to_remove,size_t num_to_remove)67 grpc_channel_args* grpc_channel_args_copy_and_remove(
68     const grpc_channel_args* src, const char** to_remove,
69     size_t num_to_remove) {
70   return grpc_channel_args_copy_and_add_and_remove(src, to_remove,
71                                                    num_to_remove, nullptr, 0);
72 }
73 
should_remove_arg(const grpc_arg * arg,const char ** to_remove,size_t num_to_remove)74 static bool should_remove_arg(const grpc_arg* arg, const char** to_remove,
75                               size_t num_to_remove) {
76   for (size_t i = 0; i < num_to_remove; ++i) {
77     if (strcmp(arg->key, to_remove[i]) == 0) return true;
78   }
79   return false;
80 }
81 
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)82 grpc_channel_args* grpc_channel_args_copy_and_add_and_remove(
83     const grpc_channel_args* src, const char** to_remove, size_t num_to_remove,
84     const grpc_arg* to_add, size_t num_to_add) {
85   // Figure out how many args we'll be copying.
86   size_t num_args_to_copy = 0;
87   if (src != nullptr) {
88     for (size_t i = 0; i < src->num_args; ++i) {
89       if (!should_remove_arg(&src->args[i], to_remove, num_to_remove)) {
90         ++num_args_to_copy;
91       }
92     }
93   }
94   // Create result.
95   grpc_channel_args* dst =
96       static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
97   dst->num_args = num_args_to_copy + num_to_add;
98   if (dst->num_args == 0) {
99     dst->args = nullptr;
100     return dst;
101   }
102   dst->args =
103       static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * dst->num_args));
104   // Copy args from src that are not being removed.
105   size_t dst_idx = 0;
106   if (src != nullptr) {
107     for (size_t i = 0; i < src->num_args; ++i) {
108       if (!should_remove_arg(&src->args[i], to_remove, num_to_remove)) {
109         dst->args[dst_idx++] = copy_arg(&src->args[i]);
110       }
111     }
112   }
113   // Add args from to_add.
114   for (size_t i = 0; i < num_to_add; ++i) {
115     dst->args[dst_idx++] = copy_arg(&to_add[i]);
116   }
117   GPR_ASSERT(dst_idx == dst->num_args);
118   return dst;
119 }
120 
grpc_channel_args_copy(const grpc_channel_args * src)121 grpc_channel_args* grpc_channel_args_copy(const grpc_channel_args* src) {
122   return grpc_channel_args_copy_and_add(src, nullptr, 0);
123 }
124 
grpc_channel_args_union(const grpc_channel_args * a,const grpc_channel_args * b)125 grpc_channel_args* grpc_channel_args_union(const grpc_channel_args* a,
126                                            const grpc_channel_args* b) {
127   if (a == nullptr) return grpc_channel_args_copy(b);
128   if (b == nullptr) return grpc_channel_args_copy(a);
129   const size_t max_out = (a->num_args + b->num_args);
130   grpc_arg* uniques =
131       static_cast<grpc_arg*>(gpr_malloc(sizeof(*uniques) * max_out));
132   for (size_t i = 0; i < a->num_args; ++i) uniques[i] = a->args[i];
133 
134   size_t uniques_idx = a->num_args;
135   for (size_t i = 0; i < b->num_args; ++i) {
136     const char* b_key = b->args[i].key;
137     if (grpc_channel_args_find(a, b_key) == nullptr) {  // not found
138       uniques[uniques_idx++] = b->args[i];
139     }
140   }
141   grpc_channel_args* result =
142       grpc_channel_args_copy_and_add(nullptr, uniques, uniques_idx);
143   gpr_free(uniques);
144   return result;
145 }
146 
cmp_arg(const grpc_arg * a,const grpc_arg * b)147 static int cmp_arg(const grpc_arg* a, const grpc_arg* b) {
148   int c = GPR_ICMP(a->type, b->type);
149   if (c != 0) return c;
150   c = strcmp(a->key, b->key);
151   if (c != 0) return c;
152   switch (a->type) {
153     case GRPC_ARG_STRING:
154       return strcmp(a->value.string, b->value.string);
155     case GRPC_ARG_INTEGER:
156       return GPR_ICMP(a->value.integer, b->value.integer);
157     case GRPC_ARG_POINTER:
158       c = GPR_ICMP(a->value.pointer.p, b->value.pointer.p);
159       if (c != 0) {
160         c = GPR_ICMP(a->value.pointer.vtable, b->value.pointer.vtable);
161         if (c == 0) {
162           c = a->value.pointer.vtable->cmp(a->value.pointer.p,
163                                            b->value.pointer.p);
164         }
165       }
166       return c;
167   }
168   GPR_UNREACHABLE_CODE(return 0);
169 }
170 
171 /* stabilizing comparison function: since channel_args ordering matters for
172  * keys with the same name, we need to preserve that ordering */
cmp_key_stable(const void * ap,const void * bp)173 static int cmp_key_stable(const void* ap, const void* bp) {
174   const grpc_arg* const* a = static_cast<const grpc_arg* const*>(ap);
175   const grpc_arg* const* b = static_cast<const grpc_arg* const*>(bp);
176   int c = strcmp((*a)->key, (*b)->key);
177   if (c == 0) c = GPR_ICMP(*a, *b);
178   return c;
179 }
180 
grpc_channel_args_normalize(const grpc_channel_args * src)181 grpc_channel_args* grpc_channel_args_normalize(const grpc_channel_args* src) {
182   grpc_arg** args =
183       static_cast<grpc_arg**>(gpr_malloc(sizeof(grpc_arg*) * src->num_args));
184   for (size_t i = 0; i < src->num_args; i++) {
185     args[i] = &src->args[i];
186   }
187   if (src->num_args > 1) {
188     qsort(args, src->num_args, sizeof(grpc_arg*), cmp_key_stable);
189   }
190 
191   grpc_channel_args* b =
192       static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
193   b->num_args = src->num_args;
194   b->args = static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * b->num_args));
195   for (size_t i = 0; i < src->num_args; i++) {
196     b->args[i] = copy_arg(args[i]);
197   }
198 
199   gpr_free(args);
200   return b;
201 }
202 
grpc_channel_args_destroy(grpc_channel_args * a)203 void grpc_channel_args_destroy(grpc_channel_args* a) {
204   size_t i;
205   if (!a) return;
206   for (i = 0; i < a->num_args; i++) {
207     switch (a->args[i].type) {
208       case GRPC_ARG_STRING:
209         gpr_free(a->args[i].value.string);
210         break;
211       case GRPC_ARG_INTEGER:
212         break;
213       case GRPC_ARG_POINTER:
214         a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p);
215         break;
216     }
217     gpr_free(a->args[i].key);
218   }
219   gpr_free(a->args);
220   gpr_free(a);
221 }
222 
grpc_channel_args_compare(const grpc_channel_args * a,const grpc_channel_args * b)223 int grpc_channel_args_compare(const grpc_channel_args* a,
224                               const grpc_channel_args* b) {
225   if (a == nullptr && b == nullptr) return 0;
226   if (a == nullptr || b == nullptr) return a == nullptr ? -1 : 1;
227   int c = GPR_ICMP(a->num_args, b->num_args);
228   if (c != 0) return c;
229   for (size_t i = 0; i < a->num_args; i++) {
230     c = cmp_arg(&a->args[i], &b->args[i]);
231     if (c != 0) return c;
232   }
233   return 0;
234 }
235 
grpc_channel_args_find(const grpc_channel_args * args,const char * name)236 const grpc_arg* grpc_channel_args_find(const grpc_channel_args* args,
237                                        const char* name) {
238   if (args != nullptr) {
239     for (size_t i = 0; i < args->num_args; ++i) {
240       if (strcmp(args->args[i].key, name) == 0) {
241         return &args->args[i];
242       }
243     }
244   }
245   return nullptr;
246 }
247 
grpc_channel_arg_get_integer(const grpc_arg * arg,const grpc_integer_options options)248 int grpc_channel_arg_get_integer(const grpc_arg* arg,
249                                  const grpc_integer_options options) {
250   if (arg == nullptr) return options.default_value;
251   if (arg->type != GRPC_ARG_INTEGER) {
252     gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
253     return options.default_value;
254   }
255   if (arg->value.integer < options.min_value) {
256     gpr_log(GPR_ERROR, "%s ignored: it must be >= %d", arg->key,
257             options.min_value);
258     return options.default_value;
259   }
260   if (arg->value.integer > options.max_value) {
261     gpr_log(GPR_ERROR, "%s ignored: it must be <= %d", arg->key,
262             options.max_value);
263     return options.default_value;
264   }
265   return arg->value.integer;
266 }
267 
grpc_channel_args_find_integer(const grpc_channel_args * args,const char * name,const grpc_integer_options options)268 int grpc_channel_args_find_integer(const grpc_channel_args* args,
269                                    const char* name,
270                                    const grpc_integer_options options) {
271   const grpc_arg* arg = grpc_channel_args_find(args, name);
272   return grpc_channel_arg_get_integer(arg, options);
273 }
274 
grpc_channel_arg_get_string(const grpc_arg * arg)275 char* grpc_channel_arg_get_string(const grpc_arg* arg) {
276   if (arg == nullptr) return nullptr;
277   if (arg->type != GRPC_ARG_STRING) {
278     gpr_log(GPR_ERROR, "%s ignored: it must be an string", arg->key);
279     return nullptr;
280   }
281   return arg->value.string;
282 }
283 
grpc_channel_args_find_string(const grpc_channel_args * args,const char * name)284 char* grpc_channel_args_find_string(const grpc_channel_args* args,
285                                     const char* name) {
286   const grpc_arg* arg = grpc_channel_args_find(args, name);
287   return grpc_channel_arg_get_string(arg);
288 }
289 
grpc_channel_arg_get_bool(const grpc_arg * arg,bool default_value)290 bool grpc_channel_arg_get_bool(const grpc_arg* arg, bool default_value) {
291   if (arg == nullptr) return default_value;
292   if (arg->type != GRPC_ARG_INTEGER) {
293     gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
294     return default_value;
295   }
296   switch (arg->value.integer) {
297     case 0:
298       return false;
299     case 1:
300       return true;
301     default:
302       gpr_log(GPR_ERROR, "%s treated as bool but set to %d (assuming true)",
303               arg->key, arg->value.integer);
304       return true;
305   }
306 }
307 
grpc_channel_args_find_bool(const grpc_channel_args * args,const char * name,bool default_value)308 bool grpc_channel_args_find_bool(const grpc_channel_args* args,
309                                  const char* name, bool default_value) {
310   const grpc_arg* arg = grpc_channel_args_find(args, name);
311   return grpc_channel_arg_get_bool(arg, default_value);
312 }
313 
grpc_channel_args_want_minimal_stack(const grpc_channel_args * args)314 bool grpc_channel_args_want_minimal_stack(const grpc_channel_args* args) {
315   return grpc_channel_arg_get_bool(
316       grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK), false);
317 }
318 
grpc_channel_arg_string_create(char * name,char * value)319 grpc_arg grpc_channel_arg_string_create(char* name, char* value) {
320   grpc_arg arg;
321   arg.type = GRPC_ARG_STRING;
322   arg.key = name;
323   arg.value.string = value;
324   return arg;
325 }
326 
grpc_channel_arg_integer_create(char * name,int value)327 grpc_arg grpc_channel_arg_integer_create(char* name, int value) {
328   grpc_arg arg;
329   arg.type = GRPC_ARG_INTEGER;
330   arg.key = name;
331   arg.value.integer = value;
332   return arg;
333 }
334 
grpc_channel_arg_pointer_create(char * name,void * value,const grpc_arg_pointer_vtable * vtable)335 grpc_arg grpc_channel_arg_pointer_create(
336     char* name, void* value, const grpc_arg_pointer_vtable* vtable) {
337   grpc_arg arg;
338   arg.type = GRPC_ARG_POINTER;
339   arg.key = name;
340   arg.value.pointer.p = value;
341   arg.value.pointer.vtable = vtable;
342   return arg;
343 }
344 
grpc_channel_args_string(const grpc_channel_args * args)345 std::string grpc_channel_args_string(const grpc_channel_args* args) {
346   if (args == nullptr) return "";
347   std::vector<std::string> arg_strings;
348   for (size_t i = 0; i < args->num_args; ++i) {
349     const grpc_arg& arg = args->args[i];
350     std::string arg_string;
351     switch (arg.type) {
352       case GRPC_ARG_INTEGER:
353         arg_string = absl::StrFormat("%s=%d", arg.key, arg.value.integer);
354         break;
355       case GRPC_ARG_STRING:
356         arg_string = absl::StrFormat("%s=%s", arg.key, arg.value.string);
357         break;
358       case GRPC_ARG_POINTER:
359         arg_string = absl::StrFormat("%s=%p", arg.key, arg.value.pointer.p);
360         break;
361       default:
362         arg_string = "arg with unknown type";
363     }
364     arg_strings.push_back(arg_string);
365   }
366   return absl::StrJoin(arg_strings, ", ");
367 }
368 
369 namespace {
370 grpc_channel_args_client_channel_creation_mutator g_mutator = nullptr;
371 }  // namespace
372 
grpc_channel_args_set_client_channel_creation_mutator(grpc_channel_args_client_channel_creation_mutator cb)373 void grpc_channel_args_set_client_channel_creation_mutator(
374     grpc_channel_args_client_channel_creation_mutator cb) {
375   GPR_DEBUG_ASSERT(g_mutator == nullptr);
376   g_mutator = cb;
377 }
378 grpc_channel_args_client_channel_creation_mutator
grpc_channel_args_get_client_channel_creation_mutator()379 grpc_channel_args_get_client_channel_creation_mutator() {
380   return g_mutator;
381 }
382