diff options
-rw-r--r-- | src/core/ext/transport/chttp2/transport/chttp2_transport.cc | 14 | ||||
-rw-r--r-- | src/core/lib/channel/channelz.cc | 77 | ||||
-rw-r--r-- | src/core/lib/channel/channelz.h | 42 | ||||
-rw-r--r-- | src/core/lib/gpr/string.cc | 45 | ||||
-rw-r--r-- | src/core/lib/gpr/string.h | 3 |
5 files changed, 159 insertions, 22 deletions
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 5168e4555e..0179831328 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -397,11 +397,14 @@ static bool read_channel_args(grpc_chttp2_transport* t, } } if (channelz_enabled) { + grpc_core::channelz::SocketAddress remote; + grpc_core::channelz::SocketAddress local; char* host = nullptr; int port_num = -1; // try to pick out just the host port (maybe trims off scheme prefix). grpc_uri* uri = grpc_uri_parse(t->peer_string, true); // if peer string was a valid URI, we can use our lib to do the trimming. + // TODO(ncteisen): handle UDS address. if (uri != nullptr) { const char* host_port = uri->path; if (*host_port == '/') ++host_port; @@ -410,15 +413,22 @@ static bool read_channel_args(grpc_chttp2_transport* t, if (port != nullptr) { port_num = atoi(port); } + remote.set_blob(gpr_string_base64_encode(host)); + remote.set_port(port_num); + remote.set_type( + grpc_core::channelz::SocketAddress::AddressType::kTcpAddress); + gpr_free(host); gpr_free(port); } else { // if peer string is not a valid URI, just use the entire string to // surface that info. - host = gpr_strdup(t->peer_string); + remote.set_blob(gpr_strdup(t->peer_string)); + remote.set_type(grpc_core::channelz::SocketAddress::AddressType:: + kDirectChannelAddress); } t->channelz_socket = grpc_core::MakeRefCounted<grpc_core::channelz::SocketNode>( - grpc_core::UniquePtr<char>(host), port_num); + std::move(local), std::move(remote)); grpc_uri_destroy(uri); } return enable_bdp; diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 6da8a172b5..d8c826c54d 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -277,10 +277,65 @@ grpc_json* ServerNode::RenderJson() { return top_level_json; } -SocketNode::SocketNode(UniquePtr<char> remote_host, int remote_port) +SocketAddress::SocketAddress() : type_(AddressType::kUnset), port_(-1) {} + +SocketAddress::SocketAddress(SocketAddress&& other) { + type_ = other.type_; + port_ = other.port_; + blob_.reset((other.blob_.release())); +} + +void SocketAddress::PopulateJson(const char* name, grpc_json* json) { + if (type_ == AddressType::kUnset) { + return; + } + grpc_json* json_iterator = nullptr; + json_iterator = grpc_json_create_child(json_iterator, json, name, nullptr, + GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + switch (type_) { + case AddressType::kTcpAddress: + json_iterator = + grpc_json_create_child(json_iterator, json, "tcpip_address", nullptr, + GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = + grpc_json_add_number_string_child(json, json_iterator, "port", port_); + json_iterator = + grpc_json_create_child(json_iterator, json, "ip_address", blob_.get(), + GRPC_JSON_STRING, false); + break; + case AddressType::kUdsAddress: + json_iterator = grpc_json_create_child(json_iterator, json, "uds_address", + nullptr, GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = + grpc_json_create_child(json_iterator, json, "filename", blob_.get(), + GRPC_JSON_STRING, false); + break; + case AddressType::kDirectChannelAddress: + json_iterator = + grpc_json_create_child(json_iterator, json, "other_address", nullptr, + GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = grpc_json_create_child( + json_iterator, json, "name", blob_.get(), GRPC_JSON_STRING, false); + break; + break; + default: + GPR_UNREACHABLE_CODE(GPR_ASSERT(0)); + break; + } +} + +SocketNode::SocketNode(SocketAddress local, SocketAddress remote) : BaseNode(EntityType::kSocket), - remote_host_(std::move(remote_host)), - remote_port_(remote_port) {} + local_(std::move(local)), + remote_(std::move(remote)) {} void SocketNode::RecordStreamStartedFromLocal() { gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1)); @@ -319,20 +374,8 @@ grpc_json* SocketNode::RenderJson() { json_iterator = grpc_json_add_number_string_child(json, json_iterator, "socketId", uuid()); json = top_level_json; - json_iterator = nullptr; - json_iterator = grpc_json_create_child(json_iterator, json, "remote", nullptr, - GRPC_JSON_OBJECT, false); - json = json_iterator; - json_iterator = nullptr; - json_iterator = grpc_json_create_child(json_iterator, json, "tcpip_address", - nullptr, GRPC_JSON_OBJECT, false); - json = json_iterator; - json_iterator = nullptr; - json_iterator = grpc_json_add_number_string_child(json, json_iterator, "port", - remote_port_); - json_iterator = - grpc_json_create_child(json_iterator, json, "ip_address", - remote_host_.get(), GRPC_JSON_STRING, false); + remote_.PopulateJson("remote", json); + local_.PopulateJson("local", json); // reset json iterators to top level object json = top_level_json; json_iterator = nullptr; diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 404d8341ff..70efbd861d 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -229,10 +229,45 @@ class ServerNode : public BaseNode { ChannelTrace trace_; }; +// helper class for holding and rendering the information about a particular +// socket's address +class SocketAddress { + public: + enum class AddressType { + kUnset, + kTcpAddress, + kUdsAddress, + kDirectChannelAddress, + }; + + SocketAddress(); + SocketAddress(SocketAddress&& other); + + void PopulateJson(const char* name, grpc_json* json); + + void set_blob(char* blob) { blob_.reset(blob); } + void set_port(int port) { port_ = port; } + void set_type(AddressType type) { type_ = type; } + + const char* blob_view() { return blob_.get(); } + int port() { return port_; } + AddressType type() { return type_; } + + private: + AddressType type_; + // this holds different information for different address types: + // kTcpAddress = host + // kUdsAddress = filename + // kDirectChannelAddress = name (which is fd num) + UniquePtr<char> blob_; + // used for kTcpAddress, otherwise -1 + int port_; +}; + // Handles channelz bookkeeping for sockets class SocketNode : public BaseNode { public: - SocketNode(UniquePtr<char> remote_host, int remote_port); + SocketNode(SocketAddress local, SocketAddress remote); ~SocketNode() override {} grpc_json* RenderJson() override; @@ -262,14 +297,15 @@ class SocketNode : public BaseNode { gpr_atm last_remote_stream_created_millis_ = 0; gpr_atm last_message_sent_millis_ = 0; gpr_atm last_message_received_millis_ = 0; - UniquePtr<char> remote_host_; - int remote_port_; + SocketAddress local_; + SocketAddress remote_; }; // Handles channelz bookkeeping for listen sockets class ListenSocketNode : public BaseNode { public: // ListenSocketNode takes ownership of host. + // TODO(ncteisen): use SocketAddress to support more address types. ListenSocketNode(UniquePtr<char> host, int port); ~ListenSocketNode() override {} diff --git a/src/core/lib/gpr/string.cc b/src/core/lib/gpr/string.cc index 0a76fc1f54..5672b7a2b9 100644 --- a/src/core/lib/gpr/string.cc +++ b/src/core/lib/gpr/string.cc @@ -156,6 +156,51 @@ int gpr_parse_bytes_to_uint32(const char* buf, size_t len, uint32_t* result) { return 1; } +static const char alphabet[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const uint8_t tail_xtra[3] = {0, 2, 3}; + +char* gpr_string_base64_encode(const char* in) { + size_t in_len = strlen(in); + size_t in_triplets = in_len / 3; + size_t tail_case = in_len % 3; + size_t out_length = in_triplets * 4 + tail_xtra[tail_case]; + char* output = static_cast<char*>(gpr_malloc(out_length + 1)); + char* out = output; + size_t i; + + /* encode full triplets */ + for (i = 0; i < in_triplets; i++) { + out[0] = alphabet[in[0] >> 2]; + out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)]; + out[2] = alphabet[((in[1] & 0xf) << 2) | (in[2] >> 6)]; + out[3] = alphabet[in[2] & 0x3f]; + out += 4; + in += 3; + } + + /* encode the remaining bytes */ + switch (tail_case) { + case 0: + break; + case 1: + out[0] = alphabet[in[0] >> 2]; + out[1] = alphabet[(in[0] & 0x3) << 4]; + out += 2; + in += 1; + break; + case 2: + out[0] = alphabet[in[0] >> 2]; + out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)]; + out[2] = alphabet[(in[1] & 0xf) << 2]; + out += 3; + in += 2; + break; + } + out[0] = '\0'; + return output; +} + void gpr_reverse_bytes(char* str, int len) { char *p1, *p2; for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) { diff --git a/src/core/lib/gpr/string.h b/src/core/lib/gpr/string.h index ce51fe4632..1bb50196e8 100644 --- a/src/core/lib/gpr/string.h +++ b/src/core/lib/gpr/string.h @@ -41,6 +41,9 @@ char* gpr_dump(const char* buf, size_t len, uint32_t flags); int gpr_parse_bytes_to_uint32(const char* data, size_t length, uint32_t* result); +/* returns allocated string with the base64 encoding of in */ +char* gpr_string_base64_encode(const char* in); + /* Minimum buffer size for calling ltoa */ #define GPR_LTOA_MIN_BUFSIZE (3 * sizeof(long)) |