diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index 587d86c98fd79eb81cf8a77385dc82590fe05c9d..dbd125e57ad03b014c18f3321a302cd9c969f9b1 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -237,6 +237,10 @@ GRPCAPI struct census_context *grpc_census_call_get_context(grpc_call *call); created for. */ GRPCAPI char *grpc_channel_get_target(grpc_channel *channel); +/** Request info about the channel. */ +GRPCAPI void grpc_channel_get_info(grpc_channel *channel, + grpc_channel_info *channel_info); + /** Create a client channel to 'target'. Additional channel level configuration MAY be provided by grpc_channel_args, though the expectation is that most clients will want to simply pass NULL. See grpc_channel_args definition for diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 0be7ab2ad2353a2c239e0a263ab6ef5b12081910..0fc86b57cc15f41b5a5254ab01ad72441feec89a 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -467,6 +467,13 @@ typedef struct grpc_op { } data; } grpc_op; +/** Information requested from the channel. */ +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; +} grpc_channel_info; + #ifdef __cplusplus } #endif diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c index a4cf6f37bd7a005c6b18957290ce98a3f1cf132a..7ace2f671e1d6e1e99d5fb73c7ef494afdec024c 100644 --- a/src/core/ext/census/grpc_filter.c +++ b/src/core/ext/census/grpc_filter.c @@ -191,6 +191,7 @@ const grpc_channel_filter grpc_client_census_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "census-client"}; const grpc_channel_filter grpc_server_census_filter = { @@ -204,4 +205,5 @@ const grpc_channel_filter grpc_server_census_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "census-server"}; diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c index 80b4f048c2facbca8d6f8a76936a3536a6c835f0..d15af0b438c3f55a05f521e26e0157c0c65fb2e8 100644 --- a/src/core/ext/client_channel/client_channel.c +++ b/src/core/ext/client_channel/client_channel.c @@ -39,6 +39,7 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include <grpc/support/string_util.h> #include <grpc/support/sync.h> #include <grpc/support/useful.h> @@ -123,6 +124,7 @@ typedef struct client_channel_channel_data { /** mutex protecting all variables below in this data structure */ gpr_mu mu; /** currently active load balancer */ + char* lb_policy_name; grpc_lb_policy *lb_policy; /** maps method names to method_parameters structs */ grpc_mdstr_hash_table *method_params_table; @@ -223,6 +225,7 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand, static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { channel_data *chand = arg; + char *lb_policy_name = NULL; grpc_lb_policy *lb_policy = NULL; grpc_lb_policy *old_lb_policy; grpc_mdstr_hash_table *method_params_table = NULL; @@ -236,12 +239,11 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, lb_policy_args.client_channel_factory = chand->client_channel_factory; // Find LB policy name. - const char *lb_policy_name = NULL; const grpc_arg *channel_arg = grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_POLICY_NAME); if (channel_arg != NULL) { GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); - lb_policy_name = channel_arg->value.string; + lb_policy_name = gpr_strdup(channel_arg->value.string); } // Special case: If all of the addresses are balancer addresses, // assume that we should use the grpclb policy, regardless of what the @@ -265,13 +267,14 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, "addresses, no backend addresses -- forcing use of grpclb LB " "policy", lb_policy_name); + gpr_free(lb_policy_name); } - lb_policy_name = "grpclb"; + lb_policy_name = gpr_strdup("grpclb"); } } // Use pick_first if nothing was specified and we didn't select grpclb // above. - if (lb_policy_name == NULL) lb_policy_name = "pick_first"; + if (lb_policy_name == NULL) lb_policy_name = gpr_strdup("pick_first"); lb_policy = grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args); @@ -299,6 +302,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, } gpr_mu_lock(&chand->mu); + if (lb_policy_name != NULL) { + gpr_free(chand->lb_policy_name); + chand->lb_policy_name = lb_policy_name; + } old_lb_policy = chand->lb_policy; chand->lb_policy = lb_policy; if (chand->method_params_table != NULL) { @@ -426,6 +433,18 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx, gpr_mu_unlock(&chand->mu); } +static void cc_get_channel_info(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_info *info) { + channel_data *chand = elem->channel_data; + gpr_mu_lock(&chand->mu); + if (info->lb_policy_name != NULL) { + *info->lb_policy_name = chand->lb_policy_name == NULL + ? NULL : gpr_strdup(chand->lb_policy_name); + } + gpr_mu_unlock(&chand->mu); +} + /* Constructor for channel_data */ static void cc_init_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, @@ -465,6 +484,7 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, chand->interested_parties); GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); } + gpr_free(chand->lb_policy_name); if (chand->method_params_table != NULL) { grpc_mdstr_hash_table_unref(chand->method_params_table); } @@ -1048,6 +1068,7 @@ const grpc_channel_filter grpc_client_channel_filter = { cc_init_channel_elem, cc_destroy_channel_elem, cc_get_peer, + cc_get_channel_info, "client-channel", }; diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c index eeae2400fbc80c8dd1cd37a35bbd7b73ff333b05..b810e20bb98d56e6e70034a95f99b6a4731346a3 100644 --- a/src/core/ext/load_reporting/load_reporting_filter.c +++ b/src/core/ext/load_reporting/load_reporting_filter.c @@ -232,4 +232,5 @@ const grpc_channel_filter grpc_load_reporting_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "load_reporting"}; diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c index 2c5367901dfdc7bf8da013985384414f32edce9e..3370f0ef459790b7c52d11515afc77f46d725400 100644 --- a/src/core/lib/channel/channel_stack.c +++ b/src/core/lib/channel/channel_stack.c @@ -255,6 +255,13 @@ char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, return next_elem->filter->get_peer(exec_ctx, next_elem); } +void grpc_channel_next_get_info(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_info *channel_info) { + grpc_channel_element *next_elem = elem + 1; + return next_elem->filter->get_channel_info(exec_ctx, next_elem, channel_info); +} + void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_transport_op *op) { grpc_channel_element *next_elem = elem + 1; diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index 27f3be7b29116ae98b8ce3d3ac727b104d47b4f3..6fbcd870641588c6a80292f992ab95d922e7f426 100644 --- a/src/core/lib/channel/channel_stack.h +++ b/src/core/lib/channel/channel_stack.h @@ -156,6 +156,10 @@ typedef struct { /* Implement grpc_call_get_peer() */ char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem); + /* Implement grpc_channel_get_info() */ + void (*get_channel_info)(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, + grpc_channel_info *channel_info); + /* The name of this filter */ const char *name; } grpc_channel_filter; @@ -273,6 +277,10 @@ void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_transport_op *op); /* Pass through a request to get_peer to the next child element */ char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem); +/* Pass through a request to get_channel_info() to the next child element */ +void grpc_channel_next_get_info(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_info *channel_info); /* Given the top element of a channel stack, get the channel stack itself */ grpc_channel_stack *grpc_channel_stack_from_top_element( diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c index 0981d59f637c7de9f0bfa7365576a90a286d0eb0..7968cf7e2655f6ff3bc0e8147893547d56e19e67 100644 --- a/src/core/lib/channel/compress_filter.c +++ b/src/core/lib/channel/compress_filter.c @@ -328,4 +328,5 @@ const grpc_channel_filter grpc_compress_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "compress"}; diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c index 918379c8457f4ee8ed0b6c2f0fb091b4fea31a92..6ae2b3b6b7bd4be4ea85585051a005fd9a417832 100644 --- a/src/core/lib/channel/connected_channel.c +++ b/src/core/lib/channel/connected_channel.c @@ -134,6 +134,11 @@ static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { return grpc_transport_get_peer(exec_ctx, chand->transport); } +/* No-op. */ +static void con_get_channel_info(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_info *channel_info) {} + static const grpc_channel_filter connected_channel_filter = { con_start_transport_stream_op, con_start_transport_op, @@ -145,6 +150,7 @@ static const grpc_channel_filter connected_channel_filter = { init_channel_elem, destroy_channel_elem, con_get_peer, + con_get_channel_info, "connected", }; diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c index d2ea5250f6c96ff2fd0cf212880299406435f994..224c823a4f4ff0ba603a28f38c2033f6e58de940 100644 --- a/src/core/lib/channel/deadline_filter.c +++ b/src/core/lib/channel/deadline_filter.c @@ -316,6 +316,7 @@ const grpc_channel_filter grpc_client_deadline_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "deadline", }; @@ -330,5 +331,6 @@ const grpc_channel_filter grpc_server_deadline_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "deadline", }; diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c index 1dc05fb20d1a03b4f144b3f69db5c05136142fab..b5ab4dd5cac8f5f51029e5a60a146b2dce877a57 100644 --- a/src/core/lib/channel/http_client_filter.c +++ b/src/core/lib/channel/http_client_filter.c @@ -448,4 +448,5 @@ const grpc_channel_filter grpc_http_client_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "http-client"}; diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c index f2221fb0fbe3e939279e105acf7acbbd53826bc6..d02a765d0d8384b1eaa3378652c95b67d2463772 100644 --- a/src/core/lib/channel/http_server_filter.c +++ b/src/core/lib/channel/http_server_filter.c @@ -344,4 +344,5 @@ const grpc_channel_filter grpc_http_server_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "http-server"}; diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c index 7dc5ae0df150632aeee44d42f254c2dfbeb8f4b5..bbcd2a21453095d61e83f373eb0cb5e897cdafd6 100644 --- a/src/core/lib/channel/message_size_filter.c +++ b/src/core/lib/channel/message_size_filter.c @@ -248,4 +248,5 @@ const grpc_channel_filter grpc_message_size_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "message_size"}; diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c index b366d1410f9ad16b8b73995d7414201ce5df17a3..3a96af2c6985d1b439476da6a1b6f742aec622a7 100644 --- a/src/core/lib/security/transport/client_auth_filter.c +++ b/src/core/lib/security/transport/client_auth_filter.c @@ -351,4 +351,5 @@ const grpc_channel_filter grpc_client_auth_filter = {auth_start_transport_op, init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "client-auth"}; diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c index b2c6815af81dd2914f83068a73de8b7712f474f7..8ecc5fd088393ddabe50bf2d6520b00404a4cfa0 100644 --- a/src/core/lib/security/transport/server_auth_filter.c +++ b/src/core/lib/security/transport/server_auth_filter.c @@ -278,4 +278,5 @@ const grpc_channel_filter grpc_server_auth_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "server-auth"}; diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c index 92d783b78da4ea4510467d9b94461b958723f304..22bf85b126126b1afb02acd44d8d4c7189940868 100644 --- a/src/core/lib/surface/channel.c +++ b/src/core/lib/surface/channel.c @@ -175,6 +175,15 @@ char *grpc_channel_get_target(grpc_channel *channel) { return gpr_strdup(channel->target); } +void grpc_channel_get_info(grpc_channel *channel, + grpc_channel_info *channel_info) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_channel_element *elem = + grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0); + elem->filter->get_channel_info(&exec_ctx, elem, channel_info); + grpc_exec_ctx_finish(&exec_ctx); +} + static grpc_call *grpc_channel_create_call_internal( grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative, diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c index d32c884e8ea32496b9d8e67917306a4cb6e0ffd1..6fd1dd921c8dbc841c550ddd484b9c6f6196c6b7 100644 --- a/src/core/lib/surface/lame_client.c +++ b/src/core/lib/surface/lame_client.c @@ -88,6 +88,10 @@ static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { return NULL; } +static void lame_get_channel_info(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_info *channel_info) {} + static void lame_start_transport_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_transport_op *op) { @@ -140,6 +144,7 @@ const grpc_channel_filter grpc_lame_filter = { init_channel_elem, destroy_channel_elem, lame_get_peer, + lame_get_channel_info, "lame-client", }; diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c index 3a90308058c7f03c510c85f6553995c17178f8fb..914b62e176033dc8274cef2381d6a04ae0bec496 100644 --- a/src/core/lib/surface/server.c +++ b/src/core/lib/surface/server.c @@ -965,6 +965,7 @@ const grpc_channel_filter grpc_server_top_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "server", }; diff --git a/test/core/client_channel/lb_policies_test.c b/test/core/client_channel/lb_policies_test.c index 844db5e6cb5b370056c32c9c53689ed700bc6891..857ba6bd52095afe7f8c06603144f393b94427f6 100644 --- a/test/core/client_channel/lb_policies_test.c +++ b/test/core/client_channel/lb_policies_test.c @@ -638,6 +638,21 @@ static void test_pending_calls(size_t concurrent_calls) { test_spec_destroy(spec); } +static void test_get_channel_info() { + grpc_channel *channel = grpc_insecure_channel_create( + "test:127.0.0.1:1234?lb_policy=round_robin", NULL, NULL); + // Ensures that resolver returns. + grpc_channel_check_connectivity_state(channel, true /* try_to_connect */); + char *lb_policy_name = NULL; + grpc_channel_info channel_info; + 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_free(lb_policy_name); + grpc_channel_destroy(channel); +} + static void print_failed_expectations(const int *expected_connection_sequence, const int *actual_connection_sequence, const size_t expected_seq_length, @@ -933,6 +948,7 @@ int main(int argc, char **argv) { test_pending_calls(4); test_ping(); + test_get_channel_info(); grpc_exec_ctx_finish(&exec_ctx); grpc_shutdown(); diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c index 0e5692f4c9f616a195f0fbe10cdbdf0c0bf11841..2f8a2a4d0460377bca753d81001a1bdc0a100cdb 100644 --- a/test/core/end2end/tests/filter_call_init_fails.c +++ b/test/core/end2end/tests/filter_call_init_fails.c @@ -231,6 +231,7 @@ static const grpc_channel_filter test_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "filter_call_init_fails"}; /******************************************************************************* diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c index d5eddc7330b1ce74a7cc8bea0bd140c074669fdd..da554142e8b4e3202089118fd05a756124a53dbd 100644 --- a/test/core/end2end/tests/filter_causes_close.c +++ b/test/core/end2end/tests/filter_causes_close.c @@ -258,6 +258,7 @@ static const grpc_channel_filter test_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "filter_causes_close"}; /*******************************************************************************