Merge pull request #8617 from markdroth/service_config_json

Use JSON tree for service config channel arg.
pull/8784/head
Mark D. Roth 8 years ago committed by GitHub
commit ed92f7bc04
  1. 16
      BUILD
  2. 6
      CMakeLists.txt
  3. 8
      Makefile
  4. 2
      binding.gyp
  5. 4
      build.yaml
  6. 2
      config.m4
  7. 6
      gRPC-Core.podspec
  8. 4
      grpc.gemspec
  9. 7
      include/grpc++/channel.h
  10. 4
      include/grpc++/support/channel_arguments.h
  11. 3
      include/grpc/impl/codegen/grpc_types.h
  12. 4
      package.xml
  13. 120
      src/core/ext/client_channel/client_channel.c
  14. 8
      src/core/ext/client_channel/lb_policy_registry.c
  15. 58
      src/core/lib/channel/message_size_filter.c
  16. 6
      src/core/lib/json/json.c
  17. 22
      src/core/lib/json/json.h
  18. 9
      src/core/lib/support/string.c
  19. 3
      src/core/lib/support/string.h
  20. 42
      src/core/lib/transport/mdstr_hash_table.c
  21. 18
      src/core/lib/transport/mdstr_hash_table.h
  22. 340
      src/core/lib/transport/method_config.c
  23. 136
      src/core/lib/transport/method_config.h
  24. 249
      src/core/lib/transport/service_config.c
  25. 70
      src/core/lib/transport/service_config.h
  26. 30
      src/cpp/client/channel_cc.cc
  27. 5
      src/cpp/common/channel_arguments.cc
  28. 2
      src/python/grpcio/grpc_core_dependencies.py
  29. 45
      test/core/client_channel/lb_policies_test.c
  30. 25
      test/core/end2end/connection_refused_test.c
  31. 26
      test/core/end2end/tests/cancel_after_accept.c
  32. 51
      test/core/end2end/tests/max_message_length.c
  33. 9
      test/cpp/end2end/round_robin_end2end_test.cc
  34. 4
      tools/doxygen/Doxyfile.core.internal
  35. 6
      tools/run_tests/sources_and_headers.json
  36. 6
      vsprojects/vcxproj/grpc/grpc.vcxproj
  37. 8
      vsprojects/vcxproj/grpc/grpc.vcxproj.filters
  38. 6
      vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
  39. 8
      vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
  40. 6
      vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
  41. 8
      vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters

16
BUILD

