From b2d24886196c5000cc15bb5953659ff50b09ad87 Mon Sep 17 00:00:00 2001
From: "Mark D. Roth" <roth@google.com>
Date: Thu, 27 Oct 2016 15:44:07 -0700
Subject: [PATCH] Add grpc_channel_get_info() to C-core API.

---
 include/grpc/grpc.h                           |  4 +++
 include/grpc/impl/codegen/grpc_types.h        |  7 +++++
 src/core/ext/census/grpc_filter.c             |  2 ++
 src/core/ext/client_channel/client_channel.c  | 29 ++++++++++++++++---
 .../load_reporting/load_reporting_filter.c    |  1 +
 src/core/lib/channel/channel_stack.c          |  7 +++++
 src/core/lib/channel/channel_stack.h          |  8 +++++
 src/core/lib/channel/compress_filter.c        |  1 +
 src/core/lib/channel/connected_channel.c      |  6 ++++
 src/core/lib/channel/deadline_filter.c        |  2 ++
 src/core/lib/channel/http_client_filter.c     |  1 +
 src/core/lib/channel/http_server_filter.c     |  1 +
 src/core/lib/channel/message_size_filter.c    |  1 +
 .../security/transport/client_auth_filter.c   |  1 +
 .../security/transport/server_auth_filter.c   |  1 +
 src/core/lib/surface/channel.c                |  9 ++++++
 src/core/lib/surface/lame_client.c            |  5 ++++
 src/core/lib/surface/server.c                 |  1 +
 test/core/client_channel/lb_policies_test.c   | 16 ++++++++++
 .../end2end/tests/filter_call_init_fails.c    |  1 +
 test/core/end2end/tests/filter_causes_close.c |  1 +
 21 files changed, 101 insertions(+), 4 deletions(-)

diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 587d86c98f..dbd125e57a 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 0be7ab2ad2..0fc86b57cc 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 a4cf6f37bd..7ace2f671e 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 80b4f048c2..d15af0b438 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 eeae2400fb..b810e20bb9 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 2c5367901d..3370f0ef45 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 27f3be7b29..6fbcd87064 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 0981d59f63..7968cf7e26 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 918379c845..6ae2b3b6b7 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 d2ea5250f6..224c823a4f 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 1dc05fb20d..b5ab4dd5ca 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 f2221fb0fb..d02a765d0d 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 7dc5ae0df1..bbcd2a2145 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 b366d1410f..3a96af2c69 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 b2c6815af8..8ecc5fd088 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 92d783b78d..22bf85b126 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 d32c884e8e..6fd1dd921c 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 3a90308058..914b62e176 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 844db5e6cb..857ba6bd52 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 0e5692f4c9..2f8a2a4d04 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 d5eddc7330..da554142e8 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"};
 
 /*******************************************************************************
-- 
GitLab