Imported Upstream version 1.41.0
[platform/upstream/grpc.git] / src / core / lib / channel / channelz.cc
index ff6b7a7..6aaf557 100644 (file)
 
 #include "src/core/lib/channel/channelz.h"
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atomic>
+
+#include "absl/strings/escaping.h"
+#include "absl/strings/strip.h"
+
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channelz_registry.h"
 #include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/useful.h"
-#include "src/core/lib/gprpp/atomic.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/slice/b64.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/channel.h"
@@ -49,40 +56,6 @@ namespace grpc_core {
 namespace channelz {
 
 //
-// channel arg code
-//
-
-namespace {
-
-void* parent_uuid_copy(void* p) { return p; }
-void parent_uuid_destroy(void* /*p*/) {}
-int parent_uuid_cmp(void* p1, void* p2) { return GPR_ICMP(p1, p2); }
-const grpc_arg_pointer_vtable parent_uuid_vtable = {
-    parent_uuid_copy, parent_uuid_destroy, parent_uuid_cmp};
-
-}  // namespace
-
-grpc_arg MakeParentUuidArg(intptr_t parent_uuid) {
-  // We would ideally like to store the uuid in an integer argument.
-  // Unfortunately, that won't work, because intptr_t (the type used for
-  // uuids) doesn't fit in an int (the type used for integer args).
-  // So instead, we use a hack to store it as a pointer, because
-  // intptr_t should be the same size as void*.
-  static_assert(sizeof(intptr_t) <= sizeof(void*),
-                "can't fit intptr_t inside of void*");
-  return grpc_channel_arg_pointer_create(
-      const_cast<char*>(GRPC_ARG_CHANNELZ_PARENT_UUID),
-      reinterpret_cast<void*>(parent_uuid), &parent_uuid_vtable);
-}
-
-intptr_t GetParentUuidFromArgs(const grpc_channel_args& args) {
-  const grpc_arg* arg =
-      grpc_channel_args_find(&args, GRPC_ARG_CHANNELZ_PARENT_UUID);
-  if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return 0;
-  return reinterpret_cast<intptr_t>(arg->value.pointer.p);
-}
-
-//
 // BaseNode
 //
 
@@ -114,57 +87,55 @@ CallCountingHelper::CallCountingHelper() {
 void CallCountingHelper::RecordCallStarted() {
   AtomicCounterData& data =
       per_cpu_counter_data_storage_[ExecCtx::Get()->starting_cpu()];
-  data.calls_started.FetchAdd(1, MemoryOrder::RELAXED);
-  data.last_call_started_cycle.Store(gpr_get_cycle_counter(),
-                                     MemoryOrder::RELAXED);
+  data.calls_started.fetch_add(1, std::memory_order_relaxed);
+  data.last_call_started_cycle.store(gpr_get_cycle_counter(),
+                                     std::memory_order_relaxed);
 }
 
 void CallCountingHelper::RecordCallFailed() {
   per_cpu_counter_data_storage_[ExecCtx::Get()->starting_cpu()]
-      .calls_failed.FetchAdd(1, MemoryOrder::RELAXED);
+      .calls_failed.fetch_add(1, std::memory_order_relaxed);
 }
 
 void CallCountingHelper::RecordCallSucceeded() {
   per_cpu_counter_data_storage_[ExecCtx::Get()->starting_cpu()]
-      .calls_succeeded.FetchAdd(1, MemoryOrder::RELAXED);
+      .calls_succeeded.fetch_add(1, std::memory_order_relaxed);
 }
 
 void CallCountingHelper::CollectData(CounterData* out) {
   for (size_t core = 0; core < num_cores_; ++core) {
     AtomicCounterData& data = per_cpu_counter_data_storage_[core];
 
-    out->calls_started += data.calls_started.Load(MemoryOrder::RELAXED);
+    out->calls_started += data.calls_started.load(std::memory_order_relaxed);
     out->calls_succeeded +=
-        per_cpu_counter_data_storage_[core].calls_succeeded.Load(
-            MemoryOrder::RELAXED);
-    out->calls_failed += per_cpu_counter_data_storage_[core].calls_failed.Load(
-        MemoryOrder::RELAXED);
+        per_cpu_counter_data_storage_[core].calls_succeeded.load(
+            std::memory_order_relaxed);
+    out->calls_failed += per_cpu_counter_data_storage_[core].calls_failed.load(
+        std::memory_order_relaxed);
     const gpr_cycle_counter last_call =
-        per_cpu_counter_data_storage_[core].last_call_started_cycle.Load(
-            MemoryOrder::RELAXED);
+        per_cpu_counter_data_storage_[core].last_call_started_cycle.load(
+            std::memory_order_relaxed);
     if (last_call > out->last_call_started_cycle) {
       out->last_call_started_cycle = last_call;
     }
   }
 }
 
-void CallCountingHelper::PopulateCallCounts(Json::Object* object) {
+void CallCountingHelper::PopulateCallCounts(Json::Object* json) {
   CounterData data;
   CollectData(&data);
   if (data.calls_started != 0) {
-    (*object)["callsStarted"] = std::to_string(data.calls_started);
+    (*json)["callsStarted"] = std::to_string(data.calls_started);
     gpr_timespec ts = gpr_convert_clock_type(
         gpr_cycle_counter_to_time(data.last_call_started_cycle),
         GPR_CLOCK_REALTIME);
-    char* ts_str = gpr_format_timespec(ts);
-    (*object)["lastCallStartedTimestamp"] = ts_str;
-    gpr_free(ts_str);
+    (*json)["lastCallStartedTimestamp"] = gpr_format_timespec(ts);
   }
   if (data.calls_succeeded != 0) {
-    (*object)["callsSucceeded"] = std::to_string(data.calls_succeeded);
+    (*json)["callsSucceeded"] = std::to_string(data.calls_succeeded);
   }
   if (data.calls_failed) {
-    (*object)["callsFailed"] = std::to_string(data.calls_failed);
+    (*json)["callsFailed"] = std::to_string(data.calls_failed);
   }
 }
 
@@ -173,13 +144,12 @@ void CallCountingHelper::PopulateCallCounts(Json::Object* object) {
 //
 
 ChannelNode::ChannelNode(std::string target, size_t channel_tracer_max_nodes,
-                         intptr_t parent_uuid)
-    : BaseNode(parent_uuid == 0 ? EntityType::kTopLevelChannel
-                                : EntityType::kInternalChannel,
+                         bool is_internal_channel)
+    : BaseNode(is_internal_channel ? EntityType::kInternalChannel
+                                   : EntityType::kTopLevelChannel,
                target),
       target_(std::move(target)),
-      trace_(channel_tracer_max_nodes),
-      parent_uuid_(parent_uuid) {}
+      trace_(channel_tracer_max_nodes) {}
 
 const char* ChannelNode::GetChannelConnectivityStateChangeString(
     grpc_connectivity_state state) {
@@ -204,7 +174,7 @@ Json ChannelNode::RenderJson() {
   };
   // Connectivity state.
   // If low-order bit is on, then the field is set.
-  int state_field = connectivity_state_.Load(MemoryOrder::RELAXED);
+  int state_field = connectivity_state_.load(std::memory_order_relaxed);
   if ((state_field & 1) != 0) {
     grpc_connectivity_state state =
         static_cast<grpc_connectivity_state>(state_field >> 1);
@@ -237,18 +207,18 @@ void ChannelNode::PopulateChildRefs(Json::Object* json) {
   MutexLock lock(&child_mu_);
   if (!child_subchannels_.empty()) {
     Json::Array array;
-    for (const auto& p : child_subchannels_) {
+    for (intptr_t subchannel_uuid : child_subchannels_) {
       array.emplace_back(Json::Object{
-          {"subchannelId", std::to_string(p.first)},
+          {"subchannelId", std::to_string(subchannel_uuid)},
       });
     }
     (*json)["subchannelRef"] = std::move(array);
   }
   if (!child_channels_.empty()) {
     Json::Array array;
-    for (const auto& p : child_channels_) {
+    for (intptr_t channel_uuid : child_channels_) {
       array.emplace_back(Json::Object{
-          {"channelId", std::to_string(p.first)},
+          {"channelId", std::to_string(channel_uuid)},
       });
     }
     (*json)["channelRef"] = std::move(array);
@@ -258,12 +228,12 @@ void ChannelNode::PopulateChildRefs(Json::Object* json) {
 void ChannelNode::SetConnectivityState(grpc_connectivity_state state) {
   // Store with low-order bit set to indicate that the field is set.
   int state_field = (state << 1) + 1;
-  connectivity_state_.Store(state_field, MemoryOrder::RELAXED);
+  connectivity_state_.store(state_field, std::memory_order_relaxed);
 }
 
 void ChannelNode::AddChildChannel(intptr_t child_uuid) {
   MutexLock lock(&child_mu_);
-  child_channels_.insert(std::make_pair(child_uuid, true));
+  child_channels_.insert(child_uuid);
 }
 
 void ChannelNode::RemoveChildChannel(intptr_t child_uuid) {
@@ -273,7 +243,7 @@ void ChannelNode::RemoveChildChannel(intptr_t child_uuid) {
 
 void ChannelNode::AddChildSubchannel(intptr_t child_uuid) {
   MutexLock lock(&child_mu_);
-  child_subchannels_.insert(std::make_pair(child_uuid, true));
+  child_subchannels_.insert(child_uuid);
 }
 
 void ChannelNode::RemoveChildSubchannel(intptr_t child_uuid) {
@@ -285,7 +255,7 @@ void ChannelNode::RemoveChildSubchannel(intptr_t child_uuid) {
 // ServerNode
 //
 
-ServerNode::ServerNode(grpc_server* /*server*/, size_t channel_tracer_max_nodes)
+ServerNode::ServerNode(size_t channel_tracer_max_nodes)
     : BaseNode(EntityType::kServer, ""), trace_(channel_tracer_max_nodes) {}
 
 ServerNode::~ServerNode() {}
@@ -312,27 +282,26 @@ void ServerNode::RemoveChildListenSocket(intptr_t child_uuid) {
 
 std::string ServerNode::RenderServerSockets(intptr_t start_socket_id,
                                             intptr_t max_results) {
+  GPR_ASSERT(start_socket_id >= 0);
+  GPR_ASSERT(max_results >= 0);
   // If user does not set max_results, we choose 500.
   size_t pagination_limit = max_results == 0 ? 500 : max_results;
   Json::Object object;
   {
     MutexLock lock(&child_mu_);
     size_t sockets_rendered = 0;
-    if (!child_sockets_.empty()) {
-      // Create list of socket refs.
-      Json::Array array;
-      const size_t limit = GPR_MIN(child_sockets_.size(), pagination_limit);
-      for (auto it = child_sockets_.lower_bound(start_socket_id);
-           it != child_sockets_.end() && sockets_rendered < limit;
-           ++it, ++sockets_rendered) {
-        array.emplace_back(Json::Object{
-            {"socketId", std::to_string(it->first)},
-            {"name", it->second->name()},
-        });
-      }
-      object["socketRef"] = std::move(array);
+    // Create list of socket refs.
+    Json::Array array;
+    auto it = child_sockets_.lower_bound(start_socket_id);
+    for (; it != child_sockets_.end() && sockets_rendered < pagination_limit;
+         ++it, ++sockets_rendered) {
+      array.emplace_back(Json::Object{
+          {"socketId", std::to_string(it->first)},
+          {"name", it->second->name()},
+      });
     }
-    if (sockets_rendered == child_sockets_.size()) object["end"] = true;
+    object["socketRef"] = std::move(array);
+    if (it == child_sockets_.end()) object["end"] = true;
   }
   Json json = std::move(object);
   return json.Dump();
@@ -373,6 +342,83 @@ Json ServerNode::RenderJson() {
 }
 
 //
+// SocketNode::Security::Tls
+//
+
+Json SocketNode::Security::Tls::RenderJson() {
+  Json::Object data;
+  if (type == NameType::kStandardName) {
+    data["standard_name"] = name;
+  } else if (type == NameType::kOtherName) {
+    data["other_name"] = name;
+  }
+  if (!local_certificate.empty()) {
+    data["local_certificate"] = absl::Base64Escape(local_certificate);
+  }
+  if (!remote_certificate.empty()) {
+    data["remote_certificate"] = absl::Base64Escape(remote_certificate);
+  }
+  return data;
+}
+
+//
+// SocketNode::Security
+//
+
+Json SocketNode::Security::RenderJson() {
+  Json::Object data;
+  switch (type) {
+    case ModelType::kUnset:
+      break;
+    case ModelType::kTls:
+      if (tls) {
+        data["tls"] = tls->RenderJson();
+      }
+      break;
+    case ModelType::kOther:
+      if (other) {
+        data["other"] = *other;
+      }
+      break;
+  }
+  return data;
+}
+
+namespace {
+
+void* SecurityArgCopy(void* p) {
+  SocketNode::Security* xds_certificate_provider =
+      static_cast<SocketNode::Security*>(p);
+  return xds_certificate_provider->Ref().release();
+}
+
+void SecurityArgDestroy(void* p) {
+  SocketNode::Security* xds_certificate_provider =
+      static_cast<SocketNode::Security*>(p);
+  xds_certificate_provider->Unref();
+}
+
+int SecurityArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
+
+const grpc_arg_pointer_vtable kChannelArgVtable = {
+    SecurityArgCopy, SecurityArgDestroy, SecurityArgCmp};
+
+}  // namespace
+
+grpc_arg SocketNode::Security::MakeChannelArg() const {
+  return grpc_channel_arg_pointer_create(
+      const_cast<char*>(GRPC_ARG_CHANNELZ_SECURITY),
+      const_cast<SocketNode::Security*>(this), &kChannelArgVtable);
+}
+
+RefCountedPtr<SocketNode::Security> SocketNode::Security::GetFromChannelArgs(
+    const grpc_channel_args* args) {
+  Security* security = grpc_channel_args_find_pointer<Security>(
+      args, GRPC_ARG_CHANNELZ_SECURITY);
+  return security != nullptr ? security->Ref() : nullptr;
+}
+
+//
 // SocketNode
 //
 
@@ -382,127 +428,129 @@ void PopulateSocketAddressJson(Json::Object* json, const char* name,
                                const char* addr_str) {
   if (addr_str == nullptr) return;
   Json::Object data;
-  grpc_uri* uri = grpc_uri_parse(addr_str, true);
-  if ((uri != nullptr) && ((strcmp(uri->scheme, "ipv4") == 0) ||
-                           (strcmp(uri->scheme, "ipv6") == 0))) {
-    const char* host_port = uri->path;
-    if (*host_port == '/') ++host_port;
-    grpc_core::UniquePtr<char> host;
-    grpc_core::UniquePtr<char> port;
-    GPR_ASSERT(SplitHostPort(host_port, &host, &port));
+  absl::StatusOr<URI> uri = URI::Parse(addr_str);
+  if (uri.ok() && (uri->scheme() == "ipv4" || uri->scheme() == "ipv6")) {
+    std::string host;
+    std::string port;
+    GPR_ASSERT(
+        SplitHostPort(absl::StripPrefix(uri->path(), "/"), &host, &port));
     int port_num = -1;
-    if (port != nullptr) {
-      port_num = atoi(port.get());
+    if (!port.empty()) {
+      port_num = atoi(port.data());
     }
-    char* b64_host =
-        grpc_base64_encode(host.get(), strlen(host.get()), false, false);
-    data["tcpip_address"] = Json::Object{
-        {"port", port_num},
-        {"ip_address", b64_host},
-    };
-    gpr_free(b64_host);
-  } else if (uri != nullptr && strcmp(uri->scheme, "unix") == 0) {
+    grpc_resolved_address resolved_host;
+    grpc_error_handle error =
+        grpc_string_to_sockaddr(&resolved_host, host.c_str(), port_num);
+    if (error == GRPC_ERROR_NONE) {
+      std::string packed_host = grpc_sockaddr_get_packed_host(&resolved_host);
+      std::string b64_host = absl::Base64Escape(packed_host);
+      data["tcpip_address"] = Json::Object{
+          {"port", port_num},
+          {"ip_address", b64_host},
+      };
+      (*json)[name] = std::move(data);
+      return;
+    }
+    GRPC_ERROR_UNREF(error);
+  }
+  if (uri.ok() && uri->scheme() == "unix") {
     data["uds_address"] = Json::Object{
-        {"filename", uri->path},
+        {"filename", uri->path()},
     };
   } else {
     data["other_address"] = Json::Object{
         {"name", addr_str},
     };
   }
-  grpc_uri_destroy(uri);
   (*json)[name] = std::move(data);
 }
 
 }  // namespace
 
-SocketNode::SocketNode(std::string local, std::string remote, std::string name)
+SocketNode::SocketNode(std::string local, std::string remote, std::string name,
+                       RefCountedPtr<Security> security)
     : BaseNode(EntityType::kSocket, std::move(name)),
       local_(std::move(local)),
-      remote_(std::move(remote)) {}
+      remote_(std::move(remote)),
+      security_(std::move(security)) {}
 
 void SocketNode::RecordStreamStartedFromLocal() {
-  streams_started_.FetchAdd(1, MemoryOrder::RELAXED);
-  last_local_stream_created_cycle_.Store(gpr_get_cycle_counter(),
-                                         MemoryOrder::RELAXED);
+  streams_started_.fetch_add(1, std::memory_order_relaxed);
+  last_local_stream_created_cycle_.store(gpr_get_cycle_counter(),
+                                         std::memory_order_relaxed);
 }
 
 void SocketNode::RecordStreamStartedFromRemote() {
-  streams_started_.FetchAdd(1, MemoryOrder::RELAXED);
-  last_remote_stream_created_cycle_.Store(gpr_get_cycle_counter(),
-                                          MemoryOrder::RELAXED);
+  streams_started_.fetch_add(1, std::memory_order_relaxed);
+  last_remote_stream_created_cycle_.store(gpr_get_cycle_counter(),
+                                          std::memory_order_relaxed);
 }
 
 void SocketNode::RecordMessagesSent(uint32_t num_sent) {
-  messages_sent_.FetchAdd(num_sent, MemoryOrder::RELAXED);
-  last_message_sent_cycle_.Store(gpr_get_cycle_counter(), MemoryOrder::RELAXED);
+  messages_sent_.fetch_add(num_sent, std::memory_order_relaxed);
+  last_message_sent_cycle_.store(gpr_get_cycle_counter(),
+                                 std::memory_order_relaxed);
 }
 
 void SocketNode::RecordMessageReceived() {
-  messages_received_.FetchAdd(1, MemoryOrder::RELAXED);
-  last_message_received_cycle_.Store(gpr_get_cycle_counter(),
-                                     MemoryOrder::RELAXED);
+  messages_received_.fetch_add(1, std::memory_order_relaxed);
+  last_message_received_cycle_.store(gpr_get_cycle_counter(),
+                                     std::memory_order_relaxed);
 }
 
 Json SocketNode::RenderJson() {
   // Create and fill the data child.
   Json::Object data;
   gpr_timespec ts;
-  int64_t streams_started = streams_started_.Load(MemoryOrder::RELAXED);
+  int64_t streams_started = streams_started_.load(std::memory_order_relaxed);
   if (streams_started != 0) {
     data["streamsStarted"] = std::to_string(streams_started);
     gpr_cycle_counter last_local_stream_created_cycle =
-        last_local_stream_created_cycle_.Load(MemoryOrder::RELAXED);
+        last_local_stream_created_cycle_.load(std::memory_order_relaxed);
     if (last_local_stream_created_cycle != 0) {
       ts = gpr_convert_clock_type(
           gpr_cycle_counter_to_time(last_local_stream_created_cycle),
           GPR_CLOCK_REALTIME);
-      char* ts_str = gpr_format_timespec(ts);
-      data["lastLocalStreamCreatedTimestamp"] = ts_str;
-      gpr_free(ts_str);
+      data["lastLocalStreamCreatedTimestamp"] = gpr_format_timespec(ts);
     }
     gpr_cycle_counter last_remote_stream_created_cycle =
-        last_remote_stream_created_cycle_.Load(MemoryOrder::RELAXED);
+        last_remote_stream_created_cycle_.load(std::memory_order_relaxed);
     if (last_remote_stream_created_cycle != 0) {
       ts = gpr_convert_clock_type(
           gpr_cycle_counter_to_time(last_remote_stream_created_cycle),
           GPR_CLOCK_REALTIME);
-      char* ts_str = gpr_format_timespec(ts);
-      data["lastRemoteStreamCreatedTimestamp"] = ts_str;
-      gpr_free(ts_str);
+      data["lastRemoteStreamCreatedTimestamp"] = gpr_format_timespec(ts);
     }
   }
-  int64_t streams_succeeded = streams_succeeded_.Load(MemoryOrder::RELAXED);
+  int64_t streams_succeeded =
+      streams_succeeded_.load(std::memory_order_relaxed);
   if (streams_succeeded != 0) {
     data["streamsSucceeded"] = std::to_string(streams_succeeded);
   }
-  int64_t streams_failed = streams_failed_.Load(MemoryOrder::RELAXED);
+  int64_t streams_failed = streams_failed_.load(std::memory_order_relaxed);
   if (streams_failed != 0) {
     data["streamsFailed"] = std::to_string(streams_failed);
   }
-  int64_t messages_sent = messages_sent_.Load(MemoryOrder::RELAXED);
+  int64_t messages_sent = messages_sent_.load(std::memory_order_relaxed);
   if (messages_sent != 0) {
     data["messagesSent"] = std::to_string(messages_sent);
     ts = gpr_convert_clock_type(
         gpr_cycle_counter_to_time(
-            last_message_sent_cycle_.Load(MemoryOrder::RELAXED)),
+            last_message_sent_cycle_.load(std::memory_order_relaxed)),
         GPR_CLOCK_REALTIME);
-    char* ts_str = gpr_format_timespec(ts);
-    data["lastMessageSentTimestamp"] = ts_str;
-    gpr_free(ts_str);
+    data["lastMessageSentTimestamp"] = gpr_format_timespec(ts);
   }
-  int64_t messages_received = messages_received_.Load(MemoryOrder::RELAXED);
+  int64_t messages_received =
+      messages_received_.load(std::memory_order_relaxed);
   if (messages_received != 0) {
     data["messagesReceived"] = std::to_string(messages_received);
     ts = gpr_convert_clock_type(
         gpr_cycle_counter_to_time(
-            last_message_received_cycle_.Load(MemoryOrder::RELAXED)),
+            last_message_received_cycle_.load(std::memory_order_relaxed)),
         GPR_CLOCK_REALTIME);
-    char* ts_str = gpr_format_timespec(ts);
-    data["lastMessageReceivedTimestamp"] = ts_str;
-    gpr_free(ts_str);
+    data["lastMessageReceivedTimestamp"] = gpr_format_timespec(ts);
   }
-  int64_t keepalives_sent = keepalives_sent_.Load(MemoryOrder::RELAXED);
+  int64_t keepalives_sent = keepalives_sent_.load(std::memory_order_relaxed);
   if (keepalives_sent != 0) {
     data["keepAlivesSent"] = std::to_string(keepalives_sent);
   }
@@ -515,6 +563,10 @@ Json SocketNode::RenderJson() {
        }},
       {"data", std::move(data)},
   };
+  if (security_ != nullptr &&
+      security_->type != SocketNode::Security::ModelType::kUnset) {
+    object["security"] = security_->RenderJson();
+  }
   PopulateSocketAddressJson(&object, "remote", remote_.c_str());
   PopulateSocketAddressJson(&object, "local", local_.c_str());
   return object;