@ -247,8 +247,8 @@ cc_library(
"src/core/lib/transport/mdstr_hash_table.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/method_config.h",
"src/core/lib/transport/pid_controller.h",
"src/core/lib/transport/service_config.h",
"src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
@ -436,8 +436,8 @@ cc_library(
"src/core/lib/transport/mdstr_hash_table.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/method_config.c",
"src/core/lib/transport/pid_controller.c",
"src/core/lib/transport/service_config.c",
"src/core/lib/transport/static_metadata.c",
"src/core/lib/transport/timeout_encoding.c",
"src/core/lib/transport/transport.c",
@ -681,8 +681,8 @@ cc_library(
"src/core/lib/transport/mdstr_hash_table.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/method_config.h",
"src/core/lib/transport/pid_controller.h",
"src/core/lib/transport/service_config.h",
"src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
@ -855,8 +855,8 @@ cc_library(
"src/core/lib/transport/mdstr_hash_table.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/method_config.c",
"src/core/lib/transport/pid_controller.c",
"src/core/lib/transport/service_config.c",
"src/core/lib/transport/static_metadata.c",
"src/core/lib/transport/timeout_encoding.c",
"src/core/lib/transport/transport.c",
@ -1070,8 +1070,8 @@ cc_library(
"src/core/lib/transport/mdstr_hash_table.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/method_config.h",
"src/core/lib/transport/pid_controller.h",
"src/core/lib/transport/service_config.h",
"src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
@ -1236,8 +1236,8 @@ cc_library(
"src/core/lib/transport/mdstr_hash_table.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/method_config.c",
"src/core/lib/transport/pid_controller.c",
"src/core/lib/transport/service_config.c",
"src/core/lib/transport/static_metadata.c",
"src/core/lib/transport/timeout_encoding.c",
"src/core/lib/transport/transport.c",
@ -2097,8 +2097,8 @@ objc_library(
"src/core/lib/transport/mdstr_hash_table.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/method_config.c",
"src/core/lib/transport/pid_controller.c",
"src/core/lib/transport/service_config.c",
"src/core/lib/transport/static_metadata.c",
"src/core/lib/transport/timeout_encoding.c",
"src/core/lib/transport/transport.c",
@ -2321,8 +2321,8 @@ objc_library(
"src/core/lib/transport/mdstr_hash_table.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/method_config.h",
"src/core/lib/transport/pid_controller.h",
"src/core/lib/transport/service_config.h",
"src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",

@ -391,8 +391,8 @@ add_library(grpc
src/core/lib/transport/mdstr_hash_table.c
src/core/lib/transport/metadata.c
src/core/lib/transport/metadata_batch.c
src/core/lib/transport/method_config.c
src/core/lib/transport/pid_controller.c
src/core/lib/transport/service_config.c
src/core/lib/transport/static_metadata.c
src/core/lib/transport/timeout_encoding.c
src/core/lib/transport/transport.c
@ -670,8 +670,8 @@ add_library(grpc_cronet
src/core/lib/transport/mdstr_hash_table.c
src/core/lib/transport/metadata.c
src/core/lib/transport/metadata_batch.c
src/core/lib/transport/method_config.c
src/core/lib/transport/pid_controller.c
src/core/lib/transport/service_config.c
src/core/lib/transport/static_metadata.c
src/core/lib/transport/timeout_encoding.c
src/core/lib/transport/transport.c
@ -921,8 +921,8 @@ add_library(grpc_unsecure
src/core/lib/transport/mdstr_hash_table.c
src/core/lib/transport/metadata.c
src/core/lib/transport/metadata_batch.c
src/core/lib/transport/method_config.c
src/core/lib/transport/pid_controller.c
src/core/lib/transport/service_config.c
src/core/lib/transport/static_metadata.c
src/core/lib/transport/timeout_encoding.c
src/core/lib/transport/transport.c

@ -2730,8 +2730,8 @@ LIBGRPC_SRC = \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/method_config.c \
src/core/lib/transport/pid_controller.c \
src/core/lib/transport/service_config.c \
src/core/lib/transport/static_metadata.c \
src/core/lib/transport/timeout_encoding.c \
src/core/lib/transport/transport.c \
@ -3027,8 +3027,8 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/method_config.c \
src/core/lib/transport/pid_controller.c \
src/core/lib/transport/service_config.c \
src/core/lib/transport/static_metadata.c \
src/core/lib/transport/timeout_encoding.c \
src/core/lib/transport/transport.c \
@ -3315,8 +3315,8 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/method_config.c \
src/core/lib/transport/pid_controller.c \
src/core/lib/transport/service_config.c \
src/core/lib/transport/static_metadata.c \
src/core/lib/transport/timeout_encoding.c \
src/core/lib/transport/transport.c \
@ -3532,8 +3532,8 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/method_config.c \
src/core/lib/transport/pid_controller.c \
src/core/lib/transport/service_config.c \
src/core/lib/transport/static_metadata.c \
src/core/lib/transport/timeout_encoding.c \
src/core/lib/transport/transport.c \

@ -671,8 +671,8 @@
'src/core/lib/transport/mdstr_hash_table.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
'src/core/lib/transport/method_config.c',
'src/core/lib/transport/pid_controller.c',
'src/core/lib/transport/service_config.c',
'src/core/lib/transport/static_metadata.c',
'src/core/lib/transport/timeout_encoding.c',
'src/core/lib/transport/transport.c',

@ -254,8 +254,8 @@ filegroups:
- src/core/lib/transport/mdstr_hash_table.h
- src/core/lib/transport/metadata.h
- src/core/lib/transport/metadata_batch.h
- src/core/lib/transport/method_config.h
- src/core/lib/transport/pid_controller.h
- src/core/lib/transport/service_config.h
- src/core/lib/transport/static_metadata.h
- src/core/lib/transport/timeout_encoding.h
- src/core/lib/transport/transport.h
@ -367,8 +367,8 @@ filegroups:
- src/core/lib/transport/mdstr_hash_table.c
- src/core/lib/transport/metadata.c
- src/core/lib/transport/metadata_batch.c
- src/core/lib/transport/method_config.c
- src/core/lib/transport/pid_controller.c
- src/core/lib/transport/service_config.c
- src/core/lib/transport/static_metadata.c
- src/core/lib/transport/timeout_encoding.c
- src/core/lib/transport/transport.c

@ -187,8 +187,8 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/method_config.c \
src/core/lib/transport/pid_controller.c \
src/core/lib/transport/service_config.c \
src/core/lib/transport/static_metadata.c \
src/core/lib/transport/timeout_encoding.c \
src/core/lib/transport/transport.c \

@ -336,8 +336,8 @@ Pod::Spec.new do |s|
'src/core/lib/transport/mdstr_hash_table.h',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/method_config.h',
'src/core/lib/transport/pid_controller.h',
'src/core/lib/transport/service_config.h',
'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',
@ -529,8 +529,8 @@ Pod::Spec.new do |s|
'src/core/lib/transport/mdstr_hash_table.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
'src/core/lib/transport/method_config.c',
'src/core/lib/transport/pid_controller.c',
'src/core/lib/transport/service_config.c',
'src/core/lib/transport/static_metadata.c',
'src/core/lib/transport/timeout_encoding.c',
'src/core/lib/transport/transport.c',
@ -739,8 +739,8 @@ Pod::Spec.new do |s|
'src/core/lib/transport/mdstr_hash_table.h',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/method_config.h',
'src/core/lib/transport/pid_controller.h',
'src/core/lib/transport/service_config.h',
'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',

@ -256,8 +256,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/mdstr_hash_table.h )
s.files += %w( src/core/lib/transport/metadata.h )
s.files += %w( src/core/lib/transport/metadata_batch.h )
s.files += %w( src/core/lib/transport/method_config.h )
s.files += %w( src/core/lib/transport/pid_controller.h )
s.files += %w( src/core/lib/transport/service_config.h )
s.files += %w( src/core/lib/transport/static_metadata.h )
s.files += %w( src/core/lib/transport/timeout_encoding.h )
s.files += %w( src/core/lib/transport/transport.h )
@ -449,8 +449,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/mdstr_hash_table.c )
s.files += %w( src/core/lib/transport/metadata.c )
s.files += %w( src/core/lib/transport/metadata_batch.c )
s.files += %w( src/core/lib/transport/method_config.c )
s.files += %w( src/core/lib/transport/pid_controller.c )
s.files += %w( src/core/lib/transport/service_config.c )
s.files += %w( src/core/lib/transport/static_metadata.c )
s.files += %w( src/core/lib/transport/timeout_encoding.c )
s.files += %w( src/core/lib/transport/transport.c )

@ -57,6 +57,13 @@ class Channel final : public ChannelInterface,
/// \a try_to_connect is set to true, try to connect.
grpc_connectivity_state GetState(bool try_to_connect) override;
/// Returns the LB policy name, or the empty string if not yet available.
grpc::string GetLoadBalancingPolicyName() const;
/// Returns the service config in JSON form, or the empty string if
/// not available.
grpc::string GetServiceConfigJSON() const;
private:
template <class InputMessage, class OutputMessage>
friend Status BlockingUnaryCall(ChannelInterface* channel,

@ -93,6 +93,10 @@ class ChannelArguments {
/// grpclb LB policy will be used, regardless of what is specified here.
void SetLoadBalancingPolicyName(const grpc::string& lb_policy_name);
/// Set service config in JSON form.
/// Primarily meant for use in unit tests.
void SetServiceConfigJSON(const grpc::string& service_config_json);
// Generic channel argument setters. Only for advanced use cases.
/// Set an integer argument \a value under \a key.
void SetInt(const grpc::string& key, int value);

@ -478,6 +478,9 @@ typedef struct {
/* If non-NULL, will be set to point to a string indicating the LB
* policy name. Caller takes ownership. */
char **lb_policy_name;
/* If non-NULL, will be set to point to a string containing the
* service config used by the channel in JSON form. */
char **service_config_json;
} grpc_channel_info;
typedef struct grpc_resource_quota grpc_resource_quota;

@ -263,8 +263,8 @@
<file baseinstalldir="/" name="src/core/lib/transport/mdstr_hash_table.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/method_config.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/pid_controller.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/service_config.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" />
@ -456,8 +456,8 @@
<file baseinstalldir="/" name="src/core/lib/transport/mdstr_hash_table.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/method_config.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/pid_controller.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/service_config.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport.c" role="src" />

@ -56,7 +56,7 @@
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/method_config.h"
#include "src/core/lib/transport/service_config.h"
#include "src/core/lib/transport/static_metadata.h"
/* Client channel implementation */
@ -82,30 +82,61 @@ static void *method_parameters_copy(void *value) {
return new_value;
}
static int method_parameters_cmp(void *value1, void *value2) {
const method_parameters *v1 = value1;
const method_parameters *v2 = value2;
const int retval = gpr_time_cmp(v1->timeout, v2->timeout);
if (retval != 0) return retval;
if (v1->wait_for_ready > v2->wait_for_ready) return 1;
if (v1->wait_for_ready < v2->wait_for_ready) return -1;
return 0;
}
static const grpc_mdstr_hash_table_vtable method_parameters_vtable = {
gpr_free, method_parameters_copy, method_parameters_cmp};
static void *method_config_convert_value(
const grpc_method_config *method_config) {
gpr_free, method_parameters_copy};
static void *method_parameters_create_from_json(const grpc_json *json) {
wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET;
gpr_timespec timeout = {0, 0, GPR_TIMESPAN};
for (grpc_json *field = json->child; field != NULL; field = field->next) {
if (field->key == NULL) continue;
if (strcmp(field->key, "waitForReady") == 0) {
if (wait_for_ready != WAIT_FOR_READY_UNSET) return NULL; // Duplicate.
if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
return NULL;
}
wait_for_ready = field->type == GRPC_JSON_TRUE ? WAIT_FOR_READY_TRUE
: WAIT_FOR_READY_FALSE;
} else if (strcmp(field->key, "timeout") == 0) {
if (timeout.tv_sec > 0 || timeout.tv_nsec > 0) return NULL; // Duplicate.
if (field->type != GRPC_JSON_STRING) return NULL;
size_t len = strlen(field->value);
if (field->value[len - 1] != 's') return NULL;
char *buf = gpr_strdup(field->value);
buf[len - 1] = '\0'; // Remove trailing 's'.
char *decimal_point = strchr(buf, '.');
if (decimal_point != NULL) {
*decimal_point = '\0';
timeout.tv_nsec = gpr_parse_nonnegative_int(decimal_point + 1);
if (timeout.tv_nsec == -1) {
gpr_free(buf);
return NULL;
}
// There should always be exactly 3, 6, or 9 fractional digits.
int multiplier = 1;
switch (strlen(decimal_point + 1)) {
case 9:
break;
case 6:
multiplier *= 1000;
break;
case 3:
multiplier *= 1000000;
break;
default: // Unsupported number of digits.
gpr_free(buf);
return NULL;
}
timeout.tv_nsec *= multiplier;
}
timeout.tv_sec = gpr_parse_nonnegative_int(buf);
if (timeout.tv_sec == -1) return NULL;
gpr_free(buf);
}
}
method_parameters *value = gpr_malloc(sizeof(method_parameters));
const gpr_timespec *timeout = grpc_method_config_get_timeout(method_config);
value->timeout = timeout != NULL ? *timeout : gpr_time_0(GPR_TIMESPAN);
const bool *wait_for_ready =
grpc_method_config_get_wait_for_ready(method_config);
value->wait_for_ready =
wait_for_ready == NULL
? WAIT_FOR_READY_UNSET
: (wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE);
value->timeout = timeout;
value->wait_for_ready = wait_for_ready;
return value;
}
@ -126,6 +157,8 @@ typedef struct client_channel_channel_data {
/** currently active load balancer */
char *lb_policy_name;
grpc_lb_policy *lb_policy;
/** service config in JSON form */
char *service_config_json;
/** maps method names to method_parameters structs */
grpc_mdstr_hash_table *method_params_table;
/** incoming resolver result - set by resolver.next() */
@ -232,15 +265,12 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
bool exit_idle = false;
grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
char *service_config_json = NULL;
if (chand->resolver_result != NULL) {
grpc_lb_policy_args lb_policy_args;
lb_policy_args.args = chand->resolver_result;
lb_policy_args.client_channel_factory = chand->client_channel_factory;
// Find LB policy name.
const grpc_arg *channel_arg =
grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_POLICY_NAME);
grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_POLICY_NAME);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
lb_policy_name = channel_arg->value.string;
@ -249,7 +279,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
// assume that we should use the grpclb policy, regardless of what the
// resolver actually specified.
channel_arg =
grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_ADDRESSES);
grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
grpc_lb_addresses *addresses = channel_arg->value.pointer.p;
@ -274,7 +304,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
// Use pick_first if nothing was specified and we didn't select grpclb
// above.
if (lb_policy_name == NULL) lb_policy_name = "pick_first";
// Instantiate LB policy.
grpc_lb_policy_args lb_policy_args;
lb_policy_args.args = chand->resolver_result;
lb_policy_args.client_channel_factory = chand->client_channel_factory;
lb_policy =
grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args);
if (lb_policy != NULL) {
@ -283,13 +316,20 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
state =
grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error);
}
// Find service config.
channel_arg =
grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_SERVICE_CONFIG);
grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
method_params_table = grpc_method_config_table_convert(
(grpc_method_config_table *)channel_arg->value.pointer.p,
method_config_convert_value, &method_parameters_vtable);
GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
service_config_json = gpr_strdup(channel_arg->value.string);
grpc_service_config *service_config =
grpc_service_config_create(service_config_json);
if (service_config != NULL) {
method_params_table = grpc_service_config_create_method_config_table(
service_config, method_parameters_create_from_json,
&method_parameters_vtable);
grpc_service_config_destroy(service_config);
}
}
// Before we clean up, save a copy of lb_policy_name, since it might
// be pointing to data inside chand->resolver_result.
@ -311,6 +351,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
}
old_lb_policy = chand->lb_policy;
chand->lb_policy = lb_policy;
if (service_config_json != NULL) {
gpr_free(chand->service_config_json);
chand->service_config_json = service_config_json;
}
if (chand->method_params_table != NULL) {
grpc_mdstr_hash_table_unref(chand->method_params_table);
}
@ -446,6 +490,11 @@ static void cc_get_channel_info(grpc_exec_ctx *exec_ctx,
? NULL
: gpr_strdup(chand->lb_policy_name);
}
if (info->service_config_json != NULL) {
*info->service_config_json = chand->service_config_json == NULL
? NULL
: gpr_strdup(chand->service_config_json);
}
gpr_mu_unlock(&chand->mu);
}
@ -489,6 +538,7 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
}
gpr_free(chand->lb_policy_name);
gpr_free(chand->service_config_json);
if (chand->method_params_table != NULL) {
grpc_mdstr_hash_table_unref(chand->method_params_table);
}

@ -35,6 +35,8 @@
#include <string.h>
#include "src/core/lib/support/string.h"
#define MAX_POLICIES 10
static grpc_lb_policy_factory *g_all_of_the_lb_policies[MAX_POLICIES];
@ -52,8 +54,8 @@ void grpc_lb_policy_registry_shutdown(void) {
void grpc_register_lb_policy(grpc_lb_policy_factory *factory) {
int i;
for (i = 0; i < g_number_of_lb_policies; i++) {
GPR_ASSERT(0 != strcmp(factory->vtable->name,
g_all_of_the_lb_policies[i]->vtable->name));
GPR_ASSERT(0 != gpr_stricmp(factory->vtable->name,
g_all_of_the_lb_policies[i]->vtable->name));
}
GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES);
grpc_lb_policy_factory_ref(factory);
@ -66,7 +68,7 @@ static grpc_lb_policy_factory *lookup_factory(const char *name) {
if (name == NULL) return NULL;
for (i = 0; i < g_number_of_lb_policies; i++) {
if (0 == strcmp(name, g_all_of_the_lb_policies[i]->vtable->name)) {
if (0 == gpr_stricmp(name, g_all_of_the_lb_policies[i]->vtable->name)) {
return g_all_of_the_lb_policies[i];
}
}

@ -39,7 +39,8 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/transport/method_config.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/service_config.h"
#define DEFAULT_MAX_SEND_MESSAGE_LENGTH -1 // Unlimited.
// The protobuf library will (by default) start warning at 100 megs.
@ -56,30 +57,29 @@ static void* message_size_limits_copy(void* value) {
return new_value;
}
static int message_size_limits_cmp(void* value1, void* value2) {
const message_size_limits* v1 = value1;
const message_size_limits* v2 = value2;
if (v1->max_send_size > v2->max_send_size) return 1;
if (v1->max_send_size < v2->max_send_size) return -1;
if (v1->max_recv_size > v2->max_recv_size) return 1;
if (v1->max_recv_size < v2->max_recv_size) return -1;
return 0;
}
static const grpc_mdstr_hash_table_vtable message_size_limits_vtable = {
gpr_free, message_size_limits_copy, message_size_limits_cmp};
gpr_free, message_size_limits_copy};
static void* method_config_convert_value(
const grpc_method_config* method_config) {
static void* message_size_limits_create_from_json(const grpc_json* json) {
int max_request_message_bytes = -1;
int max_response_message_bytes = -1;
for (grpc_json* field = json->child; field != NULL; field = field->next) {
if (field->key == NULL) continue;
if (strcmp(field->key, "maxRequestMessageBytes") == 0) {
if (max_request_message_bytes >= 0) return NULL; // Duplicate.
if (field->type != GRPC_JSON_STRING) return NULL;
max_request_message_bytes = gpr_parse_nonnegative_int(field->value);
if (max_request_message_bytes == -1) return NULL;
} else if (strcmp(field->key, "maxResponseMessageBytes") == 0) {
if (max_response_message_bytes >= 0) return NULL; // Duplicate.
if (field->type != GRPC_JSON_STRING) return NULL;
max_response_message_bytes = gpr_parse_nonnegative_int(field->value);
if (max_response_message_bytes == -1) return NULL;
}
}
message_size_limits* value = gpr_malloc(sizeof(message_size_limits));
const int32_t* max_request_message_bytes =
grpc_method_config_get_max_request_message_bytes(method_config);
value->max_send_size =
max_request_message_bytes != NULL ? *max_request_message_bytes : -1;
const int32_t* max_response_message_bytes =
grpc_method_config_get_max_response_message_bytes(method_config);
value->max_recv_size =
max_response_message_bytes != NULL ? *max_response_message_bytes : -1;
value->max_send_size = max_request_message_bytes;
value->max_recv_size = max_response_message_bytes;
return value;
}
@ -223,10 +223,16 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx,
const grpc_arg* channel_arg =
grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
chand->method_limit_table = grpc_method_config_table_convert(
(grpc_method_config_table*)channel_arg->value.pointer.p,
method_config_convert_value, &message_size_limits_vtable);
GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
grpc_service_config* service_config =
grpc_service_config_create(channel_arg->value.string);
if (service_config != NULL) {
chand->method_limit_table =
grpc_service_config_create_method_config_table(
service_config, message_size_limits_create_from_json,
&message_size_limits_vtable);
grpc_service_config_destroy(service_config);
}
}
}

@ -37,15 +37,15 @@
#include "src/core/lib/json/json.h"
grpc_json *grpc_json_create(grpc_json_type type) {
grpc_json *json = gpr_malloc(sizeof(*json));
grpc_json* grpc_json_create(grpc_json_type type) {
grpc_json* json = gpr_malloc(sizeof(*json));
memset(json, 0, sizeof(*json));
json->type = type;
return json;
}
void grpc_json_destroy(grpc_json *json) {
void grpc_json_destroy(grpc_json* json) {
while (json->child) {
grpc_json_destroy(json->child);
}

@ -42,14 +42,14 @@
* are not owned by it.
*/
typedef struct grpc_json {
struct grpc_json *next;
struct grpc_json *prev;
struct grpc_json *child;
struct grpc_json *parent;
struct grpc_json* next;
struct grpc_json* prev;
struct grpc_json* child;
struct grpc_json* parent;
grpc_json_type type;
const char *key;
const char *value;
const char* key;
const char* value;
} grpc_json;
/* The next two functions are going to parse the input string, and
@ -65,8 +65,8 @@ typedef struct grpc_json {
*
* Delete the allocated tree afterward using grpc_json_destroy().
*/
grpc_json *grpc_json_parse_string_with_len(char *input, size_t size);
grpc_json *grpc_json_parse_string(char *input);
grpc_json* grpc_json_parse_string_with_len(char* input, size_t size);
grpc_json* grpc_json_parse_string(char* input);
/* This function will create a new string using gpr_realloc, and will
* deserialize the grpc_json tree into it. It'll be zero-terminated,
@ -76,13 +76,13 @@ grpc_json *grpc_json_parse_string(char *input);
* If indent is 0, then newlines will be suppressed as well, and the
* output will be condensed at its maximum.
*/
char *grpc_json_dump_to_string(grpc_json *json, int indent);
char* grpc_json_dump_to_string(grpc_json* json, int indent);
/* Use these to create or delete a grpc_json object.
* Deletion is recursive. We will not attempt to free any of the strings
* in any of the objects of that tree.
*/
grpc_json *grpc_json_create(grpc_json_type type);
void grpc_json_destroy(grpc_json *json);
grpc_json* grpc_json_create(grpc_json_type type);
void grpc_json_destroy(grpc_json* json);
#endif /* GRPC_CORE_LIB_JSON_JSON_H */

@ -34,7 +34,9 @@
#include "src/core/lib/support/string.h"
#include <ctype.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
@ -189,6 +191,13 @@ int int64_ttoa(int64_t value, char *string) {
return i;
}
int gpr_parse_nonnegative_int(const char *value) {
char *end;
long result = strtol(value, &end, 0);
if (*end != '\0' || result < 0 || result > INT_MAX) return -1;
return (int)result;
}
char *gpr_leftpad(const char *str, char flag, size_t length) {
const size_t str_length = strlen(str);
const size_t out_length = str_length > length ? str_length : length;

@ -77,6 +77,9 @@ NOTE: This function ensures sufficient bit width even on Win x64,
where long is 32bit is size.*/
int int64_ttoa(int64_t value, char *output);
// Parses a non-negative number from a value string. Returns -1 on error.
int gpr_parse_nonnegative_int(const char *value);
/* Reverse a run of bytes */
void gpr_reverse_bytes(char *str, int len);

@ -41,7 +41,6 @@
struct grpc_mdstr_hash_table {
gpr_refcount refs;
size_t num_entries;
size_t size;
grpc_mdstr_hash_table_entry* entries;
};
@ -77,7 +76,6 @@ grpc_mdstr_hash_table* grpc_mdstr_hash_table_create(
grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table));
memset(table, 0, sizeof(*table));
gpr_ref_init(&table->refs, 1);
table->num_entries = num_entries;
// Quadratic probing gets best performance when the table is no more
// than half full.
table->size = num_entries * 2;
@ -96,7 +94,7 @@ grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table) {
return table;
}
int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) {
void grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) {
if (table != NULL && gpr_unref(&table->refs)) {
for (size_t i = 0; i < table->size; ++i) {
grpc_mdstr_hash_table_entry* entry = &table->entries[i];
@ -107,13 +105,7 @@ int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) {
}
gpr_free(table->entries);
gpr_free(table);
return 1;
}
return 0;
}
size_t grpc_mdstr_hash_table_num_entries(const grpc_mdstr_hash_table* table) {
return table->num_entries;
}
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
@ -123,35 +115,3 @@ void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
if (idx == table->size) return NULL; // Not found.
return table->entries[idx].value;
}
int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1,
const grpc_mdstr_hash_table* table2) {
// Compare by num_entries.
if (table1->num_entries < table2->num_entries) return -1;
if (table1->num_entries > table2->num_entries) return 1;
for (size_t i = 0; i < table1->num_entries; ++i) {
grpc_mdstr_hash_table_entry* e1 = &table1->entries[i];
grpc_mdstr_hash_table_entry* e2 = &table2->entries[i];
// Compare keys by hash value.
if (e1->key->hash < e2->key->hash) return -1;
if (e1->key->hash > e2->key->hash) return 1;
// Compare by vtable (pointer equality).
if (e1->vtable < e2->vtable) return -1;
if (e1->vtable > e2->vtable) return 1;
// Compare values via vtable.
const int value_result = e1->vtable->compare_value(e1->value, e2->value);
if (value_result != 0) return value_result;
}
return 0;
}
void grpc_mdstr_hash_table_iterate(
const grpc_mdstr_hash_table* table,
void (*func)(const grpc_mdstr_hash_table_entry* entry, void* user_data),
void* user_data) {
for (size_t i = 0; i < table->size; ++i) {
if (table->entries[i].key != NULL) {
func(&table->entries[i], user_data);
}
}
}

@ -51,7 +51,6 @@ typedef struct grpc_mdstr_hash_table grpc_mdstr_hash_table;
typedef struct grpc_mdstr_hash_table_vtable {
void (*destroy_value)(void* value);
void* (*copy_value)(void* value);
int (*compare_value)(void* value1, void* value2);
} grpc_mdstr_hash_table_vtable;
typedef struct grpc_mdstr_hash_table_entry {
@ -67,26 +66,11 @@ grpc_mdstr_hash_table* grpc_mdstr_hash_table_create(
size_t num_entries, grpc_mdstr_hash_table_entry* entries);
grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table);
/** Returns 1 when \a table is destroyed. */
int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table);
/** Returns the number of entries in \a table. */
size_t grpc_mdstr_hash_table_num_entries(const grpc_mdstr_hash_table* table);
void grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table);
/** Returns the value from \a table associated with \a key.
Returns NULL if \a key is not found. */
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
const grpc_mdstr* key);
/** Compares two hash tables.
The sort order is stable but undefined. */
int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1,
const grpc_mdstr_hash_table* table2);
/** Iterates over the entries in \a table, calling \a func for each entry. */
void grpc_mdstr_hash_table_iterate(
const grpc_mdstr_hash_table* table,
void (*func)(const grpc_mdstr_hash_table_entry* entry, void* user_data),
void* user_data);
#endif /* GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H */

