diff options
Diffstat (limited to 'src/core/lib/channel')
-rw-r--r-- | src/core/lib/channel/channel_args.cc | 28 | ||||
-rw-r--r-- | src/core/lib/channel/channel_args.h | 4 | ||||
-rw-r--r-- | src/core/lib/channel/channel_trace.cc | 239 | ||||
-rw-r--r-- | src/core/lib/channel/channel_trace.h | 133 | ||||
-rw-r--r-- | src/core/lib/channel/channel_trace_registry.cc | 80 | ||||
-rw-r--r-- | src/core/lib/channel/channel_trace_registry.h | 43 | ||||
-rw-r--r-- | src/core/lib/channel/handshaker.cc | 47 | ||||
-rw-r--r-- | src/core/lib/channel/handshaker.h | 4 | ||||
-rw-r--r-- | src/core/lib/channel/handshaker_factory.h | 1 | ||||
-rw-r--r-- | src/core/lib/channel/handshaker_registry.h | 1 | ||||
-rw-r--r-- | src/core/lib/channel/status_util.cc | 100 | ||||
-rw-r--r-- | src/core/lib/channel/status_util.h | 58 |
12 files changed, 736 insertions, 2 deletions
diff --git a/src/core/lib/channel/channel_args.cc b/src/core/lib/channel/channel_args.cc index 66a86c2286..e49d532e11 100644 --- a/src/core/lib/channel/channel_args.cc +++ b/src/core/lib/channel/channel_args.cc @@ -411,3 +411,31 @@ grpc_arg grpc_channel_arg_pointer_create( arg.value.pointer.vtable = vtable; return arg; } + +char* grpc_channel_args_string(const grpc_channel_args* args) { + if (args == nullptr) return nullptr; + gpr_strvec v; + gpr_strvec_init(&v); + for (size_t i = 0; i < args->num_args; ++i) { + const grpc_arg& arg = args->args[i]; + char* s; + switch (arg.type) { + case GRPC_ARG_INTEGER: + gpr_asprintf(&s, "%s=%d", arg.key, arg.value.integer); + break; + case GRPC_ARG_STRING: + gpr_asprintf(&s, "%s=%s", arg.key, arg.value.string); + break; + case GRPC_ARG_POINTER: + gpr_asprintf(&s, "%s=%p", arg.key, arg.value.pointer.p); + break; + default: + gpr_asprintf(&s, "arg with unknown type"); + } + gpr_strvec_add(&v, s); + } + char* result = + gpr_strjoin_sep(const_cast<const char**>(v.strs), v.count, ", ", nullptr); + gpr_strvec_destroy(&v); + return result; +} diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index c0d6a17356..5ff303a9dc 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -124,4 +124,8 @@ grpc_arg grpc_channel_arg_integer_create(char* name, int value); grpc_arg grpc_channel_arg_pointer_create(char* name, void* value, const grpc_arg_pointer_vtable* vtable); +// Returns a string representing channel args in human-readable form. +// Callers takes ownership of result. +char* grpc_channel_args_string(const grpc_channel_args* args); + #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H */ diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc new file mode 100644 index 0000000000..654300cd32 --- /dev/null +++ b/src/core/lib/channel/channel_trace.cc @@ -0,0 +1,239 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/impl/codegen/port_platform.h> + +#include "src/core/lib/channel/channel_trace.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/channel/channel_trace_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/memory.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/error_utils.h" + +namespace grpc_core { + +ChannelTrace::TraceEvent::TraceEvent( + Severity severity, grpc_slice data, + RefCountedPtr<ChannelTrace> referenced_tracer, ReferencedType type) + : severity_(severity), + data_(data), + timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), + GPR_CLOCK_REALTIME)), + next_(nullptr), + referenced_tracer_(std::move(referenced_tracer)), + referenced_type_(type) {} + +ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data) + : severity_(severity), + data_(data), + timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), + GPR_CLOCK_REALTIME)), + next_(nullptr) {} + +ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); } + +ChannelTrace::ChannelTrace(size_t max_events) + : channel_uuid_(-1), + num_events_logged_(0), + list_size_(0), + max_list_size_(max_events), + head_trace_(nullptr), + tail_trace_(nullptr) { + if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 + gpr_mu_init(&tracer_mu_); + channel_uuid_ = grpc_channel_trace_registry_register_channel_trace(this); + time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), + GPR_CLOCK_REALTIME); +} + +ChannelTrace::~ChannelTrace() { + if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 + TraceEvent* it = head_trace_; + while (it != nullptr) { + TraceEvent* to_free = it; + it = it->next(); + Delete<TraceEvent>(to_free); + } + grpc_channel_trace_registry_unregister_channel_trace(channel_uuid_); + gpr_mu_destroy(&tracer_mu_); +} + +intptr_t ChannelTrace::GetUuid() const { return channel_uuid_; } + +void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) { + ++num_events_logged_; + // first event case + if (head_trace_ == nullptr) { + head_trace_ = tail_trace_ = new_trace_event; + } + // regular event add case + else { + tail_trace_->set_next(new_trace_event); + tail_trace_ = tail_trace_->next(); + } + ++list_size_; + // maybe garbage collect the end + if (list_size_ > max_list_size_) { + TraceEvent* to_free = head_trace_; + head_trace_ = head_trace_->next(); + Delete<TraceEvent>(to_free); + --list_size_; + } +} + +void ChannelTrace::AddTraceEvent(Severity severity, grpc_slice data) { + if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 + AddTraceEventHelper(New<TraceEvent>(severity, data)); +} + +void ChannelTrace::AddTraceEventReferencingChannel( + Severity severity, grpc_slice data, + RefCountedPtr<ChannelTrace> referenced_tracer) { + if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 + // create and fill up the new event + AddTraceEventHelper( + New<TraceEvent>(severity, data, std::move(referenced_tracer), Channel)); +} + +void ChannelTrace::AddTraceEventReferencingSubchannel( + Severity severity, grpc_slice data, + RefCountedPtr<ChannelTrace> referenced_tracer) { + if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 + // create and fill up the new event + AddTraceEventHelper(New<TraceEvent>( + severity, data, std::move(referenced_tracer), Subchannel)); +} + +namespace { + +// returns an allocated string that represents tm according to RFC-3339, and, +// more specifically, follows: +// https://developers.google.com/protocol-buffers/docs/proto3#json +// +// "Uses RFC 3339, where generated output will always be Z-normalized and uses +// 0, 3, 6 or 9 fractional digits." +char* fmt_time(gpr_timespec tm) { + char time_buffer[35]; + char ns_buffer[11]; // '.' + 9 digits of precision + struct tm* tm_info = localtime((const time_t*)&tm.tv_sec); + strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", tm_info); + snprintf(ns_buffer, 11, ".%09d", tm.tv_nsec); + // This loop trims off trailing zeros by inserting a null character that the + // right point. We iterate in chunks of three because we want 0, 3, 6, or 9 + // fractional digits. + for (int i = 7; i >= 1; i -= 3) { + if (ns_buffer[i] == '0' && ns_buffer[i + 1] == '0' && + ns_buffer[i + 2] == '0') { + ns_buffer[i] = '\0'; + // Edge case in which all fractional digits were 0. + if (i == 1) { + ns_buffer[0] = '\0'; + } + } else { + break; + } + } + char* full_time_str; + gpr_asprintf(&full_time_str, "%s%sZ", time_buffer, ns_buffer); + return full_time_str; +} + +const char* severity_string(ChannelTrace::Severity severity) { + switch (severity) { + case ChannelTrace::Severity::Info: + return "CT_INFO"; + case ChannelTrace::Severity::Warning: + return "CT_WARNING"; + case ChannelTrace::Severity::Error: + return "CT_ERROR"; + default: + GPR_UNREACHABLE_CODE(return "CT_UNKNOWN"); + } +} + +} // anonymous namespace + +void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const { + grpc_json* json_iterator = nullptr; + json_iterator = grpc_json_create_child(json_iterator, json, "description", + grpc_slice_to_c_string(data_), + GRPC_JSON_STRING, true); + json_iterator = grpc_json_create_child(json_iterator, json, "severity", + severity_string(severity_), + GRPC_JSON_STRING, false); + json_iterator = + grpc_json_create_child(json_iterator, json, "timestamp", + fmt_time(timestamp_), GRPC_JSON_STRING, true); + if (referenced_tracer_ != nullptr) { + char* uuid_str; + gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_tracer_->channel_uuid_); + grpc_json* child_ref = grpc_json_create_child( + json_iterator, json, + (referenced_type_ == Channel) ? "channelRef" : "subchannelRef", nullptr, + GRPC_JSON_OBJECT, false); + json_iterator = grpc_json_create_child( + nullptr, child_ref, + (referenced_type_ == Channel) ? "channelId" : "subchannelId", uuid_str, + GRPC_JSON_STRING, true); + json_iterator = child_ref; + } +} + +char* ChannelTrace::RenderTrace() const { + if (!max_list_size_) + return nullptr; // tracing is disabled if max_events == 0 + grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT); + char* num_events_logged_str; + gpr_asprintf(&num_events_logged_str, "%" PRId64, num_events_logged_); + grpc_json* json_iterator = nullptr; + json_iterator = + grpc_json_create_child(json_iterator, json, "numEventsLogged", + num_events_logged_str, GRPC_JSON_STRING, true); + json_iterator = + grpc_json_create_child(json_iterator, json, "creationTime", + fmt_time(time_created_), GRPC_JSON_STRING, true); + grpc_json* events = grpc_json_create_child(json_iterator, json, "events", + nullptr, GRPC_JSON_ARRAY, false); + json_iterator = nullptr; + TraceEvent* it = head_trace_; + while (it != nullptr) { + json_iterator = grpc_json_create_child(json_iterator, events, nullptr, + nullptr, GRPC_JSON_OBJECT, false); + it->RenderTraceEvent(json_iterator); + it = it->next(); + } + char* json_str = grpc_json_dump_to_string(json, 0); + grpc_json_destroy(json); + return json_str; +} + +} // namespace grpc_core diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h new file mode 100644 index 0000000000..1df1e585f2 --- /dev/null +++ b/src/core/lib/channel/channel_trace.h @@ -0,0 +1,133 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H +#define GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H + +#include <grpc/impl/codegen/port_platform.h> + +#include <grpc/grpc.h> +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/json/json.h" + +namespace grpc_core { + +// Object used to hold live data for a channel. This data is exposed via the +// channelz service: +// https://github.com/grpc/proposal/blob/master/A14-channelz.md +class ChannelTrace : public RefCounted<ChannelTrace> { + public: + ChannelTrace(size_t max_events); + ~ChannelTrace(); + + // returns the tracer's uuid + intptr_t GetUuid() const; + + enum Severity { + Unset = 0, // never to be used + Info, // we start at 1 to avoid using proto default values + Warning, + Error + }; + + // Adds a new trace event to the tracing object + // + // TODO(ncteisen): as this call is used more and more throughout the gRPC + // stack, determine if it makes more sense to accept a char* instead of a + // slice. + void AddTraceEvent(Severity severity, grpc_slice data); + + // Adds a new trace event to the tracing object. This trace event refers to a + // an event on a child of the channel. For example, if this channel has + // created a new subchannel, then it would record that with a TraceEvent + // referencing the new subchannel. + // + // TODO(ncteisen): Once channelz is implemented, the events should reference + // the overall channelz object, not just the ChannelTrace object. + // TODO(ncteisen): as this call is used more and more throughout the gRPC + // stack, determine if it makes more sense to accept a char* instead of a + // slice. + void AddTraceEventReferencingChannel( + Severity severity, grpc_slice data, + RefCountedPtr<ChannelTrace> referenced_tracer); + void AddTraceEventReferencingSubchannel( + Severity severity, grpc_slice data, + RefCountedPtr<ChannelTrace> referenced_tracer); + + // Returns the tracing data rendered as a grpc json string. + // The string is owned by the caller and must be freed. + char* RenderTrace() const; + + private: + // Types of objects that can be references by trace events. + enum ReferencedType { Channel, Subchannel }; + // Private class to encapsulate all the data and bookkeeping needed for a + // a trace event. + class TraceEvent { + public: + // Constructor for a TraceEvent that references a different channel. + // TODO(ncteisen): once channelz is implemented, this should reference the + // overall channelz object, not just the ChannelTrace object + TraceEvent(Severity severity, grpc_slice data, + RefCountedPtr<ChannelTrace> referenced_tracer, + ReferencedType type); + + // Constructor for a TraceEvent that does not reverence a different + // channel. + TraceEvent(Severity severity, grpc_slice data); + + ~TraceEvent(); + + // Renders the data inside of this TraceEvent into a json object. This is + // used by the ChannelTrace, when it is rendering itself. + void RenderTraceEvent(grpc_json* json) const; + + // set and get for the next_ pointer. + TraceEvent* next() const { return next_; } + void set_next(TraceEvent* next) { next_ = next; } + + private: + Severity severity_; + grpc_slice data_; + gpr_timespec timestamp_; + TraceEvent* next_; + // the tracer object for the (sub)channel that this trace event refers to. + RefCountedPtr<ChannelTrace> referenced_tracer_; + // the type that the referenced tracer points to. Unused if this trace + // does not point to any channel or subchannel + ReferencedType referenced_type_; + }; // TraceEvent + + // Internal helper to add and link in a trace event + void AddTraceEventHelper(TraceEvent* new_trace_event); + + gpr_mu tracer_mu_; + intptr_t channel_uuid_; + uint64_t num_events_logged_; + size_t list_size_; + size_t max_list_size_; + TraceEvent* head_trace_; + TraceEvent* tail_trace_; + gpr_timespec time_created_; +}; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H */ diff --git a/src/core/lib/channel/channel_trace_registry.cc b/src/core/lib/channel/channel_trace_registry.cc new file mode 100644 index 0000000000..6c82431467 --- /dev/null +++ b/src/core/lib/channel/channel_trace_registry.cc @@ -0,0 +1,80 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/impl/codegen/port_platform.h> + +#include "src/core/lib/avl/avl.h" +#include "src/core/lib/channel/channel_trace.h" +#include "src/core/lib/channel/channel_trace_registry.h" +#include "src/core/lib/gpr/useful.h" + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +// file global lock and avl. +static gpr_mu g_mu; +static grpc_avl g_avl; +static gpr_atm g_uuid = 0; + +// avl vtable for uuid (intptr_t) -> ChannelTrace +// this table is only looking, it does not own anything. +static void destroy_intptr(void* not_used, void* user_data) {} +static void* copy_intptr(void* key, void* user_data) { return key; } +static long compare_intptr(void* key1, void* key2, void* user_data) { + return GPR_ICMP(key1, key2); +} + +static void destroy_channel_trace(void* trace, void* user_data) {} +static void* copy_channel_trace(void* trace, void* user_data) { return trace; } +static const grpc_avl_vtable avl_vtable = { + destroy_intptr, copy_intptr, compare_intptr, destroy_channel_trace, + copy_channel_trace}; + +void grpc_channel_trace_registry_init() { + gpr_mu_init(&g_mu); + g_avl = grpc_avl_create(&avl_vtable); +} + +void grpc_channel_trace_registry_shutdown() { + grpc_avl_unref(g_avl, nullptr); + gpr_mu_destroy(&g_mu); +} + +intptr_t grpc_channel_trace_registry_register_channel_trace( + grpc_core::ChannelTrace* channel_trace) { + intptr_t prior = gpr_atm_no_barrier_fetch_add(&g_uuid, 1); + gpr_mu_lock(&g_mu); + g_avl = grpc_avl_add(g_avl, (void*)prior, channel_trace, nullptr); + gpr_mu_unlock(&g_mu); + return prior; +} + +void grpc_channel_trace_registry_unregister_channel_trace(intptr_t uuid) { + gpr_mu_lock(&g_mu); + g_avl = grpc_avl_remove(g_avl, (void*)uuid, nullptr); + gpr_mu_unlock(&g_mu); +} + +grpc_core::ChannelTrace* grpc_channel_trace_registry_get_channel_trace( + intptr_t uuid) { + gpr_mu_lock(&g_mu); + grpc_core::ChannelTrace* ret = static_cast<grpc_core::ChannelTrace*>( + grpc_avl_get(g_avl, (void*)uuid, nullptr)); + gpr_mu_unlock(&g_mu); + return ret; +} diff --git a/src/core/lib/channel/channel_trace_registry.h b/src/core/lib/channel/channel_trace_registry.h new file mode 100644 index 0000000000..391ecba7de --- /dev/null +++ b/src/core/lib/channel/channel_trace_registry.h @@ -0,0 +1,43 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_REGISTRY_H +#define GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_REGISTRY_H + +#include <grpc/impl/codegen/port_platform.h> + +#include "src/core/lib/channel/channel_trace.h" + +#include <stdint.h> + +// TODO(ncteisen): convert this file to C++ + +void grpc_channel_trace_registry_init(); +void grpc_channel_trace_registry_shutdown(); + +// globally registers a ChannelTrace. Returns its unique uuid +intptr_t grpc_channel_trace_registry_register_channel_trace( + grpc_core::ChannelTrace* channel_trace); +// globally unregisters the ChannelTrace that is associated to uuid. +void grpc_channel_trace_registry_unregister_channel_trace(intptr_t uuid); +// if object with uuid has previously been registered, returns the ChannelTrace +// associated with that uuid. Else returns nullptr. +grpc_core::ChannelTrace* grpc_channel_trace_registry_get_channel_trace( + intptr_t uuid); + +#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_REGISTRY_H */ diff --git a/src/core/lib/channel/handshaker.cc b/src/core/lib/channel/handshaker.cc index 9b1af8d6cb..2faeb64cb6 100644 --- a/src/core/lib/channel/handshaker.cc +++ b/src/core/lib/channel/handshaker.cc @@ -22,11 +22,15 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include <grpc/support/string_util.h> #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker.h" +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/timer.h" +grpc_core::TraceFlag grpc_handshaker_trace(false, "handshaker"); + // // grpc_handshaker // @@ -52,6 +56,10 @@ void grpc_handshaker_do_handshake(grpc_handshaker* handshaker, args); } +const char* grpc_handshaker_name(grpc_handshaker* handshaker) { + return handshaker->vtable->name; +} + // // grpc_handshake_manager // @@ -127,6 +135,12 @@ static bool is_power_of_2(size_t n) { return (n & (n - 1)) == 0; } void grpc_handshake_manager_add(grpc_handshake_manager* mgr, grpc_handshaker* handshaker) { + if (grpc_handshaker_trace.enabled()) { + gpr_log( + GPR_INFO, + "handshake_manager %p: adding handshaker %s [%p] at index %" PRIuPTR, + mgr, grpc_handshaker_name(handshaker), handshaker, mgr->count); + } gpr_mu_lock(&mgr->mu); // To avoid allocating memory for each handshaker we add, we double // the number of elements every time we need more. @@ -172,23 +186,56 @@ void grpc_handshake_manager_shutdown(grpc_handshake_manager* mgr, GRPC_ERROR_UNREF(why); } +static char* handshaker_args_string(grpc_handshaker_args* args) { + char* args_str = grpc_channel_args_string(args->args); + size_t num_args = args->args != nullptr ? args->args->num_args : 0; + size_t read_buffer_length = + args->read_buffer != nullptr ? args->read_buffer->length : 0; + char* str; + gpr_asprintf(&str, + "{endpoint=%p, args=%p {size=%" PRIuPTR + ": %s}, read_buffer=%p (length=%" PRIuPTR "), exit_early=%d}", + args->endpoint, args->args, num_args, args_str, + args->read_buffer, read_buffer_length, args->exit_early); + gpr_free(args_str); + return str; +} + // Helper function to call either the next handshaker or the // on_handshake_done callback. // Returns true if we've scheduled the on_handshake_done callback. static bool call_next_handshaker_locked(grpc_handshake_manager* mgr, grpc_error* error) { + if (grpc_handshaker_trace.enabled()) { + char* args_str = handshaker_args_string(&mgr->args); + gpr_log(GPR_INFO, + "handshake_manager %p: error=%s shutdown=%d index=%" PRIuPTR + ", args=%s", + mgr, grpc_error_string(error), mgr->shutdown, mgr->index, args_str); + gpr_free(args_str); + } GPR_ASSERT(mgr->index <= mgr->count); // If we got an error or we've been shut down or we're exiting early or // we've finished the last handshaker, invoke the on_handshake_done // callback. Otherwise, call the next handshaker. if (error != GRPC_ERROR_NONE || mgr->shutdown || mgr->args.exit_early || mgr->index == mgr->count) { + if (grpc_handshaker_trace.enabled()) { + gpr_log(GPR_INFO, "handshake_manager %p: handshaking complete", mgr); + } // Cancel deadline timer, since we're invoking the on_handshake_done // callback now. grpc_timer_cancel(&mgr->deadline_timer); GRPC_CLOSURE_SCHED(&mgr->on_handshake_done, error); mgr->shutdown = true; } else { + if (grpc_handshaker_trace.enabled()) { + gpr_log( + GPR_INFO, + "handshake_manager %p: calling handshaker %s [%p] at index %" PRIuPTR, + mgr, grpc_handshaker_name(mgr->handshakers[mgr->index]), + mgr->handshakers[mgr->index], mgr->index); + } grpc_handshaker_do_handshake(mgr->handshakers[mgr->index], mgr->acceptor, &mgr->call_next_handshaker, &mgr->args); } diff --git a/src/core/lib/channel/handshaker.h b/src/core/lib/channel/handshaker.h index dfecd81004..be7fd127e4 100644 --- a/src/core/lib/channel/handshaker.h +++ b/src/core/lib/channel/handshaker.h @@ -84,6 +84,9 @@ typedef struct { grpc_tcp_server_acceptor* acceptor, grpc_closure* on_handshake_done, grpc_handshaker_args* args); + + /// The name of the handshaker, for debugging purposes. + const char* name; } grpc_handshaker_vtable; /// Base struct. To subclass, make this the first member of the @@ -102,6 +105,7 @@ void grpc_handshaker_do_handshake(grpc_handshaker* handshaker, grpc_tcp_server_acceptor* acceptor, grpc_closure* on_handshake_done, grpc_handshaker_args* args); +const char* grpc_handshaker_name(grpc_handshaker* handshaker); /// /// grpc_handshake_manager diff --git a/src/core/lib/channel/handshaker_factory.h b/src/core/lib/channel/handshaker_factory.h index 9e36443958..3e45fcf20e 100644 --- a/src/core/lib/channel/handshaker_factory.h +++ b/src/core/lib/channel/handshaker_factory.h @@ -24,7 +24,6 @@ #include <grpc/impl/codegen/grpc_types.h> #include "src/core/lib/channel/handshaker.h" -#include "src/core/lib/iomgr/exec_ctx.h" // A handshaker factory is used to create handshakers. diff --git a/src/core/lib/channel/handshaker_registry.h b/src/core/lib/channel/handshaker_registry.h index b42d61ff43..82ad9c5b9a 100644 --- a/src/core/lib/channel/handshaker_registry.h +++ b/src/core/lib/channel/handshaker_registry.h @@ -24,7 +24,6 @@ #include <grpc/impl/codegen/grpc_types.h> #include "src/core/lib/channel/handshaker_factory.h" -#include "src/core/lib/iomgr/exec_ctx.h" typedef enum { HANDSHAKER_CLIENT = 0, diff --git a/src/core/lib/channel/status_util.cc b/src/core/lib/channel/status_util.cc new file mode 100644 index 0000000000..563db40846 --- /dev/null +++ b/src/core/lib/channel/status_util.cc @@ -0,0 +1,100 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/support/port_platform.h> + +#include "src/core/lib/channel/status_util.h" + +#include "src/core/lib/gpr/useful.h" + +typedef struct { + const char* str; + grpc_status_code status; +} status_string_entry; + +static const status_string_entry g_status_string_entries[] = { + {"OK", GRPC_STATUS_OK}, + {"CANCELLED", GRPC_STATUS_CANCELLED}, + {"UNKNOWN", GRPC_STATUS_UNKNOWN}, + {"INVALID_ARGUMENT", GRPC_STATUS_INVALID_ARGUMENT}, + {"DEADLINE_EXCEEDED", GRPC_STATUS_DEADLINE_EXCEEDED}, + {"NOT_FOUND", GRPC_STATUS_NOT_FOUND}, + {"ALREADY_EXISTS", GRPC_STATUS_ALREADY_EXISTS}, + {"PERMISSION_DENIED", GRPC_STATUS_PERMISSION_DENIED}, + {"UNAUTHENTICATED", GRPC_STATUS_UNAUTHENTICATED}, + {"RESOURCE_EXHAUSTED", GRPC_STATUS_RESOURCE_EXHAUSTED}, + {"FAILED_PRECONDITION", GRPC_STATUS_FAILED_PRECONDITION}, + {"ABORTED", GRPC_STATUS_ABORTED}, + {"OUT_OF_RANGE", GRPC_STATUS_OUT_OF_RANGE}, + {"UNIMPLEMENTED", GRPC_STATUS_UNIMPLEMENTED}, + {"INTERNAL", GRPC_STATUS_INTERNAL}, + {"UNAVAILABLE", GRPC_STATUS_UNAVAILABLE}, + {"DATA_LOSS", GRPC_STATUS_DATA_LOSS}, +}; + +bool grpc_status_code_from_string(const char* status_str, + grpc_status_code* status) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(g_status_string_entries); ++i) { + if (strcmp(status_str, g_status_string_entries[i].str) == 0) { + *status = g_status_string_entries[i].status; + return true; + } + } + return false; +} + +const char* grpc_status_code_to_string(grpc_status_code status) { + switch (status) { + case GRPC_STATUS_OK: + return "OK"; + case GRPC_STATUS_CANCELLED: + return "CANCELLED"; + case GRPC_STATUS_UNKNOWN: + return "UNKNOWN"; + case GRPC_STATUS_INVALID_ARGUMENT: + return "INVALID_ARGUMENT"; + case GRPC_STATUS_DEADLINE_EXCEEDED: + return "DEADLINE_EXCEEDED"; + case GRPC_STATUS_NOT_FOUND: + return "NOT_FOUND"; + case GRPC_STATUS_ALREADY_EXISTS: + return "ALREADY_EXISTS"; + case GRPC_STATUS_PERMISSION_DENIED: + return "PERMISSION_DENIED"; + case GRPC_STATUS_UNAUTHENTICATED: + return "UNAUTHENTICATED"; + case GRPC_STATUS_RESOURCE_EXHAUSTED: + return "RESOURCE_EXHAUSTED"; + case GRPC_STATUS_FAILED_PRECONDITION: + return "FAILED_PRECONDITION"; + case GRPC_STATUS_ABORTED: + return "ABORTED"; + case GRPC_STATUS_OUT_OF_RANGE: + return "OUT_OF_RANGE"; + case GRPC_STATUS_UNIMPLEMENTED: + return "UNIMPLEMENTED"; + case GRPC_STATUS_INTERNAL: + return "INTERNAL"; + case GRPC_STATUS_UNAVAILABLE: + return "UNAVAILABLE"; + case GRPC_STATUS_DATA_LOSS: + return "DATA_LOSS"; + default: + return "UNKNOWN"; + } +} diff --git a/src/core/lib/channel/status_util.h b/src/core/lib/channel/status_util.h new file mode 100644 index 0000000000..5409de6b3c --- /dev/null +++ b/src/core/lib/channel/status_util.h @@ -0,0 +1,58 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_CHANNEL_STATUS_UTIL_H +#define GRPC_CORE_LIB_CHANNEL_STATUS_UTIL_H + +#include <grpc/support/port_platform.h> + +#include <grpc/status.h> + +#include <stdbool.h> +#include <string.h> + +/// If \a status_str is a valid status string, sets \a status to the +/// corresponding status value and returns true. +bool grpc_status_code_from_string(const char* status_str, + grpc_status_code* status); + +/// Returns the string form of \a status, or "UNKNOWN" if invalid. +const char* grpc_status_code_to_string(grpc_status_code status); + +namespace grpc_core { +namespace internal { + +/// A set of grpc_status_code values. +class StatusCodeSet { + public: + bool Empty() const { return status_code_mask_ == 0; } + + void Add(grpc_status_code status) { status_code_mask_ |= (1 << status); } + + bool Contains(grpc_status_code status) const { + return status_code_mask_ & (1 << status); + } + + private: + int status_code_mask_ = 0; // A bitfield of status codes in the set. +}; + +} // namespace internal +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_CHANNEL_STATUS_UTIL_H */ |