diff options
61 files changed, 853 insertions, 282 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 5b2ac80df6..d31aea6c73 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -26,6 +26,8 @@ If possible, provide a recipe for reproducing the error. Try being specific and ### What did you see instead? Make sure you include information that can help us debug (full error message, exception listing, stack trace, logs). + +See https://github.com/grpc/grpc/blob/master/TROUBLESHOOTING.md for how to diagnose problems better. ### Anything else we should know about your project / environment? diff --git a/CMakeLists.txt b/CMakeLists.txt index dcd7adeebe..66799c456f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ set(gRPC_INSTALL_SHAREDIR "share/grpc" CACHE STRING "Installation directory for option(gRPC_BUILD_TESTS "Build tests" OFF) option(gRPC_BUILD_CODEGEN "Build codegen" ON) option(gRPC_BUILD_CSHARP_EXT "Build C# extensions" ON) +option(gRPC_BACKWARDS_COMPATIBILITY_MODE "Build libraries that are binary compatible across a larger number of OS and libc versions" OFF) set(gRPC_INSTALL_default ON) if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) @@ -115,6 +116,14 @@ else() set(_gRPC_PROTOBUF_LIBRARY_NAME "libprotobuf") endif() +if(gRPC_BACKWARDS_COMPATIBILITY_MODE) + add_definitions(-DGPR_BACKWARDS_COMPATIBILITY_MODE) + if (_gRPC_PLATFORM_MAC) + # some C++11 constructs not supported before OS X 10.9 + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9) + endif() +endif() + if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC) # C core has C++ source code, but should not depend on libstc++ (for better portability). # We need to use a few tricks to convince cmake to do that. diff --git a/doc/ssl-performance.md b/doc/ssl-performance.md index 711b9dff09..3de1ecac00 100644 --- a/doc/ssl-performance.md +++ b/doc/ssl-performance.md @@ -25,7 +25,10 @@ In addition, we are shipping packages for language implementations. These packag Language | From source | Platform | Uses assembly optimizations ---|---|---|--- -C# | n/a | all | :x: +C# | n/a | Linux, 64bit | :heavy_check_mark: +C# | n/a | Linux, 32bit | :x: +C# | n/a | MacOS | :heavy_check_mark: +C# | n/a | Windows | :x: Node.JS | n/a | Linux | :heavy_check_mark: Node.JS | n/a | MacOS | :heavy_check_mark: Node.JS | n/a | Windows | :x: diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index d1f8834d11..3ce88a8264 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -285,10 +285,12 @@ typedef struct { #define GRPC_ARG_SOCKET_MUTATOR "grpc.socket_mutator" /** The grpc_socket_factory instance to create and bind sockets. A pointer. */ #define GRPC_ARG_SOCKET_FACTORY "grpc.socket_factory" -/** The maximum number of trace events to keep in the tracer for each channel or - * subchannel. The default is 0. If set to 0, channel tracing is disabled. */ -#define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \ - "grpc.max_channel_trace_events_per_node" +/** The maximum amount of memory used by trace events per channel trace node. + * Once the maximum is reached, subsequent events will evict the oldest events + * from the buffer. The unit for this knob is bytes. Setting it to zero causes + * channel tracing to be disabled. */ +#define GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE \ + "grpc.max_channel_trace_event_memory_per_node" /** If non-zero, gRPC library will track stats and information at at per channel * level. Disabling channelz naturally disables channel tracing. The default * is for channelz to be disabled. */ diff --git a/src/core/ext/filters/client_channel/http_connect_handshaker.cc b/src/core/ext/filters/client_channel/http_connect_handshaker.cc index bfabc68c66..7ce8da8c00 100644 --- a/src/core/ext/filters/client_channel/http_connect_handshaker.cc +++ b/src/core/ext/filters/client_channel/http_connect_handshaker.cc @@ -351,7 +351,6 @@ static grpc_handshaker* grpc_http_connect_handshaker_create() { static void handshaker_factory_add_handshakers( grpc_handshaker_factory* factory, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_handshake_manager_add(handshake_mgr, grpc_http_connect_handshaker_create()); diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index 088c9d6c00..4a668b0fa7 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -390,16 +390,16 @@ grpc_subchannel* grpc_subchannel_create(grpc_connector* connector, grpc_channel_args_find(c->args, GRPC_ARG_ENABLE_CHANNELZ); bool channelz_enabled = grpc_channel_arg_get_bool(arg, GRPC_ENABLE_CHANNELZ_DEFAULT); - arg = grpc_channel_args_find(c->args, - GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); + arg = grpc_channel_args_find( + c->args, GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE); const grpc_integer_options options = { - GRPC_MAX_CHANNEL_TRACE_EVENTS_PER_NODE_DEFAULT, 0, INT_MAX}; - size_t channel_tracer_max_nodes = + GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX}; + size_t channel_tracer_max_memory = (size_t)grpc_channel_arg_get_integer(arg, options); if (channelz_enabled) { c->channelz_subchannel = grpc_core::MakeRefCounted<grpc_core::channelz::SubchannelNode>( - c, channel_tracer_max_nodes); + c, channel_tracer_max_memory); c->channelz_subchannel->AddTraceEvent( grpc_core::channelz::ChannelTrace::Severity::Info, grpc_slice_from_static_string("Subchannel created")); diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc index 5229304fa4..0ac84032fd 100644 --- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc +++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc @@ -160,7 +160,7 @@ static void on_handshake_done(void* arg, grpc_error* error) { static void start_handshake_locked(chttp2_connector* c) { c->handshake_mgr = grpc_handshake_manager_create(); grpc_handshakers_add(HANDSHAKER_CLIENT, c->args.channel_args, - c->args.interested_parties, c->handshake_mgr); + c->handshake_mgr); grpc_endpoint_add_to_pollset_set(c->endpoint, c->args.interested_parties); grpc_handshake_manager_do_handshake( c->handshake_mgr, c->args.interested_parties, c->endpoint, diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc index b95baa9191..3f8a26ae32 100644 --- a/src/core/ext/transport/chttp2/server/chttp2_server.cc +++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc @@ -67,7 +67,6 @@ typedef struct { grpc_timer timer; grpc_closure on_timeout; grpc_closure on_receive_settings; - grpc_pollset_set* interested_parties; } server_connection_state; static void server_connection_state_unref( @@ -77,9 +76,6 @@ static void server_connection_state_unref( GRPC_CHTTP2_UNREF_TRANSPORT(connection_state->transport, "receive settings timeout"); } - grpc_pollset_set_del_pollset(connection_state->interested_parties, - connection_state->accepting_pollset); - grpc_pollset_set_destroy(connection_state->interested_parties); gpr_free(connection_state); } } @@ -193,11 +189,7 @@ static void on_accept(void* arg, grpc_endpoint* tcp, connection_state->accepting_pollset = accepting_pollset; connection_state->acceptor = acceptor; connection_state->handshake_mgr = handshake_mgr; - connection_state->interested_parties = grpc_pollset_set_create(); - grpc_pollset_set_add_pollset(connection_state->interested_parties, - connection_state->accepting_pollset); grpc_handshakers_add(HANDSHAKER_SERVER, state->args, - connection_state->interested_parties, connection_state->handshake_mgr); const grpc_arg* timeout_arg = grpc_channel_args_find(state->args, GRPC_ARG_SERVER_HANDSHAKE_TIMEOUT_MS); diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc index cfb2faba51..fe81acb617 100644 --- a/src/core/lib/channel/channel_trace.cc +++ b/src/core/lib/channel/channel_trace.cc @@ -48,31 +48,35 @@ ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data, timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME)), next_(nullptr), - referenced_entity_(std::move(referenced_entity)) {} + referenced_entity_(std::move(referenced_entity)), + memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {} 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) {} + next_(nullptr), + memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {} ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); } -ChannelTrace::ChannelTrace(size_t max_events) +ChannelTrace::ChannelTrace(size_t max_event_memory) : num_events_logged_(0), - list_size_(0), - max_list_size_(max_events), + event_list_memory_usage_(0), + max_event_memory_(max_event_memory), head_trace_(nullptr), tail_trace_(nullptr) { - if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 + if (max_event_memory_ == 0) + return; // tracing is disabled if max_event_memory_ == 0 gpr_mu_init(&tracer_mu_); 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 + if (max_event_memory_ == 0) + return; // tracing is disabled if max_event_memory_ == 0 TraceEvent* it = head_trace_; while (it != nullptr) { TraceEvent* to_free = it; @@ -93,25 +97,27 @@ void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) { 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_) { + event_list_memory_usage_ += new_trace_event->memory_usage(); + // maybe garbage collect the tail until we are under the memory limit. + while (event_list_memory_usage_ > max_event_memory_) { TraceEvent* to_free = head_trace_; + event_list_memory_usage_ -= to_free->memory_usage(); 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 + if (max_event_memory_ == 0) + return; // tracing is disabled if max_event_memory_ == 0 AddTraceEventHelper(New<TraceEvent>(severity, data)); } void ChannelTrace::AddTraceEventWithReference( Severity severity, grpc_slice data, RefCountedPtr<BaseNode> referenced_entity) { - if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 + if (max_event_memory_ == 0) + return; // tracing is disabled if max_event_memory_ == 0 // create and fill up the new event AddTraceEventHelper( New<TraceEvent>(severity, data, std::move(referenced_entity))); @@ -162,8 +168,8 @@ void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const { } grpc_json* ChannelTrace::RenderJson() const { - if (!max_list_size_) - return nullptr; // tracing is disabled if max_events == 0 + if (max_event_memory_ == 0) + return nullptr; // tracing is disabled if max_event_memory_ == 0 grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json_iterator = nullptr; if (num_events_logged_ > 0) { @@ -174,7 +180,7 @@ grpc_json* ChannelTrace::RenderJson() const { json_iterator, json, "creationTimestamp", gpr_format_timespec(time_created_), GRPC_JSON_STRING, true); // only add in the event list if it is non-empty. - if (num_events_logged_ > 0) { + if (head_trace_ != nullptr) { grpc_json* events = grpc_json_create_child(json_iterator, json, "events", nullptr, GRPC_JSON_ARRAY, false); json_iterator = nullptr; diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h index 94fea20b45..8ff91ee8c8 100644 --- a/src/core/lib/channel/channel_trace.h +++ b/src/core/lib/channel/channel_trace.h @@ -30,6 +30,10 @@ namespace grpc_core { namespace channelz { +namespace testing { +size_t GetSizeofTraceEvent(void); +} + class BaseNode; // Object used to hold live data for a channel. This data is exposed via the @@ -37,7 +41,7 @@ class BaseNode; // https://github.com/grpc/proposal/blob/master/A14-channelz.md class ChannelTrace { public: - ChannelTrace(size_t max_events); + ChannelTrace(size_t max_event_memory); ~ChannelTrace(); enum Severity { @@ -49,6 +53,12 @@ class ChannelTrace { // Adds a new trace event to the tracing object // + // NOTE: each ChannelTrace tracks the memory used by its list of trace + // events, so adding an event with a large amount of data could cause other + // trace event to be evicted. If a single trace is larger than the limit, it + // will cause all events to be evicted. The limit is set with the arg: + // GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE. + // // 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. @@ -59,9 +69,9 @@ class ChannelTrace { // channel has created a new subchannel, then it would record that with // a TraceEvent referencing the new subchannel. // - // 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. + // NOTE: see the note in the method above. + // + // TODO(ncteisen): see the todo in the method above. void AddTraceEventWithReference(Severity severity, grpc_slice data, RefCountedPtr<BaseNode> referenced_entity); @@ -70,6 +80,8 @@ class ChannelTrace { grpc_json* RenderJson() const; private: + friend size_t testing::GetSizeofTraceEvent(void); + // Private class to encapsulate all the data and bookkeeping needed for a // a trace event. class TraceEvent { @@ -92,6 +104,8 @@ class ChannelTrace { TraceEvent* next() const { return next_; } void set_next(TraceEvent* next) { next_ = next; } + size_t memory_usage() const { return memory_usage_; } + private: Severity severity_; grpc_slice data_; @@ -99,6 +113,7 @@ class ChannelTrace { TraceEvent* next_; // the tracer object for the (sub)channel that this trace event refers to. RefCountedPtr<BaseNode> referenced_entity_; + size_t memory_usage_; }; // TraceEvent // Internal helper to add and link in a trace event @@ -106,8 +121,8 @@ class ChannelTrace { gpr_mu tracer_mu_; uint64_t num_events_logged_; - size_t list_size_; - size_t max_list_size_; + size_t event_list_memory_usage_; + size_t max_event_memory_; TraceEvent* head_trace_; TraceEvent* tail_trace_; gpr_timespec time_created_; diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 339c827525..573292fba1 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -34,6 +34,7 @@ #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/iomgr/exec_ctx.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/transport/error_utils.h" @@ -55,35 +56,75 @@ char* BaseNode::RenderJsonString() { } CallCountingHelper::CallCountingHelper() { - gpr_atm_no_barrier_store(&last_call_started_millis_, - (gpr_atm)ExecCtx::Get()->Now()); + num_cores_ = GPR_MAX(1, gpr_cpu_num_cores()); + per_cpu_counter_data_storage_ = static_cast<AtomicCounterData*>( + gpr_zalloc(sizeof(AtomicCounterData) * num_cores_)); } -CallCountingHelper::~CallCountingHelper() {} +CallCountingHelper::~CallCountingHelper() { + gpr_free(per_cpu_counter_data_storage_); +} void CallCountingHelper::RecordCallStarted() { - gpr_atm_no_barrier_fetch_add(&calls_started_, static_cast<gpr_atm>(1)); - gpr_atm_no_barrier_store(&last_call_started_millis_, - (gpr_atm)ExecCtx::Get()->Now()); + gpr_atm_no_barrier_fetch_add( + &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()] + .calls_started, + static_cast<gpr_atm>(1)); + gpr_atm_no_barrier_store( + &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()] + .last_call_started_millis, + (gpr_atm)ExecCtx::Get()->Now()); +} + +void CallCountingHelper::RecordCallFailed() { + gpr_atm_no_barrier_fetch_add( + &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()] + .calls_failed, + static_cast<gpr_atm>(1)); +} + +void CallCountingHelper::RecordCallSucceeded() { + gpr_atm_no_barrier_fetch_add( + &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()] + .calls_succeeded, + static_cast<gpr_atm>(1)); +} + +void CallCountingHelper::CollectData(CounterData* out) { + for (size_t core = 0; core < num_cores_; ++core) { + out->calls_started += gpr_atm_no_barrier_load( + &per_cpu_counter_data_storage_[core].calls_started); + out->calls_succeeded += gpr_atm_no_barrier_load( + &per_cpu_counter_data_storage_[core].calls_succeeded); + out->calls_failed += gpr_atm_no_barrier_load( + &per_cpu_counter_data_storage_[core].calls_failed); + gpr_atm last_call = gpr_atm_no_barrier_load( + &per_cpu_counter_data_storage_[core].last_call_started_millis); + if (last_call > out->last_call_started_millis) { + out->last_call_started_millis = last_call; + } + } } void CallCountingHelper::PopulateCallCounts(grpc_json* json) { grpc_json* json_iterator = nullptr; - if (calls_started_ != 0) { + CounterData data; + CollectData(&data); + if (data.calls_started != 0) { json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "callsStarted", calls_started_); + json, json_iterator, "callsStarted", data.calls_started); } - if (calls_succeeded_ != 0) { + if (data.calls_succeeded != 0) { json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "callsSucceeded", calls_succeeded_); + json, json_iterator, "callsSucceeded", data.calls_succeeded); } - if (calls_failed_) { + if (data.calls_failed) { json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "callsFailed", calls_failed_); + json, json_iterator, "callsFailed", data.calls_failed); } - if (calls_started_ != 0) { - gpr_timespec ts = - grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME); + if (data.calls_started != 0) { + gpr_timespec ts = grpc_millis_to_timespec(data.last_call_started_millis, + GPR_CLOCK_REALTIME); json_iterator = grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp", gpr_format_timespec(ts), GRPC_JSON_STRING, true); diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index d949e1b449..3f728cda6d 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -43,10 +43,11 @@ * GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value. */ #define GRPC_ENABLE_CHANNELZ_DEFAULT false -/** This is the default value for number of trace events per node. If - * GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE is set, it will override this - * default value. */ -#define GRPC_MAX_CHANNEL_TRACE_EVENTS_PER_NODE_DEFAULT 0 +/** This is the default value for the maximum amount of memory used by trace + * events per channel trace node. If + * GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE is set, it will override + * this default value. */ +#define GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT 0 namespace grpc_core { namespace channelz { @@ -100,12 +101,8 @@ class CallCountingHelper { ~CallCountingHelper(); void RecordCallStarted(); - void RecordCallFailed() { - gpr_atm_no_barrier_fetch_add(&calls_failed_, static_cast<gpr_atm>(1)); - } - void RecordCallSucceeded() { - gpr_atm_no_barrier_fetch_add(&calls_succeeded_, static_cast<gpr_atm>(1)); - } + void RecordCallFailed(); + void RecordCallSucceeded(); // Common rendering of the call count data and last_call_started_timestamp. void PopulateCallCounts(grpc_json* json); @@ -114,10 +111,25 @@ class CallCountingHelper { // testing peer friend. friend class testing::CallCountingHelperPeer; - gpr_atm calls_started_ = 0; - gpr_atm calls_succeeded_ = 0; - gpr_atm calls_failed_ = 0; - gpr_atm last_call_started_millis_ = 0; + struct AtomicCounterData { + gpr_atm calls_started = 0; + gpr_atm calls_succeeded = 0; + gpr_atm calls_failed = 0; + gpr_atm last_call_started_millis = 0; + }; + + struct CounterData { + intptr_t calls_started = 0; + intptr_t calls_succeeded = 0; + intptr_t calls_failed = 0; + intptr_t last_call_started_millis = 0; + }; + + // collects the sharded data into one CounterData struct. + void CollectData(CounterData* out); + + AtomicCounterData* per_cpu_counter_data_storage_ = nullptr; + size_t num_cores_ = 0; }; // Handles channelz bookkeeping for channels diff --git a/src/core/lib/channel/handshaker_factory.cc b/src/core/lib/channel/handshaker_factory.cc index 8ade8fe4e2..4fd43635b6 100644 --- a/src/core/lib/channel/handshaker_factory.cc +++ b/src/core/lib/channel/handshaker_factory.cc @@ -24,12 +24,11 @@ void grpc_handshaker_factory_add_handshakers( grpc_handshaker_factory* handshaker_factory, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { if (handshaker_factory != nullptr) { GPR_ASSERT(handshaker_factory->vtable != nullptr); - handshaker_factory->vtable->add_handshakers( - handshaker_factory, args, interested_parties, handshake_mgr); + handshaker_factory->vtable->add_handshakers(handshaker_factory, args, + handshake_mgr); } } diff --git a/src/core/lib/channel/handshaker_factory.h b/src/core/lib/channel/handshaker_factory.h index e17a678179..3e45fcf20e 100644 --- a/src/core/lib/channel/handshaker_factory.h +++ b/src/core/lib/channel/handshaker_factory.h @@ -32,7 +32,6 @@ typedef struct grpc_handshaker_factory grpc_handshaker_factory; typedef struct { void (*add_handshakers)(grpc_handshaker_factory* handshaker_factory, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr); void (*destroy)(grpc_handshaker_factory* handshaker_factory); } grpc_handshaker_factory_vtable; @@ -43,7 +42,6 @@ struct grpc_handshaker_factory { void grpc_handshaker_factory_add_handshakers( grpc_handshaker_factory* handshaker_factory, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr); void grpc_handshaker_factory_destroy( diff --git a/src/core/lib/channel/handshaker_registry.cc b/src/core/lib/channel/handshaker_registry.cc index fbafc43e79..eec3e1b352 100644 --- a/src/core/lib/channel/handshaker_registry.cc +++ b/src/core/lib/channel/handshaker_registry.cc @@ -51,11 +51,9 @@ static void grpc_handshaker_factory_list_register( static void grpc_handshaker_factory_list_add_handshakers( grpc_handshaker_factory_list* list, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { for (size_t i = 0; i < list->num_factories; ++i) { - grpc_handshaker_factory_add_handshakers(list->list[i], args, - interested_parties, handshake_mgr); + grpc_handshaker_factory_add_handshakers(list->list[i], args, handshake_mgr); } } @@ -93,9 +91,7 @@ void grpc_handshaker_factory_register(bool at_start, void grpc_handshakers_add(grpc_handshaker_type handshaker_type, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_handshaker_factory_list_add_handshakers( - &g_handshaker_factory_lists[handshaker_type], args, interested_parties, - handshake_mgr); + &g_handshaker_factory_lists[handshaker_type], args, handshake_mgr); } diff --git a/src/core/lib/channel/handshaker_registry.h b/src/core/lib/channel/handshaker_registry.h index 3dd4316de6..82ad9c5b9a 100644 --- a/src/core/lib/channel/handshaker_registry.h +++ b/src/core/lib/channel/handshaker_registry.h @@ -43,7 +43,6 @@ void grpc_handshaker_factory_register(bool at_start, void grpc_handshakers_add(grpc_handshaker_type handshaker_type, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr); #endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H */ diff --git a/src/core/lib/gpr/sync_posix.cc b/src/core/lib/gpr/sync_posix.cc index 848d23730c..69bd609485 100644 --- a/src/core/lib/gpr/sync_posix.cc +++ b/src/core/lib/gpr/sync_posix.cc @@ -27,6 +27,24 @@ #include <time.h> #include "src/core/lib/profiling/timers.h" +// For debug of the timer manager crash only. +// TODO (mxyan): remove after bug is fixed. +#ifdef GRPC_DEBUG_TIMER_MANAGER +void (*g_grpc_debug_timer_manager_stats)( + int64_t timer_manager_init_count, int64_t timer_manager_shutdown_count, + int64_t fork_count, int64_t timer_wait_err, int64_t timer_cv_value, + int64_t timer_mu_value, int64_t abstime_sec_value, + int64_t abstime_nsec_value) = nullptr; +int64_t g_timer_manager_init_count = 0; +int64_t g_timer_manager_shutdown_count = 0; +int64_t g_fork_count = 0; +int64_t g_timer_wait_err = 0; +int64_t g_timer_cv_value = 0; +int64_t g_timer_mu_value = 0; +int64_t g_abstime_sec_value = -1; +int64_t g_abstime_nsec_value = -1; +#endif // GRPC_DEBUG_TIMER_MANAGER + #ifdef GPR_LOW_LEVEL_COUNTERS gpr_atm gpr_mu_locks = 0; gpr_atm gpr_counter_atm_cas = 0; @@ -87,7 +105,31 @@ int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { abs_deadline_ts.tv_sec = static_cast<time_t>(abs_deadline.tv_sec); abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec; err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts); +#ifdef GRPC_DEBUG_TIMER_MANAGER + // For debug of the timer manager crash only. + // TODO (mxyan): remove after bug is fixed. + if (GPR_UNLIKELY(!(err == 0 || err == ETIMEDOUT || err == EAGAIN))) { + g_abstime_sec_value = abs_deadline_ts.tv_sec; + g_abstime_nsec_value = abs_deadline_ts.tv_nsec; + } +#endif } + +#ifdef GRPC_DEBUG_TIMER_MANAGER + // For debug of the timer manager crash only. + // TODO (mxyan): remove after bug is fixed. + if (GPR_UNLIKELY(!(err == 0 || err == ETIMEDOUT || err == EAGAIN))) { + if (g_grpc_debug_timer_manager_stats) { + g_timer_wait_err = err; + g_timer_cv_value = (int64_t)cv; + g_timer_mu_value = (int64_t)mu; + g_grpc_debug_timer_manager_stats( + g_timer_manager_init_count, g_timer_manager_shutdown_count, + g_fork_count, g_timer_wait_err, g_timer_cv_value, g_timer_mu_value, + g_abstime_sec_value, g_abstime_nsec_value); + } + } +#endif GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN); return err == ETIMEDOUT; } diff --git a/src/core/lib/http/httpcli_security_connector.cc b/src/core/lib/http/httpcli_security_connector.cc index 98fb7d3937..50078c37a1 100644 --- a/src/core/lib/http/httpcli_security_connector.cc +++ b/src/core/lib/http/httpcli_security_connector.cc @@ -189,8 +189,7 @@ static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host, grpc_arg channel_arg = grpc_security_connector_to_arg(&sc->base); grpc_channel_args args = {1, &channel_arg}; c->handshake_mgr = grpc_handshake_manager_create(); - grpc_handshakers_add(HANDSHAKER_CLIENT, &args, - nullptr /* interested_parties */, c->handshake_mgr); + grpc_handshakers_add(HANDSHAKER_CLIENT, &args, c->handshake_mgr); grpc_handshake_manager_do_handshake( c->handshake_mgr, nullptr /* interested_parties */, tcp, nullptr /* channel_args */, deadline, nullptr /* acceptor */, diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h index f3528d527a..e90eb54cd3 100644 --- a/src/core/lib/iomgr/exec_ctx.h +++ b/src/core/lib/iomgr/exec_ctx.h @@ -116,12 +116,7 @@ class ExecCtx { ExecCtx(const ExecCtx&) = delete; ExecCtx& operator=(const ExecCtx&) = delete; - /** Return starting_cpu. This is only required for stats collection and is - * hence only defined if GRPC_COLLECT_STATS is enabled. - */ -#if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) unsigned starting_cpu() const { return starting_cpu_; } -#endif /* defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) */ struct CombinerData { /* currently active combiner: updated only via combiner.c */ @@ -223,9 +218,7 @@ class ExecCtx { CombinerData combiner_data_ = {nullptr, nullptr}; uintptr_t flags_; -#if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) unsigned starting_cpu_ = gpr_cpu_current_cpu(); -#endif /* defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) */ bool now_is_valid_ = false; grpc_millis now_ = 0; diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc index 26de216671..e272d228f8 100644 --- a/src/core/lib/iomgr/timer_manager.cc +++ b/src/core/lib/iomgr/timer_manager.cc @@ -61,6 +61,14 @@ static uint64_t g_timed_waiter_generation; static void timer_thread(void* completed_thread_ptr); +// For debug of the timer manager crash only. +// TODO (mxyan): remove after bug is fixed. +#ifdef GRPC_DEBUG_TIMER_MANAGER +extern int64_t g_timer_manager_init_count; +extern int64_t g_timer_manager_shutdown_count; +extern int64_t g_fork_count; +#endif // GRPC_DEBUG_TIMER_MANAGER + static void gc_completed_threads(void) { if (g_completed_threads != nullptr) { completed_thread* to_gc = g_completed_threads; @@ -284,6 +292,11 @@ static void start_threads(void) { void grpc_timer_manager_init(void) { gpr_mu_init(&g_mu); gpr_cv_init(&g_cv_wait); +#ifdef GRPC_DEBUG_TIMER_MANAGER + // For debug of the timer manager crash only. + // TODO (mxyan): remove after bug is fixed. + g_timer_manager_init_count++; +#endif gpr_cv_init(&g_cv_shutdown); g_threaded = false; g_thread_count = 0; @@ -319,6 +332,11 @@ static void stop_threads(void) { } void grpc_timer_manager_shutdown(void) { +#ifdef GRPC_DEBUG_TIMER_MANAGER + // For debug of the timer manager crash only. + // TODO (mxyan): remove after bug is fixed. + g_timer_manager_shutdown_count++; +#endif stop_threads(); gpr_mu_destroy(&g_mu); @@ -327,6 +345,11 @@ void grpc_timer_manager_shutdown(void) { } void grpc_timer_manager_set_threading(bool threaded) { +#ifdef GRPC_DEBUG_TIMER_MANAGER + // For debug of the timer manager crash only. + // TODO (mxyan): remove after bug is fixed. + g_fork_count++; +#endif if (threaded) { start_threads(); } else { diff --git a/src/core/lib/security/security_connector/alts_security_connector.cc b/src/core/lib/security/security_connector/alts_security_connector.cc index f157c93171..35a787871a 100644 --- a/src/core/lib/security/security_connector/alts_security_connector.cc +++ b/src/core/lib/security/security_connector/alts_security_connector.cc @@ -70,9 +70,9 @@ static void alts_channel_add_handshakers( auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc); grpc_alts_credentials* creds = reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds); - GPR_ASSERT(alts_tsi_handshaker_create( - creds->options, c->target_name, creds->handshaker_service_url, - true, sc->base.interested_parties, &handshaker) == TSI_OK); + GPR_ASSERT(alts_tsi_handshaker_create(creds->options, c->target_name, + creds->handshaker_service_url, true, + &handshaker) == TSI_OK); grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create( handshaker, &sc->base)); } @@ -84,9 +84,9 @@ static void alts_server_add_handshakers( auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc); grpc_alts_server_credentials* creds = reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds); - GPR_ASSERT(alts_tsi_handshaker_create( - creds->options, nullptr, creds->handshaker_service_url, false, - sc->base.interested_parties, &handshaker) == TSI_OK); + GPR_ASSERT(alts_tsi_handshaker_create(creds->options, nullptr, + creds->handshaker_service_url, false, + &handshaker) == TSI_OK); grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create( handshaker, &sc->base)); } diff --git a/src/core/lib/security/security_connector/security_connector.cc b/src/core/lib/security/security_connector/security_connector.cc index f4490582a3..6246613e7b 100644 --- a/src/core/lib/security/security_connector/security_connector.cc +++ b/src/core/lib/security/security_connector/security_connector.cc @@ -156,13 +156,6 @@ int grpc_security_connector_cmp(grpc_security_connector* sc, return sc->vtable->cmp(sc, other); } -void grpc_security_connector_set_interested_parties( - grpc_security_connector* sc, grpc_pollset_set* interested_parties) { - if (sc != nullptr) { - sc->interested_parties = interested_parties; - } -} - int grpc_channel_security_connector_cmp(grpc_channel_security_connector* sc1, grpc_channel_security_connector* sc2) { GPR_ASSERT(sc1->channel_creds != nullptr); diff --git a/src/core/lib/security/security_connector/security_connector.h b/src/core/lib/security/security_connector/security_connector.h index f0172594ad..67a506b576 100644 --- a/src/core/lib/security/security_connector/security_connector.h +++ b/src/core/lib/security/security_connector/security_connector.h @@ -63,7 +63,6 @@ struct grpc_security_connector { const grpc_security_connector_vtable* vtable; gpr_refcount refcount; const char* url_scheme; - grpc_pollset_set* interested_parties; }; /* Refcounting. */ @@ -107,10 +106,6 @@ grpc_security_connector* grpc_security_connector_from_arg(const grpc_arg* arg); grpc_security_connector* grpc_security_connector_find_in_args( const grpc_channel_args* args); -/* Util to set the interested_parties whose ownership is not transferred. */ -void grpc_security_connector_set_interested_parties( - grpc_security_connector* sc, grpc_pollset_set* interested_parties); - /* --- channel_security_connector object. --- A channel security connector object represents a way to configure the diff --git a/src/core/lib/security/transport/security_handshaker.cc b/src/core/lib/security/transport/security_handshaker.cc index f3bdf573b3..d76d582638 100644 --- a/src/core/lib/security/transport/security_handshaker.cc +++ b/src/core/lib/security/transport/security_handshaker.cc @@ -475,30 +475,20 @@ static grpc_handshaker* fail_handshaker_create() { static void client_handshaker_factory_add_handshakers( grpc_handshaker_factory* handshaker_factory, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_channel_security_connector* security_connector = reinterpret_cast<grpc_channel_security_connector*>( grpc_security_connector_find_in_args(args)); - if (security_connector != nullptr) { - grpc_security_connector_set_interested_parties(&security_connector->base, - interested_parties); - } grpc_channel_security_connector_add_handshakers(security_connector, handshake_mgr); } static void server_handshaker_factory_add_handshakers( grpc_handshaker_factory* hf, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_server_security_connector* security_connector = reinterpret_cast<grpc_server_security_connector*>( grpc_security_connector_find_in_args(args)); - if (security_connector != nullptr) { - grpc_security_connector_set_interested_parties(&security_connector->base, - interested_parties); - } grpc_server_security_connector_add_handshakers(security_connector, handshake_mgr); } diff --git a/src/core/lib/slice/slice.cc b/src/core/lib/slice/slice.cc index 419474129b..e842d84f11 100644 --- a/src/core/lib/slice/slice.cc +++ b/src/core/lib/slice/slice.cc @@ -88,6 +88,14 @@ static const grpc_slice_refcount_vtable noop_refcount_vtable = { static grpc_slice_refcount noop_refcount = {&noop_refcount_vtable, &noop_refcount}; +size_t grpc_slice_memory_usage(grpc_slice s) { + if (s.refcount == nullptr || s.refcount == &noop_refcount) { + return 0; + } else { + return s.data.refcounted.length; + } +} + grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) { grpc_slice slice; slice.refcount = &noop_refcount; diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h index 5d3d26b67b..5b05951522 100644 --- a/src/core/lib/slice/slice_internal.h +++ b/src/core/lib/slice/slice_internal.h @@ -46,4 +46,9 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice, uint32_t grpc_static_slice_hash(grpc_slice s); int grpc_static_slice_eq(grpc_slice a, grpc_slice b); +// Returns the memory used by this slice, not counting the slice structure +// itself. This means that inlined and slices from static strings will return +// 0. All other slices will return the size of the allocated chars. +size_t grpc_slice_memory_usage(grpc_slice s); + #endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */ diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index 4996c3f177..4294434504 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -102,8 +102,8 @@ grpc_channel* grpc_channel_create_with_builder( channel->target = target; channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type); - size_t channel_tracer_max_nodes = 0; // default to off bool channelz_enabled = GRPC_ENABLE_CHANNELZ_DEFAULT; + size_t channel_tracer_max_memory = 0; // default to off bool internal_channel = false; // this creates the default ChannelNode. Different types of channels may // override this to ensure a correct ChannelNode is created. @@ -141,12 +141,11 @@ grpc_channel* grpc_channel_create_with_builder( static_cast<uint32_t>(args->args[i].value.integer) | 0x1; /* always support no compression */ } else if (0 == strcmp(args->args[i].key, - GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE)) { - GPR_ASSERT(channel_tracer_max_nodes == 0); - // max_nodes defaults to 0 (which is off), clamped between 0 and INT_MAX + GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE)) { + GPR_ASSERT(channel_tracer_max_memory == 0); const grpc_integer_options options = { - GRPC_MAX_CHANNEL_TRACE_EVENTS_PER_NODE_DEFAULT, 0, INT_MAX}; - channel_tracer_max_nodes = + GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX}; + channel_tracer_max_memory = (size_t)grpc_channel_arg_get_integer(&args->args[i], options); } else if (0 == strcmp(args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) { // channelz will not be enabled by default until all concerns in @@ -171,7 +170,7 @@ grpc_channel* grpc_channel_create_with_builder( // bookkeeping for server channels occurs in src/core/lib/surface/server.cc if (channelz_enabled && channel->is_client) { channel->channelz_channel = channel_node_create_func( - channel, channel_tracer_max_nodes, !internal_channel); + channel, channel_tracer_max_memory, !internal_channel); channel->channelz_channel->AddTraceEvent( grpc_core::channelz::ChannelTrace::Severity::Info, grpc_slice_from_static_string("Channel created")); diff --git a/src/core/lib/surface/init_secure.cc b/src/core/lib/surface/init_secure.cc index 28c6f7b121..765350cced 100644 --- a/src/core/lib/surface/init_secure.cc +++ b/src/core/lib/surface/init_secure.cc @@ -74,7 +74,7 @@ void grpc_register_security_filters(void) { maybe_prepend_client_auth_filter, nullptr); grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX - 1, maybe_prepend_client_auth_filter, nullptr); - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX - 1, maybe_prepend_server_auth_filter, nullptr); } diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 1dd583c3f7..449aef768e 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -1009,13 +1009,14 @@ grpc_server* grpc_server_create(const grpc_channel_args* args, void* reserved) { const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_ENABLE_CHANNELZ); if (grpc_channel_arg_get_bool(arg, GRPC_ENABLE_CHANNELZ_DEFAULT)) { - arg = grpc_channel_args_find(args, - GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); - size_t trace_events_per_node = grpc_channel_arg_get_integer( - arg, {GRPC_MAX_CHANNEL_TRACE_EVENTS_PER_NODE_DEFAULT, 0, INT_MAX}); + arg = grpc_channel_args_find( + args, GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE); + size_t channel_tracer_max_memory = grpc_channel_arg_get_integer( + arg, + {GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX}); server->channelz_server = grpc_core::MakeRefCounted<grpc_core::channelz::ServerNode>( - trace_events_per_node); + channel_tracer_max_memory); server->channelz_server->AddTraceEvent( grpc_core::channelz::ChannelTrace::Severity::Info, grpc_slice_from_static_string("Server created")); diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc index dfdd659b87..34608a3de1 100644 --- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc +++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc @@ -347,8 +347,7 @@ static void init_shared_resources(const char* handshaker_service_url) { tsi_result alts_tsi_handshaker_create( const grpc_alts_credentials_options* options, const char* target_name, - const char* handshaker_service_url, bool is_client, - grpc_pollset_set* interested_parties, tsi_handshaker** self) { + const char* handshaker_service_url, bool is_client, tsi_handshaker** self) { if (handshaker_service_url == nullptr || self == nullptr || options == nullptr || (is_client && target_name == nullptr)) { gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_handshaker_create()"); diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h index 48ce69b1da..227b30ce53 100644 --- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h +++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h @@ -23,7 +23,6 @@ #include <grpc/grpc.h> -#include "src/core/lib/iomgr/pollset_set.h" #include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" #include "src/core/tsi/alts_transport_security.h" #include "src/core/tsi/transport_security.h" @@ -52,7 +51,6 @@ typedef struct alts_tsi_handshaker alts_tsi_handshaker; * "host:port". * - is_client: boolean value indicating if the handshaker is used at the client * (is_client = true) or server (is_client = false) side. - * - interested_parties: set of pollsets interested in this connection. * - self: address of ALTS TSI handshaker instance to be returned from the * method. * @@ -60,8 +58,7 @@ typedef struct alts_tsi_handshaker alts_tsi_handshaker; */ tsi_result alts_tsi_handshaker_create( const grpc_alts_credentials_options* options, const char* target_name, - const char* handshaker_service_url, bool is_client, - grpc_pollset_set* interested_parties, tsi_handshaker** self); + const char* handshaker_service_url, bool is_client, tsi_handshaker** self); /** * This method handles handshaker response returned from ALTS handshaker diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs index 6ad5d56cad..880f2bef5f 100644 --- a/src/csharp/Grpc.Core/ChannelOptions.cs +++ b/src/csharp/Grpc.Core/ChannelOptions.cs @@ -26,8 +26,10 @@ namespace Grpc.Core /// <summary> /// Channel option specified when creating a channel. /// Corresponds to grpc_channel_args from grpc/grpc.h. + /// Commonly used channel option names are defined in <c>ChannelOptions</c>, + /// but any of the GRPC_ARG_* channel options names defined in grpc_types.h can be used. /// </summary> - public sealed class ChannelOption + public sealed class ChannelOption : IEquatable<ChannelOption> { /// <summary> /// Type of <c>ChannelOption</c>. @@ -119,10 +121,60 @@ namespace Grpc.Core return stringValue; } } + + /// <summary> + /// Determines whether the specified object is equal to the current object. + /// </summary> + public override bool Equals(object obj) + { + return Equals(obj as ChannelOption); + } + + /// <summary> + /// Determines whether the specified object is equal to the current object. + /// </summary> + public bool Equals(ChannelOption other) + { + return other != null && + type == other.type && + name == other.name && + intValue == other.intValue && + stringValue == other.stringValue; + } + + /// <summary> + /// A hash code for the current object. + /// </summary> + public override int GetHashCode() + { + var hashCode = 1412678443; + hashCode = hashCode * -1521134295 + type.GetHashCode(); + hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(name); + hashCode = hashCode * -1521134295 + intValue.GetHashCode(); + hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(stringValue); + return hashCode; + } + + /// <summary> + /// Equality operator. + /// </summary> + public static bool operator ==(ChannelOption option1, ChannelOption option2) + { + return EqualityComparer<ChannelOption>.Default.Equals(option1, option2); + } + + /// <summary> + /// Inequality operator. + /// </summary> + public static bool operator !=(ChannelOption option1, ChannelOption option2) + { + return !(option1 == option2); + } } /// <summary> - /// Defines names of supported channel options. + /// Defines names of most commonly used channel options. + /// Other supported options names can be found in grpc_types.h (GRPC_ARG_* definitions) /// </summary> public static class ChannelOptions { diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs index 153a52f947..a45cbe4107 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs @@ -505,7 +505,7 @@ namespace Grpc.Core.Internal public delegate void grpcsharp_redirect_log_delegate(GprLogDelegate callback); public delegate CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin_delegate(NativeMetadataInterceptor interceptor); public delegate void grpcsharp_metadata_credentials_notify_from_plugin_delegate(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails); - public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth); + public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest); public delegate void grpcsharp_server_credentials_release_delegate(IntPtr credentials); public delegate ServerSafeHandle grpcsharp_server_create_delegate(ChannelArgsSafeHandle args); public delegate void grpcsharp_server_register_completion_queue_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq); @@ -752,7 +752,7 @@ namespace Grpc.Core.Internal public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails); [DllImport(ImportName)] - public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth); + public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest); [DllImport(ImportName)] public static extern void grpcsharp_server_credentials_release(IntPtr credentials); @@ -1045,7 +1045,7 @@ namespace Grpc.Core.Internal public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails); [DllImport(ImportName)] - public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth); + public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest); [DllImport(ImportName)] public static extern void grpcsharp_server_credentials_release(IntPtr credentials); diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs index 545e581f94..5f8c95c4ea 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs @@ -32,13 +32,13 @@ namespace Grpc.Core.Internal { } - public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, bool forceClientAuth) + public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, SslClientCertificateRequestType clientCertificateRequest) { GrpcPreconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length); return Native.grpcsharp_ssl_server_credentials_create(pemRootCerts, keyCertPairCertChainArray, keyCertPairPrivateKeyArray, new UIntPtr((ulong)keyCertPairCertChainArray.Length), - forceClientAuth ? 1 : 0); + clientCertificateRequest); } protected override bool ReleaseHandle() diff --git a/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include b/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include index e3bbeb071e..af660064a4 100644 --- a/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include +++ b/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include @@ -1,6 +1,6 @@ <Project> <ItemGroup> - <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.so"> + <Content Include="..\..\..\cmake\build\libgrpc_csharp_ext.so"> <Link>libgrpc_csharp_ext.x64.so</Link> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <Pack>false</Pack> diff --git a/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include b/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include index 309e33d47e..570b0cd8b7 100644 --- a/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include +++ b/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include @@ -1,6 +1,6 @@ <Project> <ItemGroup> - <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.dylib"> + <Content Include="..\..\..\cmake\build\libgrpc_csharp_ext.dylib"> <Link>libgrpc_csharp_ext.x64.dylib</Link> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <Pack>false</Pack> diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs index 703f9ff6b3..8e4e44ba50 100644 --- a/src/csharp/Grpc.Core/ServerCredentials.cs +++ b/src/csharp/Grpc.Core/ServerCredentials.cs @@ -58,41 +58,106 @@ namespace Grpc.Core } /// <summary> + /// Modes of requesting client's SSL certificate by the server. + /// Corresponds to <c>grpc_ssl_client_certificate_request_type</c>. + /// </summary> + public enum SslClientCertificateRequestType { + /// <summary> + /// Server does not request client certificate. + /// The certificate presented by the client is not checked by the server at + /// all. (A client may present a self signed or signed certificate or not + /// present a certificate at all and any of those option would be accepted) + /// </summary> + DontRequest = 0, + /// <summary> + /// Server requests client certificate but does not enforce that the client + /// presents a certificate. + /// If the client presents a certificate, the client authentication is left to + /// the application (the necessary metadata will be available to the + /// application via authentication context properties, see grpc_auth_context). + /// The client's key certificate pair must be valid for the SSL connection to + /// be established. + ///</summary> + RequestButDontVerify, + /// <summary> + /// Server requests client certificate but does not enforce that the client + /// presents a certificate. + /// If the client presents a certificate, the client authentication is done by + /// the gRPC framework. (For a successful connection the client needs to either + /// present a certificate that can be verified against the root certificate + /// configured by the server or not present a certificate at all) + /// The client's key certificate pair must be valid for the SSL connection to + /// be established. + /// </summary> + RequestAndVerify, + /// <summary> + /// Server requests client certificate and enforces that the client presents a + /// certificate. + /// If the client presents a certificate, the client authentication is left to + /// the application (the necessary metadata will be available to the + /// application via authentication context properties, see grpc_auth_context). + /// The client's key certificate pair must be valid for the SSL connection to + /// be established. + ///</summary> + RequestAndRequireButDontVerify, + /// <summary> + /// Server requests client certificate and enforces that the client presents a + /// certificate. + /// The cerificate presented by the client is verified by the gRPC framework. + /// (For a successful connection the client needs to present a certificate that + /// can be verified against the root certificate configured by the server) + /// The client's key certificate pair must be valid for the SSL connection to + /// be established. + /// </summary> + RequestAndRequireAndVerify, + } + /// <summary> /// Server-side SSL credentials. /// </summary> public class SslServerCredentials : ServerCredentials { readonly IList<KeyCertificatePair> keyCertificatePairs; readonly string rootCertificates; - readonly bool forceClientAuth; + readonly SslClientCertificateRequestType clientCertificateRequest; /// <summary> /// Creates server-side SSL credentials. /// </summary> /// <param name="keyCertificatePairs">Key-certificates to use.</param> /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param> - /// <param name="forceClientAuth">If true, client will be rejected unless it proves its unthenticity using against rootCertificates.</param> + /// <param name="forceClientAuth">Deprecated, use clientCertificateRequest overload instead.</param> public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates, bool forceClientAuth) + : this(keyCertificatePairs, rootCertificates, forceClientAuth ? SslClientCertificateRequestType.RequestAndRequireAndVerify : SslClientCertificateRequestType.DontRequest) + { + } + + /// <summary> + /// Creates server-side SSL credentials. + /// </summary> + /// <param name="keyCertificatePairs">Key-certificates to use.</param> + /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param> + /// <param name="clientCertificateRequest">Options for requesting and verifying client certificate.</param> + public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates, SslClientCertificateRequestType clientCertificateRequest) { this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly(); GrpcPreconditions.CheckArgument(this.keyCertificatePairs.Count > 0, "At least one KeyCertificatePair needs to be provided."); - if (forceClientAuth) + if (clientCertificateRequest == SslClientCertificateRequestType.RequestAndRequireAndVerify) { GrpcPreconditions.CheckNotNull(rootCertificates, - "Cannot force client authentication unless you provide rootCertificates."); + "Cannot require and verify client certificate unless you provide rootCertificates."); } this.rootCertificates = rootCertificates; - this.forceClientAuth = forceClientAuth; + this.clientCertificateRequest = clientCertificateRequest; } /// <summary> /// Creates server-side SSL credentials. - /// This constructor should be use if you do not wish to autheticate client - /// using client root certificates. + /// This constructor should be used if you do not wish to authenticate the client. + /// (client certificate won't be requested and checked by the server at all). /// </summary> /// <param name="keyCertificatePairs">Key-certificates to use.</param> - public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null, false) + public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null, SslClientCertificateRequestType.DontRequest) { } @@ -119,13 +184,24 @@ namespace Grpc.Core } /// <summary> - /// If true, the authenticity of client check will be enforced. + /// Deprecated. If true, the authenticity of client check will be enforced. /// </summary> public bool ForceClientAuthentication { get { - return this.forceClientAuth; + return this.clientCertificateRequest == SslClientCertificateRequestType.RequestAndRequireAndVerify; + } + } + + /// <summary> + /// Mode of requesting certificate from client by the server. + /// </summary> + public SslClientCertificateRequestType ClientCertificateRequest + { + get + { + return this.clientCertificateRequest; } } @@ -139,7 +215,7 @@ namespace Grpc.Core certChains[i] = keyCertificatePairs[i].CertificateChain; keys[i] = keyCertificatePairs[i].PrivateKey; } - return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys, forceClientAuth); + return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys, clientCertificateRequest); } } } diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs index 152d8feab9..b3c47c2d8d 100644 --- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs @@ -37,20 +37,24 @@ namespace Grpc.IntegrationTesting public class SslCredentialsTest { const string Host = "localhost"; + const string IsPeerAuthenticatedMetadataKey = "test_only_is_peer_authenticated"; Server server; Channel channel; TestService.TestServiceClient client; - [OneTimeSetUp] - public void Init() + string rootCert; + KeyCertificatePair keyCertPair; + + public void InitClientAndServer(bool clientAddKeyCertPair, + SslClientCertificateRequestType clientCertRequestType) { - var rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath); - var keyCertPair = new KeyCertificatePair( + rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath); + keyCertPair = new KeyCertificatePair( File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerPrivateKeyPath)); - var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, true); - var clientCredentials = new SslCredentials(rootCert, keyCertPair); + var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, clientCertRequestType); + var clientCredentials = clientAddKeyCertPair ? new SslCredentials(rootCert, keyCertPair) : new SslCredentials(rootCert); // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755 server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) @@ -72,19 +76,133 @@ namespace Grpc.IntegrationTesting [OneTimeTearDown] public void Cleanup() { - channel.ShutdownAsync().Wait(); - server.ShutdownAsync().Wait(); + if (channel != null) + { + channel.ShutdownAsync().Wait(); + } + if (server != null) + { + server.ShutdownAsync().Wait(); + } } [Test] - public void AuthenticatedClientAndServer() + public async Task NoClientCert_DontRequestClientCertificate_Accepted() { - var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 }); - Assert.AreEqual(10, response.Payload.Body.Length); + InitClientAndServer( + clientAddKeyCertPair: false, + clientCertRequestType: SslClientCertificateRequestType.DontRequest); + + await CheckAccepted(expectPeerAuthenticated: false); } [Test] - public async Task AuthContextIsPopulated() + public async Task ClientWithCert_DontRequestClientCertificate_AcceptedButPeerNotAuthenticated() + { + InitClientAndServer( + clientAddKeyCertPair: true, + clientCertRequestType: SslClientCertificateRequestType.DontRequest); + + await CheckAccepted(expectPeerAuthenticated: false); + } + + [Test] + public async Task NoClientCert_RequestClientCertificateButDontVerify_Accepted() + { + InitClientAndServer( + clientAddKeyCertPair: false, + clientCertRequestType: SslClientCertificateRequestType.RequestButDontVerify); + + await CheckAccepted(expectPeerAuthenticated: false); + } + + [Test] + public async Task NoClientCert_RequestClientCertificateAndVerify_Accepted() + { + InitClientAndServer( + clientAddKeyCertPair: false, + clientCertRequestType: SslClientCertificateRequestType.RequestAndVerify); + + await CheckAccepted(expectPeerAuthenticated: false); + } + + [Test] + public async Task ClientWithCert_RequestAndRequireClientCertificateButDontVerify_Accepted() + { + InitClientAndServer( + clientAddKeyCertPair: true, + clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireButDontVerify); + + await CheckAccepted(expectPeerAuthenticated: true); + await CheckAuthContextIsPopulated(); + } + + [Test] + public async Task ClientWithCert_RequestAndRequireClientCertificateAndVerify_Accepted() + { + InitClientAndServer( + clientAddKeyCertPair: true, + clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireAndVerify); + + await CheckAccepted(expectPeerAuthenticated: true); + await CheckAuthContextIsPopulated(); + } + + [Test] + public void NoClientCert_RequestAndRequireClientCertificateButDontVerify_Rejected() + { + InitClientAndServer( + clientAddKeyCertPair: false, + clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireButDontVerify); + + CheckRejected(); + } + + [Test] + public void NoClientCert_RequestAndRequireClientCertificateAndVerify_Rejected() + { + InitClientAndServer( + clientAddKeyCertPair: false, + clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireAndVerify); + + CheckRejected(); + } + + [Test] + public void Constructor_LegacyForceClientAuth() + { + var creds = new SslServerCredentials(new[] { keyCertPair }, rootCert, true); + Assert.AreEqual(SslClientCertificateRequestType.RequestAndRequireAndVerify, creds.ClientCertificateRequest); + + var creds2 = new SslServerCredentials(new[] { keyCertPair }, rootCert, false); + Assert.AreEqual(SslClientCertificateRequestType.DontRequest, creds2.ClientCertificateRequest); + } + + [Test] + public void Constructor_NullRootCerts() + { + var keyCertPairs = new[] { keyCertPair }; + Assert.DoesNotThrow(() => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.DontRequest)); + Assert.DoesNotThrow(() => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestAndVerify)); + Assert.DoesNotThrow(() => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestAndRequireButDontVerify)); + Assert.Throws(typeof(ArgumentNullException), () => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestAndRequireAndVerify)); + } + + private async Task CheckAccepted(bool expectPeerAuthenticated) + { + var call = client.UnaryCallAsync(new SimpleRequest { ResponseSize = 10 }); + var response = await call; + Assert.AreEqual(10, response.Payload.Body.Length); + Assert.AreEqual(expectPeerAuthenticated.ToString(), call.GetTrailers().First((entry) => entry.Key == IsPeerAuthenticatedMetadataKey).Value); + } + + private void CheckRejected() + { + var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { ResponseSize = 10 })); + Assert.AreEqual(StatusCode.Unavailable, ex.Status.StatusCode); + } + + private async Task CheckAuthContextIsPopulated() { var call = client.StreamingInputCall(); await call.RequestStream.CompleteAsync(); @@ -96,6 +214,7 @@ namespace Grpc.IntegrationTesting { public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context) { + context.ResponseTrailers.Add(IsPeerAuthenticatedMetadataKey, context.AuthContext.IsPeerAuthenticated.ToString()); return Task.FromResult(new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) }); } diff --git a/src/csharp/doc/README.md b/src/csharp/doc/README.md index 46cce013a1..427f457eb6 100644 --- a/src/csharp/doc/README.md +++ b/src/csharp/doc/README.md @@ -1,9 +1,28 @@ DocFX-generated C# API Reference -------------------------------- +## Generating docs manually (on Windows) + Install docfx based on instructions here: https://github.com/dotnet/docfx ``` # generate docfx documentation into ./html directory $ docfx ``` + +## Release process: script for regenerating the docs automatically + +After each gRPC C# release, the docs need to be regenerated +and updated on the grpc.io site. The automated script will +re-generate the docs (using dockerized docfx installation) +and make everything ready for creating a PR to update the docs. + +``` +# 1. Run the script on Linux with docker installed +$ ./generate_reference_docs.sh + +# 2. Enter the git repo with updated "gh-pages" branch +$ cd grpc-gh-pages + +# 3. Review the changes and create a pull request +``` diff --git a/src/csharp/doc/generate_reference_docs.sh b/src/csharp/doc/generate_reference_docs.sh new file mode 100755 index 0000000000..c20d6c30bd --- /dev/null +++ b/src/csharp/doc/generate_reference_docs.sh @@ -0,0 +1,38 @@ +#!/bin/sh +# Copyright 2018 The 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. + +# Generates C# API docs using docfx inside docker. +set -ex +cd $(dirname $0) + +# cleanup temporary files +rm -rf html obj grpc-gh-pages + +# generate into src/csharp/doc/html directory +cd .. +docker run --rm -v "$(pwd)":/work -w /work/doc --user "$(id -u):$(id -g)" -it tsgkadot/docker-docfx:latest docfx +cd doc + +# prepare a clone of "gh-pages" branch where the generated docs are stored +GITHUB_USER="${USER}" +git clone -b gh-pages -o upstream git@github.com:grpc/grpc.git grpc-gh-pages +cd grpc-gh-pages +git remote add origin "git@github.com:${GITHUB_USER}/grpc.git" + +# replace old generated docs by the ones we just generated +rm -r csharp +cp -r ../html csharp + +echo "Done. Go to src/csharp/doc/grpc-gh-pages git repository and create a pull request to update the generated docs." diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 87a2516f8d..ed002ae1ff 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -964,7 +964,7 @@ GPR_EXPORT grpc_server_credentials* GPR_CALLTYPE grpcsharp_ssl_server_credentials_create( const char* pem_root_certs, const char** key_cert_pair_cert_chain_array, const char** key_cert_pair_private_key_array, size_t num_key_cert_pairs, - int force_client_auth) { + grpc_ssl_client_certificate_request_type client_request_type) { size_t i; grpc_server_credentials* creds; grpc_ssl_pem_key_cert_pair* key_cert_pairs = @@ -979,12 +979,9 @@ grpcsharp_ssl_server_credentials_create( key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i]; } } - creds = grpc_ssl_server_credentials_create_ex( - pem_root_certs, key_cert_pairs, num_key_cert_pairs, - force_client_auth - ? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY - : GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, - NULL); + creds = grpc_ssl_server_credentials_create_ex(pem_root_certs, key_cert_pairs, + num_key_cert_pairs, + client_request_type, NULL); gpr_free(key_cert_pairs); return creds; } diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template index aec1624acd..1628493d00 100644 --- a/templates/CMakeLists.txt.template +++ b/templates/CMakeLists.txt.template @@ -88,6 +88,7 @@ option(gRPC_BUILD_TESTS "Build tests" OFF) option(gRPC_BUILD_CODEGEN "Build codegen" ON) option(gRPC_BUILD_CSHARP_EXT "Build C# extensions" ON) + option(gRPC_BACKWARDS_COMPATIBILITY_MODE "Build libraries that are binary compatible across a larger number of OS and libc versions" OFF) set(gRPC_INSTALL_default ON) if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) @@ -164,6 +165,14 @@ set(_gRPC_PROTOBUF_LIBRARY_NAME "libprotobuf") endif() + if(gRPC_BACKWARDS_COMPATIBILITY_MODE) + add_definitions(-DGPR_BACKWARDS_COMPATIBILITY_MODE) + if (_gRPC_PLATFORM_MAC) + # some C++11 constructs not supported before OS X 10.9 + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9) + endif() + endif() + if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC) # C core has C++ source code, but should not depend on libstc++ (for better portability). # We need to use a few tricks to convince cmake to do that. diff --git a/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template b/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template index 8ce2a57323..774fc2c56f 100644 --- a/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template +++ b/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template @@ -73,7 +73,7 @@ 'void grpcsharp_redirect_log(GprLogDelegate callback)', 'CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor)', 'void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails)', - 'ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth)', + 'ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest)', 'void grpcsharp_server_credentials_release(IntPtr credentials)', 'ServerSafeHandle grpcsharp_server_create(ChannelArgsSafeHandle args)', 'void grpcsharp_server_register_completion_queue(ServerSafeHandle server, CompletionQueueSafeHandle cq)', diff --git a/templates/tools/dockerfile/csharp_deps.include b/templates/tools/dockerfile/csharp_deps.include index 3a40711e37..7ed0074867 100644 --- a/templates/tools/dockerfile/csharp_deps.include +++ b/templates/tools/dockerfile/csharp_deps.include @@ -15,3 +15,10 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y ${'\\'} && apt-get clean RUN nuget update -self + +#================= +# Use cmake 3.6 from jessie-backports +# needed to build grpc_csharp_ext with cmake + +RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list +RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index d594445bfb..3d8de79e37 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -30,6 +30,7 @@ #include "src/core/lib/gpr/useful.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/json/json.h" +#include "src/core/lib/surface/channel.h" #include "test/core/util/test_config.h" #include "test/cpp/util/channel_trace_proto_helper.h" @@ -51,6 +52,8 @@ class ChannelNodePeer { ChannelNode* node_; }; +size_t GetSizeofTraceEvent() { return sizeof(ChannelTrace::TraceEvent); } + namespace { grpc_json* GetJsonChild(grpc_json* parent, const char* key) { @@ -65,6 +68,11 @@ grpc_json* GetJsonChild(grpc_json* parent, const char* key) { void ValidateJsonArraySize(grpc_json* json, const char* key, size_t expected_size) { grpc_json* arr = GetJsonChild(json, key); + // the events array should not be present if there are no events. + if (expected_size == 0) { + EXPECT_EQ(arr, nullptr); + return; + } ASSERT_NE(arr, nullptr); ASSERT_EQ(arr->type, GRPC_JSON_ARRAY); size_t count = 0; @@ -94,29 +102,29 @@ void AddSimpleTrace(ChannelTrace* tracer) { } // checks for the existence of all the required members of the tracer. -void ValidateChannelTrace(ChannelTrace* tracer, - size_t expected_num_event_logged, size_t max_nodes) { - if (!max_nodes) return; +void ValidateChannelTraceCustom(ChannelTrace* tracer, size_t num_events_logged, + size_t num_events_expected) { grpc_json* json = tracer->RenderJson(); EXPECT_NE(json, nullptr); char* json_str = grpc_json_dump_to_string(json, 0); grpc_json_destroy(json); grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str); grpc_json* parsed_json = grpc_json_parse_string(json_str); - ValidateChannelTraceData(parsed_json, expected_num_event_logged, - GPR_MIN(expected_num_event_logged, max_nodes)); + ValidateChannelTraceData(parsed_json, num_events_logged, num_events_expected); grpc_json_destroy(parsed_json); gpr_free(json_str); } +void ValidateChannelTrace(ChannelTrace* tracer, size_t num_events_logged) { + ValidateChannelTraceCustom(tracer, num_events_logged, num_events_logged); +} + class ChannelFixture { public: - ChannelFixture(int max_trace_nodes) { - grpc_arg client_a; - client_a.type = GRPC_ARG_INTEGER; - client_a.key = - const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); - client_a.value.integer = max_trace_nodes; + ChannelFixture(int max_tracer_event_memory) { + grpc_arg client_a = grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE), + max_tracer_event_memory); grpc_channel_args client_args = {1, &client_a}; channel_ = grpc_insecure_channel_create("fake_target", &client_args, nullptr); @@ -132,67 +140,67 @@ class ChannelFixture { } // anonymous namespace -class ChannelTracerTest : public ::testing::TestWithParam<size_t> {}; +const int kEventListMemoryLimit = 1024 * 1024; // Tests basic ChannelTrace functionality like construction, adding trace, and // lookups by uuid. -TEST_P(ChannelTracerTest, BasicTest) { +TEST(ChannelTracerTest, BasicTest) { grpc_core::ExecCtx exec_ctx; - ChannelTrace tracer(GetParam()); + ChannelTrace tracer(kEventListMemoryLimit); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); tracer.AddTraceEvent(ChannelTrace::Severity::Info, grpc_slice_from_static_string("trace three")); tracer.AddTraceEvent(ChannelTrace::Severity::Error, grpc_slice_from_static_string("trace four error")); - ValidateChannelTrace(&tracer, 4, GetParam()); + ValidateChannelTrace(&tracer, 4); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); - ValidateChannelTrace(&tracer, 6, GetParam()); + ValidateChannelTrace(&tracer, 6); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); - ValidateChannelTrace(&tracer, 10, GetParam()); + ValidateChannelTrace(&tracer, 10); } // Tests more complex functionality, like a parent channel tracking // subchannles. This exercises the ref/unref patterns since the parent tracer // and this function will both hold refs to the subchannel. -TEST_P(ChannelTracerTest, ComplexTest) { +TEST(ChannelTracerTest, ComplexTest) { grpc_core::ExecCtx exec_ctx; - ChannelTrace tracer(GetParam()); + ChannelTrace tracer(kEventListMemoryLimit); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); - ChannelFixture channel1(GetParam()); - RefCountedPtr<ChannelNode> sc1 = - MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true); + ChannelFixture channel1(kEventListMemoryLimit); + RefCountedPtr<ChannelNode> sc1 = MakeRefCounted<ChannelNode>( + channel1.channel(), kEventListMemoryLimit, true); ChannelNodePeer sc1_peer(sc1.get()); tracer.AddTraceEventWithReference( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); - ValidateChannelTrace(&tracer, 3, GetParam()); + ValidateChannelTrace(&tracer, 3); AddSimpleTrace(sc1_peer.trace()); AddSimpleTrace(sc1_peer.trace()); AddSimpleTrace(sc1_peer.trace()); - ValidateChannelTrace(sc1_peer.trace(), 3, GetParam()); + ValidateChannelTrace(sc1_peer.trace(), 3); AddSimpleTrace(sc1_peer.trace()); AddSimpleTrace(sc1_peer.trace()); AddSimpleTrace(sc1_peer.trace()); - ValidateChannelTrace(sc1_peer.trace(), 6, GetParam()); + ValidateChannelTrace(sc1_peer.trace(), 6); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); - ValidateChannelTrace(&tracer, 5, GetParam()); - ChannelFixture channel2(GetParam()); - RefCountedPtr<ChannelNode> sc2 = - MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true); + ValidateChannelTrace(&tracer, 5); + ChannelFixture channel2(kEventListMemoryLimit); + RefCountedPtr<ChannelNode> sc2 = MakeRefCounted<ChannelNode>( + channel2.channel(), kEventListMemoryLimit, true); tracer.AddTraceEventWithReference( ChannelTrace::Severity::Info, grpc_slice_from_static_string("LB channel two created"), sc2); tracer.AddTraceEventWithReference( ChannelTrace::Severity::Warning, grpc_slice_from_static_string("subchannel one inactive"), sc1); - ValidateChannelTrace(&tracer, 7, GetParam()); + ValidateChannelTrace(&tracer, 7); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); @@ -206,38 +214,38 @@ TEST_P(ChannelTracerTest, ComplexTest) { // Test a case in which the parent channel has subchannels and the subchannels // have connections. Ensures that everything lives as long as it should then // gets deleted. -TEST_P(ChannelTracerTest, TestNesting) { +TEST(ChannelTracerTest, TestNesting) { grpc_core::ExecCtx exec_ctx; - ChannelTrace tracer(GetParam()); + ChannelTrace tracer(kEventListMemoryLimit); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); - ValidateChannelTrace(&tracer, 2, GetParam()); - ChannelFixture channel1(GetParam()); - RefCountedPtr<ChannelNode> sc1 = - MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true); + ValidateChannelTrace(&tracer, 2); + ChannelFixture channel1(kEventListMemoryLimit); + RefCountedPtr<ChannelNode> sc1 = MakeRefCounted<ChannelNode>( + channel1.channel(), kEventListMemoryLimit, true); ChannelNodePeer sc1_peer(sc1.get()); tracer.AddTraceEventWithReference( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); - ValidateChannelTrace(&tracer, 3, GetParam()); + ValidateChannelTrace(&tracer, 3); AddSimpleTrace(sc1_peer.trace()); - ChannelFixture channel2(GetParam()); - RefCountedPtr<ChannelNode> conn1 = - MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true); + ChannelFixture channel2(kEventListMemoryLimit); + RefCountedPtr<ChannelNode> conn1 = MakeRefCounted<ChannelNode>( + channel2.channel(), kEventListMemoryLimit, true); ChannelNodePeer conn1_peer(conn1.get()); // nesting one level deeper. sc1_peer.trace()->AddTraceEventWithReference( ChannelTrace::Severity::Info, grpc_slice_from_static_string("connection one created"), conn1); - ValidateChannelTrace(&tracer, 3, GetParam()); + ValidateChannelTrace(&tracer, 3); AddSimpleTrace(conn1_peer.trace()); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); - ValidateChannelTrace(&tracer, 5, GetParam()); - ValidateChannelTrace(conn1_peer.trace(), 1, GetParam()); - ChannelFixture channel3(GetParam()); - RefCountedPtr<ChannelNode> sc2 = - MakeRefCounted<ChannelNode>(channel3.channel(), GetParam(), true); + ValidateChannelTrace(&tracer, 5); + ValidateChannelTrace(conn1_peer.trace(), 1); + ChannelFixture channel3(kEventListMemoryLimit); + RefCountedPtr<ChannelNode> sc2 = MakeRefCounted<ChannelNode>( + channel3.channel(), kEventListMemoryLimit, true); tracer.AddTraceEventWithReference( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel two created"), sc2); @@ -247,14 +255,87 @@ TEST_P(ChannelTracerTest, TestNesting) { ChannelTrace::Severity::Warning, grpc_slice_from_static_string("subchannel one inactive"), sc1); AddSimpleTrace(&tracer); - ValidateChannelTrace(&tracer, 8, GetParam()); + ValidateChannelTrace(&tracer, 8); sc1.reset(); sc2.reset(); conn1.reset(); } -INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest, - ::testing::Values(0, 1, 2, 6, 10, 15)); +TEST(ChannelTracerTest, TestSmallMemoryLimit) { + grpc_core::ExecCtx exec_ctx; + // doesn't make sense, but serves a testing purpose for the channel tracing + // bookkeeping. All tracing events added should will get immediately garbage + // collected. + const int kSmallMemoryLimit = 1; + ChannelTrace tracer(kSmallMemoryLimit); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + tracer.AddTraceEvent(ChannelTrace::Severity::Info, + grpc_slice_from_static_string("trace three")); + tracer.AddTraceEvent(ChannelTrace::Severity::Error, + grpc_slice_from_static_string("trace four error")); + ValidateChannelTraceCustom(&tracer, 4, 0); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + ValidateChannelTraceCustom(&tracer, 6, 0); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + ValidateChannelTraceCustom(&tracer, 10, 0); +} + +TEST(ChannelTracerTest, TestEviction) { + grpc_core::ExecCtx exec_ctx; + const int kTraceEventSize = GetSizeofTraceEvent(); + const int kNumEvents = 5; + ChannelTrace tracer(kTraceEventSize * kNumEvents); + for (int i = 1; i <= kNumEvents; ++i) { + AddSimpleTrace(&tracer); + ValidateChannelTrace(&tracer, i); + } + // at this point the list is full, and each subsequent enntry will cause an + // eviction. + for (int i = 1; i <= kNumEvents; ++i) { + AddSimpleTrace(&tracer); + ValidateChannelTraceCustom(&tracer, kNumEvents + i, kNumEvents); + } +} + +TEST(ChannelTracerTest, TestMultipleEviction) { + grpc_core::ExecCtx exec_ctx; + const int kTraceEventSize = GetSizeofTraceEvent(); + const int kNumEvents = 5; + ChannelTrace tracer(kTraceEventSize * kNumEvents); + for (int i = 1; i <= kNumEvents; ++i) { + AddSimpleTrace(&tracer); + ValidateChannelTrace(&tracer, i); + } + // at this point the list is full, and each subsequent enntry will cause an + // eviction. We will now add in a trace event that has a copied string. This + // uses more memory, so it will cause a double eviciction + tracer.AddTraceEvent( + ChannelTrace::Severity::Info, + grpc_slice_from_copied_string( + "long enough string to trigger a multiple eviction")); + ValidateChannelTraceCustom(&tracer, kNumEvents + 1, kNumEvents - 1); +} + +TEST(ChannelTracerTest, TestTotalEviction) { + grpc_core::ExecCtx exec_ctx; + const int kTraceEventSize = GetSizeofTraceEvent(); + const int kNumEvents = 5; + ChannelTrace tracer(kTraceEventSize * kNumEvents); + for (int i = 1; i <= kNumEvents; ++i) { + AddSimpleTrace(&tracer); + ValidateChannelTrace(&tracer, i); + } + // at this point the list is full. Now we add such a big slice that + // everything gets evicted. + grpc_slice huge_slice = grpc_slice_malloc(kTraceEventSize * (kNumEvents + 1)); + tracer.AddTraceEvent(ChannelTrace::Severity::Info, huge_slice); + ValidateChannelTraceCustom(&tracer, kNumEvents + 1, 0); +} } // namespace testing } // namespace channelz diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index bcda30d9f2..aed1fba47c 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -49,8 +49,9 @@ class CallCountingHelperPeer { public: explicit CallCountingHelperPeer(CallCountingHelper* node) : node_(node) {} grpc_millis last_call_started_millis() const { - return (grpc_millis)gpr_atm_no_barrier_load( - &node_->last_call_started_millis_); + CallCountingHelper::CounterData data; + node_->CollectData(&data); + return (grpc_millis)gpr_atm_no_barrier_load(&data.last_call_started_millis); } private: @@ -124,11 +125,11 @@ void ValidateGetServers(size_t expected_servers) { class ChannelFixture { public: - ChannelFixture(int max_trace_nodes = 0) { + ChannelFixture(int max_tracer_event_memory = 0) { grpc_arg client_a[2]; client_a[0] = grpc_channel_arg_integer_create( - const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE), - max_trace_nodes); + const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE), + max_tracer_event_memory); client_a[1] = grpc_channel_arg_integer_create( const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true); grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; @@ -146,11 +147,11 @@ class ChannelFixture { class ServerFixture { public: - explicit ServerFixture(int max_trace_nodes = 0) { + explicit ServerFixture(int max_tracer_event_memory = 0) { grpc_arg server_a[] = { grpc_channel_arg_integer_create( - const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE), - max_trace_nodes), + const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE), + max_tracer_event_memory), grpc_channel_arg_integer_create( const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true), }; @@ -360,10 +361,10 @@ TEST(ChannelzGetServersTest, ManyServersTest) { } INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest, - ::testing::Values(0, 1, 2, 6, 10, 15)); + ::testing::Values(0, 8, 64, 1024, 1024 * 1024)); INSTANTIATE_TEST_CASE_P(ChannelzServerTestSweep, ChannelzServerTest, - ::testing::Values(0, 1, 2, 6, 10, 15)); + ::testing::Values(0, 8, 64, 1024, 1024 * 1024)); } // namespace testing } // namespace channelz diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 40a0370f0e..0e3ad6a476 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -199,10 +199,8 @@ static void run_one_request(grpc_end2end_test_config config, static void test_channelz(grpc_end2end_test_config config) { grpc_end2end_test_fixture f; - grpc_arg arg; - arg.type = GRPC_ARG_INTEGER; - arg.key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ); - arg.value.integer = true; + grpc_arg arg = grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true); grpc_channel_args args = {1, &arg}; f = begin_test(config, "test_channelz", &args, &args); @@ -266,12 +264,11 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { grpc_end2end_test_fixture f; grpc_arg arg[2]; - arg[0].type = GRPC_ARG_INTEGER; - arg[0].key = const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); - arg[0].value.integer = 5; - arg[1].type = GRPC_ARG_INTEGER; - arg[1].key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ); - arg[1].value.integer = true; + arg[0] = grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE), + 1024 * 1024); + arg[1] = grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true); grpc_channel_args args = {GPR_ARRAY_SIZE(arg), arg}; f = begin_test(config, "test_channelz_with_channel_trace", &args, &args); diff --git a/test/core/handshake/readahead_handshaker_server_ssl.cc b/test/core/handshake/readahead_handshaker_server_ssl.cc index 14d96b5d89..97e9c20ee4 100644 --- a/test/core/handshake/readahead_handshaker_server_ssl.cc +++ b/test/core/handshake/readahead_handshaker_server_ssl.cc @@ -75,7 +75,6 @@ static grpc_handshaker* readahead_handshaker_create() { static void readahead_handshaker_factory_add_handshakers( grpc_handshaker_factory* hf, const grpc_channel_args* args, - grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_handshake_manager_add(handshake_mgr, readahead_handshaker_create()); } diff --git a/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc b/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc index e9eb7e175f..85a58114ba 100644 --- a/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc +++ b/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc @@ -421,7 +421,7 @@ static tsi_handshaker* create_test_handshaker(bool used_for_success_test, alts_mock_handshaker_client_create(used_for_success_test); grpc_alts_credentials_options* options = grpc_alts_credentials_client_options_create(); - alts_tsi_handshaker_create(options, "target_name", "lame", is_client, nullptr, + alts_tsi_handshaker_create(options, "target_name", "lame", is_client, &handshaker); alts_tsi_handshaker* alts_handshaker = reinterpret_cast<alts_tsi_handshaker*>(handshaker); diff --git a/test/cpp/end2end/channelz_service_test.cc b/test/cpp/end2end/channelz_service_test.cc index a597fd9c4b..df9e23d50c 100644 --- a/test/cpp/end2end/channelz_service_test.cc +++ b/test/cpp/end2end/channelz_service_test.cc @@ -115,8 +115,8 @@ class ChannelzServerTest : public ::testing::Test { InsecureServerCredentials()); // forces channelz and channel tracing to be enabled. proxy_builder.AddChannelArgument(GRPC_ARG_ENABLE_CHANNELZ, 1); - proxy_builder.AddChannelArgument(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE, - 10); + proxy_builder.AddChannelArgument( + GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE, 1024); proxy_builder.RegisterService(&proxy_service_); proxy_server_ = proxy_builder.BuildAndStart(); } @@ -142,7 +142,7 @@ class ChannelzServerTest : public ::testing::Test { // are the ones that our test will actually be validating. ChannelArguments args; args.SetInt(GRPC_ARG_ENABLE_CHANNELZ, 1); - args.SetInt(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE, 10); + args.SetInt(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE, 1024); std::shared_ptr<Channel> channel_to_backend = CreateCustomChannel( backend_server_address, InsecureChannelCredentials(), args); proxy_service_.AddChannelToBackend(channel_to_backend); diff --git a/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile index 228efef698..7ec061ebe5 100644 --- a/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile +++ b/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile @@ -68,6 +68,13 @@ RUN apt-get update && apt-get install -y \ php5 php5-dev php-pear phpunit && apt-get clean +################## +# C# dependencies (needed to build grpc_csharp_ext) + +# Use cmake 3.6 from jessie-backports +RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list +RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean + RUN mkdir /var/local/jenkins # Define the default command. diff --git a/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile index d33e0f83ea..f81d8e5ba0 100644 --- a/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile +++ b/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile @@ -60,6 +60,13 @@ RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc" RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc" RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc" +################## +# C# dependencies (needed to build grpc_csharp_ext) + +# Use cmake 3.6 from jessie-backports +RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list +RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean + RUN mkdir /var/local/jenkins # Define the default command. diff --git a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile index 511e2932d6..b2216c79d4 100644 --- a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile @@ -82,6 +82,13 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \ RUN nuget update -self +#================= +# Use cmake 3.6 from jessie-backports +# needed to build grpc_csharp_ext with cmake + +RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list +RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean + # Install dotnet SDK based on https://www.microsoft.com/net/core#debian RUN apt-get update && apt-get install -y curl libunwind8 gettext # dotnet-dev-1.0.0-preview2-003131 diff --git a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile index 511e2932d6..b2216c79d4 100644 --- a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile @@ -82,6 +82,13 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \ RUN nuget update -self +#================= +# Use cmake 3.6 from jessie-backports +# needed to build grpc_csharp_ext with cmake + +RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list +RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean + # Install dotnet SDK based on https://www.microsoft.com/net/core#debian RUN apt-get update && apt-get install -y curl libunwind8 gettext # dotnet-dev-1.0.0-preview2-003131 diff --git a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile index 56bfb89925..578bf427cd 100644 --- a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile +++ b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile @@ -86,6 +86,13 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \ RUN nuget update -self +#================= +# Use cmake 3.6 from jessie-backports +# needed to build grpc_csharp_ext with cmake + +RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list +RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean + # Install dotnet SDK based on https://www.microsoft.com/net/core#debian RUN apt-get update && apt-get install -y curl libunwind8 gettext # dotnet-dev-1.0.0-preview2-003131 diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile index a82e7050fc..ad719f330f 100644 --- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile +++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile @@ -71,6 +71,13 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \ RUN nuget update -self +#================= +# Use cmake 3.6 from jessie-backports +# needed to build grpc_csharp_ext with cmake + +RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list +RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean + # Install dotnet SDK based on https://www.microsoft.com/net/core#debian RUN apt-get update && apt-get install -y curl libunwind8 gettext # dotnet-dev-1.0.0-preview2-003131 diff --git a/tools/run_tests/artifacts/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py index bdeb258e1f..054561aac9 100644 --- a/tools/run_tests/artifacts/artifact_targets.py +++ b/tools/run_tests/artifacts/artifact_targets.py @@ -248,29 +248,31 @@ class CSharpExtArtifact: ], use_workspace=True) else: - environ = { - 'CONFIG': 'opt', - 'EMBED_OPENSSL': 'true', - 'EMBED_ZLIB': 'true', - 'CFLAGS': '-DGPR_BACKWARDS_COMPATIBILITY_MODE', - 'CXXFLAGS': '-DGPR_BACKWARDS_COMPATIBILITY_MODE', - 'LDFLAGS': '' - } if self.platform == 'linux': + cmake_arch_option = '' # x64 is the default architecture + if self.arch == 'x86': + # TODO(jtattermusch): more work needed to enable + # boringssl assembly optimizations for 32-bit linux. + # Problem: currently we are building the artifact under + # 32-bit docker image, but CMAKE_SYSTEM_PROCESSOR is still + # set to x86_64, so the resulting boringssl binary + # would have undefined symbols. + cmake_arch_option = '-DOPENSSL_NO_ASM=ON' return create_docker_jobspec( self.name, 'tools/dockerfile/grpc_artifact_linux_%s' % self.arch, 'tools/run_tests/artifacts/build_artifact_csharp.sh', - environ=environ) + environ={ + 'CMAKE_ARCH_OPTION': cmake_arch_option + }) else: - archflag = _ARCH_FLAG_MAP[self.arch] - environ['CFLAGS'] += ' %s %s' % (archflag, _MACOS_COMPAT_FLAG) - environ['CXXFLAGS'] += ' %s %s' % (archflag, _MACOS_COMPAT_FLAG) - environ['LDFLAGS'] += ' %s' % archflag + cmake_arch_option = '' # x64 is the default architecture + if self.arch == 'x86': + cmake_arch_option = '-DCMAKE_OSX_ARCHITECTURES=i386' return create_jobspec( self.name, ['tools/run_tests/artifacts/build_artifact_csharp.sh'], - environ=environ, + environ={'CMAKE_ARCH_OPTION': cmake_arch_option}, use_workspace=True) def __str__(self): diff --git a/tools/run_tests/artifacts/build_artifact_csharp.sh b/tools/run_tests/artifacts/build_artifact_csharp.sh index d65340261d..bb8a91b520 100755 --- a/tools/run_tests/artifacts/build_artifact_csharp.sh +++ b/tools/run_tests/artifacts/build_artifact_csharp.sh @@ -17,7 +17,17 @@ set -ex cd "$(dirname "$0")/../../.." -make grpc_csharp_ext +mkdir -p cmake/build +cd cmake/build + +cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DgRPC_BACKWARDS_COMPATIBILITY_MODE=ON \ + -DgRPC_BUILD_TESTS=OFF \ + "${CMAKE_ARCH_OPTION}" \ + ../.. + +make grpc_csharp_ext -j2 +cd ../.. mkdir -p "${ARTIFACTS_OUT}" -cp libs/opt/libgrpc_csharp_ext.so "${ARTIFACTS_OUT}" || cp libs/opt/libgrpc_csharp_ext.dylib "${ARTIFACTS_OUT}" +cp cmake/build/libgrpc_csharp_ext.so "${ARTIFACTS_OUT}" || cp cmake/build/libgrpc_csharp_ext.dylib "${ARTIFACTS_OUT}" diff --git a/tools/run_tests/helper_scripts/pre_build_csharp.sh b/tools/run_tests/helper_scripts/pre_build_csharp.sh index f9f5440a61..7d83986f90 100755 --- a/tools/run_tests/helper_scripts/pre_build_csharp.sh +++ b/tools/run_tests/helper_scripts/pre_build_csharp.sh @@ -15,7 +15,14 @@ set -ex -# cd to gRPC csharp directory -cd "$(dirname "$0")/../../../src/csharp" +# cd to repository root +cd "$(dirname "$0")/../../.." + +mkdir -p cmake/build +cd cmake/build + +cmake -DgRPC_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE="${MSBUILD_CONFIG}" ../.. + +cd ../../src/csharp dotnet restore Grpc.sln diff --git a/tools/run_tests/performance/build_performance.sh b/tools/run_tests/performance/build_performance.sh index 35d9e90598..f235582579 100755 --- a/tools/run_tests/performance/build_performance.sh +++ b/tools/run_tests/performance/build_performance.sh @@ -53,7 +53,10 @@ do fi ;; "csharp") - python tools/run_tests/run_tests.py -l "$language" -c "$CONFIG" --build_only -j 8 --compiler coreclr + python tools/run_tests/run_tests.py -l "$language" -c "$CONFIG" --build_only -j 8 + # unbreak subsequent make builds by restoring zconf.h (previously renamed by cmake portion of C#'s build) + # See https://github.com/grpc/grpc/issues/11581 + (cd third_party/zlib; git checkout zconf.h) ;; "node"|"node_purejs") tools/run_tests/performance/build_performance_node.sh diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 3d73f9ec0e..c9b4c8b28b 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -922,20 +922,13 @@ class CSharpLanguage(object): self.config = config self.args = args if self.platform == 'windows': - _check_compiler(self.args.compiler, ['coreclr', 'default']) + _check_compiler(self.args.compiler, ['default', 'coreclr']) _check_arch(self.args.arch, ['default']) self._cmake_arch_option = 'x64' - self._make_options = [] else: _check_compiler(self.args.compiler, ['default', 'coreclr']) self._docker_distro = 'jessie' - if self.platform == 'mac': - # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build - self._make_options = ['EMBED_OPENSSL=true'] - else: - self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true'] - def test_specs(self): with open('src/csharp/tests.json') as f: tests_by_assembly = json.load(f) @@ -1010,7 +1003,7 @@ class CSharpLanguage(object): return ['grpc_csharp_ext'] def make_options(self): - return self._make_options + return [] def build_steps(self): if self.platform == 'windows': @@ -1028,7 +1021,9 @@ class CSharpLanguage(object): if self.platform == 'windows': return 'cmake/build/%s/Makefile' % self._cmake_arch_option else: - return 'Makefile' + # no need to set x86 specific flags as run_tests.py + # currently forbids x86 C# builds on both Linux and MacOS. + return 'cmake/build/Makefile' def dockerfile_dir(self): return 'tools/dockerfile/test/csharp_%s_%s' % ( |