@ -1,340 +0,0 @@
//
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "src/core/lib/transport/method_config.h"
#include <string.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/transport/mdstr_hash_table.h"
#include "src/core/lib/transport/metadata.h"
//
// grpc_method_config
//
// bool vtable
static void* bool_copy(void* valuep) {
bool value = *(bool*)valuep;
bool* new_value = gpr_malloc(sizeof(bool));
*new_value = value;
return new_value;
}
static int bool_cmp(void* v1, void* v2) {
bool b1 = *(bool*)v1;
bool b2 = *(bool*)v2;
if (!b1 && b2) return -1;
if (b1 && !b2) return 1;
return 0;
}
static grpc_mdstr_hash_table_vtable bool_vtable = {gpr_free, bool_copy,
bool_cmp};
// timespec vtable
static void* timespec_copy(void* valuep) {
gpr_timespec value = *(gpr_timespec*)valuep;
gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec));
*new_value = value;
return new_value;
}
static int timespec_cmp(void* v1, void* v2) {
return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2);
}
static grpc_mdstr_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy,
timespec_cmp};
// int32 vtable
static void* int32_copy(void* valuep) {
int32_t value = *(int32_t*)valuep;
int32_t* new_value = gpr_malloc(sizeof(int32_t));
*new_value = value;
return new_value;
}
static int int32_cmp(void* v1, void* v2) {
int32_t i1 = *(int32_t*)v1;
int32_t i2 = *(int32_t*)v2;
if (i1 < i2) return -1;
if (i1 > i2) return 1;
return 0;
}
static grpc_mdstr_hash_table_vtable int32_vtable = {gpr_free, int32_copy,
int32_cmp};
// Hash table keys.
#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool
#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec
#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \
"grpc.max_request_message_bytes" // int32
#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \
"grpc.max_response_message_bytes" // int32
struct grpc_method_config {
grpc_mdstr_hash_table* table;
grpc_mdstr* wait_for_ready_key;
grpc_mdstr* timeout_key;
grpc_mdstr* max_request_message_bytes_key;
grpc_mdstr* max_response_message_bytes_key;
};
grpc_method_config* grpc_method_config_create(
bool* wait_for_ready, gpr_timespec* timeout,
int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) {
grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config));
memset(method_config, 0, sizeof(grpc_method_config));
method_config->wait_for_ready_key =
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY);
method_config->timeout_key =
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT);
method_config->max_request_message_bytes_key =
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES);
method_config->max_response_message_bytes_key =
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES);
grpc_mdstr_hash_table_entry entries[4];
size_t num_entries = 0;
if (wait_for_ready != NULL) {
entries[num_entries].key = method_config->wait_for_ready_key;
entries[num_entries].value = wait_for_ready;
entries[num_entries].vtable = &bool_vtable;
++num_entries;
}
if (timeout != NULL) {
entries[num_entries].key = method_config->timeout_key;
entries[num_entries].value = timeout;
entries[num_entries].vtable = &timespec_vtable;
++num_entries;
}
if (max_request_message_bytes != NULL) {
entries[num_entries].key = method_config->max_request_message_bytes_key;
entries[num_entries].value = max_request_message_bytes;
entries[num_entries].vtable = &int32_vtable;
++num_entries;
}
if (max_response_message_bytes != NULL) {
entries[num_entries].key = method_config->max_response_message_bytes_key;
entries[num_entries].value = max_response_message_bytes;
entries[num_entries].vtable = &int32_vtable;
++num_entries;
}
method_config->table = grpc_mdstr_hash_table_create(num_entries, entries);
return method_config;
}
grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) {
grpc_mdstr_hash_table_ref(method_config->table);
return method_config;
}
void grpc_method_config_unref(grpc_method_config* method_config) {
if (grpc_mdstr_hash_table_unref(method_config->table)) {
GRPC_MDSTR_UNREF(method_config->wait_for_ready_key);
GRPC_MDSTR_UNREF(method_config->timeout_key);
GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key);
GRPC_MDSTR_UNREF(method_config->max_response_message_bytes_key);
gpr_free(method_config);
}
}
int grpc_method_config_cmp(const grpc_method_config* method_config1,
const grpc_method_config* method_config2) {
return grpc_mdstr_hash_table_cmp(method_config1->table,
method_config2->table);
}
const bool* grpc_method_config_get_wait_for_ready(
const grpc_method_config* method_config) {
return grpc_mdstr_hash_table_get(method_config->table,
method_config->wait_for_ready_key);
}
const gpr_timespec* grpc_method_config_get_timeout(
const grpc_method_config* method_config) {
return grpc_mdstr_hash_table_get(method_config->table,
method_config->timeout_key);
}
const int32_t* grpc_method_config_get_max_request_message_bytes(
const grpc_method_config* method_config) {
return grpc_mdstr_hash_table_get(
method_config->table, method_config->max_request_message_bytes_key);
}
const int32_t* grpc_method_config_get_max_response_message_bytes(
const grpc_method_config* method_config) {
return grpc_mdstr_hash_table_get(
method_config->table, method_config->max_response_message_bytes_key);
}
//
// grpc_method_config_table
//
static void method_config_unref(void* valuep) {
grpc_method_config_unref(valuep);
}
static void* method_config_ref(void* valuep) {
return grpc_method_config_ref(valuep);
}
static int method_config_cmp(void* valuep1, void* valuep2) {
return grpc_method_config_cmp(valuep1, valuep2);
}
static const grpc_mdstr_hash_table_vtable method_config_table_vtable = {
method_config_unref, method_config_ref, method_config_cmp};
grpc_method_config_table* grpc_method_config_table_create(
size_t num_entries, grpc_method_config_table_entry* entries) {
grpc_mdstr_hash_table_entry* hash_table_entries =
gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) * num_entries);
for (size_t i = 0; i < num_entries; ++i) {
hash_table_entries[i].key = entries[i].method_name;
hash_table_entries[i].value = entries[i].method_config;
hash_table_entries[i].vtable = &method_config_table_vtable;
}
grpc_method_config_table* method_config_table =
grpc_mdstr_hash_table_create(num_entries, hash_table_entries);
gpr_free(hash_table_entries);
return method_config_table;
}
grpc_method_config_table* grpc_method_config_table_ref(
grpc_method_config_table* table) {
return grpc_mdstr_hash_table_ref(table);
}
void grpc_method_config_table_unref(grpc_method_config_table* table) {
grpc_mdstr_hash_table_unref(table);
}
int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
const grpc_method_config_table* table2) {
return grpc_mdstr_hash_table_cmp(table1, table2);
}
void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
const grpc_mdstr* path) {
void* value = grpc_mdstr_hash_table_get(table, path);
// If we didn't find a match for the path, try looking for a wildcard
// entry (i.e., change "/service/method" to "/service/*").
if (value == NULL) {
const char* path_str = grpc_mdstr_as_c_string(path);
const char* sep = strrchr(path_str, '/') + 1;
const size_t len = (size_t)(sep - path_str);
char* buf = gpr_malloc(len + 2); // '*' and NUL
memcpy(buf, path_str, len);
buf[len] = '*';
buf[len + 1] = '\0';
grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
gpr_free(buf);
value = grpc_mdstr_hash_table_get(table, wildcard_path);
GRPC_MDSTR_UNREF(wildcard_path);
}
return value;
}
static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); }
static void destroy_arg(void* p) { grpc_method_config_table_unref(p); }
static int cmp_arg(void* p1, void* p2) {
return grpc_method_config_table_cmp(p1, p2);
}
static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg};
grpc_arg grpc_method_config_table_create_channel_arg(
grpc_method_config_table* table) {
grpc_arg arg;
arg.type = GRPC_ARG_POINTER;
arg.key = GRPC_ARG_SERVICE_CONFIG;
arg.value.pointer.p = table;
arg.value.pointer.vtable = &arg_vtable;
return arg;
}
// State used by convert_entry() below.
typedef struct conversion_state {
void* (*convert_value)(const grpc_method_config* method_config);
const grpc_mdstr_hash_table_vtable* vtable;
size_t num_entries;
grpc_mdstr_hash_table_entry* entries;
} conversion_state;
// A function to be passed to grpc_mdstr_hash_table_iterate() to create
// a copy of the entries.
static void convert_entry(const grpc_mdstr_hash_table_entry* entry,
void* user_data) {
conversion_state* state = user_data;
state->entries[state->num_entries].key = GRPC_MDSTR_REF(entry->key);
state->entries[state->num_entries].value = state->convert_value(entry->value);
state->entries[state->num_entries].vtable = state->vtable;
++state->num_entries;
}
grpc_mdstr_hash_table* grpc_method_config_table_convert(
const grpc_method_config_table* table,
void* (*convert_value)(const grpc_method_config* method_config),
const grpc_mdstr_hash_table_vtable* vtable) {
// Create an array of the entries in the table with converted values.
conversion_state state;
state.convert_value = convert_value;
state.vtable = vtable;
state.num_entries = 0;
state.entries = gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) *
grpc_mdstr_hash_table_num_entries(table));
grpc_mdstr_hash_table_iterate(table, convert_entry, &state);
// Create a new table based on the array we just constructed.
grpc_mdstr_hash_table* new_table =
grpc_mdstr_hash_table_create(state.num_entries, state.entries);
// Clean up the array.
for (size_t i = 0; i < state.num_entries; ++i) {
GRPC_MDSTR_UNREF(state.entries[i].key);
vtable->destroy_value(state.entries[i].value);
}
gpr_free(state.entries);
// Return the new table.
return new_table;
}

