• 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 * a)181 grpc_channel_args* grpc_channel_args_normalize(const grpc_channel_args* a) {
182   grpc_arg** args =
183       static_cast<grpc_arg**>(gpr_malloc(sizeof(grpc_arg*) * a->num_args));
184   for (size_t i = 0; i < a->num_args; i++) {
185     args[i] = &a->args[i];
186   }
187   if (a->num_args > 1)
188     qsort(args, a->num_args, sizeof(grpc_arg*), cmp_key_stable);
189 
190   grpc_channel_args* b =
191       static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
192   b->num_args = a->num_args;
193   b->args = static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * b->num_args));
194   for (size_t i = 0; i < a->num_args; i++) {
195     b->args[i] = copy_arg(args[i]);
196   }
197 
198   gpr_free(args);
199   return b;
200 }
201 
grpc_channel_args_destroy(grpc_channel_args * a)202 void grpc_channel_args_destroy(grpc_channel_args* a) {
203   size_t i;
204   if (!a) return;
205   for (i = 0; i < a->num_args; i++) {
206     switch (a->args[i].type) {
207       case GRPC_ARG_STRING:
208         gpr_free(a->args[i].value.string);
209         break;
210       case GRPC_ARG_INTEGER:
211         break;
212       case GRPC_ARG_POINTER:
213         a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p);
214         break;
215     }
216     gpr_free(a->args[i].key);
217   }
218   gpr_free(a->args);
219   gpr_free(a);
220 }
221 
grpc_channel_args_compare(const grpc_channel_args * a,const grpc_channel_args * b)222 int grpc_channel_args_compare(const grpc_channel_args* a,
223                               const grpc_channel_args* b) {
224   if (a == nullptr && b == nullptr) return 0;
225   if (a == nullptr || b == nullptr) return a == nullptr ? -1 : 1;
226   int c = GPR_ICMP(a->num_args, b->num_args);
227   if (c != 0) return c;
228   for (size_t i = 0; i < a->num_args; i++) {
229     c = cmp_arg(&a->args[i], &b->args[i]);
230     if (c != 0) return c;
231   }
232   return 0;
233 }
234 
grpc_channel_args_find(const grpc_channel_args * args,const char * name)235 const grpc_arg* grpc_channel_args_find(const grpc_channel_args* args,
236                                        const char* name) {
237   if (args != nullptr) {
238     for (size_t i = 0; i < args->num_args; ++i) {
239       if (strcmp(args->args[i].key, name) == 0) {
240         return &args->args[i];
241       }
242     }
243   }
244   return nullptr;
245 }
246 
grpc_channel_arg_get_integer(const grpc_arg * arg,const grpc_integer_options options)247 int grpc_channel_arg_get_integer(const grpc_arg* arg,
248                                  const grpc_integer_options options) {
249   if (arg == nullptr) return options.default_value;
250   if (arg->type != GRPC_ARG_INTEGER) {
251     gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
252     return options.default_value;
253   }
254   if (arg->value.integer < options.min_value) {
255     gpr_log(GPR_ERROR, "%s ignored: it must be >= %d", arg->key,
256             options.min_value);
257     return options.default_value;
258   }
259   if (arg->value.integer > options.max_value) {
260     gpr_log(GPR_ERROR, "%s ignored: it must be <= %d", arg->key,
261             options.max_value);
262     return options.default_value;
263   }
264   return arg->value.integer;
265 }
266 
grpc_channel_args_find_integer(const grpc_channel_args * args,const char * name,const grpc_integer_options options)267 int grpc_channel_args_find_integer(const grpc_channel_args* args,
268                                    const char* name,
269                                    const grpc_integer_options options) {
270   const grpc_arg* arg = grpc_channel_args_find(args, name);
271   return grpc_channel_arg_get_integer(arg, options);
272 }
273 
grpc_channel_arg_get_string(const grpc_arg * arg)274 char* grpc_channel_arg_get_string(const grpc_arg* arg) {
275   if (arg == nullptr) return nullptr;
276   if (arg->type != GRPC_ARG_STRING) {
277     gpr_log(GPR_ERROR, "%s ignored: it must be an string", arg->key);
278     return nullptr;
279   }
280   return arg->value.string;
281 }
282 
grpc_channel_args_find_string(const grpc_channel_args * args,const char * name)283 char* grpc_channel_args_find_string(const grpc_channel_args* args,
284                                     const char* name) {
285   const grpc_arg* arg = grpc_channel_args_find(args, name);
286   return grpc_channel_arg_get_string(arg);
287 }
288 
grpc_channel_arg_get_bool(const grpc_arg * arg,bool default_value)289 bool grpc_channel_arg_get_bool(const grpc_arg* arg, bool default_value) {
290   if (arg == nullptr) return default_value;
291   if (arg->type != GRPC_ARG_INTEGER) {
292     gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
293     return default_value;
294   }
295   switch (arg->value.integer) {
296     case 0:
297       return false;
298     case 1:
299       return true;
300     default:
301       gpr_log(GPR_ERROR, "%s treated as bool but set to %d (assuming true)",
302               arg->key, arg->value.integer);
303       return true;
304   }
305 }
306 
grpc_channel_args_find_bool(const grpc_channel_args * args,const char * name,bool default_value)307 bool grpc_channel_args_find_bool(const grpc_channel_args* args,
308                                  const char* name, bool default_value) {
309   const grpc_arg* arg = grpc_channel_args_find(args, name);
310   return grpc_channel_arg_get_bool(arg, default_value);
311 }
312 
grpc_channel_args_want_minimal_stack(const grpc_channel_args * args)313 bool grpc_channel_args_want_minimal_stack(const grpc_channel_args* args) {
314   return grpc_channel_arg_get_bool(
315       grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK), false);
316 }
317 
grpc_channel_arg_string_create(char * name,char * value)318 grpc_arg grpc_channel_arg_string_create(char* name, char* value) {
319   grpc_arg arg;
320   arg.type = GRPC_ARG_STRING;
321   arg.key = name;
322   arg.value.string = value;
323   return arg;
324 }
325 
grpc_channel_arg_integer_create(char * name,int value)326 grpc_arg grpc_channel_arg_integer_create(char* name, int value) {
327   grpc_arg arg;
328   arg.type = GRPC_ARG_INTEGER;
329   arg.key = name;
330   arg.value.integer = value;
331   return arg;
332 }
333 
grpc_channel_arg_pointer_create(char * name,void * value,const grpc_arg_pointer_vtable * vtable)334 grpc_arg grpc_channel_arg_pointer_create(
335     char* name, void* value, const grpc_arg_pointer_vtable* vtable) {
336   grpc_arg arg;
337   arg.type = GRPC_ARG_POINTER;
338   arg.key = name;
339   arg.value.pointer.p = value;
340   arg.value.pointer.vtable = vtable;
341   return arg;
342 }
343 
grpc_channel_args_string(const grpc_channel_args * args)344 std::string grpc_channel_args_string(const grpc_channel_args* args) {
345   if (args == nullptr) return "";
346   std::vector<std::string> arg_strings;
347   for (size_t i = 0; i < args->num_args; ++i) {
348     const grpc_arg& arg = args->args[i];
349     std::string arg_string;
350     switch (arg.type) {
351       case GRPC_ARG_INTEGER:
352         arg_string = absl::StrFormat("%s=%d", arg.key, arg.value.integer);
353         break;
354       case GRPC_ARG_STRING:
355         arg_string = absl::StrFormat("%s=%s", arg.key, arg.value.string);
356         break;
357       case GRPC_ARG_POINTER:
358         arg_string = absl::StrFormat("%s=%p", arg.key, arg.value.pointer.p);
359         break;
360       default:
361         arg_string = "arg with unknown type";
362     }
363     arg_strings.push_back(arg_string);
364   }
365   return absl::StrJoin(arg_strings, ", ");
366 }
367 
368 namespace {
369 grpc_channel_args_client_channel_creation_mutator g_mutator = nullptr;
370 }  // namespace
371 
grpc_channel_args_set_client_channel_creation_mutator(grpc_channel_args_client_channel_creation_mutator cb)372 void grpc_channel_args_set_client_channel_creation_mutator(
373     grpc_channel_args_client_channel_creation_mutator cb) {
374   GPR_DEBUG_ASSERT(g_mutator == nullptr);
375   g_mutator = cb;
376 }
377 grpc_channel_args_client_channel_creation_mutator
grpc_channel_args_get_client_channel_creation_mutator()378 grpc_channel_args_get_client_channel_creation_mutator() {
379   return g_mutator;
380 }
381