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 "src/core/lib/channel/channel_args.h"
20
21 #include <grpc/impl/channel_arg_names.h>
22 #include <grpc/support/alloc.h>
23 #include <grpc/support/port_platform.h>
24 #include <grpc/support/string_util.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <algorithm>
30 #include <map>
31 #include <memory>
32 #include <string>
33 #include <vector>
34
35 #include "absl/log/check.h"
36 #include "absl/log/log.h"
37 #include "absl/strings/match.h"
38 #include "absl/strings/str_cat.h"
39 #include "absl/strings/str_format.h"
40 #include "absl/strings/str_join.h"
41 #include "src/core/util/useful.h"
42
43 namespace grpc_core {
44
45 const grpc_arg_pointer_vtable ChannelArgs::Value::int_vtable_{
46 // copy
__anon40c8e0f50102(void* p) 47 [](void* p) { return p; },
48 // destroy
__anon40c8e0f50202(void*) 49 [](void*) {},
50 // cmp
__anon40c8e0f50302(void* p1, void* p2) 51 [](void* p1, void* p2) -> int {
52 return QsortCompare(reinterpret_cast<intptr_t>(p1),
53 reinterpret_cast<intptr_t>(p2));
54 },
55 };
56
57 const grpc_arg_pointer_vtable ChannelArgs::Value::string_vtable_{
58 // copy
__anon40c8e0f50402(void* p) 59 [](void* p) -> void* {
60 return static_cast<RefCountedString*>(p)->Ref().release();
61 },
62 // destroy
__anon40c8e0f50502(void* p) 63 [](void* p) { static_cast<RefCountedString*>(p)->Unref(); },
64 // cmp
__anon40c8e0f50602(void* p1, void* p2) 65 [](void* p1, void* p2) -> int {
66 return QsortCompare(static_cast<RefCountedString*>(p1)->as_string_view(),
67 static_cast<RefCountedString*>(p2)->as_string_view());
68 },
69 };
70
Pointer(void * p,const grpc_arg_pointer_vtable * vtable)71 ChannelArgs::Pointer::Pointer(void* p, const grpc_arg_pointer_vtable* vtable)
72 : p_(p), vtable_(vtable == nullptr ? EmptyVTable() : vtable) {}
73
Pointer(const Pointer & other)74 ChannelArgs::Pointer::Pointer(const Pointer& other)
75 : p_(other.vtable_->copy(other.p_)), vtable_(other.vtable_) {}
76
Pointer(Pointer && other)77 ChannelArgs::Pointer::Pointer(Pointer&& other) noexcept
78 : p_(other.p_), vtable_(other.vtable_) {
79 other.p_ = nullptr;
80 other.vtable_ = EmptyVTable();
81 }
82
EmptyVTable()83 const grpc_arg_pointer_vtable* ChannelArgs::Pointer::EmptyVTable() {
84 static const grpc_arg_pointer_vtable vtable = {
85 // copy
86 [](void* p) { return p; },
87 // destroy
88 [](void*) {},
89 // cmp
90 [](void* p1, void* p2) -> int { return QsortCompare(p1, p2); },
91 };
92 return &vtable;
93 }
94
95 ChannelArgs::ChannelArgs() = default;
96 ChannelArgs::~ChannelArgs() = default;
97 ChannelArgs::ChannelArgs(const ChannelArgs& other) = default;
98 ChannelArgs& ChannelArgs::operator=(const ChannelArgs& other) = default;
99 ChannelArgs::ChannelArgs(ChannelArgs&& other) noexcept = default;
100 ChannelArgs& ChannelArgs::operator=(ChannelArgs&& other) noexcept = default;
101
Get(absl::string_view name) const102 const ChannelArgs::Value* ChannelArgs::Get(absl::string_view name) const {
103 return args_.Lookup(name);
104 }
105
Contains(absl::string_view name) const106 bool ChannelArgs::Contains(absl::string_view name) const {
107 return Get(name) != nullptr;
108 }
109
operator <(const ChannelArgs & other) const110 bool ChannelArgs::operator<(const ChannelArgs& other) const {
111 return args_ < other.args_;
112 }
113
operator ==(const ChannelArgs & other) const114 bool ChannelArgs::operator==(const ChannelArgs& other) const {
115 return args_ == other.args_;
116 }
117
operator !=(const ChannelArgs & other) const118 bool ChannelArgs::operator!=(const ChannelArgs& other) const {
119 return !(*this == other);
120 }
121
WantMinimalStack() const122 bool ChannelArgs::WantMinimalStack() const {
123 return GetBool(GRPC_ARG_MINIMAL_STACK).value_or(false);
124 }
125
ChannelArgs(AVL<RefCountedStringValue,Value> args)126 ChannelArgs::ChannelArgs(AVL<RefCountedStringValue, Value> args)
127 : args_(std::move(args)) {}
128
Set(grpc_arg arg) const129 ChannelArgs ChannelArgs::Set(grpc_arg arg) const {
130 switch (arg.type) {
131 case GRPC_ARG_INTEGER:
132 return Set(arg.key, arg.value.integer);
133 case GRPC_ARG_STRING:
134 if (arg.value.string != nullptr) return Set(arg.key, arg.value.string);
135 return Set(arg.key, "");
136 case GRPC_ARG_POINTER:
137 return Set(arg.key,
138 Pointer(arg.value.pointer.vtable->copy(arg.value.pointer.p),
139 arg.value.pointer.vtable));
140 }
141 GPR_UNREACHABLE_CODE(return ChannelArgs());
142 }
143
FromC(const grpc_channel_args * args)144 ChannelArgs ChannelArgs::FromC(const grpc_channel_args* args) {
145 ChannelArgs result;
146 if (args != nullptr) {
147 for (size_t i = 0; i < args->num_args; i++) {
148 result = result.Set(args->args[i]);
149 }
150 }
151 return result;
152 }
153
MakeCArg(const char * name) const154 grpc_arg ChannelArgs::Value::MakeCArg(const char* name) const {
155 char* c_name = const_cast<char*>(name);
156 if (rep_.c_vtable() == &int_vtable_) {
157 return grpc_channel_arg_integer_create(
158 c_name, reinterpret_cast<intptr_t>(rep_.c_pointer()));
159 }
160 if (rep_.c_vtable() == &string_vtable_) {
161 return grpc_channel_arg_string_create(
162 c_name, const_cast<char*>(
163 static_cast<RefCountedString*>(rep_.c_pointer())->c_str()));
164 }
165 return grpc_channel_arg_pointer_create(c_name, rep_.c_pointer(),
166 rep_.c_vtable());
167 }
168
ToC() const169 ChannelArgs::CPtr ChannelArgs::ToC() const {
170 std::vector<grpc_arg> c_args;
171 args_.ForEach(
172 [&c_args](const RefCountedStringValue& key, const Value& value) {
173 c_args.push_back(value.MakeCArg(key.c_str()));
174 });
175 return CPtr(static_cast<const grpc_channel_args*>(
176 grpc_channel_args_copy_and_add(nullptr, c_args.data(), c_args.size())));
177 }
178
Set(absl::string_view name,Pointer value) const179 ChannelArgs ChannelArgs::Set(absl::string_view name, Pointer value) const {
180 return Set(name, Value(std::move(value)));
181 }
182
Set(absl::string_view name,int value) const183 ChannelArgs ChannelArgs::Set(absl::string_view name, int value) const {
184 return Set(name, Value(value));
185 }
186
Set(absl::string_view name,Value value) const187 ChannelArgs ChannelArgs::Set(absl::string_view name, Value value) const {
188 if (const auto* p = args_.Lookup(name)) {
189 if (*p == value) return *this; // already have this value for this key
190 }
191 return ChannelArgs(args_.Add(RefCountedStringValue(name), std::move(value)));
192 }
193
Set(absl::string_view name,absl::string_view value) const194 ChannelArgs ChannelArgs::Set(absl::string_view name,
195 absl::string_view value) const {
196 return Set(name, std::string(value));
197 }
198
Set(absl::string_view name,const char * value) const199 ChannelArgs ChannelArgs::Set(absl::string_view name, const char* value) const {
200 return Set(name, std::string(value));
201 }
202
Set(absl::string_view name,std::string value) const203 ChannelArgs ChannelArgs::Set(absl::string_view name, std::string value) const {
204 return Set(name, Value(std::move(value)));
205 }
206
Remove(absl::string_view name) const207 ChannelArgs ChannelArgs::Remove(absl::string_view name) const {
208 if (args_.Lookup(name) == nullptr) return *this;
209 return ChannelArgs(args_.Remove(name));
210 }
211
RemoveAllKeysWithPrefix(absl::string_view prefix) const212 ChannelArgs ChannelArgs::RemoveAllKeysWithPrefix(
213 absl::string_view prefix) const {
214 auto args = args_;
215 args_.ForEach([&](const RefCountedStringValue& key, const Value&) {
216 if (absl::StartsWith(key.as_string_view(), prefix)) args = args.Remove(key);
217 });
218 return ChannelArgs(std::move(args));
219 }
220
GetInt(absl::string_view name) const221 absl::optional<int> ChannelArgs::GetInt(absl::string_view name) const {
222 auto* v = Get(name);
223 if (v == nullptr) return absl::nullopt;
224 return v->GetIfInt();
225 }
226
GetDurationFromIntMillis(absl::string_view name) const227 absl::optional<Duration> ChannelArgs::GetDurationFromIntMillis(
228 absl::string_view name) const {
229 auto ms = GetInt(name);
230 if (!ms.has_value()) return absl::nullopt;
231 if (*ms == INT_MAX) return Duration::Infinity();
232 if (*ms == INT_MIN) return Duration::NegativeInfinity();
233 return Duration::Milliseconds(*ms);
234 }
235
GetString(absl::string_view name) const236 absl::optional<absl::string_view> ChannelArgs::GetString(
237 absl::string_view name) const {
238 auto* v = Get(name);
239 if (v == nullptr) return absl::nullopt;
240 const auto s = v->GetIfString();
241 if (s == nullptr) return absl::nullopt;
242 return s->as_string_view();
243 }
244
GetOwnedString(absl::string_view name) const245 absl::optional<std::string> ChannelArgs::GetOwnedString(
246 absl::string_view name) const {
247 absl::optional<absl::string_view> v = GetString(name);
248 if (!v.has_value()) return absl::nullopt;
249 return std::string(*v);
250 }
251
GetVoidPointer(absl::string_view name) const252 void* ChannelArgs::GetVoidPointer(absl::string_view name) const {
253 auto* v = Get(name);
254 if (v == nullptr) return nullptr;
255 const auto* pp = v->GetIfPointer();
256 if (pp == nullptr) return nullptr;
257 return pp->c_pointer();
258 }
259
GetBool(absl::string_view name) const260 absl::optional<bool> ChannelArgs::GetBool(absl::string_view name) const {
261 auto* v = Get(name);
262 if (v == nullptr) return absl::nullopt;
263 auto i = v->GetIfInt();
264 if (!i.has_value()) {
265 LOG(ERROR) << name << " ignored: it must be an integer";
266 return absl::nullopt;
267 }
268 switch (*i) {
269 case 0:
270 return false;
271 case 1:
272 return true;
273 default:
274 LOG(ERROR) << name << " treated as bool but set to " << *i
275 << " (assuming true)";
276 return true;
277 }
278 }
279
ToString(std::list<std::string> & backing_strings) const280 absl::string_view ChannelArgs::Value::ToString(
281 std::list<std::string>& backing_strings) const {
282 if (rep_.c_vtable() == &string_vtable_) {
283 return static_cast<RefCountedString*>(rep_.c_pointer())->as_string_view();
284 }
285 if (rep_.c_vtable() == &int_vtable_) {
286 backing_strings.emplace_back(
287 std::to_string(reinterpret_cast<intptr_t>(rep_.c_pointer())));
288 return backing_strings.back();
289 }
290 backing_strings.emplace_back(absl::StrFormat("%p", rep_.c_pointer()));
291 return backing_strings.back();
292 }
293
ToString() const294 std::string ChannelArgs::ToString() const {
295 std::vector<absl::string_view> strings;
296 std::list<std::string> backing_strings;
297 strings.push_back("{");
298 bool first = true;
299 args_.ForEach([&strings, &first, &backing_strings](
300 const RefCountedStringValue& key, const Value& value) {
301 if (!first) strings.push_back(", ");
302 first = false;
303 strings.push_back(key.as_string_view());
304 strings.push_back("=");
305 strings.push_back(value.ToString(backing_strings));
306 });
307 strings.push_back("}");
308 return absl::StrJoin(strings, "");
309 }
310
UnionWith(ChannelArgs other) const311 ChannelArgs ChannelArgs::UnionWith(ChannelArgs other) const {
312 if (args_.Empty()) return other;
313 if (other.args_.Empty()) return *this;
314 if (args_.Height() <= other.args_.Height()) {
315 args_.ForEach(
316 [&other](const RefCountedStringValue& key, const Value& value) {
317 other.args_ = other.args_.Add(key, value);
318 });
319 return other;
320 } else {
321 auto result = *this;
322 other.args_.ForEach(
323 [&result](const RefCountedStringValue& key, const Value& value) {
324 if (result.args_.Lookup(key) == nullptr) {
325 result.args_ = result.args_.Add(key, value);
326 }
327 });
328 return result;
329 }
330 }
331
FuzzingReferenceUnionWith(ChannelArgs other) const332 ChannelArgs ChannelArgs::FuzzingReferenceUnionWith(ChannelArgs other) const {
333 // DO NOT OPTIMIZE THIS!!
334 args_.ForEach([&other](const RefCountedStringValue& key, const Value& value) {
335 other.args_ = other.args_.Add(key, value);
336 });
337 return other;
338 }
339
operator ()(const grpc_channel_args * p) const340 void ChannelArgs::ChannelArgsDeleter::operator()(
341 const grpc_channel_args* p) const {
342 grpc_channel_args_destroy(p);
343 }
344
operator <<(std::ostream & out,const ChannelArgs & args)345 std::ostream& operator<<(std::ostream& out, const ChannelArgs& args) {
346 return out << args.ToString();
347 }
348
349 } // namespace grpc_core
350
copy_arg(const grpc_arg * src)351 static grpc_arg copy_arg(const grpc_arg* src) {
352 grpc_arg dst;
353 dst.type = src->type;
354 dst.key = gpr_strdup(src->key);
355 switch (dst.type) {
356 case GRPC_ARG_STRING:
357 dst.value.string = gpr_strdup(src->value.string);
358 break;
359 case GRPC_ARG_INTEGER:
360 dst.value.integer = src->value.integer;
361 break;
362 case GRPC_ARG_POINTER:
363 dst.value.pointer = src->value.pointer;
364 dst.value.pointer.p =
365 src->value.pointer.vtable->copy(src->value.pointer.p);
366 break;
367 }
368 return dst;
369 }
370
grpc_channel_args_copy_and_add(const grpc_channel_args * src,const grpc_arg * to_add,size_t num_to_add)371 grpc_channel_args* grpc_channel_args_copy_and_add(const grpc_channel_args* src,
372 const grpc_arg* to_add,
373 size_t num_to_add) {
374 return grpc_channel_args_copy_and_add_and_remove(src, nullptr, 0, to_add,
375 num_to_add);
376 }
377
grpc_channel_args_copy_and_remove(const grpc_channel_args * src,const char ** to_remove,size_t num_to_remove)378 grpc_channel_args* grpc_channel_args_copy_and_remove(
379 const grpc_channel_args* src, const char** to_remove,
380 size_t num_to_remove) {
381 return grpc_channel_args_copy_and_add_and_remove(src, to_remove,
382 num_to_remove, nullptr, 0);
383 }
384
should_remove_arg(const grpc_arg * arg,const char ** to_remove,size_t num_to_remove)385 static bool should_remove_arg(const grpc_arg* arg, const char** to_remove,
386 size_t num_to_remove) {
387 for (size_t i = 0; i < num_to_remove; ++i) {
388 if (strcmp(arg->key, to_remove[i]) == 0) return true;
389 }
390 return false;
391 }
392
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)393 grpc_channel_args* grpc_channel_args_copy_and_add_and_remove(
394 const grpc_channel_args* src, const char** to_remove, size_t num_to_remove,
395 const grpc_arg* to_add, size_t num_to_add) {
396 // Figure out how many args we'll be copying.
397 size_t num_args_to_copy = 0;
398 if (src != nullptr) {
399 for (size_t i = 0; i < src->num_args; ++i) {
400 if (!should_remove_arg(&src->args[i], to_remove, num_to_remove)) {
401 ++num_args_to_copy;
402 }
403 }
404 }
405 // Create result.
406 grpc_channel_args* dst =
407 static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
408 dst->num_args = num_args_to_copy + num_to_add;
409 if (dst->num_args == 0) {
410 dst->args = nullptr;
411 return dst;
412 }
413 dst->args =
414 static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * dst->num_args));
415 // Copy args from src that are not being removed.
416 size_t dst_idx = 0;
417 if (src != nullptr) {
418 for (size_t i = 0; i < src->num_args; ++i) {
419 if (!should_remove_arg(&src->args[i], to_remove, num_to_remove)) {
420 dst->args[dst_idx++] = copy_arg(&src->args[i]);
421 }
422 }
423 }
424 // Add args from to_add.
425 for (size_t i = 0; i < num_to_add; ++i) {
426 dst->args[dst_idx++] = copy_arg(&to_add[i]);
427 }
428 CHECK(dst_idx == dst->num_args);
429 return dst;
430 }
431
grpc_channel_args_copy(const grpc_channel_args * src)432 grpc_channel_args* grpc_channel_args_copy(const grpc_channel_args* src) {
433 return grpc_channel_args_copy_and_add(src, nullptr, 0);
434 }
435
grpc_channel_args_union(const grpc_channel_args * a,const grpc_channel_args * b)436 grpc_channel_args* grpc_channel_args_union(const grpc_channel_args* a,
437 const grpc_channel_args* b) {
438 if (a == nullptr) return grpc_channel_args_copy(b);
439 if (b == nullptr) return grpc_channel_args_copy(a);
440 const size_t max_out = (a->num_args + b->num_args);
441 grpc_arg* uniques =
442 static_cast<grpc_arg*>(gpr_malloc(sizeof(*uniques) * max_out));
443 for (size_t i = 0; i < a->num_args; ++i) uniques[i] = a->args[i];
444
445 size_t uniques_idx = a->num_args;
446 for (size_t i = 0; i < b->num_args; ++i) {
447 const char* b_key = b->args[i].key;
448 if (grpc_channel_args_find(a, b_key) == nullptr) { // not found
449 uniques[uniques_idx++] = b->args[i];
450 }
451 }
452 grpc_channel_args* result =
453 grpc_channel_args_copy_and_add(nullptr, uniques, uniques_idx);
454 gpr_free(uniques);
455 return result;
456 }
457
cmp_arg(const grpc_arg * a,const grpc_arg * b)458 static int cmp_arg(const grpc_arg* a, const grpc_arg* b) {
459 int c = grpc_core::QsortCompare(a->type, b->type);
460 if (c != 0) return c;
461 c = strcmp(a->key, b->key);
462 if (c != 0) return c;
463 switch (a->type) {
464 case GRPC_ARG_STRING:
465 return strcmp(a->value.string, b->value.string);
466 case GRPC_ARG_INTEGER:
467 return grpc_core::QsortCompare(a->value.integer, b->value.integer);
468 case GRPC_ARG_POINTER:
469 return grpc_core::channel_args_detail::PointerCompare(
470 a->value.pointer.p, a->value.pointer.vtable, b->value.pointer.p,
471 b->value.pointer.vtable);
472 }
473 GPR_UNREACHABLE_CODE(return 0);
474 }
475
476 // stabilizing comparison function: since channel_args ordering matters for
477 // keys with the same name, we need to preserve that ordering
cmp_key_stable(const void * ap,const void * bp)478 static int cmp_key_stable(const void* ap, const void* bp) {
479 const grpc_arg* const* a = static_cast<const grpc_arg* const*>(ap);
480 const grpc_arg* const* b = static_cast<const grpc_arg* const*>(bp);
481 int c = strcmp((*a)->key, (*b)->key);
482 if (c == 0) c = grpc_core::QsortCompare(*a, *b);
483 return c;
484 }
485
grpc_channel_args_normalize(const grpc_channel_args * src)486 grpc_channel_args* grpc_channel_args_normalize(const grpc_channel_args* src) {
487 grpc_arg** args =
488 static_cast<grpc_arg**>(gpr_malloc(sizeof(grpc_arg*) * src->num_args));
489 for (size_t i = 0; i < src->num_args; i++) {
490 args[i] = &src->args[i];
491 }
492 if (src->num_args > 1) {
493 qsort(args, src->num_args, sizeof(grpc_arg*), cmp_key_stable);
494 }
495
496 grpc_channel_args* b =
497 static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
498 b->num_args = src->num_args;
499 b->args = static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * b->num_args));
500 for (size_t i = 0; i < src->num_args; i++) {
501 b->args[i] = copy_arg(args[i]);
502 }
503
504 gpr_free(args);
505 return b;
506 }
507
grpc_channel_args_destroy(grpc_channel_args * a)508 void grpc_channel_args_destroy(grpc_channel_args* a) {
509 size_t i;
510 if (!a) return;
511 for (i = 0; i < a->num_args; i++) {
512 switch (a->args[i].type) {
513 case GRPC_ARG_STRING:
514 gpr_free(a->args[i].value.string);
515 break;
516 case GRPC_ARG_INTEGER:
517 break;
518 case GRPC_ARG_POINTER:
519 a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p);
520 break;
521 }
522 gpr_free(a->args[i].key);
523 }
524 gpr_free(a->args);
525 gpr_free(a);
526 }
527
grpc_channel_args_compare(const grpc_channel_args * a,const grpc_channel_args * b)528 int grpc_channel_args_compare(const grpc_channel_args* a,
529 const grpc_channel_args* b) {
530 if (a == nullptr && b == nullptr) return 0;
531 if (a == nullptr || b == nullptr) return a == nullptr ? -1 : 1;
532 int c = grpc_core::QsortCompare(a->num_args, b->num_args);
533 if (c != 0) return c;
534 for (size_t i = 0; i < a->num_args; i++) {
535 c = cmp_arg(&a->args[i], &b->args[i]);
536 if (c != 0) return c;
537 }
538 return 0;
539 }
540
grpc_channel_args_find(const grpc_channel_args * args,const char * name)541 const grpc_arg* grpc_channel_args_find(const grpc_channel_args* args,
542 const char* name) {
543 if (args != nullptr) {
544 for (size_t i = 0; i < args->num_args; ++i) {
545 if (strcmp(args->args[i].key, name) == 0) {
546 return &args->args[i];
547 }
548 }
549 }
550 return nullptr;
551 }
552
grpc_channel_arg_get_integer(const grpc_arg * arg,const grpc_integer_options options)553 int grpc_channel_arg_get_integer(const grpc_arg* arg,
554 const grpc_integer_options options) {
555 if (arg == nullptr) return options.default_value;
556 if (arg->type != GRPC_ARG_INTEGER) {
557 LOG(ERROR) << arg->key << " ignored: it must be an integer";
558 return options.default_value;
559 }
560 if (arg->value.integer < options.min_value) {
561 LOG(ERROR) << arg->key << " ignored: it must be >= " << options.min_value;
562 return options.default_value;
563 }
564 if (arg->value.integer > options.max_value) {
565 LOG(ERROR) << arg->key << " ignored: it must be <= " << options.max_value;
566 return options.default_value;
567 }
568 return arg->value.integer;
569 }
570
grpc_channel_args_find_integer(const grpc_channel_args * args,const char * name,const grpc_integer_options options)571 int grpc_channel_args_find_integer(const grpc_channel_args* args,
572 const char* name,
573 const grpc_integer_options options) {
574 const grpc_arg* arg = grpc_channel_args_find(args, name);
575 return grpc_channel_arg_get_integer(arg, options);
576 }
577
grpc_channel_arg_get_string(const grpc_arg * arg)578 char* grpc_channel_arg_get_string(const grpc_arg* arg) {
579 if (arg == nullptr) return nullptr;
580 if (arg->type != GRPC_ARG_STRING) {
581 LOG(ERROR) << arg->key << " ignored: it must be an string";
582 return nullptr;
583 }
584 return arg->value.string;
585 }
586
grpc_channel_args_find_string(const grpc_channel_args * args,const char * name)587 char* grpc_channel_args_find_string(const grpc_channel_args* args,
588 const char* name) {
589 const grpc_arg* arg = grpc_channel_args_find(args, name);
590 return grpc_channel_arg_get_string(arg);
591 }
592
grpc_channel_arg_get_bool(const grpc_arg * arg,bool default_value)593 bool grpc_channel_arg_get_bool(const grpc_arg* arg, bool default_value) {
594 if (arg == nullptr) return default_value;
595 if (arg->type != GRPC_ARG_INTEGER) {
596 LOG(ERROR) << arg->key << " ignored: it must be an integer";
597 return default_value;
598 }
599 switch (arg->value.integer) {
600 case 0:
601 return false;
602 case 1:
603 return true;
604 default:
605 LOG(ERROR) << arg->key << " treated as bool but set to "
606 << arg->value.integer << " (assuming true)";
607 return true;
608 }
609 }
610
grpc_channel_args_find_bool(const grpc_channel_args * args,const char * name,bool default_value)611 bool grpc_channel_args_find_bool(const grpc_channel_args* args,
612 const char* name, bool default_value) {
613 const grpc_arg* arg = grpc_channel_args_find(args, name);
614 return grpc_channel_arg_get_bool(arg, default_value);
615 }
616
grpc_channel_args_want_minimal_stack(const grpc_channel_args * args)617 bool grpc_channel_args_want_minimal_stack(const grpc_channel_args* args) {
618 return grpc_channel_arg_get_bool(
619 grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK), false);
620 }
621
grpc_channel_arg_string_create(char * name,char * value)622 grpc_arg grpc_channel_arg_string_create(char* name, char* value) {
623 grpc_arg arg;
624 arg.type = GRPC_ARG_STRING;
625 arg.key = name;
626 arg.value.string = value;
627 return arg;
628 }
629
grpc_channel_arg_integer_create(char * name,int value)630 grpc_arg grpc_channel_arg_integer_create(char* name, int value) {
631 grpc_arg arg;
632 arg.type = GRPC_ARG_INTEGER;
633 arg.key = name;
634 arg.value.integer = value;
635 return arg;
636 }
637
grpc_channel_arg_pointer_create(char * name,void * value,const grpc_arg_pointer_vtable * vtable)638 grpc_arg grpc_channel_arg_pointer_create(
639 char* name, void* value, const grpc_arg_pointer_vtable* vtable) {
640 grpc_arg arg;
641 arg.type = GRPC_ARG_POINTER;
642 arg.key = name;
643 arg.value.pointer.p = value;
644 arg.value.pointer.vtable = vtable;
645 return arg;
646 }
647
grpc_channel_args_string(const grpc_channel_args * args)648 std::string grpc_channel_args_string(const grpc_channel_args* args) {
649 return grpc_core::ChannelArgs::FromC(args).ToString();
650 }
651
652 namespace grpc_core {
ChannelArgsBuiltinPrecondition(const grpc_channel_args * src)653 ChannelArgs ChannelArgsBuiltinPrecondition(const grpc_channel_args* src) {
654 if (src == nullptr) return ChannelArgs();
655 ChannelArgs output;
656 std::map<absl::string_view, std::vector<absl::string_view>>
657 concatenated_values;
658 for (size_t i = 0; i < src->num_args; i++) {
659 absl::string_view key = src->args[i].key;
660 // User-agent strings were traditionally multi-valued and concatenated.
661 // We preserve this behavior for backwards compatibility.
662 if (key == GRPC_ARG_PRIMARY_USER_AGENT_STRING ||
663 key == GRPC_ARG_SECONDARY_USER_AGENT_STRING) {
664 if (src->args[i].type != GRPC_ARG_STRING) {
665 LOG(ERROR) << "Channel argument '" << key << "' should be a string";
666 } else {
667 concatenated_values[key].push_back(src->args[i].value.string);
668 }
669 continue;
670 } else if (absl::StartsWith(key, "grpc.internal.")) {
671 continue;
672 }
673 if (!output.Contains(key)) {
674 output = output.Set(src->args[i]);
675 } else {
676 // Traditional grpc_channel_args_find behavior was to pick the first
677 // value.
678 // For compatibility with existing users, we will do the same here.
679 }
680 }
681 // Concatenate the concatenated values.
682 for (const auto& concatenated_value : concatenated_values) {
683 output = output.Set(concatenated_value.first,
684 absl::StrJoin(concatenated_value.second, " "));
685 }
686 return output;
687 }
688
689 } // namespace grpc_core
690
691 namespace {
692 grpc_channel_args_client_channel_creation_mutator g_mutator = nullptr;
693 } // namespace
694
grpc_channel_args_set_client_channel_creation_mutator(grpc_channel_args_client_channel_creation_mutator cb)695 void grpc_channel_args_set_client_channel_creation_mutator(
696 grpc_channel_args_client_channel_creation_mutator cb) {
697 DCHECK_EQ(g_mutator, nullptr);
698 g_mutator = cb;
699 }
700 grpc_channel_args_client_channel_creation_mutator
grpc_channel_args_get_client_channel_creation_mutator()701 grpc_channel_args_get_client_channel_creation_mutator() {
702 return g_mutator;
703 }
704