@ -1,136 +0,0 @@
//
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H
#define GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H
#include <stdbool.h>
#include <grpc/impl/codegen/gpr_types.h>
#include <grpc/impl/codegen/grpc_types.h>
#include "src/core/lib/transport/mdstr_hash_table.h"
#include "src/core/lib/transport/metadata.h"
/// Per-method configuration.
typedef struct grpc_method_config grpc_method_config;
/// Creates a grpc_method_config with the specified parameters.
/// Any parameter may be NULL to indicate that the value is unset.
///
/// \a wait_for_ready indicates whether the client should wait until the
/// request deadline for the channel to become ready, even if there is a
/// temporary failure before the deadline while attempting to connect.
///
/// \a timeout indicates the timeout for calls.
///
/// \a max_request_message_bytes and \a max_response_message_bytes
/// indicate the maximum sizes of the request (checked when sending) and
/// response (checked when receiving) messages.
grpc_method_config* grpc_method_config_create(
bool* wait_for_ready, gpr_timespec* timeout,
int32_t* max_request_message_bytes, int32_t* max_response_message_bytes);
grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config);
void grpc_method_config_unref(grpc_method_config* method_config);
/// Compares two grpc_method_configs.
/// The sort order is stable but undefined.
int grpc_method_config_cmp(const grpc_method_config* method_config1,
const grpc_method_config* method_config2);
/// These methods return NULL if the requested field is unset.
/// The caller does NOT take ownership of the result.
const bool* grpc_method_config_get_wait_for_ready(
const grpc_method_config* method_config);
const gpr_timespec* grpc_method_config_get_timeout(
const grpc_method_config* method_config);
const int32_t* grpc_method_config_get_max_request_message_bytes(
const grpc_method_config* method_config);
const int32_t* grpc_method_config_get_max_response_message_bytes(
const grpc_method_config* method_config);
/// A table of method configs.
typedef grpc_mdstr_hash_table grpc_method_config_table;
typedef struct grpc_method_config_table_entry {
/// The name is of one of the following forms:
/// service/method -- specifies exact service and method name
/// service/* -- matches all methods for the specified service
grpc_mdstr* method_name;
grpc_method_config* method_config;
} grpc_method_config_table_entry;
/// Takes new references to all keys and values in \a entries.
grpc_method_config_table* grpc_method_config_table_create(
size_t num_entries, grpc_method_config_table_entry* entries);
grpc_method_config_table* grpc_method_config_table_ref(
grpc_method_config_table* table);
void grpc_method_config_table_unref(grpc_method_config_table* table);
/// Compares two grpc_method_config_tables.
/// The sort order is stable but undefined.
int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
const grpc_method_config_table* table2);
/// Gets the method config for the specified \a path, which should be of
/// the form "/service/method".
/// Returns NULL if the method has no config.
/// Caller does NOT own a reference to the result.
///
/// Note: This returns a void* instead of a grpc_method_config* so that
/// it can also be used for tables constructed via
/// grpc_method_config_table_convert().
void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
const grpc_mdstr* path);
/// Returns a channel arg containing \a table.
grpc_arg grpc_method_config_table_create_channel_arg(
grpc_method_config_table* table);
/// Generates a new table from \a table whose values are converted to a
/// new form via the \a convert_value function. The new table will use
/// \a vtable for its values.
///
/// This is generally used to convert the table's value type from
/// grpc_method_config to a simple struct containing only the parameters
/// relevant to a particular filter, thus avoiding the need for a hash
/// table lookup on the fast path. In that scenario, \a convert_value
/// will return a new instance of the struct containing the values from
/// the grpc_method_config, and \a vtable provides the methods for
/// operating on the struct type.
grpc_mdstr_hash_table* grpc_method_config_table_convert(
const grpc_method_config_table* table,
void* (*convert_value)(const grpc_method_config* method_config),
const grpc_mdstr_hash_table_vtable* vtable);
#endif /* GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H */

@ -0,0 +1,249 @@
//
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "src/core/lib/transport/service_config.h"
#include <string.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/json/json.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/mdstr_hash_table.h"
// The main purpose of the code here is to parse the service config in
// JSON form, which will look like this:
//
// {
// "loadBalancingPolicy": "string", // optional
// "methodConfig": [ // array of one or more method_config objects
// {
// "name": [ // array of one or more name objects
// {
// "service": "string", // required
// "method": "string", // optional
// }
// ],
// // remaining fields are optional.
// // see https://developers.google.com/protocol-buffers/docs/proto3#json
// // for format details.
// "waitForReady": bool,
// "timeout": "duration_string",
// "maxRequestMessageBytes": "int64_string",
// "maxResponseMessageBytes": "int64_string",
// }
// ]
// }
struct grpc_service_config {
char* json_string; // Underlying storage for json_tree.
grpc_json* json_tree;
};
grpc_service_config* grpc_service_config_create(const char* json_string) {
grpc_service_config* service_config = gpr_malloc(sizeof(*service_config));
service_config->json_string = gpr_strdup(json_string);
service_config->json_tree =
grpc_json_parse_string(service_config->json_string);
if (service_config->json_tree == NULL) {
gpr_log(GPR_INFO, "failed to parse JSON for service config");
gpr_free(service_config->json_string);
gpr_free(service_config);
return NULL;
}
return service_config;
}
void grpc_service_config_destroy(grpc_service_config* service_config) {
grpc_json_destroy(service_config->json_tree);
gpr_free(service_config->json_string);
gpr_free(service_config);
}
const char* grpc_service_config_get_lb_policy_name(
const grpc_service_config* service_config) {
const grpc_json* json = service_config->json_tree;
if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL;
const char* lb_policy_name = NULL;
for (grpc_json* field = json->child; field != NULL; field = field->next) {
if (field->key == NULL) return NULL;
if (strcmp(field->key, "loadBalancingPolicy") == 0) {
if (lb_policy_name != NULL) return NULL; // Duplicate.
if (field->type != GRPC_JSON_STRING) return NULL;
lb_policy_name = field->value;
}
}
return lb_policy_name;
}
// Returns the number of names specified in the method config \a json.
static size_t count_names_in_method_config_json(grpc_json* json) {
size_t num_names = 0;
for (grpc_json* field = json->child; field != NULL; field = field->next) {
if (field->key != NULL && strcmp(field->key, "name") == 0) ++num_names;
}
return num_names;
}
// Returns a path string for the JSON name object specified by \a json.
// Returns NULL on error. Caller takes ownership of result.
static char* parse_json_method_name(grpc_json* json) {
if (json->type != GRPC_JSON_OBJECT) return NULL;
const char* service_name = NULL;
const char* method_name = NULL;
for (grpc_json* child = json->child; child != NULL; child = child->next) {
if (child->key == NULL) return NULL;
if (child->type != GRPC_JSON_STRING) return NULL;
if (strcmp(child->key, "service") == 0) {
if (service_name != NULL) return NULL; // Duplicate.
if (child->value == NULL) return NULL;
service_name = child->value;
} else if (strcmp(child->key, "method") == 0) {
if (method_name != NULL) return NULL; // Duplicate.
if (child->value == NULL) return NULL;
method_name = child->value;
}
}
if (service_name == NULL) return NULL; // Required field.
char* path;
gpr_asprintf(&path, "/%s/%s", service_name,
method_name == NULL ? "*" : method_name);
return path;
}
// Parses the method config from \a json. Adds an entry to \a entries for
// each name found, incrementing \a idx for each entry added.
// Returns false on error.
static bool parse_json_method_config(
grpc_json* json, void* (*create_value)(const grpc_json* method_config_json),
const grpc_mdstr_hash_table_vtable* vtable,
grpc_mdstr_hash_table_entry* entries, size_t* idx) {
// Construct value.
void* method_config = create_value(json);
if (method_config == NULL) return false;
// Construct list of paths.
bool success = false;
gpr_strvec paths;
gpr_strvec_init(&paths);
for (grpc_json* child = json->child; child != NULL; child = child->next) {
if (child->key == NULL) continue;
if (strcmp(child->key, "name") == 0) {
if (child->type != GRPC_JSON_ARRAY) goto done;
for (grpc_json* name = child->child; name != NULL; name = name->next) {
char* path = parse_json_method_name(name);
gpr_strvec_add(&paths, path);
}
}
}
if (paths.count == 0) goto done; // No names specified.
// Add entry for each path.
for (size_t i = 0; i < paths.count; ++i) {
entries[*idx].key = grpc_mdstr_from_string(paths.strs[i]);
entries[*idx].value = vtable->copy_value(method_config);
entries[*idx].vtable = vtable;
++*idx;
}
success = true;
done:
vtable->destroy_value(method_config);
gpr_strvec_destroy(&paths);
return success;
}
grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
const grpc_service_config* service_config,
void* (*create_value)(const grpc_json* method_config_json),
const grpc_mdstr_hash_table_vtable* vtable) {
const grpc_json* json = service_config->json_tree;
// Traverse parsed JSON tree.
if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL;
size_t num_entries = 0;
grpc_mdstr_hash_table_entry* entries = NULL;
for (grpc_json* field = json->child; field != NULL; field = field->next) {
if (field->key == NULL) return NULL;
if (strcmp(field->key, "methodConfig") == 0) {
if (entries != NULL) return NULL; // Duplicate.
if (field->type != GRPC_JSON_ARRAY) return NULL;
// Find number of entries.
for (grpc_json* method = field->child; method != NULL;
method = method->next) {
num_entries += count_names_in_method_config_json(method);
}
// Populate method config table entries.
entries = gpr_malloc(num_entries * sizeof(grpc_mdstr_hash_table_entry));
size_t idx = 0;
for (grpc_json* method = field->child; method != NULL;
method = method->next) {
if (!parse_json_method_config(method, create_value, vtable, entries,
&idx)) {
return NULL;
}
}
GPR_ASSERT(idx == num_entries);
}
}
// Instantiate method config table.
grpc_mdstr_hash_table* method_config_table = NULL;
if (entries != NULL) {
method_config_table = grpc_mdstr_hash_table_create(num_entries, entries);
// Clean up.
for (size_t i = 0; i < num_entries; ++i) {
GRPC_MDSTR_UNREF(entries[i].key);
vtable->destroy_value(entries[i].value);
}
gpr_free(entries);
}
return method_config_table;
}
void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
const grpc_mdstr* path) {
void* value = grpc_mdstr_hash_table_get(table, path);
// If we didn't find a match for the path, try looking for a wildcard
// entry (i.e., change "/service/method" to "/service/*").
if (value == NULL) {
const char* path_str = grpc_mdstr_as_c_string(path);
const char* sep = strrchr(path_str, '/') + 1;
const size_t len = (size_t)(sep - path_str);
char* buf = gpr_malloc(len + 2); // '*' and NUL
memcpy(buf, path_str, len);
buf[len] = '*';
buf[len + 1] = '\0';
grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
gpr_free(buf);
value = grpc_mdstr_hash_table_get(table, wildcard_path);
GRPC_MDSTR_UNREF(wildcard_path);
}
return value;
}

@ -0,0 +1,70 @@
//
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H
#define GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H
#include <grpc/impl/codegen/grpc_types.h>
#include "src/core/lib/json/json.h"
#include "src/core/lib/transport/mdstr_hash_table.h"
typedef struct grpc_service_config grpc_service_config;
grpc_service_config* grpc_service_config_create(const char* json_string);
void grpc_service_config_destroy(grpc_service_config* service_config);
/// Gets the LB policy name from \a service_config.
/// Returns NULL if no LB policy name was specified.
/// Caller does NOT take ownership.
const char* grpc_service_config_get_lb_policy_name(
const grpc_service_config* service_config);
/// Creates a method config table based on the data in \a json.
/// The table's keys are request paths. The table's value type is
/// returned by \a create_value(), based on data parsed from the JSON tree.
/// \a vtable provides methods used to manage the values.
/// Returns NULL on error.
grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
const grpc_service_config* service_config,
void* (*create_value)(const grpc_json* method_config_json),
const grpc_mdstr_hash_table_vtable* vtable);
/// A helper function for looking up values in the table returned by
/// \a grpc_service_config_create_method_config_table().
/// Gets the method config for the specified \a path, which should be of
/// the form "/service/method".
/// Returns NULL if the method has no config.
/// Caller does NOT own a reference to the result.
void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
const grpc_mdstr* path);
#endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */

@ -48,6 +48,7 @@
#include <grpc++/support/time.h>
#include <grpc/grpc.h>
#include <grpc/slice.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/profiling/timers.h"
@ -61,6 +62,35 @@ Channel::Channel(const grpc::string& host, grpc_channel* channel)
Channel::~Channel() { grpc_channel_destroy(c_channel_); }
namespace {
grpc::string GetChannelInfoField(grpc_channel* channel,
grpc_channel_info* channel_info,
char*** channel_info_field) {
char* value = NULL;
memset(channel_info, 0, sizeof(*channel_info));
*channel_info_field = &value;
grpc_channel_get_info(channel, channel_info);
if (value == NULL) return "";
grpc::string result = value;
gpr_free(value);
return result;
}
} // namespace
grpc::string Channel::GetLoadBalancingPolicyName() const {
grpc_channel_info channel_info;
return GetChannelInfoField(c_channel_, &channel_info,
&channel_info.lb_policy_name);
}
grpc::string Channel::GetServiceConfigJSON() const {
grpc_channel_info channel_info;
return GetChannelInfoField(c_channel_, &channel_info,
&channel_info.service_config_json);
}
Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) {
const bool kRegistered = method.channel_tag() && context->authority().empty();

@ -143,6 +143,11 @@ void ChannelArguments::SetLoadBalancingPolicyName(
SetString(GRPC_ARG_LB_POLICY_NAME, lb_policy_name);
}
void ChannelArguments::SetServiceConfigJSON(
const grpc::string& service_config_json) {
SetString(GRPC_ARG_SERVICE_CONFIG, service_config_json);
}
void ChannelArguments::SetInt(const grpc::string& key, int value) {
grpc_arg arg;
arg.type = GRPC_ARG_INTEGER;

@ -181,8 +181,8 @@ CORE_SOURCE_FILES = [
'src/core/lib/transport/mdstr_hash_table.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
'src/core/lib/transport/method_config.c',
'src/core/lib/transport/pid_controller.c',
'src/core/lib/transport/service_config.c',
'src/core/lib/transport/static_metadata.c',
'src/core/lib/transport/timeout_encoding.c',
'src/core/lib/transport/transport.c',

@ -43,6 +43,7 @@
#include "src/core/ext/client_channel/client_channel.h"
#include "src/core/ext/client_channel/lb_policy_registry.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/channel.h"
@ -522,7 +523,7 @@ static grpc_channel *create_client(const servers_fixture *f) {
arg_array[0].value.integer = RETRY_TIMEOUT;
arg_array[1].type = GRPC_ARG_STRING;
arg_array[1].key = GRPC_ARG_LB_POLICY_NAME;
arg_array[1].value.string = "round_robin";
arg_array[1].value.string = "ROUND_ROBIN";
args.num_args = 2;
args.args = arg_array;
@ -611,29 +612,43 @@ static void test_pending_calls(size_t concurrent_calls) {
}
static void test_get_channel_info() {
grpc_channel_args args;
grpc_arg arg_array[1];
arg_array[0].type = GRPC_ARG_STRING;
arg_array[0].key = GRPC_ARG_LB_POLICY_NAME;
arg_array[0].value.string = "round_robin";
args.num_args = 1;
args.args = arg_array;
grpc_channel *channel =
grpc_insecure_channel_create("ipv4:127.0.0.1:1234", &args, NULL);
grpc_insecure_channel_create("ipv4:127.0.0.1:1234", NULL, NULL);
// Ensures that resolver returns.
grpc_channel_check_connectivity_state(channel, true /* try_to_connect */);
// Use grpc_channel_get_info() to get LB policy name.
char *lb_policy_name = NULL;
// First, request no fields. This is a no-op.
grpc_channel_info channel_info;
memset(&channel_info, 0, sizeof(channel_info));
grpc_channel_get_info(channel, &channel_info);
// Request LB policy name.
char *lb_policy_name = NULL;
channel_info.lb_policy_name = &lb_policy_name;
grpc_channel_get_info(channel, &channel_info);
GPR_ASSERT(lb_policy_name != NULL);
GPR_ASSERT(strcmp(lb_policy_name, "round_robin") == 0);
GPR_ASSERT(strcmp(lb_policy_name, "pick_first") == 0);
gpr_free(lb_policy_name);
// Try again without requesting anything. This is a no-op.
channel_info.lb_policy_name = NULL;
// Request service config, which does not exist, so we'll get nothing back.
memset(&channel_info, 0, sizeof(channel_info));
char *service_config_json = "dummy_string";
channel_info.service_config_json = &service_config_json;
grpc_channel_get_info(channel, &channel_info);
GPR_ASSERT(service_config_json == NULL);
// Recreate the channel such that it has a service config.
grpc_channel_destroy(channel);
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = GRPC_ARG_SERVICE_CONFIG;
arg.value.string = "{\"loadBalancingPolicy\": \"ROUND_ROBIN\"}";
grpc_channel_args *args = grpc_channel_args_copy_and_add(NULL, &arg, 1);
channel = grpc_insecure_channel_create("ipv4:127.0.0.1:1234", args, NULL);
grpc_channel_args_destroy(args);
// Ensures that resolver returns.
grpc_channel_check_connectivity_state(channel, true /* try_to_connect */);
// Now request the service config again.
grpc_channel_get_info(channel, &channel_info);
GPR_ASSERT(service_config_json != NULL);
GPR_ASSERT(strcmp(service_config_json, arg.value.string) == 0);
gpr_free(service_config_json);
// Clean up.
grpc_channel_destroy(channel);
}

@ -41,7 +41,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/method_config.h"
#include "src/core/lib/transport/service_config.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/util/port.h"
@ -76,18 +76,19 @@ static void run_test(bool wait_for_ready, bool use_service_config) {
grpc_channel_args *args = NULL;
if (use_service_config) {
GPR_ASSERT(wait_for_ready);
grpc_method_config_table_entry entry = {
grpc_mdstr_from_string("/service/method"),
grpc_method_config_create(&wait_for_ready, NULL, NULL, NULL),
};
grpc_method_config_table *method_config_table =
grpc_method_config_table_create(1, &entry);
GRPC_MDSTR_UNREF(entry.method_name);
grpc_method_config_unref(entry.method_config);
grpc_arg arg =
grpc_method_config_table_create_channel_arg(method_config_table);
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = GRPC_ARG_SERVICE_CONFIG;
arg.value.string =
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"waitForReady\": true\n"
" } ]\n"
"}";
args = grpc_channel_args_copy_and_add(args, &arg, 1);
grpc_method_config_table_unref(method_config_table);
}
/* create a call, channel to a port which will refuse connection */

@ -44,7 +44,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/method_config.h"
#include "src/core/lib/transport/service_config.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
@ -134,19 +134,19 @@ static void test_cancel_after_accept(grpc_end2end_test_config config,
grpc_channel_args *args = NULL;
if (use_service_config) {
gpr_timespec timeout = {5, 0, GPR_TIMESPAN};
grpc_method_config_table_entry entry = {
grpc_mdstr_from_string("/service/method"),
grpc_method_config_create(NULL, &timeout, NULL, NULL),
};
grpc_method_config_table *method_config_table =
grpc_method_config_table_create(1, &entry);
GRPC_MDSTR_UNREF(entry.method_name);
grpc_method_config_unref(entry.method_config);
grpc_arg arg =
grpc_method_config_table_create_channel_arg(method_config_table);
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = GRPC_ARG_SERVICE_CONFIG;
arg.value.string =
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"timeout\": \"5s\"\n"
" } ]\n"
"}";
args = grpc_channel_args_copy_and_add(args, &arg, 1);
grpc_method_config_table_unref(method_config_table);
}
grpc_end2end_test_fixture f =

@ -44,7 +44,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/method_config.h"
#include "src/core/lib/transport/service_config.h"
#include "test/core/end2end/cq_verifier.h"
@ -138,19 +138,19 @@ static void test_max_message_length_on_request(grpc_end2end_test_config config,
if (use_service_config) {
// We don't currently support service configs on the server side.
GPR_ASSERT(send_limit);
int32_t max_request_message_bytes = 5;
grpc_method_config_table_entry entry = {
grpc_mdstr_from_string("/service/method"),
grpc_method_config_create(NULL, NULL, &max_request_message_bytes, NULL),
};
grpc_method_config_table *method_config_table =
grpc_method_config_table_create(1, &entry);
GRPC_MDSTR_UNREF(entry.method_name);
grpc_method_config_unref(entry.method_config);
grpc_arg arg =
grpc_method_config_table_create_channel_arg(method_config_table);
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = GRPC_ARG_SERVICE_CONFIG;
arg.value.string =
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"maxRequestMessageBytes\": \"5\"\n"
" } ]\n"
"}";
client_args = grpc_channel_args_copy_and_add(NULL, &arg, 1);
grpc_method_config_table_unref(method_config_table);
} else {
// Set limit via channel args.
grpc_arg arg;
@ -312,20 +312,19 @@ static void test_max_message_length_on_response(grpc_end2end_test_config config,
if (use_service_config) {
// We don't currently support service configs on the server side.
GPR_ASSERT(!send_limit);
int32_t max_response_message_bytes = 5;
grpc_method_config_table_entry entry = {
grpc_mdstr_from_string("/service/method"),
grpc_method_config_create(NULL, NULL, NULL,
&max_response_message_bytes),
};
grpc_method_config_table *method_config_table =
grpc_method_config_table_create(1, &entry);
GRPC_MDSTR_UNREF(entry.method_name);
grpc_method_config_unref(entry.method_config);
grpc_arg arg =
grpc_method_config_table_create_channel_arg(method_config_table);
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = GRPC_ARG_SERVICE_CONFIG;
arg.value.string =
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"maxResponseMessageBytes\": \"5\"\n"
" } ]\n"
"}";
client_args = grpc_channel_args_copy_and_add(NULL, &arg, 1);
grpc_method_config_table_unref(method_config_table);
} else {
// Set limit via channel args.
grpc_arg arg;

@ -109,9 +109,9 @@ class RoundRobinEnd2endTest : public ::testing::Test {
uri << "127.0.0.1:" << servers_[i]->port_ << ",";
}
uri << "127.0.0.1:" << servers_[servers_.size() - 1]->port_;
std::shared_ptr<Channel> channel =
channel_ =
CreateCustomChannel(uri.str(), InsecureChannelCredentials(), args);
stub_ = grpc::testing::EchoTestService::NewStub(channel);
stub_ = grpc::testing::EchoTestService::NewStub(channel_);
}
void SendRpc(int num_rpcs) {
@ -165,6 +165,7 @@ class RoundRobinEnd2endTest : public ::testing::Test {
const grpc::string server_host_;
CompletionQueue cli_cq_;
std::shared_ptr<Channel> channel_;
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::vector<std::unique_ptr<ServerData>> servers_;
};
@ -186,6 +187,8 @@ TEST_F(RoundRobinEnd2endTest, PickFirst) {
}
}
EXPECT_TRUE(found);
// Check LB policy name for the channel.
EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName());
}
TEST_F(RoundRobinEnd2endTest, RoundRobin) {
@ -198,6 +201,8 @@ TEST_F(RoundRobinEnd2endTest, RoundRobin) {
for (size_t i = 0; i < servers_.size(); ++i) {
EXPECT_EQ(1, servers_[i]->service_.request_count());
}
// Check LB policy name for the channel.
EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName());
}
} // namespace

@ -879,8 +879,8 @@ src/core/lib/transport/connectivity_state.h \
src/core/lib/transport/mdstr_hash_table.h \
src/core/lib/transport/metadata.h \
src/core/lib/transport/metadata_batch.h \
src/core/lib/transport/method_config.h \
src/core/lib/transport/pid_controller.h \
src/core/lib/transport/service_config.h \
src/core/lib/transport/static_metadata.h \
src/core/lib/transport/timeout_encoding.h \
src/core/lib/transport/transport.h \
@ -1072,8 +1072,8 @@ src/core/lib/transport/connectivity_state.c \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/method_config.c \
src/core/lib/transport/pid_controller.c \
src/core/lib/transport/service_config.c \
src/core/lib/transport/static_metadata.c \
src/core/lib/transport/timeout_encoding.c \
src/core/lib/transport/transport.c \

@ -6761,8 +6761,8 @@
"src/core/lib/transport/mdstr_hash_table.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/method_config.h",
"src/core/lib/transport/pid_controller.h",
"src/core/lib/transport/service_config.h",
"src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
@ -6978,10 +6978,10 @@
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/method_config.c",
"src/core/lib/transport/method_config.h",
"src/core/lib/transport/pid_controller.c",
"src/core/lib/transport/pid_controller.h",
"src/core/lib/transport/service_config.c",
"src/core/lib/transport/service_config.h",
"src/core/lib/transport/static_metadata.c",
"src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/timeout_encoding.c",

@ -388,8 +388,8 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\mdstr_hash_table.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
@ -690,10 +690,10 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">

@ -322,10 +322,10 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
@ -1001,10 +1001,10 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h">
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">

@ -281,8 +281,8 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\mdstr_hash_table.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
@ -541,10 +541,10 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">

@ -379,10 +379,10 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
@ -797,10 +797,10 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h">
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">

@ -378,8 +378,8 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\mdstr_hash_table.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
@ -658,10 +658,10 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">

@ -325,10 +325,10 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
@ -914,10 +914,10 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h">
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">

Loading…
Cancel
Save