diff options
Diffstat (limited to 'src')
383 files changed, 25500 insertions, 5908 deletions
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 1e0c36451b..56716493dc 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -128,6 +128,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file, ""); } static const char* headers_strs[] = { + "functional", "grpcpp/impl/codegen/async_generic_service.h", "grpcpp/impl/codegen/async_stream.h", "grpcpp/impl/codegen/async_unary_call.h", @@ -547,6 +548,116 @@ void PrintHeaderClientMethod(grpc_generator::Printer* printer, } } +void PrintHeaderClientMethodCallbackInterfacesStart( + grpc_generator::Printer* printer, + std::map<grpc::string, grpc::string>* vars) { + // This declares the interface for the callback-based API. The components + // are pure; even though this is new (post-1.0) API, it can be pure because + // it is an entirely new interface that happens to be scoped within + // StubInterface, not new additions to StubInterface itself + printer->Print("class experimental_async_interface {\n"); + // All methods in this new interface are public. There is no need for private + // "Raw" methods since the callback-based API returns unowned raw pointers + printer->Print(" public:\n"); + printer->Indent(); + printer->Print("virtual ~experimental_async_interface() {}\n"); +} + +void PrintHeaderClientMethodCallbackInterfaces( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + std::map<grpc::string, grpc::string>* vars, bool is_public) { + // Reserve is_public for future expansion + assert(is_public); + + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + if (method->NoStreaming()) { + printer->Print(*vars, + "virtual void $Method$(::grpc::ClientContext* context, " + "const $Request$* request, $Response$* response, " + "std::function<void(::grpc::Status)>) = 0;\n"); + } else if (ClientOnlyStreaming(method)) { + // TODO(vjpai): Add support for client-side streaming + } else if (ServerOnlyStreaming(method)) { + // TODO(vjpai): Add support for server-side streaming + } else if (method->BidiStreaming()) { + // TODO(vjpai): Add support for bidi streaming + } +} + +void PrintHeaderClientMethodCallbackInterfacesEnd( + grpc_generator::Printer* printer, + std::map<grpc::string, grpc::string>* vars) { + printer->Outdent(); + printer->Print("};\n"); + + // Declare a function to give the async stub contents. It can't be pure + // since this is a new API in StubInterface, but it is meaningless by default + // (since any stub that wants to use it must have its own implementation of + // the callback functions therein), so make the default return value nullptr. + // Intentionally include the word "class" to avoid possible shadowing. + printer->Print( + "virtual class experimental_async_interface* experimental_async() { " + "return nullptr; }\n"); +} + +void PrintHeaderClientMethodCallbackStart( + grpc_generator::Printer* printer, + std::map<grpc::string, grpc::string>* vars) { + // This declares the stub entry for the callback-based API. + printer->Print("class experimental_async final :\n"); + printer->Print(" public StubInterface::experimental_async_interface {\n"); + printer->Print(" public:\n"); + printer->Indent(); +} + +void PrintHeaderClientMethodCallback(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + std::map<grpc::string, grpc::string>* vars, + bool is_public) { + // Reserve is_public for future expansion + assert(is_public); + + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + if (method->NoStreaming()) { + printer->Print(*vars, + "void $Method$(::grpc::ClientContext* context, " + "const $Request$* request, $Response$* response, " + "std::function<void(::grpc::Status)>) override;\n"); + } else if (ClientOnlyStreaming(method)) { + // TODO(vjpai): Add support for client-side streaming + } else if (ServerOnlyStreaming(method)) { + // TODO(vjpai): Add support for server-side streaming + } else if (method->BidiStreaming()) { + // TODO(vjpai): Add support for bidi streaming + } +} + +void PrintHeaderClientMethodCallbackEnd( + grpc_generator::Printer* printer, + std::map<grpc::string, grpc::string>* vars) { + printer->Outdent(); + printer->Print(" private:\n"); + printer->Indent(); + printer->Print("friend class Stub;\n"); + printer->Print("explicit experimental_async(Stub* stub): stub_(stub) { }\n"); + // include a function with a dummy use of stub_ to avoid an unused + // private member warning for service with no methods + printer->Print("Stub* stub() { return stub_; }\n"); + printer->Print("Stub* stub_;\n"); + printer->Outdent(); + printer->Print("};\n"); + + printer->Print( + "class experimental_async_interface* experimental_async() override { " + "return &async_stub_; }\n"); +} + void PrintHeaderClientMethodData(grpc_generator::Printer* printer, const grpc_generator::Method* method, std::map<grpc::string, grpc::string>* vars) { @@ -951,6 +1062,14 @@ void PrintHeaderService(grpc_generator::Printer* printer, true); printer->Print(service->method(i)->GetTrailingComments("//").c_str()); } + PrintHeaderClientMethodCallbackInterfacesStart(printer, vars); + for (int i = 0; i < service->method_count(); ++i) { + printer->Print(service->method(i)->GetLeadingComments("//").c_str()); + PrintHeaderClientMethodCallbackInterfaces(printer, service->method(i).get(), + vars, true); + printer->Print(service->method(i)->GetTrailingComments("//").c_str()); + } + PrintHeaderClientMethodCallbackInterfacesEnd(printer, vars); printer->Outdent(); printer->Print("private:\n"); printer->Indent(); @@ -970,10 +1089,17 @@ void PrintHeaderService(grpc_generator::Printer* printer, for (int i = 0; i < service->method_count(); ++i) { PrintHeaderClientMethod(printer, service->method(i).get(), vars, true); } + PrintHeaderClientMethodCallbackStart(printer, vars); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodCallback(printer, service->method(i).get(), vars, + true); + } + PrintHeaderClientMethodCallbackEnd(printer, vars); printer->Outdent(); printer->Print("\n private:\n"); printer->Indent(); printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n"); + printer->Print("class experimental_async async_stub_{this};\n"); for (int i = 0; i < service->method_count(); ++i) { PrintHeaderClientMethod(printer, service->method(i).get(), vars, false); } @@ -1199,10 +1325,12 @@ grpc::string GetSourceIncludes(grpc_generator::File* file, std::map<grpc::string, grpc::string> vars; static const char* headers_strs[] = { + "functional", "grpcpp/impl/codegen/async_stream.h", "grpcpp/impl/codegen/async_unary_call.h", "grpcpp/impl/codegen/channel_interface.h", "grpcpp/impl/codegen/client_unary_call.h", + "grpcpp/impl/codegen/client_callback.h", "grpcpp/impl/codegen/method_handler_impl.h", "grpcpp/impl/codegen/rpc_service_method.h", "grpcpp/impl/codegen/service_type.h", @@ -1247,6 +1375,17 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, " return ::grpc::internal::BlockingUnaryCall" "(channel_.get(), rpcmethod_$Method$_, " "context, request, response);\n}\n\n"); + + printer->Print(*vars, + "void $ns$$Service$::Stub::experimental_async::$Method$(" + "::grpc::ClientContext* context, " + "const $Request$* request, $Response$* response, " + "std::function<void(::grpc::Status)> f) {\n"); + printer->Print(*vars, + " return ::grpc::internal::CallbackUnaryCall" + "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " + "context, request, response, std::move(f));\n}\n\n"); + for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; (*vars)["AsyncStart"] = async_prefix.start; @@ -1277,6 +1416,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "rpcmethod_$Method$_, " "context, response);\n" "}\n\n"); + + // TODO(vjpai): Add callback version + for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; (*vars)["AsyncStart"] = async_prefix.start; @@ -1308,6 +1450,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "rpcmethod_$Method$_, " "context, request);\n" "}\n\n"); + + // TODO(vjpai): Add callback version + for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; (*vars)["AsyncStart"] = async_prefix.start; @@ -1339,6 +1484,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "rpcmethod_$Method$_, " "context);\n" "}\n\n"); + + // TODO(vjpai): Add callback version + for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; (*vars)["AsyncStart"] = async_prefix.start; diff --git a/src/compiler/ruby_generator.cc b/src/compiler/ruby_generator.cc index c7af9c38fa..e39d8be5d4 100644 --- a/src/compiler/ruby_generator.cc +++ b/src/compiler/ruby_generator.cc @@ -160,12 +160,20 @@ grpc::string GetServices(const FileDescriptor* file) { return output; } + std::string package_name; + + if (file->options().has_ruby_package()) { + package_name = file->options().ruby_package(); + } else { + package_name = file->package(); + } + // Write out a file header. std::map<grpc::string, grpc::string> header_comment_vars = ListToDict({ "file.name", file->name(), "file.package", - file->package(), + package_name, }); out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n"); out.Print(header_comment_vars, @@ -190,7 +198,7 @@ grpc::string GetServices(const FileDescriptor* file) { // Write out services within the modules out.Print("\n"); - std::vector<grpc::string> modules = Split(file->package(), '.'); + std::vector<grpc::string> modules = Split(package_name, '.'); for (size_t i = 0; i < modules.size(); ++i) { std::map<grpc::string, grpc::string> module_vars = ListToDict({ "module.name", diff --git a/src/cpp/ext/filters/census/grpc_context.cc b/src/core/ext/filters/census/grpc_context.cc index 599a798dda..599a798dda 100644 --- a/src/cpp/ext/filters/census/grpc_context.cc +++ b/src/core/ext/filters/census/grpc_context.cc diff --git a/src/core/ext/filters/client_channel/OWNERS b/src/core/ext/filters/client_channel/OWNERS index c8760d947b..d38970e0fa 100644 --- a/src/core/ext/filters/client_channel/OWNERS +++ b/src/core/ext/filters/client_channel/OWNERS @@ -1,4 +1,4 @@ set noparent @markdroth -@dgquintas +@apolcyn @AspirinSJL diff --git a/src/core/ext/filters/client_channel/README.md b/src/core/ext/filters/client_channel/README.md index 7c209db12e..9676a4535b 100644 --- a/src/core/ext/filters/client_channel/README.md +++ b/src/core/ext/filters/client_channel/README.md @@ -46,20 +46,4 @@ construction arguments for concrete grpc_subchannel instances. Naming for GRPC =============== -Names in GRPC are represented by a URI (as defined in -[RFC 3986](https://tools.ietf.org/html/rfc3986)). - -The following schemes are currently supported: - -dns:///host:port - dns schemes are currently supported so long as authority is - empty (authority based dns resolution is expected in a future - release) - -unix:path - the unix scheme is used to create and connect to unix domain - sockets - the authority must be empty, and the path - represents the absolute or relative path to the desired - socket - -ipv4:host:port - a pre-resolved ipv4 dotted decimal address/port combination - -ipv6:[host]:port - a pre-resolved ipv6 address/port combination +See [/doc/naming.md](gRPC name resolution). diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index b06f09d8c7..23da11363b 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -129,6 +129,8 @@ typedef struct client_channel_channel_data { grpc_core::UniquePtr<char> info_lb_policy_name; /** service config in JSON form */ grpc_core::UniquePtr<char> info_service_config_json; + /* backpointer to grpc_channel's channelz node */ + grpc_core::channelz::ClientChannelNode* channelz_channel; } channel_data; typedef struct { @@ -153,6 +155,23 @@ static void watch_lb_policy_locked(channel_data* chand, grpc_core::LoadBalancingPolicy* lb_policy, grpc_connectivity_state current_state); +static const char* channel_connectivity_state_change_string( + grpc_connectivity_state state) { + switch (state) { + case GRPC_CHANNEL_IDLE: + return "Channel state change to IDLE"; + case GRPC_CHANNEL_CONNECTING: + return "Channel state change to CONNECTING"; + case GRPC_CHANNEL_READY: + return "Channel state change to READY"; + case GRPC_CHANNEL_TRANSIENT_FAILURE: + return "Channel state change to TRANSIENT_FAILURE"; + case GRPC_CHANNEL_SHUTDOWN: + return "Channel state change to SHUTDOWN"; + } + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} + static void set_channel_connectivity_state_locked(channel_data* chand, grpc_connectivity_state state, grpc_error* error, @@ -177,6 +196,12 @@ static void set_channel_connectivity_state_locked(channel_data* chand, gpr_log(GPR_INFO, "chand=%p: setting connectivity state to %s", chand, grpc_connectivity_state_name(state)); } + if (chand->channelz_channel != nullptr) { + chand->channelz_channel->AddTraceEvent( + grpc_core::channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string( + channel_connectivity_state_change_string(state))); + } grpc_connectivity_state_set(&chand->state_tracker, state, error, reason); } @@ -457,7 +482,6 @@ get_service_config_from_resolver_result_locked(channel_data* chand) { grpc_uri* uri = grpc_uri_parse(server_uri, true); GPR_ASSERT(uri->path[0] != '\0'); service_config_parsing_state parsing_state; - memset(&parsing_state, 0, sizeof(parsing_state)); parsing_state.server_name = uri->path[0] == '/' ? uri->path + 1 : uri->path; service_config->ParseGlobalParams(parse_retry_throttle_params, @@ -700,6 +724,7 @@ static grpc_error* cc_init_channel_elem(grpc_channel_element* elem, // Record enable_retries. arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_ENABLE_RETRIES); chand->enable_retries = grpc_channel_arg_get_bool(arg, true); + chand->channelz_channel = nullptr; // Record client channel factory. arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_CLIENT_CHANNEL_FACTORY); @@ -1778,23 +1803,22 @@ static void recv_message_ready(void* arg, grpc_error* error) { // recv_trailing_metadata handling // -// Sets *status and *server_pushback_md based on batch_data and error. -static void get_call_status(subchannel_batch_data* batch_data, - grpc_error* error, grpc_status_code* status, +// Sets *status and *server_pushback_md based on md_batch and error. +// Only sets *server_pushback_md if server_pushback_md != nullptr. +static void get_call_status(grpc_call_element* elem, + grpc_metadata_batch* md_batch, grpc_error* error, + grpc_status_code* status, grpc_mdelem** server_pushback_md) { - grpc_call_element* elem = batch_data->elem; call_data* calld = static_cast<call_data*>(elem->call_data); if (error != GRPC_ERROR_NONE) { grpc_error_get_status(error, calld->deadline, status, nullptr, nullptr, nullptr); } else { - grpc_metadata_batch* md_batch = - batch_data->batch.payload->recv_trailing_metadata - .recv_trailing_metadata; GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr); *status = grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md); - if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) { + if (server_pushback_md != nullptr && + md_batch->idx.named.grpc_retry_pushback_ms != nullptr) { *server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md; } } @@ -1967,7 +1991,9 @@ static void recv_trailing_metadata_ready(void* arg, grpc_error* error) { // Get the call's status and check for server pushback metadata. grpc_status_code status = GRPC_STATUS_OK; grpc_mdelem* server_pushback_md = nullptr; - get_call_status(batch_data, GRPC_ERROR_REF(error), &status, + grpc_metadata_batch* md_batch = + batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata; + get_call_status(elem, md_batch, GRPC_ERROR_REF(error), &status, &server_pushback_md); if (grpc_client_channel_trace.enabled()) { gpr_log(GPR_INFO, "chand=%p calld=%p: call finished, status=%s", chand, @@ -2194,9 +2220,9 @@ static void add_retriable_send_initial_metadata_op( .grpc_previous_rpc_attempts); } if (GPR_UNLIKELY(calld->num_attempts_completed > 0)) { - grpc_mdelem retry_md = grpc_mdelem_from_slices( + grpc_mdelem retry_md = grpc_mdelem_create( GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS, - *retry_count_strings[calld->num_attempts_completed - 1]); + *retry_count_strings[calld->num_attempts_completed - 1], nullptr); grpc_error* error = grpc_metadata_batch_add_tail( &retry_state->send_initial_metadata, &retry_state->send_initial_metadata_storage[calld->send_initial_metadata @@ -2601,6 +2627,11 @@ static void create_subchannel_call(grpc_call_element* elem, grpc_error* error) { new_error = grpc_error_add_child(new_error, error); pending_batches_fail(elem, new_error, true /* yield_call_combiner */); } else { + grpc_core::channelz::SubchannelNode* channelz_subchannel = + calld->pick.connected_subchannel->channelz_subchannel(); + if (channelz_subchannel != nullptr) { + channelz_subchannel->RecordCallStarted(); + } if (parent_data_size > 0) { subchannel_call_retry_state* retry_state = static_cast<subchannel_call_retry_state*>( @@ -3101,7 +3132,7 @@ static void cc_start_transport_stream_op_batch( // For all other batches, release the call combiner. if (grpc_client_channel_trace.enabled()) { gpr_log(GPR_INFO, - "chand=%p calld=%p: saved batch, yeilding call combiner", chand, + "chand=%p calld=%p: saved batch, yielding call combiner", chand, calld); } GRPC_CALL_COMBINER_STOP(calld->call_combiner, @@ -3203,9 +3234,16 @@ static void try_to_connect_locked(void* arg, grpc_error* error_ignored) { GRPC_CHANNEL_STACK_UNREF(chand->owning_stack, "try_to_connect"); } +void grpc_client_channel_set_channelz_node( + grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node) { + channel_data* chand = static_cast<channel_data*>(elem->channel_data); + chand->channelz_channel = node; +} + void grpc_client_channel_populate_child_refs( - grpc_channel_element* elem, grpc_core::ChildRefsList* child_subchannels, - grpc_core::ChildRefsList* child_channels) { + grpc_channel_element* elem, + grpc_core::channelz::ChildRefsList* child_subchannels, + grpc_core::channelz::ChildRefsList* child_channels) { channel_data* chand = static_cast<channel_data*>(elem->channel_data); if (chand->lb_policy != nullptr) { chand->lb_policy->FillChildRefsForChannelz(child_subchannels, diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h index 0b44a17562..4935fd24d8 100644 --- a/src/core/ext/filters/client_channel/client_channel.h +++ b/src/core/ext/filters/client_channel/client_channel.h @@ -40,9 +40,13 @@ extern grpc_core::TraceFlag grpc_client_channel_trace; extern const grpc_channel_filter grpc_client_channel_filter; +void grpc_client_channel_set_channelz_node( + grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node); + void grpc_client_channel_populate_child_refs( - grpc_channel_element* elem, grpc_core::ChildRefsList* child_subchannels, - grpc_core::ChildRefsList* child_channels); + grpc_channel_element* elem, + grpc_core::channelz::ChildRefsList* child_subchannels, + grpc_core::channelz::ChildRefsList* child_channels); grpc_connectivity_state grpc_client_channel_check_connectivity_state( grpc_channel_element* elem, int try_to_connect); diff --git a/src/core/ext/filters/client_channel/client_channel_channelz.cc b/src/core/ext/filters/client_channel/client_channel_channelz.cc index 86c765df52..bad1ef668c 100644 --- a/src/core/ext/filters/client_channel/client_channel_channelz.cc +++ b/src/core/ext/filters/client_channel/client_channel_channelz.cc @@ -20,10 +20,13 @@ #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/client_channel_channelz.h" +#include "src/core/lib/channel/channelz_registry.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/transport/connectivity_state.h" +#include <grpc/support/string_util.h> + namespace grpc_core { namespace channelz { namespace { @@ -46,6 +49,7 @@ ClientChannelNode::ClientChannelNode(grpc_channel* channel, : ChannelNode(channel, channel_tracer_max_nodes, is_top_level_channel) { client_channel_ = grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); + grpc_client_channel_set_channelz_node(client_channel_, this); GPR_ASSERT(client_channel_->filter == &grpc_client_channel_filter); } @@ -109,5 +113,73 @@ RefCountedPtr<ChannelNode> ClientChannelNode::MakeClientChannelNode( is_top_level_channel); } +SubchannelNode::SubchannelNode(grpc_subchannel* subchannel, + size_t channel_tracer_max_nodes) + : BaseNode(EntityType::kSubchannel), + subchannel_(subchannel), + target_( + UniquePtr<char>(gpr_strdup(grpc_subchannel_get_target(subchannel_)))), + trace_(channel_tracer_max_nodes) {} + +SubchannelNode::~SubchannelNode() {} + +void SubchannelNode::PopulateConnectivityState(grpc_json* json) { + grpc_connectivity_state state; + if (subchannel_ == nullptr) { + state = GRPC_CHANNEL_SHUTDOWN; + } else { + state = grpc_subchannel_check_connectivity(subchannel_, nullptr); + } + json = grpc_json_create_child(nullptr, json, "state", nullptr, + GRPC_JSON_OBJECT, false); + grpc_json_create_child(nullptr, json, "state", + grpc_connectivity_state_name(state), GRPC_JSON_STRING, + false); +} + +grpc_json* SubchannelNode::RenderJson() { + grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json* json = top_level_json; + grpc_json* json_iterator = nullptr; + json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr, + GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = grpc_json_add_number_string_child(json, json_iterator, + "subchannelId", uuid()); + // reset json iterators to top level object + json = top_level_json; + json_iterator = nullptr; + // create and fill the data child. + grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr, + GRPC_JSON_OBJECT, false); + json = data; + json_iterator = nullptr; + PopulateConnectivityState(json); + GPR_ASSERT(target_.get() != nullptr); + grpc_json_create_child(nullptr, json, "target", target_.get(), + GRPC_JSON_STRING, false); + // fill in the channel trace if applicable + grpc_json* trace_json = trace_.RenderJson(); + if (trace_json != nullptr) { + trace_json->key = "trace"; // this object is named trace in channelz.proto + grpc_json_link_child(json, trace_json, nullptr); + } + // ask CallCountingHelper to populate trace and call count data. + call_counter_.PopulateCallCounts(json); + json = top_level_json; + // populate the child socket. + intptr_t socket_uuid = grpc_subchannel_get_child_socket_uuid(subchannel_); + if (socket_uuid != 0) { + grpc_json* array_parent = grpc_json_create_child( + nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false); + json_iterator = grpc_json_create_child(json_iterator, array_parent, nullptr, + nullptr, GRPC_JSON_OBJECT, false); + grpc_json_add_number_string_child(json_iterator, nullptr, "socketId", + socket_uuid); + } + return top_level_json; +} + } // namespace channelz } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/client_channel_channelz.h b/src/core/ext/filters/client_channel/client_channel_channelz.h index 6f27b5c8b7..8a5c3e7e5e 100644 --- a/src/core/ext/filters/client_channel/client_channel_channelz.h +++ b/src/core/ext/filters/client_channel/client_channel_channelz.h @@ -23,16 +23,12 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/channel/channel_trace.h" #include "src/core/lib/channel/channelz.h" -#include "src/core/lib/gprpp/inlined_vector.h" -namespace grpc_core { - -// TODO(ncteisen), this only contains the uuids of the children for now, -// since that is all that is strictly needed. In a future enhancement we will -// add human readable names as in the channelz.proto -typedef InlinedVector<intptr_t, 10> ChildRefsList; +typedef struct grpc_subchannel grpc_subchannel; +namespace grpc_core { namespace channelz { // Subtype of ChannelNode that overrides and provides client_channel specific @@ -43,28 +39,59 @@ class ClientChannelNode : public ChannelNode { grpc_channel* channel, size_t channel_tracer_max_nodes, bool is_top_level_channel); - // Override this functionality since client_channels have a notion of - // channel connectivity. - void PopulateConnectivityState(grpc_json* json) override; + ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, + bool is_top_level_channel); + virtual ~ClientChannelNode() {} - // Override this functionality since client_channels have subchannels + // Overriding template methods from ChannelNode to render information that + // only ClientChannelNode knows about. + void PopulateConnectivityState(grpc_json* json) override; void PopulateChildRefs(grpc_json* json) override; // Helper to create a channel arg to ensure this type of ChannelNode is // created. static grpc_arg CreateChannelArg(); - protected: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW - ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel); - virtual ~ClientChannelNode() {} - private: grpc_channel_element* client_channel_; }; +// Handles channelz bookkeeping for sockets +class SubchannelNode : public BaseNode { + public: + SubchannelNode(grpc_subchannel* subchannel, size_t channel_tracer_max_nodes); + ~SubchannelNode() override; + + void MarkSubchannelDestroyed() { + GPR_ASSERT(subchannel_ != nullptr); + subchannel_ = nullptr; + } + + grpc_json* RenderJson() override; + + // proxy methods to composed classes. + void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) { + trace_.AddTraceEvent(severity, data); + } + void AddTraceEventWithReference(ChannelTrace::Severity severity, + grpc_slice data, + RefCountedPtr<BaseNode> referenced_channel) { + trace_.AddTraceEventWithReference(severity, data, + std::move(referenced_channel)); + } + void RecordCallStarted() { call_counter_.RecordCallStarted(); } + void RecordCallFailed() { call_counter_.RecordCallFailed(); } + void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } + + private: + grpc_subchannel* subchannel_; + UniquePtr<char> target_; + CallCountingHelper call_counter_; + ChannelTrace trace_; + + void PopulateConnectivityState(grpc_json* json); +}; + } // namespace channelz } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/client_channel_plugin.cc b/src/core/ext/filters/client_channel/client_channel_plugin.cc index 71da648660..e0784b7e5c 100644 --- a/src/core/ext/filters/client_channel/client_channel_plugin.cc +++ b/src/core/ext/filters/client_channel/client_channel_plugin.cc @@ -56,7 +56,7 @@ void grpc_client_channel_init(void) { grpc_register_http_proxy_mapper(); grpc_subchannel_index_init(); grpc_channel_init_register_stage( - GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, append_filter, + GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, append_filter, (void*)&grpc_client_channel_filter); grpc_http_connect_register_handshaker_factory(); } diff --git a/src/core/ext/filters/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h index 556594929c..ea34dcdab5 100644 --- a/src/core/ext/filters/client_channel/connector.h +++ b/src/core/ext/filters/client_channel/connector.h @@ -47,6 +47,9 @@ typedef struct { /** channel arguments (to be passed to the filters) */ grpc_channel_args* channel_args; + + /** socket uuid of the connected transport. 0 if not available */ + intptr_t socket_uuid; } grpc_connect_out_args; struct grpc_connector_vtable { 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 4e8b8b71db..bfabc68c66 100644 --- a/src/core/ext/filters/client_channel/http_connect_handshaker.cc +++ b/src/core/ext/filters/client_channel/http_connect_handshaker.cc @@ -320,7 +320,7 @@ static void http_connect_handshaker_do_handshake( // Take a new ref to be held by the write callback. gpr_ref(&handshaker->refcount); grpc_endpoint_write(args->endpoint, &handshaker->write_buffer, - &handshaker->request_done_closure); + &handshaker->request_done_closure, nullptr); gpr_mu_unlock(&handshaker->mu); } @@ -351,6 +351,7 @@ 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/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h index 3c0a9c1118..21f80b7b94 100644 --- a/src/core/ext/filters/client_channel/lb_policy.h +++ b/src/core/ext/filters/client_channel/lb_policy.h @@ -151,9 +151,9 @@ class LoadBalancingPolicy /// LB policy's referenced children. This is not invoked from the /// client_channel's combiner. The implementation is responsible for /// providing its own synchronization. - virtual void FillChildRefsForChannelz(ChildRefsList* child_subchannels, - ChildRefsList* child_channels) - GRPC_ABSTRACT; + virtual void FillChildRefsForChannelz( + channelz::ChildRefsList* child_subchannels, + channelz::ChildRefsList* child_channels) GRPC_ABSTRACT; void Orphan() override { // Invoke ShutdownAndUnrefLocked() inside of the combiner. @@ -212,8 +212,8 @@ class LoadBalancingPolicy // Dummy classes needed for alignment issues. // See https://github.com/grpc/grpc/issues/16032 for context. // TODO(ncteisen): remove this as soon as the issue is resolved. - ChildRefsList dummy_list_foo; - ChildRefsList dummy_list_bar; + channelz::ChildRefsList dummy_list_foo; + channelz::ChildRefsList dummy_list_bar; }; } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc index 6581385ff9..5511df7a27 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc @@ -92,6 +92,7 @@ #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/gprpp/mutex_lock.h" #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/combiner.h" @@ -135,8 +136,9 @@ class GrpcLb : public LoadBalancingPolicy { void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override; void ExitIdleLocked() override; void ResetBackoffLocked() override; - void FillChildRefsForChannelz(ChildRefsList* child_subchannels, - ChildRefsList* child_channels) override; + void FillChildRefsForChannelz( + channelz::ChildRefsList* child_subchannels, + channelz::ChildRefsList* child_channels) override; private: /// Linked list of pending pick requests. It stores all information needed to @@ -851,10 +853,12 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked( } } else { // No valid initial response or serverlist found. + char* response_slice_str = + grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX); gpr_log(GPR_ERROR, "[grpclb %p] Invalid LB response received: '%s'. Ignoring.", - grpclb_policy, - grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX)); + grpclb_policy, response_slice_str); + gpr_free(response_slice_str); } grpc_slice_unref_internal(response_slice); if (!grpclb_policy->shutting_down_) { @@ -1255,16 +1259,17 @@ bool GrpcLb::PickLocked(PickState* pick, grpc_error** error) { return pick_done; } -void GrpcLb::FillChildRefsForChannelz(ChildRefsList* child_subchannels, - ChildRefsList* child_channels) { +void GrpcLb::FillChildRefsForChannelz( + channelz::ChildRefsList* child_subchannels, + channelz::ChildRefsList* child_channels) { // delegate to the RoundRobin to fill the children subchannels. rr_policy_->FillChildRefsForChannelz(child_subchannels, child_channels); - mu_guard guard(&lb_channel_mu_); + MutexLock lock(&lb_channel_mu_); if (lb_channel_ != nullptr) { grpc_core::channelz::ChannelNode* channel_node = grpc_channel_get_channelz_node(lb_channel_); if (channel_node != nullptr) { - child_channels->push_back(channel_node->channel_uuid()); + child_channels->push_back(channel_node->uuid()); } } } @@ -1486,7 +1491,7 @@ void GrpcLb::OnBalancerChannelConnectivityChangedLocked(void* arg, grpclb_policy->lb_call_backoff_.Reset(); grpclb_policy->StartBalancerCallLocked(); } - // Fall through. + // fallthrough case GRPC_CHANNEL_SHUTDOWN: done: grpclb_policy->watching_lb_channel_ = false; @@ -1890,7 +1895,7 @@ void grpc_lb_policy_grpclb_init() { grpc_core::UniquePtr<grpc_core::LoadBalancingPolicyFactory>( grpc_core::New<grpc_core::GrpcLbFactory>())); grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_LOW, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_client_load_reporting_filter, (void*)&grpc_client_load_reporting_filter); } diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index bc51903ef5..f4dca146f7 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -27,6 +27,7 @@ #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/gprpp/mutex_lock.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/transport/connectivity_state.h" @@ -58,8 +59,8 @@ class PickFirst : public LoadBalancingPolicy { void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override; void ExitIdleLocked() override; void ResetBackoffLocked() override; - void FillChildRefsForChannelz(ChildRefsList* child_subchannels, - ChildRefsList* ignored) override; + void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, + channelz::ChildRefsList* ignored) override; private: ~PickFirst(); @@ -70,16 +71,22 @@ class PickFirst : public LoadBalancingPolicy { : public SubchannelData<PickFirstSubchannelList, PickFirstSubchannelData> { public: - PickFirstSubchannelData(PickFirstSubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, - grpc_subchannel* subchannel, - grpc_combiner* combiner) + PickFirstSubchannelData( + SubchannelList<PickFirstSubchannelList, PickFirstSubchannelData>* + subchannel_list, + const grpc_lb_user_data_vtable* user_data_vtable, + const grpc_lb_address& address, grpc_subchannel* subchannel, + grpc_combiner* combiner) : SubchannelData(subchannel_list, user_data_vtable, address, subchannel, combiner) {} void ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state, grpc_error* error) override; + + // Processes the connectivity change to READY for an unselected subchannel. + void ProcessUnselectedReadyLocked(); + + void CheckConnectivityStateAndStartWatchingLocked(); }; class PickFirstSubchannelList @@ -120,7 +127,6 @@ class PickFirst : public LoadBalancingPolicy { void ShutdownLocked() override; void StartPickingLocked(); - void DestroyUnselectedSubchannelsLocked(); void UpdateChildRefsLocked(); // All our subchannels. @@ -141,8 +147,8 @@ class PickFirst : public LoadBalancingPolicy { /// Lock and data used to capture snapshots of this channels child /// channels and subchannels. This data is consumed by channelz. gpr_mu child_refs_mu_; - ChildRefsList child_subchannels_; - ChildRefsList child_channels_; + channelz::ChildRefsList child_subchannels_; + channelz::ChildRefsList child_channels_; }; PickFirst::PickFirst(const Args& args) : LoadBalancingPolicy(args) { @@ -244,13 +250,9 @@ void PickFirst::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask, void PickFirst::StartPickingLocked() { started_picking_ = true; - if (subchannel_list_ != nullptr) { - for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) { - if (subchannel_list_->subchannel(i)->subchannel() != nullptr) { - subchannel_list_->subchannel(i)->StartConnectivityWatchLocked(); - break; - } - } + if (subchannel_list_ != nullptr && subchannel_list_->num_subchannels() > 0) { + subchannel_list_->subchannel(0) + ->CheckConnectivityStateAndStartWatchingLocked(); } } @@ -287,15 +289,6 @@ bool PickFirst::PickLocked(PickState* pick, grpc_error** error) { return false; } -void PickFirst::DestroyUnselectedSubchannelsLocked() { - for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) { - PickFirstSubchannelData* sd = subchannel_list_->subchannel(i); - if (selected_ != sd) { - sd->UnrefSubchannelLocked("selected_different_subchannel"); - } - } -} - grpc_connectivity_state PickFirst::CheckConnectivityLocked(grpc_error** error) { return grpc_connectivity_state_get(&state_tracker_, error); } @@ -307,8 +300,9 @@ void PickFirst::NotifyOnStateChangeLocked(grpc_connectivity_state* current, } void PickFirst::FillChildRefsForChannelz( - ChildRefsList* child_subchannels_to_fill, ChildRefsList* ignored) { - mu_guard guard(&child_refs_mu_); + channelz::ChildRefsList* child_subchannels_to_fill, + channelz::ChildRefsList* ignored) { + MutexLock lock(&child_refs_mu_); for (size_t i = 0; i < child_subchannels_.size(); ++i) { // TODO(ncteisen): implement a de dup loop that is not O(n^2). Might // have to implement lightweight set. For now, we don't care about @@ -327,7 +321,7 @@ void PickFirst::FillChildRefsForChannelz( } void PickFirst::UpdateChildRefsLocked() { - ChildRefsList cs; + channelz::ChildRefsList cs; if (subchannel_list_ != nullptr) { subchannel_list_->PopulateChildRefsList(&cs); } @@ -335,7 +329,7 @@ void PickFirst::UpdateChildRefsLocked() { latest_pending_subchannel_list_->PopulateChildRefsList(&cs); } // atomically update the data that channelz will actually be looking at. - mu_guard guard(&child_refs_mu_); + MutexLock lock(&child_refs_mu_); child_subchannels_ = std::move(cs); } @@ -386,7 +380,8 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) { // If we've started picking, start trying to connect to the first // subchannel in the new list. if (started_picking_) { - subchannel_list_->subchannel(0)->StartConnectivityWatchLocked(); + subchannel_list_->subchannel(0) + ->CheckConnectivityStateAndStartWatchingLocked(); } } else { // We do have a selected subchannel. @@ -411,7 +406,6 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) { if (sd->CheckConnectivityStateLocked(&error) == GRPC_CHANNEL_READY) { selected_ = sd; subchannel_list_ = std::move(subchannel_list); - DestroyUnselectedSubchannelsLocked(); sd->StartConnectivityWatchLocked(); // If there was a previously pending update (which may or may // not have contained the currently selected subchannel), drop @@ -440,7 +434,7 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) { // subchannel in the new list. if (started_picking_) { latest_pending_subchannel_list_->subchannel(0) - ->StartConnectivityWatchLocked(); + ->CheckConnectivityStateAndStartWatchingLocked(); } } } @@ -496,7 +490,6 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( p->TryReresolutionLocked(&grpc_lb_pick_first_trace, GRPC_ERROR_NONE); // In transient failure. Rely on re-resolution to recover. p->selected_ = nullptr; - UnrefSubchannelLocked("pf_selected_shutdown"); StopConnectivityWatchLocked(); } else { grpc_connectivity_state_set(&p->state_tracker_, connectivity_state, @@ -519,41 +512,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( // select in place of the current one. switch (connectivity_state) { case GRPC_CHANNEL_READY: { - // Case 2. Promote p->latest_pending_subchannel_list_ to - // p->subchannel_list_. - if (subchannel_list() == p->latest_pending_subchannel_list_.get()) { - if (grpc_lb_pick_first_trace.enabled()) { - gpr_log(GPR_INFO, - "Pick First %p promoting pending subchannel list %p to " - "replace %p", - p, p->latest_pending_subchannel_list_.get(), - p->subchannel_list_.get()); - } - p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_); - } - // Cases 1 and 2. - grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_READY, - GRPC_ERROR_NONE, "connecting_ready"); - p->selected_ = this; - if (grpc_lb_pick_first_trace.enabled()) { - gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, - subchannel()); - } - // Drop all other subchannels, since we are now connected. - p->DestroyUnselectedSubchannelsLocked(); - // Update any calls that were waiting for a pick. - PickState* pick; - while ((pick = p->pending_picks_)) { - p->pending_picks_ = pick->next; - pick->connected_subchannel = - p->selected_->connected_subchannel()->Ref(); - if (grpc_lb_pick_first_trace.enabled()) { - gpr_log(GPR_INFO, - "Servicing pending pick with selected subchannel %p", - p->selected_->subchannel()); - } - GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE); - } + ProcessUnselectedReadyLocked(); // Renew notification. RenewConnectivityWatchLocked(); break; @@ -561,11 +520,9 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( case GRPC_CHANNEL_TRANSIENT_FAILURE: { StopConnectivityWatchLocked(); PickFirstSubchannelData* sd = this; - do { - size_t next_index = - (sd->Index() + 1) % subchannel_list()->num_subchannels(); - sd = subchannel_list()->subchannel(next_index); - } while (sd->subchannel() == nullptr); + size_t next_index = + (sd->Index() + 1) % subchannel_list()->num_subchannels(); + sd = subchannel_list()->subchannel(next_index); // Case 1: Only set state to TRANSIENT_FAILURE if we've tried // all subchannels. if (sd->Index() == 0 && subchannel_list() == p->subchannel_list_.get()) { @@ -574,7 +531,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( &p->state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error), "exhausted_subchannels"); } - sd->StartConnectivityWatchLocked(); + sd->CheckConnectivityStateAndStartWatchingLocked(); break; } case GRPC_CHANNEL_CONNECTING: @@ -595,6 +552,65 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( GRPC_ERROR_UNREF(error); } +void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() { + PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy()); + // If we get here, there are two possible cases: + // 1. We do not currently have a selected subchannel, and the update is + // for a subchannel in p->subchannel_list_ that we're trying to + // connect to. The goal here is to find a subchannel that we can + // select. + // 2. We do currently have a selected subchannel, and the update is + // for a subchannel in p->latest_pending_subchannel_list_. The + // goal here is to find a subchannel from the update that we can + // select in place of the current one. + GPR_ASSERT(subchannel_list() == p->subchannel_list_.get() || + subchannel_list() == p->latest_pending_subchannel_list_.get()); + // Case 2. Promote p->latest_pending_subchannel_list_ to p->subchannel_list_. + if (subchannel_list() == p->latest_pending_subchannel_list_.get()) { + if (grpc_lb_pick_first_trace.enabled()) { + gpr_log(GPR_INFO, + "Pick First %p promoting pending subchannel list %p to " + "replace %p", + p, p->latest_pending_subchannel_list_.get(), + p->subchannel_list_.get()); + } + p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_); + } + // Cases 1 and 2. + grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_READY, + GRPC_ERROR_NONE, "subchannel_ready"); + p->selected_ = this; + if (grpc_lb_pick_first_trace.enabled()) { + gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel()); + } + // Update any calls that were waiting for a pick. + PickState* pick; + while ((pick = p->pending_picks_)) { + p->pending_picks_ = pick->next; + pick->connected_subchannel = p->selected_->connected_subchannel()->Ref(); + if (grpc_lb_pick_first_trace.enabled()) { + gpr_log(GPR_INFO, "Servicing pending pick with selected subchannel %p", + p->selected_->subchannel()); + } + GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE); + } +} + +void PickFirst::PickFirstSubchannelData:: + CheckConnectivityStateAndStartWatchingLocked() { + PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy()); + grpc_error* error = GRPC_ERROR_NONE; + if (p->selected_ != this && + CheckConnectivityStateLocked(&error) == GRPC_CHANNEL_READY) { + // We must process the READY subchannel before we start watching it. + // Otherwise, we won't know it's READY because we will be waiting for its + // connectivity state to change from READY. + ProcessUnselectedReadyLocked(); + } + GRPC_ERROR_UNREF(error); + StartConnectivityWatchLocked(); +} + // // factory // diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index fea84331d8..e9ed85cf66 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -36,6 +36,7 @@ #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/debug/trace.h" +#include "src/core/lib/gprpp/mutex_lock.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -69,8 +70,8 @@ class RoundRobin : public LoadBalancingPolicy { void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override; void ExitIdleLocked() override; void ResetBackoffLocked() override; - void FillChildRefsForChannelz(ChildRefsList* child_subchannels, - ChildRefsList* ignored) override; + void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, + channelz::ChildRefsList* ignored) override; private: ~RoundRobin(); @@ -88,11 +89,12 @@ class RoundRobin : public LoadBalancingPolicy { : public SubchannelData<RoundRobinSubchannelList, RoundRobinSubchannelData> { public: - RoundRobinSubchannelData(RoundRobinSubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, - grpc_subchannel* subchannel, - grpc_combiner* combiner) + RoundRobinSubchannelData( + SubchannelList<RoundRobinSubchannelList, RoundRobinSubchannelData>* + subchannel_list, + const grpc_lb_user_data_vtable* user_data_vtable, + const grpc_lb_address& address, grpc_subchannel* subchannel, + grpc_combiner* combiner) : SubchannelData(subchannel_list, user_data_vtable, address, subchannel, combiner), user_data_vtable_(user_data_vtable), @@ -138,7 +140,8 @@ class RoundRobin : public LoadBalancingPolicy { grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) : SubchannelList(policy, tracer, addresses, combiner, - client_channel_factory, args) { + client_channel_factory, args), + last_ready_index_(num_subchannels() - 1) { // Need to maintain a ref to the LB policy as long as we maintain // any references to subchannels, since the subchannels' // pollset_sets will include the LB policy's pollset_set. @@ -179,7 +182,7 @@ class RoundRobin : public LoadBalancingPolicy { size_t num_connecting_ = 0; size_t num_transient_failure_ = 0; grpc_error* last_transient_failure_error_ = GRPC_ERROR_NONE; - size_t last_ready_index_ = -1; // Index into list of last pick. + size_t last_ready_index_; // Index into list of last pick. }; // Helper class to ensure that any function that modifies the child refs @@ -220,8 +223,8 @@ class RoundRobin : public LoadBalancingPolicy { /// Lock and data used to capture snapshots of this channel's child /// channels and subchannels. This data is consumed by channelz. gpr_mu child_refs_mu_; - ChildRefsList child_subchannels_; - ChildRefsList child_channels_; + channelz::ChildRefsList child_subchannels_; + channelz::ChildRefsList child_channels_; }; RoundRobin::RoundRobin(const Args& args) : LoadBalancingPolicy(args) { @@ -399,8 +402,9 @@ bool RoundRobin::PickLocked(PickState* pick, grpc_error** error) { } void RoundRobin::FillChildRefsForChannelz( - ChildRefsList* child_subchannels_to_fill, ChildRefsList* ignored) { - mu_guard guard(&child_refs_mu_); + channelz::ChildRefsList* child_subchannels_to_fill, + channelz::ChildRefsList* ignored) { + MutexLock lock(&child_refs_mu_); for (size_t i = 0; i < child_subchannels_.size(); ++i) { // TODO(ncteisen): implement a de dup loop that is not O(n^2). Might // have to implement lightweight set. For now, we don't care about @@ -419,7 +423,7 @@ void RoundRobin::FillChildRefsForChannelz( } void RoundRobin::UpdateChildRefsLocked() { - ChildRefsList cs; + channelz::ChildRefsList cs; if (subchannel_list_ != nullptr) { subchannel_list_->PopulateChildRefsList(&cs); } @@ -427,7 +431,7 @@ void RoundRobin::UpdateChildRefsLocked() { latest_pending_subchannel_list_->PopulateChildRefsList(&cs); } // atomically update the data that channelz will actually be looking at. - mu_guard guard(&child_refs_mu_); + MutexLock lock(&child_refs_mu_); child_subchannels_ = std::move(cs); } diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index 0fa2f04e73..e0e0e1e638 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -65,6 +65,10 @@ class MySubchannelList namespace grpc_core { +// Forward declaration. +template <typename SubchannelListType, typename SubchannelDataType> +class SubchannelList; + // Stores data for a particular subchannel in a subchannel list. // Callers must create a subclass that implements the // ProcessConnectivityChangeLocked() method. @@ -72,7 +76,9 @@ template <typename SubchannelListType, typename SubchannelDataType> class SubchannelData { public: // Returns a pointer to the subchannel list containing this object. - SubchannelListType* subchannel_list() const { return subchannel_list_; } + SubchannelListType* subchannel_list() const { + return static_cast<SubchannelListType*>(subchannel_list_); + } // Returns the index into the subchannel list of this object. size_t Index() const { @@ -102,11 +108,6 @@ class SubchannelData { return pending_connectivity_state_unsafe_; } - // Unrefs the subchannel. May be used if an individual subchannel is - // no longer needed even though the subchannel list as a whole is not - // being unreffed. - virtual void UnrefSubchannelLocked(const char* reason); - // Resets the connection backoff. // TODO(roth): This method should go away when we move the backoff // code out of the subchannel and into the LB policies. @@ -138,10 +139,11 @@ class SubchannelData { GRPC_ABSTRACT_BASE_CLASS protected: - SubchannelData(SubchannelListType* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, grpc_subchannel* subchannel, - grpc_combiner* combiner); + SubchannelData( + SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list, + const grpc_lb_user_data_vtable* user_data_vtable, + const grpc_lb_address& address, grpc_subchannel* subchannel, + grpc_combiner* combiner); virtual ~SubchannelData(); @@ -154,6 +156,10 @@ class SubchannelData { grpc_connectivity_state connectivity_state, grpc_error* error) GRPC_ABSTRACT; + // Unrefs the subchannel. May be overridden by subclasses that need + // to perform extra cleanup when unreffing the subchannel. + virtual void UnrefSubchannelLocked(const char* reason); + private: // Updates connected_subchannel_ based on pending_connectivity_state_unsafe_. // Returns true if the connectivity state should be reported. @@ -162,7 +168,7 @@ class SubchannelData { static void OnConnectivityChangedLocked(void* arg, grpc_error* error); // Backpointer to owning subchannel list. Not owned. - SubchannelListType* subchannel_list_; + SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list_; // The subchannel and connected subchannel. grpc_subchannel* subchannel_; @@ -195,13 +201,13 @@ class SubchannelList bool shutting_down() const { return shutting_down_; } // Populates refs_list with the uuids of this SubchannelLists's subchannels. - void PopulateChildRefsList(ChildRefsList* refs_list) { + void PopulateChildRefsList(channelz::ChildRefsList* refs_list) { for (size_t i = 0; i < subchannels_.size(); ++i) { if (subchannels_[i].subchannel() != nullptr) { grpc_core::channelz::SubchannelNode* subchannel_node = grpc_subchannel_get_channelz_node(subchannels_[i].subchannel()); if (subchannel_node != nullptr) { - refs_list->push_back(subchannel_node->subchannel_uuid()); + refs_list->push_back(subchannel_node->uuid()); } } } @@ -269,7 +275,7 @@ class SubchannelList template <typename SubchannelListType, typename SubchannelDataType> SubchannelData<SubchannelListType, SubchannelDataType>::SubchannelData( - SubchannelListType* subchannel_list, + SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list, const grpc_lb_user_data_vtable* user_data_vtable, const grpc_lb_address& address, grpc_subchannel* subchannel, grpc_combiner* combiner) @@ -533,8 +539,7 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList( address_uri); gpr_free(address_uri); } - subchannels_.emplace_back(static_cast<SubchannelListType*>(this), - addresses->user_data_vtable, + subchannels_.emplace_back(this, addresses->user_data_vtable, addresses->addresses[i], subchannel, combiner); } } diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc b/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc new file mode 100644 index 0000000000..d79453d008 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc @@ -0,0 +1,140 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/support/port_platform.h> + +#include "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h" + +#include <grpc/support/atm.h> +#include <grpc/support/log.h> + +#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/profiling/timers.h" + +static grpc_error* init_channel_elem(grpc_channel_element* elem, + grpc_channel_element_args* args) { + return GRPC_ERROR_NONE; +} + +static void destroy_channel_elem(grpc_channel_element* elem) {} + +namespace { + +struct call_data { + // Stats object to update. + grpc_core::RefCountedPtr<grpc_core::XdsLbClientStats> client_stats; + // State for intercepting send_initial_metadata. + grpc_closure on_complete_for_send; + grpc_closure* original_on_complete_for_send; + bool send_initial_metadata_succeeded; + // State for intercepting recv_initial_metadata. + grpc_closure recv_initial_metadata_ready; + grpc_closure* original_recv_initial_metadata_ready; + bool recv_initial_metadata_succeeded; +}; + +} // namespace + +static void on_complete_for_send(void* arg, grpc_error* error) { + call_data* calld = static_cast<call_data*>(arg); + if (error == GRPC_ERROR_NONE) { + calld->send_initial_metadata_succeeded = true; + } + GRPC_CLOSURE_RUN(calld->original_on_complete_for_send, GRPC_ERROR_REF(error)); +} + +static void recv_initial_metadata_ready(void* arg, grpc_error* error) { + call_data* calld = static_cast<call_data*>(arg); + if (error == GRPC_ERROR_NONE) { + calld->recv_initial_metadata_succeeded = true; + } + GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready, + GRPC_ERROR_REF(error)); +} + +static grpc_error* init_call_elem(grpc_call_element* elem, + const grpc_call_element_args* args) { + call_data* calld = static_cast<call_data*>(elem->call_data); + // Get stats object from context and take a ref. + GPR_ASSERT(args->context != nullptr); + if (args->context[GRPC_GRPCLB_CLIENT_STATS].value != nullptr) { + calld->client_stats = static_cast<grpc_core::XdsLbClientStats*>( + args->context[GRPC_GRPCLB_CLIENT_STATS].value) + ->Ref(); + // Record call started. + calld->client_stats->AddCallStarted(); + } + return GRPC_ERROR_NONE; +} + +static void destroy_call_elem(grpc_call_element* elem, + const grpc_call_final_info* final_info, + grpc_closure* ignored) { + call_data* calld = static_cast<call_data*>(elem->call_data); + if (calld->client_stats != nullptr) { + // Record call finished, optionally setting client_failed_to_send and + // received. + calld->client_stats->AddCallFinished( + !calld->send_initial_metadata_succeeded /* client_failed_to_send */, + calld->recv_initial_metadata_succeeded /* known_received */); + // All done, so unref the stats object. + // TODO(roth): Eliminate this once filter stack is converted to C++. + calld->client_stats.reset(); + } +} + +static void start_transport_stream_op_batch( + grpc_call_element* elem, grpc_transport_stream_op_batch* batch) { + call_data* calld = static_cast<call_data*>(elem->call_data); + GPR_TIMER_SCOPE("clr_start_transport_stream_op_batch", 0); + if (calld->client_stats != nullptr) { + // Intercept send_initial_metadata. + if (batch->send_initial_metadata) { + calld->original_on_complete_for_send = batch->on_complete; + GRPC_CLOSURE_INIT(&calld->on_complete_for_send, on_complete_for_send, + calld, grpc_schedule_on_exec_ctx); + batch->on_complete = &calld->on_complete_for_send; + } + // Intercept recv_initial_metadata. + if (batch->recv_initial_metadata) { + calld->original_recv_initial_metadata_ready = + batch->payload->recv_initial_metadata.recv_initial_metadata_ready; + GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, + recv_initial_metadata_ready, calld, + grpc_schedule_on_exec_ctx); + batch->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->recv_initial_metadata_ready; + } + } + // Chain to next filter. + grpc_call_next_op(elem, batch); +} + +const grpc_channel_filter xds_client_load_reporting_filter = { + start_transport_stream_op_batch, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + destroy_call_elem, + 0, // sizeof(channel_data) + init_channel_elem, + destroy_channel_elem, + grpc_channel_next_get_info, + "client_load_reporting"}; diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h b/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h new file mode 100644 index 0000000000..31a799154c --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h @@ -0,0 +1,29 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_CLIENT_LOAD_REPORTING_FILTER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_CLIENT_LOAD_REPORTING_FILTER_H + +#include <grpc/support/port_platform.h> + +#include "src/core/lib/channel/channel_stack.h" + +extern const grpc_channel_filter xds_client_load_reporting_filter; + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_CLIENT_LOAD_REPORTING_FILTER_H \ + */ diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc b/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc new file mode 100644 index 0000000000..3bd2653635 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc @@ -0,0 +1,307 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/support/port_platform.h> + +#include "pb_decode.h" +#include "pb_encode.h" +#include "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h" + +#include <grpc/support/alloc.h> + +/* invoked once for every Server in ServerList */ +static bool count_serverlist(pb_istream_t* stream, const pb_field_t* field, + void** arg) { + xds_grpclb_serverlist* sl = static_cast<xds_grpclb_serverlist*>(*arg); + xds_grpclb_server server; + if (GPR_UNLIKELY(!pb_decode(stream, grpc_lb_v1_Server_fields, &server))) { + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream)); + return false; + } + ++sl->num_servers; + return true; +} + +typedef struct decode_serverlist_arg { + /* The decoding callback is invoked once per server in serverlist. Remember + * which index of the serverlist are we currently decoding */ + size_t decoding_idx; + /* The decoded serverlist */ + xds_grpclb_serverlist* serverlist; +} decode_serverlist_arg; + +/* invoked once for every Server in ServerList */ +static bool decode_serverlist(pb_istream_t* stream, const pb_field_t* field, + void** arg) { + decode_serverlist_arg* dec_arg = static_cast<decode_serverlist_arg*>(*arg); + GPR_ASSERT(dec_arg->serverlist->num_servers >= dec_arg->decoding_idx); + xds_grpclb_server* server = + static_cast<xds_grpclb_server*>(gpr_zalloc(sizeof(xds_grpclb_server))); + if (GPR_UNLIKELY(!pb_decode(stream, grpc_lb_v1_Server_fields, server))) { + gpr_free(server); + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream)); + return false; + } + dec_arg->serverlist->servers[dec_arg->decoding_idx++] = server; + return true; +} + +xds_grpclb_request* xds_grpclb_request_create(const char* lb_service_name) { + xds_grpclb_request* req = + static_cast<xds_grpclb_request*>(gpr_malloc(sizeof(xds_grpclb_request))); + req->has_client_stats = false; + req->has_initial_request = true; + req->initial_request.has_name = true; + strncpy(req->initial_request.name, lb_service_name, + XDS_SERVICE_NAME_MAX_LENGTH); + return req; +} + +static void populate_timestamp(gpr_timespec timestamp, + xds_grpclb_timestamp* timestamp_pb) { + timestamp_pb->has_seconds = true; + timestamp_pb->seconds = timestamp.tv_sec; + timestamp_pb->has_nanos = true; + timestamp_pb->nanos = timestamp.tv_nsec; +} + +static bool encode_string(pb_ostream_t* stream, const pb_field_t* field, + void* const* arg) { + char* str = static_cast<char*>(*arg); + if (!pb_encode_tag_for_field(stream, field)) return false; + return pb_encode_string(stream, reinterpret_cast<uint8_t*>(str), strlen(str)); +} + +static bool encode_drops(pb_ostream_t* stream, const pb_field_t* field, + void* const* arg) { + grpc_core::XdsLbClientStats::DroppedCallCounts* drop_entries = + static_cast<grpc_core::XdsLbClientStats::DroppedCallCounts*>(*arg); + if (drop_entries == nullptr) return true; + for (size_t i = 0; i < drop_entries->size(); ++i) { + if (!pb_encode_tag_for_field(stream, field)) return false; + grpc_lb_v1_ClientStatsPerToken drop_message; + drop_message.load_balance_token.funcs.encode = encode_string; + drop_message.load_balance_token.arg = (*drop_entries)[i].token.get(); + drop_message.has_num_calls = true; + drop_message.num_calls = (*drop_entries)[i].count; + if (!pb_encode_submessage(stream, grpc_lb_v1_ClientStatsPerToken_fields, + &drop_message)) { + return false; + } + } + return true; +} + +xds_grpclb_request* xds_grpclb_load_report_request_create_locked( + grpc_core::XdsLbClientStats* client_stats) { + xds_grpclb_request* req = + static_cast<xds_grpclb_request*>(gpr_zalloc(sizeof(xds_grpclb_request))); + req->has_client_stats = true; + req->client_stats.has_timestamp = true; + populate_timestamp(gpr_now(GPR_CLOCK_REALTIME), &req->client_stats.timestamp); + req->client_stats.has_num_calls_started = true; + req->client_stats.has_num_calls_finished = true; + req->client_stats.has_num_calls_finished_with_client_failed_to_send = true; + req->client_stats.has_num_calls_finished_with_client_failed_to_send = true; + req->client_stats.has_num_calls_finished_known_received = true; + req->client_stats.calls_finished_with_drop.funcs.encode = encode_drops; + grpc_core::UniquePtr<grpc_core::XdsLbClientStats::DroppedCallCounts> + drop_counts; + client_stats->GetLocked( + &req->client_stats.num_calls_started, + &req->client_stats.num_calls_finished, + &req->client_stats.num_calls_finished_with_client_failed_to_send, + &req->client_stats.num_calls_finished_known_received, &drop_counts); + // Will be deleted in xds_grpclb_request_destroy(). + req->client_stats.calls_finished_with_drop.arg = drop_counts.release(); + return req; +} + +grpc_slice xds_grpclb_request_encode(const xds_grpclb_request* request) { + size_t encoded_length; + pb_ostream_t sizestream; + pb_ostream_t outputstream; + grpc_slice slice; + memset(&sizestream, 0, sizeof(pb_ostream_t)); + pb_encode(&sizestream, grpc_lb_v1_LoadBalanceRequest_fields, request); + encoded_length = sizestream.bytes_written; + + slice = GRPC_SLICE_MALLOC(encoded_length); + outputstream = + pb_ostream_from_buffer(GRPC_SLICE_START_PTR(slice), encoded_length); + GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v1_LoadBalanceRequest_fields, + request) != 0); + return slice; +} + +void xds_grpclb_request_destroy(xds_grpclb_request* request) { + if (request->has_client_stats) { + grpc_core::XdsLbClientStats::DroppedCallCounts* drop_entries = + static_cast<grpc_core::XdsLbClientStats::DroppedCallCounts*>( + request->client_stats.calls_finished_with_drop.arg); + grpc_core::Delete(drop_entries); + } + gpr_free(request); +} + +typedef grpc_lb_v1_LoadBalanceResponse xds_grpclb_response; +xds_grpclb_initial_response* xds_grpclb_initial_response_parse( + grpc_slice encoded_xds_grpclb_response) { + pb_istream_t stream = + pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_xds_grpclb_response), + GRPC_SLICE_LENGTH(encoded_xds_grpclb_response)); + xds_grpclb_response res; + memset(&res, 0, sizeof(xds_grpclb_response)); + if (GPR_UNLIKELY( + !pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res))) { + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); + return nullptr; + } + + if (!res.has_initial_response) return nullptr; + + xds_grpclb_initial_response* initial_res = + static_cast<xds_grpclb_initial_response*>( + gpr_malloc(sizeof(xds_grpclb_initial_response))); + memcpy(initial_res, &res.initial_response, + sizeof(xds_grpclb_initial_response)); + + return initial_res; +} + +xds_grpclb_serverlist* xds_grpclb_response_parse_serverlist( + grpc_slice encoded_xds_grpclb_response) { + pb_istream_t stream = + pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_xds_grpclb_response), + GRPC_SLICE_LENGTH(encoded_xds_grpclb_response)); + pb_istream_t stream_at_start = stream; + xds_grpclb_serverlist* sl = static_cast<xds_grpclb_serverlist*>( + gpr_zalloc(sizeof(xds_grpclb_serverlist))); + xds_grpclb_response res; + memset(&res, 0, sizeof(xds_grpclb_response)); + // First pass: count number of servers. + res.server_list.servers.funcs.decode = count_serverlist; + res.server_list.servers.arg = sl; + bool status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res); + if (GPR_UNLIKELY(!status)) { + gpr_free(sl); + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); + return nullptr; + } + // Second pass: populate servers. + if (sl->num_servers > 0) { + sl->servers = static_cast<xds_grpclb_server**>( + gpr_zalloc(sizeof(xds_grpclb_server*) * sl->num_servers)); + decode_serverlist_arg decode_arg; + memset(&decode_arg, 0, sizeof(decode_arg)); + decode_arg.serverlist = sl; + res.server_list.servers.funcs.decode = decode_serverlist; + res.server_list.servers.arg = &decode_arg; + status = pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields, + &res); + if (GPR_UNLIKELY(!status)) { + xds_grpclb_destroy_serverlist(sl); + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); + return nullptr; + } + } + return sl; +} + +void xds_grpclb_destroy_serverlist(xds_grpclb_serverlist* serverlist) { + if (serverlist == nullptr) { + return; + } + for (size_t i = 0; i < serverlist->num_servers; i++) { + gpr_free(serverlist->servers[i]); + } + gpr_free(serverlist->servers); + gpr_free(serverlist); +} + +xds_grpclb_serverlist* xds_grpclb_serverlist_copy( + const xds_grpclb_serverlist* sl) { + xds_grpclb_serverlist* copy = static_cast<xds_grpclb_serverlist*>( + gpr_zalloc(sizeof(xds_grpclb_serverlist))); + copy->num_servers = sl->num_servers; + copy->servers = static_cast<xds_grpclb_server**>( + gpr_malloc(sizeof(xds_grpclb_server*) * sl->num_servers)); + for (size_t i = 0; i < sl->num_servers; i++) { + copy->servers[i] = + static_cast<xds_grpclb_server*>(gpr_malloc(sizeof(xds_grpclb_server))); + memcpy(copy->servers[i], sl->servers[i], sizeof(xds_grpclb_server)); + } + return copy; +} + +bool xds_grpclb_serverlist_equals(const xds_grpclb_serverlist* lhs, + const xds_grpclb_serverlist* rhs) { + if (lhs == nullptr || rhs == nullptr) { + return false; + } + if (lhs->num_servers != rhs->num_servers) { + return false; + } + for (size_t i = 0; i < lhs->num_servers; i++) { + if (!xds_grpclb_server_equals(lhs->servers[i], rhs->servers[i])) { + return false; + } + } + return true; +} + +bool xds_grpclb_server_equals(const xds_grpclb_server* lhs, + const xds_grpclb_server* rhs) { + return memcmp(lhs, rhs, sizeof(xds_grpclb_server)) == 0; +} + +int xds_grpclb_duration_compare(const xds_grpclb_duration* lhs, + const xds_grpclb_duration* rhs) { + GPR_ASSERT(lhs && rhs); + if (lhs->has_seconds && rhs->has_seconds) { + if (lhs->seconds < rhs->seconds) return -1; + if (lhs->seconds > rhs->seconds) return 1; + } else if (lhs->has_seconds) { + return 1; + } else if (rhs->has_seconds) { + return -1; + } + + GPR_ASSERT(lhs->seconds == rhs->seconds); + if (lhs->has_nanos && rhs->has_nanos) { + if (lhs->nanos < rhs->nanos) return -1; + if (lhs->nanos > rhs->nanos) return 1; + } else if (lhs->has_nanos) { + return 1; + } else if (rhs->has_nanos) { + return -1; + } + + return 0; +} + +grpc_millis xds_grpclb_duration_to_millis(xds_grpclb_duration* duration_pb) { + return static_cast<grpc_millis>( + (duration_pb->has_seconds ? duration_pb->seconds : 0) * GPR_MS_PER_SEC + + (duration_pb->has_nanos ? duration_pb->nanos : 0) / GPR_NS_PER_MS); +} + +void xds_grpclb_initial_response_destroy( + xds_grpclb_initial_response* response) { + gpr_free(response); +} diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h new file mode 100644 index 0000000000..3f096af6d6 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h @@ -0,0 +1,89 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_LOAD_BALANCER_API_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_LOAD_BALANCER_API_H + +#include <grpc/support/port_platform.h> + +#include <grpc/slice_buffer.h> + +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" +#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" + +#define XDS_SERVICE_NAME_MAX_LENGTH 128 + +typedef grpc_lb_v1_Server_ip_address_t xds_grpclb_ip_address; +typedef grpc_lb_v1_LoadBalanceRequest xds_grpclb_request; +typedef grpc_lb_v1_InitialLoadBalanceResponse xds_grpclb_initial_response; +typedef grpc_lb_v1_Server xds_grpclb_server; +typedef google_protobuf_Duration xds_grpclb_duration; +typedef google_protobuf_Timestamp xds_grpclb_timestamp; + +typedef struct { + xds_grpclb_server** servers; + size_t num_servers; +} xds_grpclb_serverlist; + +/** Create a request for a gRPC LB service under \a lb_service_name */ +xds_grpclb_request* xds_grpclb_request_create(const char* lb_service_name); +xds_grpclb_request* xds_grpclb_load_report_request_create_locked( + grpc_core::XdsLbClientStats* client_stats); + +/** Protocol Buffers v3-encode \a request */ +grpc_slice xds_grpclb_request_encode(const xds_grpclb_request* request); + +/** Destroy \a request */ +void xds_grpclb_request_destroy(xds_grpclb_request* request); + +/** Parse (ie, decode) the bytes in \a encoded_xds_grpclb_response as a \a + * xds_grpclb_initial_response */ +xds_grpclb_initial_response* xds_grpclb_initial_response_parse( + grpc_slice encoded_xds_grpclb_response); + +/** Parse the list of servers from an encoded \a xds_grpclb_response */ +xds_grpclb_serverlist* xds_grpclb_response_parse_serverlist( + grpc_slice encoded_xds_grpclb_response); + +/** Return a copy of \a sl. The caller is responsible for calling \a + * xds_grpclb_destroy_serverlist on the returned copy. */ +xds_grpclb_serverlist* xds_grpclb_serverlist_copy( + const xds_grpclb_serverlist* sl); + +bool xds_grpclb_serverlist_equals(const xds_grpclb_serverlist* lhs, + const xds_grpclb_serverlist* rhs); + +bool xds_grpclb_server_equals(const xds_grpclb_server* lhs, + const xds_grpclb_server* rhs); + +/** Destroy \a serverlist */ +void xds_grpclb_destroy_serverlist(xds_grpclb_serverlist* serverlist); + +/** Compare \a lhs against \a rhs and return 0 if \a lhs and \a rhs are equal, + * < 0 if \a lhs represents a duration shorter than \a rhs and > 0 otherwise */ +int xds_grpclb_duration_compare(const xds_grpclb_duration* lhs, + const xds_grpclb_duration* rhs); + +grpc_millis xds_grpclb_duration_to_millis(xds_grpclb_duration* duration_pb); + +/** Destroy \a initial_response */ +void xds_grpclb_initial_response_destroy(xds_grpclb_initial_response* response); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_LOAD_BALANCER_API_H \ + */ diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc new file mode 100644 index 0000000000..16e910b2d9 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc @@ -0,0 +1,1894 @@ +/* + * + * Copyright 2018 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. + * + */ + +/// Implementation of the gRPC LB policy. +/// +/// This policy takes as input a list of resolved addresses, which must +/// include at least one balancer address. +/// +/// An internal channel (\a lb_channel_) is created for the addresses +/// from that are balancers. This channel behaves just like a regular +/// channel that uses pick_first to select from the list of balancer +/// addresses. +/// +/// The first time the policy gets a request for a pick, a ping, or to exit +/// the idle state, \a StartPickingLocked() is called. This method is +/// responsible for instantiating the internal *streaming* call to the LB +/// server (whichever address pick_first chose). The call will be complete +/// when either the balancer sends status or when we cancel the call (e.g., +/// because we are shutting down). In needed, we retry the call. If we +/// received at least one valid message from the server, a new call attempt +/// will be made immediately; otherwise, we apply back-off delays between +/// attempts. +/// +/// We maintain an internal round_robin policy instance for distributing +/// requests across backends. Whenever we receive a new serverlist from +/// the balancer, we update the round_robin policy with the new list of +/// addresses. If we cannot communicate with the balancer on startup, +/// however, we may enter fallback mode, in which case we will populate +/// the RR policy's addresses from the backend addresses returned by the +/// resolver. +/// +/// Once an RR policy instance is in place (and getting updated as described), +/// calls for a pick, a ping, or a cancellation will be serviced right +/// away by forwarding them to the RR instance. Any time there's no RR +/// policy available (i.e., right after the creation of the gRPCLB policy), +/// pick and ping requests are added to a list of pending picks and pings +/// to be flushed and serviced when the RR policy instance becomes available. +/// +/// \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the +/// high level design and details. + +// With the addition of a libuv endpoint, sockaddr.h now includes uv.h when +// using that endpoint. Because of various transitive includes in uv.h, +// including windows.h on Windows, uv.h must be included before other system +// headers. Therefore, sockaddr.h must always be included first. +#include <grpc/support/port_platform.h> + +#include "src/core/lib/iomgr/sockaddr.h" +#include "src/core/lib/iomgr/socket_utils.h" + +#include <inttypes.h> +#include <limits.h> +#include <string.h> + +#include <grpc/byte_buffer_reader.h> +#include <grpc/grpc.h> +#include <grpc/support/alloc.h> +#include <grpc/support/string_util.h> +#include <grpc/support/time.h> + +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/client_channel_factory.h" +#include "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h" +#include "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h" +#include "src/core/ext/filters/client_channel/lb_policy/xds/xds.h" +#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h" +#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/parse_address.h" +#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/subchannel_index.h" +#include "src/core/lib/backoff/backoff.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/gpr/host_port.h" +#include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/manual_constructor.h" +#include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/gprpp/mutex_lock.h" +#include "src/core/lib/gprpp/orphanable.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/sockaddr.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/slice/slice_hash_table.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/channel_init.h" +#include "src/core/lib/transport/static_metadata.h" + +#define GRPC_XDS_INITIAL_CONNECT_BACKOFF_SECONDS 1 +#define GRPC_XDS_RECONNECT_BACKOFF_MULTIPLIER 1.6 +#define GRPC_XDS_RECONNECT_MAX_BACKOFF_SECONDS 120 +#define GRPC_XDS_RECONNECT_JITTER 0.2 +#define GRPC_XDS_DEFAULT_FALLBACK_TIMEOUT_MS 10000 + +namespace grpc_core { + +TraceFlag grpc_lb_xds_trace(false, "xds"); + +namespace { + +class XdsLb : public LoadBalancingPolicy { + public: + XdsLb(const grpc_lb_addresses* addresses, const Args& args); + + void UpdateLocked(const grpc_channel_args& args) override; + bool PickLocked(PickState* pick, grpc_error** error) override; + void CancelPickLocked(PickState* pick, grpc_error* error) override; + void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask, + uint32_t initial_metadata_flags_eq, + grpc_error* error) override; + void NotifyOnStateChangeLocked(grpc_connectivity_state* state, + grpc_closure* closure) override; + grpc_connectivity_state CheckConnectivityLocked( + grpc_error** connectivity_error) override; + void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override; + void ExitIdleLocked() override; + void ResetBackoffLocked() override; + void FillChildRefsForChannelz( + channelz::ChildRefsList* child_subchannels, + channelz::ChildRefsList* child_channels) override; + + private: + /// Linked list of pending pick requests. It stores all information needed to + /// eventually call (Round Robin's) pick() on them. They mainly stay pending + /// waiting for the RR policy to be created. + /// + /// Note that when a pick is sent to the RR policy, we inject our own + /// on_complete callback, so that we can intercept the result before + /// invoking the original on_complete callback. This allows us to set the + /// LB token metadata and add client_stats to the call context. + /// See \a pending_pick_complete() for details. + struct PendingPick { + // The xds lb instance that created the wrapping. This instance is not + // owned; reference counts are untouched. It's used only for logging + // purposes. + XdsLb* xdslb_policy; + // The original pick. + PickState* pick; + // Our on_complete closure and the original one. + grpc_closure on_complete; + grpc_closure* original_on_complete; + // The LB token associated with the pick. This is set via user_data in + // the pick. + grpc_mdelem lb_token; + // Stats for client-side load reporting. + RefCountedPtr<XdsLbClientStats> client_stats; + // Next pending pick. + PendingPick* next = nullptr; + }; + + /// Contains a call to the LB server and all the data related to the call. + class BalancerCallState + : public InternallyRefCountedWithTracing<BalancerCallState> { + public: + explicit BalancerCallState( + RefCountedPtr<LoadBalancingPolicy> parent_xdslb_policy); + + // It's the caller's responsibility to ensure that Orphan() is called from + // inside the combiner. + void Orphan() override; + + void StartQuery(); + + XdsLbClientStats* client_stats() const { return client_stats_.get(); } + + bool seen_initial_response() const { return seen_initial_response_; } + + private: + // So Delete() can access our private dtor. + template <typename T> + friend void grpc_core::Delete(T*); + + ~BalancerCallState(); + + XdsLb* xdslb_policy() const { + return static_cast<XdsLb*>(xdslb_policy_.get()); + } + + void ScheduleNextClientLoadReportLocked(); + void SendClientLoadReportLocked(); + + static bool LoadReportCountersAreZero(xds_grpclb_request* request); + + static void MaybeSendClientLoadReportLocked(void* arg, grpc_error* error); + static void ClientLoadReportDoneLocked(void* arg, grpc_error* error); + static void OnInitialRequestSentLocked(void* arg, grpc_error* error); + static void OnBalancerMessageReceivedLocked(void* arg, grpc_error* error); + static void OnBalancerStatusReceivedLocked(void* arg, grpc_error* error); + + // The owning LB policy. + RefCountedPtr<LoadBalancingPolicy> xdslb_policy_; + + // The streaming call to the LB server. Always non-NULL. + grpc_call* lb_call_ = nullptr; + + // recv_initial_metadata + grpc_metadata_array lb_initial_metadata_recv_; + + // send_message + grpc_byte_buffer* send_message_payload_ = nullptr; + grpc_closure lb_on_initial_request_sent_; + + // recv_message + grpc_byte_buffer* recv_message_payload_ = nullptr; + grpc_closure lb_on_balancer_message_received_; + bool seen_initial_response_ = false; + + // recv_trailing_metadata + grpc_closure lb_on_balancer_status_received_; + grpc_metadata_array lb_trailing_metadata_recv_; + grpc_status_code lb_call_status_; + grpc_slice lb_call_status_details_; + + // The stats for client-side load reporting associated with this LB call. + // Created after the first serverlist is received. + RefCountedPtr<XdsLbClientStats> client_stats_; + grpc_millis client_stats_report_interval_ = 0; + grpc_timer client_load_report_timer_; + bool client_load_report_timer_callback_pending_ = false; + bool last_client_load_report_counters_were_zero_ = false; + bool client_load_report_is_due_ = false; + // The closure used for either the load report timer or the callback for + // completion of sending the load report. + grpc_closure client_load_report_closure_; + }; + + ~XdsLb(); + + void ShutdownLocked() override; + + // Helper function used in ctor and UpdateLocked(). + void ProcessChannelArgsLocked(const grpc_channel_args& args); + + // Methods for dealing with the balancer channel and call. + void StartPickingLocked(); + void StartBalancerCallLocked(); + static void OnFallbackTimerLocked(void* arg, grpc_error* error); + void StartBalancerCallRetryTimerLocked(); + static void OnBalancerCallRetryTimerLocked(void* arg, grpc_error* error); + static void OnBalancerChannelConnectivityChangedLocked(void* arg, + grpc_error* error); + + // Pending pick methods. + static void PendingPickSetMetadataAndContext(PendingPick* pp); + PendingPick* PendingPickCreate(PickState* pick); + void AddPendingPick(PendingPick* pp); + static void OnPendingPickComplete(void* arg, grpc_error* error); + + // Methods for dealing with the RR policy. + void CreateOrUpdateRoundRobinPolicyLocked(); + grpc_channel_args* CreateRoundRobinPolicyArgsLocked(); + void CreateRoundRobinPolicyLocked(const Args& args); + bool PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp, + grpc_error** error); + void UpdateConnectivityStateFromRoundRobinPolicyLocked( + grpc_error* rr_state_error); + static void OnRoundRobinConnectivityChangedLocked(void* arg, + grpc_error* error); + static void OnRoundRobinRequestReresolutionLocked(void* arg, + grpc_error* error); + + // Who the client is trying to communicate with. + const char* server_name_ = nullptr; + + // Current channel args from the resolver. + grpc_channel_args* args_ = nullptr; + + // Internal state. + bool started_picking_ = false; + bool shutting_down_ = false; + grpc_connectivity_state_tracker state_tracker_; + + // The channel for communicating with the LB server. + grpc_channel* lb_channel_ = nullptr; + // Mutex to protect the channel to the LB server. This is used when + // processing a channelz request. + gpr_mu lb_channel_mu_; + grpc_connectivity_state lb_channel_connectivity_; + grpc_closure lb_channel_on_connectivity_changed_; + // Are we already watching the LB channel's connectivity? + bool watching_lb_channel_ = false; + // Response generator to inject address updates into lb_channel_. + RefCountedPtr<FakeResolverResponseGenerator> response_generator_; + + // The data associated with the current LB call. It holds a ref to this LB + // policy. It's initialized every time we query for backends. It's reset to + // NULL whenever the current LB call is no longer needed (e.g., the LB policy + // is shutting down, or the LB call has ended). A non-NULL lb_calld_ always + // contains a non-NULL lb_call_. + OrphanablePtr<BalancerCallState> lb_calld_; + // Timeout in milliseconds for the LB call. 0 means no deadline. + int lb_call_timeout_ms_ = 0; + // Balancer call retry state. + BackOff lb_call_backoff_; + bool retry_timer_callback_pending_ = false; + grpc_timer lb_call_retry_timer_; + grpc_closure lb_on_call_retry_; + + // The deserialized response from the balancer. May be nullptr until one + // such response has arrived. + xds_grpclb_serverlist* serverlist_ = nullptr; + // Index into serverlist for next pick. + // If the server at this index is a drop, we return a drop. + // Otherwise, we delegate to the RR policy. + size_t serverlist_index_ = 0; + + // Timeout in milliseconds for before using fallback backend addresses. + // 0 means not using fallback. + int lb_fallback_timeout_ms_ = 0; + // The backend addresses from the resolver. + grpc_lb_addresses* fallback_backend_addresses_ = nullptr; + // Fallback timer. + bool fallback_timer_callback_pending_ = false; + grpc_timer lb_fallback_timer_; + grpc_closure lb_on_fallback_; + + // Pending picks that are waiting on the RR policy's connectivity. + PendingPick* pending_picks_ = nullptr; + + // The RR policy to use for the backends. + OrphanablePtr<LoadBalancingPolicy> rr_policy_; + grpc_connectivity_state rr_connectivity_state_; + grpc_closure on_rr_connectivity_changed_; + grpc_closure on_rr_request_reresolution_; +}; + +// +// serverlist parsing code +// + +// vtable for LB tokens in grpc_lb_addresses +void* lb_token_copy(void* token) { + return token == nullptr + ? nullptr + : (void*)GRPC_MDELEM_REF(grpc_mdelem{(uintptr_t)token}).payload; +} +void lb_token_destroy(void* token) { + if (token != nullptr) { + GRPC_MDELEM_UNREF(grpc_mdelem{(uintptr_t)token}); + } +} +int lb_token_cmp(void* token1, void* token2) { + if (token1 > token2) return 1; + if (token1 < token2) return -1; + return 0; +} +const grpc_lb_user_data_vtable lb_token_vtable = { + lb_token_copy, lb_token_destroy, lb_token_cmp}; + +// Returns the backend addresses extracted from the given addresses. +grpc_lb_addresses* ExtractBackendAddresses(const grpc_lb_addresses* addresses) { + // First pass: count the number of backend addresses. + size_t num_backends = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (!addresses->addresses[i].is_balancer) { + ++num_backends; + } + } + // Second pass: actually populate the addresses and (empty) LB tokens. + grpc_lb_addresses* backend_addresses = + grpc_lb_addresses_create(num_backends, &lb_token_vtable); + size_t num_copied = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) continue; + const grpc_resolved_address* addr = &addresses->addresses[i].address; + grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr, + addr->len, false /* is_balancer */, + nullptr /* balancer_name */, + (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload); + ++num_copied; + } + return backend_addresses; +} + +bool IsServerValid(const xds_grpclb_server* server, size_t idx, bool log) { + if (server->drop) return false; + const xds_grpclb_ip_address* ip = &server->ip_address; + if (GPR_UNLIKELY(server->port >> 16 != 0)) { + if (log) { + gpr_log(GPR_ERROR, + "Invalid port '%d' at index %lu of serverlist. Ignoring.", + server->port, (unsigned long)idx); + } + return false; + } + if (GPR_UNLIKELY(ip->size != 4 && ip->size != 16)) { + if (log) { + gpr_log(GPR_ERROR, + "Expected IP to be 4 or 16 bytes, got %d at index %lu of " + "serverlist. Ignoring", + ip->size, (unsigned long)idx); + } + return false; + } + return true; +} + +void ParseServer(const xds_grpclb_server* server, grpc_resolved_address* addr) { + memset(addr, 0, sizeof(*addr)); + if (server->drop) return; + const uint16_t netorder_port = grpc_htons((uint16_t)server->port); + /* the addresses are given in binary format (a in(6)_addr struct) in + * server->ip_address.bytes. */ + const xds_grpclb_ip_address* ip = &server->ip_address; + if (ip->size == 4) { + addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in)); + grpc_sockaddr_in* addr4 = reinterpret_cast<grpc_sockaddr_in*>(&addr->addr); + addr4->sin_family = GRPC_AF_INET; + memcpy(&addr4->sin_addr, ip->bytes, ip->size); + addr4->sin_port = netorder_port; + } else if (ip->size == 16) { + addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6)); + grpc_sockaddr_in6* addr6 = (grpc_sockaddr_in6*)&addr->addr; + addr6->sin6_family = GRPC_AF_INET6; + memcpy(&addr6->sin6_addr, ip->bytes, ip->size); + addr6->sin6_port = netorder_port; + } +} + +// Returns addresses extracted from \a serverlist. +grpc_lb_addresses* ProcessServerlist(const xds_grpclb_serverlist* serverlist) { + size_t num_valid = 0; + /* first pass: count how many are valid in order to allocate the necessary + * memory in a single block */ + for (size_t i = 0; i < serverlist->num_servers; ++i) { + if (IsServerValid(serverlist->servers[i], i, true)) ++num_valid; + } + grpc_lb_addresses* lb_addresses = + grpc_lb_addresses_create(num_valid, &lb_token_vtable); + /* second pass: actually populate the addresses and LB tokens (aka user data + * to the outside world) to be read by the RR policy during its creation. + * Given that the validity tests are very cheap, they are performed again + * instead of marking the valid ones during the first pass, as this would + * incurr in an allocation due to the arbitrary number of server */ + size_t addr_idx = 0; + for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { + const xds_grpclb_server* server = serverlist->servers[sl_idx]; + if (!IsServerValid(serverlist->servers[sl_idx], sl_idx, false)) continue; + GPR_ASSERT(addr_idx < num_valid); + /* address processing */ + grpc_resolved_address addr; + ParseServer(server, &addr); + /* lb token processing */ + void* user_data; + if (server->has_load_balance_token) { + const size_t lb_token_max_length = + GPR_ARRAY_SIZE(server->load_balance_token); + const size_t lb_token_length = + strnlen(server->load_balance_token, lb_token_max_length); + grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer( + server->load_balance_token, lb_token_length); + user_data = + (void*)grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr) + .payload; + } else { + char* uri = grpc_sockaddr_to_uri(&addr); + gpr_log(GPR_INFO, + "Missing LB token for backend address '%s'. The empty token will " + "be used instead", + uri); + gpr_free(uri); + user_data = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; + } + grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, + false /* is_balancer */, + nullptr /* balancer_name */, user_data); + ++addr_idx; + } + GPR_ASSERT(addr_idx == num_valid); + return lb_addresses; +} + +// +// XdsLb::BalancerCallState +// + +XdsLb::BalancerCallState::BalancerCallState( + RefCountedPtr<LoadBalancingPolicy> parent_xdslb_policy) + : InternallyRefCountedWithTracing<BalancerCallState>(&grpc_lb_xds_trace), + xdslb_policy_(std::move(parent_xdslb_policy)) { + GPR_ASSERT(xdslb_policy_ != nullptr); + GPR_ASSERT(!xdslb_policy()->shutting_down_); + // Init the LB call. Note that the LB call will progress every time there's + // activity in xdslb_policy_->interested_parties(), which is comprised of + // the polling entities from client_channel. + GPR_ASSERT(xdslb_policy()->server_name_ != nullptr); + GPR_ASSERT(xdslb_policy()->server_name_[0] != '\0'); + const grpc_millis deadline = + xdslb_policy()->lb_call_timeout_ms_ == 0 + ? GRPC_MILLIS_INF_FUTURE + : ExecCtx::Get()->Now() + xdslb_policy()->lb_call_timeout_ms_; + lb_call_ = grpc_channel_create_pollset_set_call( + xdslb_policy()->lb_channel_, nullptr, GRPC_PROPAGATE_DEFAULTS, + xdslb_policy_->interested_parties(), + GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD, + nullptr, deadline, nullptr); + // Init the LB call request payload. + xds_grpclb_request* request = + xds_grpclb_request_create(xdslb_policy()->server_name_); + grpc_slice request_payload_slice = xds_grpclb_request_encode(request); + send_message_payload_ = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_slice_unref_internal(request_payload_slice); + xds_grpclb_request_destroy(request); + // Init other data associated with the LB call. + grpc_metadata_array_init(&lb_initial_metadata_recv_); + grpc_metadata_array_init(&lb_trailing_metadata_recv_); + GRPC_CLOSURE_INIT(&lb_on_initial_request_sent_, OnInitialRequestSentLocked, + this, grpc_combiner_scheduler(xdslb_policy()->combiner())); + GRPC_CLOSURE_INIT(&lb_on_balancer_message_received_, + OnBalancerMessageReceivedLocked, this, + grpc_combiner_scheduler(xdslb_policy()->combiner())); + GRPC_CLOSURE_INIT(&lb_on_balancer_status_received_, + OnBalancerStatusReceivedLocked, this, + grpc_combiner_scheduler(xdslb_policy()->combiner())); +} + +XdsLb::BalancerCallState::~BalancerCallState() { + GPR_ASSERT(lb_call_ != nullptr); + grpc_call_unref(lb_call_); + grpc_metadata_array_destroy(&lb_initial_metadata_recv_); + grpc_metadata_array_destroy(&lb_trailing_metadata_recv_); + grpc_byte_buffer_destroy(send_message_payload_); + grpc_byte_buffer_destroy(recv_message_payload_); + grpc_slice_unref_internal(lb_call_status_details_); +} + +void XdsLb::BalancerCallState::Orphan() { + GPR_ASSERT(lb_call_ != nullptr); + // If we are here because xdslb_policy wants to cancel the call, + // lb_on_balancer_status_received_ will complete the cancellation and clean + // up. Otherwise, we are here because xdslb_policy has to orphan a failed + // call, then the following cancellation will be a no-op. + grpc_call_cancel(lb_call_, nullptr); + if (client_load_report_timer_callback_pending_) { + grpc_timer_cancel(&client_load_report_timer_); + } + // Note that the initial ref is hold by lb_on_balancer_status_received_ + // instead of the caller of this function. So the corresponding unref happens + // in lb_on_balancer_status_received_ instead of here. +} + +void XdsLb::BalancerCallState::StartQuery() { + GPR_ASSERT(lb_call_ != nullptr); + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, "[xdslb %p] Starting LB call (lb_calld: %p, lb_call: %p)", + xdslb_policy_.get(), this, lb_call_); + } + // Create the ops. + grpc_call_error call_error; + grpc_op ops[3]; + memset(ops, 0, sizeof(ops)); + // Op: send initial metadata. + grpc_op* op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = nullptr; + op++; + // Op: send request message. + GPR_ASSERT(send_message_payload_ != nullptr); + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = send_message_payload_; + op->flags = 0; + op->reserved = nullptr; + op++; + // TODO(roth): We currently track this ref manually. Once the + // ClosureRef API is ready, we should pass the RefCountedPtr<> along + // with the callback. + auto self = Ref(DEBUG_LOCATION, "on_initial_request_sent"); + self.release(); + call_error = grpc_call_start_batch_and_execute( + lb_call_, ops, (size_t)(op - ops), &lb_on_initial_request_sent_); + GPR_ASSERT(GRPC_CALL_OK == call_error); + // Op: recv initial metadata. + op = ops; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata.recv_initial_metadata = + &lb_initial_metadata_recv_; + op->flags = 0; + op->reserved = nullptr; + op++; + // Op: recv response. + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &recv_message_payload_; + op->flags = 0; + op->reserved = nullptr; + op++; + // TODO(roth): We currently track this ref manually. Once the + // ClosureRef API is ready, we should pass the RefCountedPtr<> along + // with the callback. + self = Ref(DEBUG_LOCATION, "on_message_received"); + self.release(); + call_error = grpc_call_start_batch_and_execute( + lb_call_, ops, (size_t)(op - ops), &lb_on_balancer_message_received_); + GPR_ASSERT(GRPC_CALL_OK == call_error); + // Op: recv server status. + op = ops; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = + &lb_trailing_metadata_recv_; + op->data.recv_status_on_client.status = &lb_call_status_; + op->data.recv_status_on_client.status_details = &lb_call_status_details_; + op->flags = 0; + op->reserved = nullptr; + op++; + // This callback signals the end of the LB call, so it relies on the initial + // ref instead of a new ref. When it's invoked, it's the initial ref that is + // unreffed. + call_error = grpc_call_start_batch_and_execute( + lb_call_, ops, (size_t)(op - ops), &lb_on_balancer_status_received_); + GPR_ASSERT(GRPC_CALL_OK == call_error); +} + +void XdsLb::BalancerCallState::ScheduleNextClientLoadReportLocked() { + const grpc_millis next_client_load_report_time = + ExecCtx::Get()->Now() + client_stats_report_interval_; + GRPC_CLOSURE_INIT(&client_load_report_closure_, + MaybeSendClientLoadReportLocked, this, + grpc_combiner_scheduler(xdslb_policy()->combiner())); + grpc_timer_init(&client_load_report_timer_, next_client_load_report_time, + &client_load_report_closure_); + client_load_report_timer_callback_pending_ = true; +} + +void XdsLb::BalancerCallState::MaybeSendClientLoadReportLocked( + void* arg, grpc_error* error) { + BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg); + XdsLb* xdslb_policy = lb_calld->xdslb_policy(); + lb_calld->client_load_report_timer_callback_pending_ = false; + if (error != GRPC_ERROR_NONE || lb_calld != xdslb_policy->lb_calld_.get()) { + lb_calld->Unref(DEBUG_LOCATION, "client_load_report"); + return; + } + // If we've already sent the initial request, then we can go ahead and send + // the load report. Otherwise, we need to wait until the initial request has + // been sent to send this (see OnInitialRequestSentLocked()). + if (lb_calld->send_message_payload_ == nullptr) { + lb_calld->SendClientLoadReportLocked(); + } else { + lb_calld->client_load_report_is_due_ = true; + } +} + +bool XdsLb::BalancerCallState::LoadReportCountersAreZero( + xds_grpclb_request* request) { + XdsLbClientStats::DroppedCallCounts* drop_entries = + static_cast<XdsLbClientStats::DroppedCallCounts*>( + request->client_stats.calls_finished_with_drop.arg); + return request->client_stats.num_calls_started == 0 && + request->client_stats.num_calls_finished == 0 && + request->client_stats.num_calls_finished_with_client_failed_to_send == + 0 && + request->client_stats.num_calls_finished_known_received == 0 && + (drop_entries == nullptr || drop_entries->empty()); +} + +void XdsLb::BalancerCallState::SendClientLoadReportLocked() { + // Construct message payload. + GPR_ASSERT(send_message_payload_ == nullptr); + xds_grpclb_request* request = + xds_grpclb_load_report_request_create_locked(client_stats_.get()); + // Skip client load report if the counters were all zero in the last + // report and they are still zero in this one. + if (LoadReportCountersAreZero(request)) { + if (last_client_load_report_counters_were_zero_) { + xds_grpclb_request_destroy(request); + ScheduleNextClientLoadReportLocked(); + return; + } + last_client_load_report_counters_were_zero_ = true; + } else { + last_client_load_report_counters_were_zero_ = false; + } + grpc_slice request_payload_slice = xds_grpclb_request_encode(request); + send_message_payload_ = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_slice_unref_internal(request_payload_slice); + xds_grpclb_request_destroy(request); + // Send the report. + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_SEND_MESSAGE; + op.data.send_message.send_message = send_message_payload_; + GRPC_CLOSURE_INIT(&client_load_report_closure_, ClientLoadReportDoneLocked, + this, grpc_combiner_scheduler(xdslb_policy()->combiner())); + grpc_call_error call_error = grpc_call_start_batch_and_execute( + lb_call_, &op, 1, &client_load_report_closure_); + if (GPR_UNLIKELY(call_error != GRPC_CALL_OK)) { + gpr_log(GPR_ERROR, "[xdslb %p] call_error=%d", xdslb_policy_.get(), + call_error); + GPR_ASSERT(GRPC_CALL_OK == call_error); + } +} + +void XdsLb::BalancerCallState::ClientLoadReportDoneLocked(void* arg, + grpc_error* error) { + BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg); + XdsLb* xdslb_policy = lb_calld->xdslb_policy(); + grpc_byte_buffer_destroy(lb_calld->send_message_payload_); + lb_calld->send_message_payload_ = nullptr; + if (error != GRPC_ERROR_NONE || lb_calld != xdslb_policy->lb_calld_.get()) { + lb_calld->Unref(DEBUG_LOCATION, "client_load_report"); + return; + } + lb_calld->ScheduleNextClientLoadReportLocked(); +} + +void XdsLb::BalancerCallState::OnInitialRequestSentLocked(void* arg, + grpc_error* error) { + BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg); + grpc_byte_buffer_destroy(lb_calld->send_message_payload_); + lb_calld->send_message_payload_ = nullptr; + // If we attempted to send a client load report before the initial request was + // sent (and this lb_calld is still in use), send the load report now. + if (lb_calld->client_load_report_is_due_ && + lb_calld == lb_calld->xdslb_policy()->lb_calld_.get()) { + lb_calld->SendClientLoadReportLocked(); + lb_calld->client_load_report_is_due_ = false; + } + lb_calld->Unref(DEBUG_LOCATION, "on_initial_request_sent"); +} + +void XdsLb::BalancerCallState::OnBalancerMessageReceivedLocked( + void* arg, grpc_error* error) { + BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg); + XdsLb* xdslb_policy = lb_calld->xdslb_policy(); + // Empty payload means the LB call was cancelled. + if (lb_calld != xdslb_policy->lb_calld_.get() || + lb_calld->recv_message_payload_ == nullptr) { + lb_calld->Unref(DEBUG_LOCATION, "on_message_received"); + return; + } + grpc_byte_buffer_reader bbr; + grpc_byte_buffer_reader_init(&bbr, lb_calld->recv_message_payload_); + grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr); + grpc_byte_buffer_reader_destroy(&bbr); + grpc_byte_buffer_destroy(lb_calld->recv_message_payload_); + lb_calld->recv_message_payload_ = nullptr; + xds_grpclb_initial_response* initial_response; + xds_grpclb_serverlist* serverlist; + if (!lb_calld->seen_initial_response_ && + (initial_response = xds_grpclb_initial_response_parse(response_slice)) != + nullptr) { + // Have NOT seen initial response, look for initial response. + if (initial_response->has_client_stats_report_interval) { + lb_calld->client_stats_report_interval_ = GPR_MAX( + GPR_MS_PER_SEC, xds_grpclb_duration_to_millis( + &initial_response->client_stats_report_interval)); + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, + "[xdslb %p] Received initial LB response message; " + "client load reporting interval = %" PRId64 " milliseconds", + xdslb_policy, lb_calld->client_stats_report_interval_); + } + } else if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, + "[xdslb %p] Received initial LB response message; client load " + "reporting NOT enabled", + xdslb_policy); + } + xds_grpclb_initial_response_destroy(initial_response); + lb_calld->seen_initial_response_ = true; + } else if ((serverlist = xds_grpclb_response_parse_serverlist( + response_slice)) != nullptr) { + // Have seen initial response, look for serverlist. + GPR_ASSERT(lb_calld->lb_call_ != nullptr); + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, + "[xdslb %p] Serverlist with %" PRIuPTR " servers received", + xdslb_policy, serverlist->num_servers); + for (size_t i = 0; i < serverlist->num_servers; ++i) { + grpc_resolved_address addr; + ParseServer(serverlist->servers[i], &addr); + char* ipport; + grpc_sockaddr_to_string(&ipport, &addr, false); + gpr_log(GPR_INFO, "[xdslb %p] Serverlist[%" PRIuPTR "]: %s", + xdslb_policy, i, ipport); + gpr_free(ipport); + } + } + /* update serverlist */ + if (serverlist->num_servers > 0) { + // Start sending client load report only after we start using the + // serverlist returned from the current LB call. + if (lb_calld->client_stats_report_interval_ > 0 && + lb_calld->client_stats_ == nullptr) { + lb_calld->client_stats_.reset(New<XdsLbClientStats>()); + // TODO(roth): We currently track this ref manually. Once the + // ClosureRef API is ready, we should pass the RefCountedPtr<> along + // with the callback. + auto self = lb_calld->Ref(DEBUG_LOCATION, "client_load_report"); + self.release(); + lb_calld->ScheduleNextClientLoadReportLocked(); + } + if (xds_grpclb_serverlist_equals(xdslb_policy->serverlist_, serverlist)) { + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, + "[xdslb %p] Incoming server list identical to current, " + "ignoring.", + xdslb_policy); + } + xds_grpclb_destroy_serverlist(serverlist); + } else { /* new serverlist */ + if (xdslb_policy->serverlist_ != nullptr) { + /* dispose of the old serverlist */ + xds_grpclb_destroy_serverlist(xdslb_policy->serverlist_); + } else { + /* or dispose of the fallback */ + grpc_lb_addresses_destroy(xdslb_policy->fallback_backend_addresses_); + xdslb_policy->fallback_backend_addresses_ = nullptr; + if (xdslb_policy->fallback_timer_callback_pending_) { + grpc_timer_cancel(&xdslb_policy->lb_fallback_timer_); + } + } + // and update the copy in the XdsLb instance. This + // serverlist instance will be destroyed either upon the next + // update or when the XdsLb instance is destroyed. + xdslb_policy->serverlist_ = serverlist; + xdslb_policy->serverlist_index_ = 0; + xdslb_policy->CreateOrUpdateRoundRobinPolicyLocked(); + } + } else { + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, "[xdslb %p] Received empty server list, ignoring.", + xdslb_policy); + } + xds_grpclb_destroy_serverlist(serverlist); + } + } else { + // No valid initial response or serverlist found. + char* response_slice_str = + grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX); + gpr_log(GPR_ERROR, + "[xdslb %p] Invalid LB response received: '%s'. Ignoring.", + xdslb_policy, response_slice_str); + gpr_free(response_slice_str); + } + grpc_slice_unref_internal(response_slice); + if (!xdslb_policy->shutting_down_) { + // Keep listening for serverlist updates. + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_RECV_MESSAGE; + op.data.recv_message.recv_message = &lb_calld->recv_message_payload_; + op.flags = 0; + op.reserved = nullptr; + // Reuse the "OnBalancerMessageReceivedLocked" ref taken in StartQuery(). + const grpc_call_error call_error = grpc_call_start_batch_and_execute( + lb_calld->lb_call_, &op, 1, + &lb_calld->lb_on_balancer_message_received_); + GPR_ASSERT(GRPC_CALL_OK == call_error); + } else { + lb_calld->Unref(DEBUG_LOCATION, "on_message_received+grpclb_shutdown"); + } +} + +void XdsLb::BalancerCallState::OnBalancerStatusReceivedLocked( + void* arg, grpc_error* error) { + BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg); + XdsLb* xdslb_policy = lb_calld->xdslb_policy(); + GPR_ASSERT(lb_calld->lb_call_ != nullptr); + if (grpc_lb_xds_trace.enabled()) { + char* status_details = + grpc_slice_to_c_string(lb_calld->lb_call_status_details_); + gpr_log(GPR_INFO, + "[xdslb %p] Status from LB server received. Status = %d, details " + "= '%s', (lb_calld: %p, lb_call: %p), error '%s'", + xdslb_policy, lb_calld->lb_call_status_, status_details, lb_calld, + lb_calld->lb_call_, grpc_error_string(error)); + gpr_free(status_details); + } + xdslb_policy->TryReresolutionLocked(&grpc_lb_xds_trace, GRPC_ERROR_NONE); + // If this lb_calld is still in use, this call ended because of a failure so + // we want to retry connecting. Otherwise, we have deliberately ended this + // call and no further action is required. + if (lb_calld == xdslb_policy->lb_calld_.get()) { + xdslb_policy->lb_calld_.reset(); + GPR_ASSERT(!xdslb_policy->shutting_down_); + if (lb_calld->seen_initial_response_) { + // If we lose connection to the LB server, reset the backoff and restart + // the LB call immediately. + xdslb_policy->lb_call_backoff_.Reset(); + xdslb_policy->StartBalancerCallLocked(); + } else { + // If this LB call fails establishing any connection to the LB server, + // retry later. + xdslb_policy->StartBalancerCallRetryTimerLocked(); + } + } + lb_calld->Unref(DEBUG_LOCATION, "lb_call_ended"); +} + +// +// helper code for creating balancer channel +// + +grpc_lb_addresses* ExtractBalancerAddresses( + const grpc_lb_addresses* addresses) { + size_t num_grpclb_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + } + // There must be at least one balancer address, or else the + // client_channel would not have chosen this LB policy. + GPR_ASSERT(num_grpclb_addrs > 0); + grpc_lb_addresses* lb_addresses = + grpc_lb_addresses_create(num_grpclb_addrs, nullptr); + size_t lb_addresses_idx = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (!addresses->addresses[i].is_balancer) continue; + if (GPR_UNLIKELY(addresses->addresses[i].user_data != nullptr)) { + gpr_log(GPR_ERROR, + "This LB policy doesn't support user data. It will be ignored"); + } + grpc_lb_addresses_set_address( + lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr, + addresses->addresses[i].address.len, false /* is balancer */, + addresses->addresses[i].balancer_name, nullptr /* user data */); + } + GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx); + return lb_addresses; +} + +/* Returns the channel args for the LB channel, used to create a bidirectional + * stream for the reception of load balancing updates. + * + * Inputs: + * - \a addresses: corresponding to the balancers. + * - \a response_generator: in order to propagate updates from the resolver + * above the grpclb policy. + * - \a args: other args inherited from the grpclb policy. */ +grpc_channel_args* BuildBalancerChannelArgs( + const grpc_lb_addresses* addresses, + FakeResolverResponseGenerator* response_generator, + const grpc_channel_args* args) { + grpc_lb_addresses* lb_addresses = ExtractBalancerAddresses(addresses); + // Channel args to remove. + static const char* args_to_remove[] = { + // LB policy name, since we want to use the default (pick_first) in + // the LB channel. + GRPC_ARG_LB_POLICY_NAME, + // The channel arg for the server URI, since that will be different for + // the LB channel than for the parent channel. The client channel + // factory will re-add this arg with the right value. + GRPC_ARG_SERVER_URI, + // The resolved addresses, which will be generated by the name resolver + // used in the LB channel. Note that the LB channel will use the fake + // resolver, so this won't actually generate a query to DNS (or some + // other name service). However, the addresses returned by the fake + // resolver will have is_balancer=false, whereas our own addresses have + // is_balancer=true. We need the LB channel to return addresses with + // is_balancer=false so that it does not wind up recursively using the + // grpclb LB policy, as per the special case logic in client_channel.c. + GRPC_ARG_LB_ADDRESSES, + // The fake resolver response generator, because we are replacing it + // with the one from the grpclb policy, used to propagate updates to + // the LB channel. + GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR, + // The LB channel should use the authority indicated by the target + // authority table (see \a grpc_lb_policy_xds_modify_lb_channel_args), + // as opposed to the authority from the parent channel. + GRPC_ARG_DEFAULT_AUTHORITY, + // Just as for \a GRPC_ARG_DEFAULT_AUTHORITY, the LB channel should be + // treated as a stand-alone channel and not inherit this argument from the + // args of the parent channel. + GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, + }; + // Channel args to add. + const grpc_arg args_to_add[] = { + // New LB addresses. + // Note that we pass these in both when creating the LB channel + // and via the fake resolver. The latter is what actually gets used. + grpc_lb_addresses_create_channel_arg(lb_addresses), + // The fake resolver response generator, which we use to inject + // address updates into the LB channel. + grpc_core::FakeResolverResponseGenerator::MakeChannelArg( + response_generator), + // A channel arg indicating the target is a grpclb load balancer. + grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER), 1), + // A channel arg indicating this is an internal channels, aka it is + // owned by components in Core, not by the user application. + grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), 1), + }; + // Construct channel args. + grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove( + args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add, + GPR_ARRAY_SIZE(args_to_add)); + // Make any necessary modifications for security. + new_args = grpc_lb_policy_xds_modify_lb_channel_args(new_args); + // Clean up. + grpc_lb_addresses_destroy(lb_addresses); + return new_args; +} + +// +// ctor and dtor +// + +XdsLb::XdsLb(const grpc_lb_addresses* addresses, + const LoadBalancingPolicy::Args& args) + : LoadBalancingPolicy(args), + response_generator_(MakeRefCounted<FakeResolverResponseGenerator>()), + lb_call_backoff_( + BackOff::Options() + .set_initial_backoff(GRPC_XDS_INITIAL_CONNECT_BACKOFF_SECONDS * + 1000) + .set_multiplier(GRPC_XDS_RECONNECT_BACKOFF_MULTIPLIER) + .set_jitter(GRPC_XDS_RECONNECT_JITTER) + .set_max_backoff(GRPC_XDS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) { + // Initialization. + gpr_mu_init(&lb_channel_mu_); + grpc_subchannel_index_ref(); + GRPC_CLOSURE_INIT(&lb_channel_on_connectivity_changed_, + &XdsLb::OnBalancerChannelConnectivityChangedLocked, this, + grpc_combiner_scheduler(args.combiner)); + GRPC_CLOSURE_INIT(&on_rr_connectivity_changed_, + &XdsLb::OnRoundRobinConnectivityChangedLocked, this, + grpc_combiner_scheduler(args.combiner)); + GRPC_CLOSURE_INIT(&on_rr_request_reresolution_, + &XdsLb::OnRoundRobinRequestReresolutionLocked, this, + grpc_combiner_scheduler(args.combiner)); + grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE, "xds"); + // Record server name. + const grpc_arg* arg = grpc_channel_args_find(args.args, GRPC_ARG_SERVER_URI); + const char* server_uri = grpc_channel_arg_get_string(arg); + GPR_ASSERT(server_uri != nullptr); + grpc_uri* uri = grpc_uri_parse(server_uri, true); + GPR_ASSERT(uri->path[0] != '\0'); + server_name_ = gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path); + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, + "[xdslb %p] Will use '%s' as the server name for LB request.", this, + server_name_); + } + grpc_uri_destroy(uri); + // Record LB call timeout. + arg = grpc_channel_args_find(args.args, GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS); + lb_call_timeout_ms_ = grpc_channel_arg_get_integer(arg, {0, 0, INT_MAX}); + // Record fallback timeout. + arg = grpc_channel_args_find(args.args, GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS); + lb_fallback_timeout_ms_ = grpc_channel_arg_get_integer( + arg, {GRPC_XDS_DEFAULT_FALLBACK_TIMEOUT_MS, 0, INT_MAX}); + // Process channel args. + ProcessChannelArgsLocked(*args.args); +} + +XdsLb::~XdsLb() { + GPR_ASSERT(pending_picks_ == nullptr); + gpr_mu_destroy(&lb_channel_mu_); + gpr_free((void*)server_name_); + grpc_channel_args_destroy(args_); + grpc_connectivity_state_destroy(&state_tracker_); + if (serverlist_ != nullptr) { + xds_grpclb_destroy_serverlist(serverlist_); + } + if (fallback_backend_addresses_ != nullptr) { + grpc_lb_addresses_destroy(fallback_backend_addresses_); + } + grpc_subchannel_index_unref(); +} + +void XdsLb::ShutdownLocked() { + grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown"); + shutting_down_ = true; + lb_calld_.reset(); + if (retry_timer_callback_pending_) { + grpc_timer_cancel(&lb_call_retry_timer_); + } + if (fallback_timer_callback_pending_) { + grpc_timer_cancel(&lb_fallback_timer_); + } + rr_policy_.reset(); + TryReresolutionLocked(&grpc_lb_xds_trace, GRPC_ERROR_CANCELLED); + // We destroy the LB channel here instead of in our destructor because + // destroying the channel triggers a last callback to + // OnBalancerChannelConnectivityChangedLocked(), and we need to be + // alive when that callback is invoked. + if (lb_channel_ != nullptr) { + gpr_mu_lock(&lb_channel_mu_); + grpc_channel_destroy(lb_channel_); + lb_channel_ = nullptr; + gpr_mu_unlock(&lb_channel_mu_); + } + grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_SHUTDOWN, + GRPC_ERROR_REF(error), "grpclb_shutdown"); + // Clear pending picks. + PendingPick* pp; + while ((pp = pending_picks_) != nullptr) { + pending_picks_ = pp->next; + pp->pick->connected_subchannel.reset(); + // Note: pp is deleted in this callback. + GRPC_CLOSURE_SCHED(&pp->on_complete, GRPC_ERROR_REF(error)); + } + GRPC_ERROR_UNREF(error); +} + +// +// public methods +// + +void XdsLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) { + PendingPick* pp; + while ((pp = pending_picks_) != nullptr) { + pending_picks_ = pp->next; + pp->pick->on_complete = pp->original_on_complete; + pp->pick->user_data = nullptr; + grpc_error* error = GRPC_ERROR_NONE; + if (new_policy->PickLocked(pp->pick, &error)) { + // Synchronous return; schedule closure. + GRPC_CLOSURE_SCHED(pp->pick->on_complete, error); + } + Delete(pp); + } +} + +// Cancel a specific pending pick. +// +// A grpclb pick progresses as follows: +// - If there's a Round Robin policy (rr_policy_) available, it'll be +// handed over to the RR policy (in CreateRoundRobinPolicyLocked()). From +// that point onwards, it'll be RR's responsibility. For cancellations, that +// implies the pick needs also be cancelled by the RR instance. +// - Otherwise, without an RR instance, picks stay pending at this policy's +// level (grpclb), inside the pending_picks_ list. To cancel these, +// we invoke the completion closure and set the pick's connected +// subchannel to nullptr right here. +void XdsLb::CancelPickLocked(PickState* pick, grpc_error* error) { + PendingPick* pp = pending_picks_; + pending_picks_ = nullptr; + while (pp != nullptr) { + PendingPick* next = pp->next; + if (pp->pick == pick) { + pick->connected_subchannel.reset(); + // Note: pp is deleted in this callback. + GRPC_CLOSURE_SCHED(&pp->on_complete, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick Cancelled", &error, 1)); + } else { + pp->next = pending_picks_; + pending_picks_ = pp; + } + pp = next; + } + if (rr_policy_ != nullptr) { + rr_policy_->CancelPickLocked(pick, GRPC_ERROR_REF(error)); + } + GRPC_ERROR_UNREF(error); +} + +// Cancel all pending picks. +// +// A grpclb pick progresses as follows: +// - If there's a Round Robin policy (rr_policy_) available, it'll be +// handed over to the RR policy (in CreateRoundRobinPolicyLocked()). From +// that point onwards, it'll be RR's responsibility. For cancellations, that +// implies the pick needs also be cancelled by the RR instance. +// - Otherwise, without an RR instance, picks stay pending at this policy's +// level (grpclb), inside the pending_picks_ list. To cancel these, +// we invoke the completion closure and set the pick's connected +// subchannel to nullptr right here. +void XdsLb::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask, + uint32_t initial_metadata_flags_eq, + grpc_error* error) { + PendingPick* pp = pending_picks_; + pending_picks_ = nullptr; + while (pp != nullptr) { + PendingPick* next = pp->next; + if ((pp->pick->initial_metadata_flags & initial_metadata_flags_mask) == + initial_metadata_flags_eq) { + // Note: pp is deleted in this callback. + GRPC_CLOSURE_SCHED(&pp->on_complete, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick Cancelled", &error, 1)); + } else { + pp->next = pending_picks_; + pending_picks_ = pp; + } + pp = next; + } + if (rr_policy_ != nullptr) { + rr_policy_->CancelMatchingPicksLocked(initial_metadata_flags_mask, + initial_metadata_flags_eq, + GRPC_ERROR_REF(error)); + } + GRPC_ERROR_UNREF(error); +} + +void XdsLb::ExitIdleLocked() { + if (!started_picking_) { + StartPickingLocked(); + } +} + +void XdsLb::ResetBackoffLocked() { + if (lb_channel_ != nullptr) { + grpc_channel_reset_connect_backoff(lb_channel_); + } + if (rr_policy_ != nullptr) { + rr_policy_->ResetBackoffLocked(); + } +} + +bool XdsLb::PickLocked(PickState* pick, grpc_error** error) { + PendingPick* pp = PendingPickCreate(pick); + bool pick_done = false; + if (rr_policy_ != nullptr) { + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, "[xdslb %p] about to PICK from RR %p", this, + rr_policy_.get()); + } + pick_done = + PickFromRoundRobinPolicyLocked(false /* force_async */, pp, error); + } else { // rr_policy_ == NULL + if (pick->on_complete == nullptr) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "No pick result available but synchronous result required."); + pick_done = true; + } else { + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, + "[xdslb %p] No RR policy. Adding to grpclb's pending picks", + this); + } + AddPendingPick(pp); + if (!started_picking_) { + StartPickingLocked(); + } + pick_done = false; + } + } + return pick_done; +} + +void XdsLb::FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, + channelz::ChildRefsList* child_channels) { + // delegate to the RoundRobin to fill the children subchannels. + rr_policy_->FillChildRefsForChannelz(child_subchannels, child_channels); + MutexLock lock(&lb_channel_mu_); + if (lb_channel_ != nullptr) { + grpc_core::channelz::ChannelNode* channel_node = + grpc_channel_get_channelz_node(lb_channel_); + if (channel_node != nullptr) { + child_channels->push_back(channel_node->uuid()); + } + } +} + +grpc_connectivity_state XdsLb::CheckConnectivityLocked( + grpc_error** connectivity_error) { + return grpc_connectivity_state_get(&state_tracker_, connectivity_error); +} + +void XdsLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current, + grpc_closure* closure) { + grpc_connectivity_state_notify_on_state_change(&state_tracker_, current, + closure); +} + +void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { + const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); + if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { + // Ignore this update. + gpr_log(GPR_ERROR, + "[xdslb %p] No valid LB addresses channel arg in update, ignoring.", + this); + return; + } + const grpc_lb_addresses* addresses = + static_cast<const grpc_lb_addresses*>(arg->value.pointer.p); + // Update fallback address list. + if (fallback_backend_addresses_ != nullptr) { + grpc_lb_addresses_destroy(fallback_backend_addresses_); + } + fallback_backend_addresses_ = ExtractBackendAddresses(addresses); + // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args, + // since we use this to trigger the client_load_reporting filter. + static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME}; + grpc_arg new_arg = grpc_channel_arg_string_create( + (char*)GRPC_ARG_LB_POLICY_NAME, (char*)"xds"); + grpc_channel_args_destroy(args_); + args_ = grpc_channel_args_copy_and_add_and_remove( + &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); + // Construct args for balancer channel. + grpc_channel_args* lb_channel_args = + BuildBalancerChannelArgs(addresses, response_generator_.get(), &args); + // Create balancer channel if needed. + if (lb_channel_ == nullptr) { + char* uri_str; + gpr_asprintf(&uri_str, "fake:///%s", server_name_); + gpr_mu_lock(&lb_channel_mu_); + lb_channel_ = grpc_client_channel_factory_create_channel( + client_channel_factory(), uri_str, + GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, lb_channel_args); + gpr_mu_unlock(&lb_channel_mu_); + GPR_ASSERT(lb_channel_ != nullptr); + gpr_free(uri_str); + } + // Propagate updates to the LB channel (pick_first) through the fake + // resolver. + response_generator_->SetResponse(lb_channel_args); + grpc_channel_args_destroy(lb_channel_args); +} + +void XdsLb::UpdateLocked(const grpc_channel_args& args) { + ProcessChannelArgsLocked(args); + // If fallback is configured and the RR policy already exists, update + // it with the new fallback addresses. + if (lb_fallback_timeout_ms_ > 0 && rr_policy_ != nullptr) { + CreateOrUpdateRoundRobinPolicyLocked(); + } + // Start watching the LB channel connectivity for connection, if not + // already doing so. + if (!watching_lb_channel_) { + lb_channel_connectivity_ = grpc_channel_check_connectivity_state( + lb_channel_, true /* try to connect */); + grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(lb_channel_)); + GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter); + watching_lb_channel_ = true; + // TODO(roth): We currently track this ref manually. Once the + // ClosureRef API is ready, we should pass the RefCountedPtr<> along + // with the callback. + auto self = Ref(DEBUG_LOCATION, "watch_lb_channel_connectivity"); + self.release(); + grpc_client_channel_watch_connectivity_state( + client_channel_elem, + grpc_polling_entity_create_from_pollset_set(interested_parties()), + &lb_channel_connectivity_, &lb_channel_on_connectivity_changed_, + nullptr); + } +} + +// +// code for balancer channel and call +// + +void XdsLb::StartPickingLocked() { + // Start a timer to fall back. + if (lb_fallback_timeout_ms_ > 0 && serverlist_ == nullptr && + !fallback_timer_callback_pending_) { + grpc_millis deadline = ExecCtx::Get()->Now() + lb_fallback_timeout_ms_; + // TODO(roth): We currently track this ref manually. Once the + // ClosureRef API is ready, we should pass the RefCountedPtr<> along + // with the callback. + auto self = Ref(DEBUG_LOCATION, "on_fallback_timer"); + self.release(); + GRPC_CLOSURE_INIT(&lb_on_fallback_, &XdsLb::OnFallbackTimerLocked, this, + grpc_combiner_scheduler(combiner())); + fallback_timer_callback_pending_ = true; + grpc_timer_init(&lb_fallback_timer_, deadline, &lb_on_fallback_); + } + started_picking_ = true; + StartBalancerCallLocked(); +} + +void XdsLb::StartBalancerCallLocked() { + GPR_ASSERT(lb_channel_ != nullptr); + if (shutting_down_) return; + // Init the LB call data. + GPR_ASSERT(lb_calld_ == nullptr); + lb_calld_ = MakeOrphanable<BalancerCallState>(Ref()); + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, + "[xdslb %p] Query for backends (lb_channel: %p, lb_calld: %p)", + this, lb_channel_, lb_calld_.get()); + } + lb_calld_->StartQuery(); +} + +void XdsLb::OnFallbackTimerLocked(void* arg, grpc_error* error) { + XdsLb* xdslb_policy = static_cast<XdsLb*>(arg); + xdslb_policy->fallback_timer_callback_pending_ = false; + // If we receive a serverlist after the timer fires but before this callback + // actually runs, don't fall back. + if (xdslb_policy->serverlist_ == nullptr && !xdslb_policy->shutting_down_ && + error == GRPC_ERROR_NONE) { + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, "[xdslb %p] Falling back to use backends from resolver", + xdslb_policy); + } + GPR_ASSERT(xdslb_policy->fallback_backend_addresses_ != nullptr); + xdslb_policy->CreateOrUpdateRoundRobinPolicyLocked(); + } + xdslb_policy->Unref(DEBUG_LOCATION, "on_fallback_timer"); +} + +void XdsLb::StartBalancerCallRetryTimerLocked() { + grpc_millis next_try = lb_call_backoff_.NextAttemptTime(); + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, "[xdslb %p] Connection to LB server lost...", this); + grpc_millis timeout = next_try - ExecCtx::Get()->Now(); + if (timeout > 0) { + gpr_log(GPR_INFO, "[xdslb %p] ... retry_timer_active in %" PRId64 "ms.", + this, timeout); + } else { + gpr_log(GPR_INFO, "[xdslb %p] ... retry_timer_active immediately.", this); + } + } + // TODO(roth): We currently track this ref manually. Once the + // ClosureRef API is ready, we should pass the RefCountedPtr<> along + // with the callback. + auto self = Ref(DEBUG_LOCATION, "on_balancer_call_retry_timer"); + self.release(); + GRPC_CLOSURE_INIT(&lb_on_call_retry_, &XdsLb::OnBalancerCallRetryTimerLocked, + this, grpc_combiner_scheduler(combiner())); + retry_timer_callback_pending_ = true; + grpc_timer_init(&lb_call_retry_timer_, next_try, &lb_on_call_retry_); +} + +void XdsLb::OnBalancerCallRetryTimerLocked(void* arg, grpc_error* error) { + XdsLb* xdslb_policy = static_cast<XdsLb*>(arg); + xdslb_policy->retry_timer_callback_pending_ = false; + if (!xdslb_policy->shutting_down_ && error == GRPC_ERROR_NONE && + xdslb_policy->lb_calld_ == nullptr) { + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, "[xdslb %p] Restarting call to LB server", + xdslb_policy); + } + xdslb_policy->StartBalancerCallLocked(); + } + xdslb_policy->Unref(DEBUG_LOCATION, "on_balancer_call_retry_timer"); +} + +// Invoked as part of the update process. It continues watching the LB channel +// until it shuts down or becomes READY. It's invoked even if the LB channel +// stayed READY throughout the update (for example if the update is identical). +void XdsLb::OnBalancerChannelConnectivityChangedLocked(void* arg, + grpc_error* error) { + XdsLb* xdslb_policy = static_cast<XdsLb*>(arg); + if (xdslb_policy->shutting_down_) goto done; + // Re-initialize the lb_call. This should also take care of updating the + // embedded RR policy. Note that the current RR policy, if any, will stay in + // effect until an update from the new lb_call is received. + switch (xdslb_policy->lb_channel_connectivity_) { + case GRPC_CHANNEL_CONNECTING: + case GRPC_CHANNEL_TRANSIENT_FAILURE: { + // Keep watching the LB channel. + grpc_channel_element* client_channel_elem = + grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(xdslb_policy->lb_channel_)); + GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter); + grpc_client_channel_watch_connectivity_state( + client_channel_elem, + grpc_polling_entity_create_from_pollset_set( + xdslb_policy->interested_parties()), + &xdslb_policy->lb_channel_connectivity_, + &xdslb_policy->lb_channel_on_connectivity_changed_, nullptr); + break; + } + // The LB channel may be IDLE because it's shut down before the update. + // Restart the LB call to kick the LB channel into gear. + case GRPC_CHANNEL_IDLE: + case GRPC_CHANNEL_READY: + xdslb_policy->lb_calld_.reset(); + if (xdslb_policy->started_picking_) { + if (xdslb_policy->retry_timer_callback_pending_) { + grpc_timer_cancel(&xdslb_policy->lb_call_retry_timer_); + } + xdslb_policy->lb_call_backoff_.Reset(); + xdslb_policy->StartBalancerCallLocked(); + } + [[fallthrough]]; + // Fall through. + case GRPC_CHANNEL_SHUTDOWN: + done: + xdslb_policy->watching_lb_channel_ = false; + xdslb_policy->Unref(DEBUG_LOCATION, + "watch_lb_channel_connectivity_cb_shutdown"); + } +} + +// +// PendingPick +// + +// Adds lb_token of selected subchannel (address) to the call's initial +// metadata. +grpc_error* AddLbTokenToInitialMetadata( + grpc_mdelem lb_token, grpc_linked_mdelem* lb_token_mdelem_storage, + grpc_metadata_batch* initial_metadata) { + GPR_ASSERT(lb_token_mdelem_storage != nullptr); + GPR_ASSERT(!GRPC_MDISNULL(lb_token)); + return grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage, + lb_token); +} + +// Destroy function used when embedding client stats in call context. +void DestroyClientStats(void* arg) { + static_cast<XdsLbClientStats*>(arg)->Unref(); +} + +void XdsLb::PendingPickSetMetadataAndContext(PendingPick* pp) { + /* if connected_subchannel is nullptr, no pick has been made by the RR + * policy (e.g., all addresses failed to connect). There won't be any + * user_data/token available */ + if (pp->pick->connected_subchannel != nullptr) { + if (GPR_LIKELY(!GRPC_MDISNULL(pp->lb_token))) { + AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(pp->lb_token), + &pp->pick->lb_token_mdelem_storage, + pp->pick->initial_metadata); + } else { + gpr_log(GPR_ERROR, + "[xdslb %p] No LB token for connected subchannel pick %p", + pp->xdslb_policy, pp->pick); + abort(); + } + // Pass on client stats via context. Passes ownership of the reference. + if (pp->client_stats != nullptr) { + pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].value = + pp->client_stats.release(); + pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].destroy = + DestroyClientStats; + } + } else { + pp->client_stats.reset(); + } +} + +/* The \a on_complete closure passed as part of the pick requires keeping a + * reference to its associated round robin instance. We wrap this closure in + * order to unref the round robin instance upon its invocation */ +void XdsLb::OnPendingPickComplete(void* arg, grpc_error* error) { + PendingPick* pp = static_cast<PendingPick*>(arg); + PendingPickSetMetadataAndContext(pp); + GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_REF(error)); + Delete(pp); +} + +XdsLb::PendingPick* XdsLb::PendingPickCreate(PickState* pick) { + PendingPick* pp = New<PendingPick>(); + pp->xdslb_policy = this; + pp->pick = pick; + GRPC_CLOSURE_INIT(&pp->on_complete, &XdsLb::OnPendingPickComplete, pp, + grpc_schedule_on_exec_ctx); + pp->original_on_complete = pick->on_complete; + pick->on_complete = &pp->on_complete; + return pp; +} + +void XdsLb::AddPendingPick(PendingPick* pp) { + pp->next = pending_picks_; + pending_picks_ = pp; +} + +// +// code for interacting with the RR policy +// + +// Performs a pick over \a rr_policy_. Given that a pick can return +// immediately (ignoring its completion callback), we need to perform the +// cleanups this callback would otherwise be responsible for. +// If \a force_async is true, then we will manually schedule the +// completion callback even if the pick is available immediately. +bool XdsLb::PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp, + grpc_error** error) { + // Check for drops if we are not using fallback backend addresses. + if (serverlist_ != nullptr) { + // Look at the index into the serverlist to see if we should drop this call. + xds_grpclb_server* server = serverlist_->servers[serverlist_index_++]; + if (serverlist_index_ == serverlist_->num_servers) { + serverlist_index_ = 0; // Wrap-around. + } + if (server->drop) { + // Update client load reporting stats to indicate the number of + // dropped calls. Note that we have to do this here instead of in + // the client_load_reporting filter, because we do not create a + // subchannel call (and therefore no client_load_reporting filter) + // for dropped calls. + if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { + lb_calld_->client_stats()->AddCallDroppedLocked( + server->load_balance_token); + } + if (force_async) { + GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_NONE); + Delete(pp); + return false; + } + Delete(pp); + return true; + } + } + // Set client_stats and user_data. + if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { + pp->client_stats = lb_calld_->client_stats()->Ref(); + } + GPR_ASSERT(pp->pick->user_data == nullptr); + pp->pick->user_data = (void**)&pp->lb_token; + // Pick via the RR policy. + bool pick_done = rr_policy_->PickLocked(pp->pick, error); + if (pick_done) { + PendingPickSetMetadataAndContext(pp); + if (force_async) { + GRPC_CLOSURE_SCHED(pp->original_on_complete, *error); + *error = GRPC_ERROR_NONE; + pick_done = false; + } + Delete(pp); + } + // else, the pending pick will be registered and taken care of by the + // pending pick list inside the RR policy. Eventually, + // OnPendingPickComplete() will be called, which will (among other + // things) add the LB token to the call's initial metadata. + return pick_done; +} + +void XdsLb::CreateRoundRobinPolicyLocked(const Args& args) { + GPR_ASSERT(rr_policy_ == nullptr); + rr_policy_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy( + "round_robin", args); + if (GPR_UNLIKELY(rr_policy_ == nullptr)) { + gpr_log(GPR_ERROR, "[xdslb %p] Failure creating a RoundRobin policy", this); + return; + } + // TODO(roth): We currently track this ref manually. Once the new + // ClosureRef API is done, pass the RefCountedPtr<> along with the closure. + auto self = Ref(DEBUG_LOCATION, "on_rr_reresolution_requested"); + self.release(); + rr_policy_->SetReresolutionClosureLocked(&on_rr_request_reresolution_); + grpc_error* rr_state_error = nullptr; + rr_connectivity_state_ = rr_policy_->CheckConnectivityLocked(&rr_state_error); + // Connectivity state is a function of the RR policy updated/created. + UpdateConnectivityStateFromRoundRobinPolicyLocked(rr_state_error); + // Add the gRPC LB's interested_parties pollset_set to that of the newly + // created RR policy. This will make the RR policy progress upon activity on + // gRPC LB, which in turn is tied to the application's call. + grpc_pollset_set_add_pollset_set(rr_policy_->interested_parties(), + interested_parties()); + // Subscribe to changes to the connectivity of the new RR. + // TODO(roth): We currently track this ref manually. Once the new + // ClosureRef API is done, pass the RefCountedPtr<> along with the closure. + self = Ref(DEBUG_LOCATION, "on_rr_connectivity_changed"); + self.release(); + rr_policy_->NotifyOnStateChangeLocked(&rr_connectivity_state_, + &on_rr_connectivity_changed_); + rr_policy_->ExitIdleLocked(); + // Send pending picks to RR policy. + PendingPick* pp; + while ((pp = pending_picks_)) { + pending_picks_ = pp->next; + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, + "[xdslb %p] Pending pick about to (async) PICK from RR %p", this, + rr_policy_.get()); + } + grpc_error* error = GRPC_ERROR_NONE; + PickFromRoundRobinPolicyLocked(true /* force_async */, pp, &error); + } +} + +grpc_channel_args* XdsLb::CreateRoundRobinPolicyArgsLocked() { + grpc_lb_addresses* addresses; + bool is_backend_from_grpclb_load_balancer = false; + if (serverlist_ != nullptr) { + GPR_ASSERT(serverlist_->num_servers > 0); + addresses = ProcessServerlist(serverlist_); + is_backend_from_grpclb_load_balancer = true; + } else { + // If CreateOrUpdateRoundRobinPolicyLocked() is invoked when we haven't + // received any serverlist from the balancer, we use the fallback backends + // returned by the resolver. Note that the fallback backend list may be + // empty, in which case the new round_robin policy will keep the requested + // picks pending. + GPR_ASSERT(fallback_backend_addresses_ != nullptr); + addresses = grpc_lb_addresses_copy(fallback_backend_addresses_); + } + GPR_ASSERT(addresses != nullptr); + // Replace the LB addresses in the channel args that we pass down to + // the subchannel. + static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; + const grpc_arg args_to_add[] = { + grpc_lb_addresses_create_channel_arg(addresses), + // A channel arg indicating if the target is a backend inferred from a + // grpclb load balancer. + grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_ADDRESS_IS_BACKEND_FROM_XDS_LOAD_BALANCER), + is_backend_from_grpclb_load_balancer), + }; + grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove( + args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add, + GPR_ARRAY_SIZE(args_to_add)); + grpc_lb_addresses_destroy(addresses); + return args; +} + +void XdsLb::CreateOrUpdateRoundRobinPolicyLocked() { + if (shutting_down_) return; + grpc_channel_args* args = CreateRoundRobinPolicyArgsLocked(); + GPR_ASSERT(args != nullptr); + if (rr_policy_ != nullptr) { + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, "[xdslb %p] Updating RR policy %p", this, + rr_policy_.get()); + } + rr_policy_->UpdateLocked(*args); + } else { + LoadBalancingPolicy::Args lb_policy_args; + lb_policy_args.combiner = combiner(); + lb_policy_args.client_channel_factory = client_channel_factory(); + lb_policy_args.args = args; + CreateRoundRobinPolicyLocked(lb_policy_args); + if (grpc_lb_xds_trace.enabled()) { + gpr_log(GPR_INFO, "[xdslb %p] Created new RR policy %p", this, + rr_policy_.get()); + } + } + grpc_channel_args_destroy(args); +} + +void XdsLb::OnRoundRobinRequestReresolutionLocked(void* arg, + grpc_error* error) { + XdsLb* xdslb_policy = static_cast<XdsLb*>(arg); + if (xdslb_policy->shutting_down_ || error != GRPC_ERROR_NONE) { + xdslb_policy->Unref(DEBUG_LOCATION, "on_rr_reresolution_requested"); + return; + } + if (grpc_lb_xds_trace.enabled()) { + gpr_log( + GPR_INFO, + "[xdslb %p] Re-resolution requested from the internal RR policy (%p).", + xdslb_policy, xdslb_policy->rr_policy_.get()); + } + // If we are talking to a balancer, we expect to get updated addresses form + // the balancer, so we can ignore the re-resolution request from the RR + // policy. Otherwise, handle the re-resolution request using the + // grpclb policy's original re-resolution closure. + if (xdslb_policy->lb_calld_ == nullptr || + !xdslb_policy->lb_calld_->seen_initial_response()) { + xdslb_policy->TryReresolutionLocked(&grpc_lb_xds_trace, GRPC_ERROR_NONE); + } + // Give back the wrapper closure to the RR policy. + xdslb_policy->rr_policy_->SetReresolutionClosureLocked( + &xdslb_policy->on_rr_request_reresolution_); +} + +void XdsLb::UpdateConnectivityStateFromRoundRobinPolicyLocked( + grpc_error* rr_state_error) { + const grpc_connectivity_state curr_glb_state = + grpc_connectivity_state_check(&state_tracker_); + /* The new connectivity status is a function of the previous one and the new + * input coming from the status of the RR policy. + * + * current state (grpclb's) + * | + * v || I | C | R | TF | SD | <- new state (RR's) + * ===++====+=====+=====+======+======+ + * I || I | C | R | [I] | [I] | + * ---++----+-----+-----+------+------+ + * C || I | C | R | [C] | [C] | + * ---++----+-----+-----+------+------+ + * R || I | C | R | [R] | [R] | + * ---++----+-----+-----+------+------+ + * TF || I | C | R | [TF] | [TF] | + * ---++----+-----+-----+------+------+ + * SD || NA | NA | NA | NA | NA | (*) + * ---++----+-----+-----+------+------+ + * + * A [STATE] indicates that the old RR policy is kept. In those cases, STATE + * is the current state of grpclb, which is left untouched. + * + * In summary, if the new state is TRANSIENT_FAILURE or SHUTDOWN, stick to + * the previous RR instance. + * + * Note that the status is never updated to SHUTDOWN as a result of calling + * this function. Only glb_shutdown() has the power to set that state. + * + * (*) This function mustn't be called during shutting down. */ + GPR_ASSERT(curr_glb_state != GRPC_CHANNEL_SHUTDOWN); + switch (rr_connectivity_state_) { + case GRPC_CHANNEL_TRANSIENT_FAILURE: + case GRPC_CHANNEL_SHUTDOWN: + GPR_ASSERT(rr_state_error != GRPC_ERROR_NONE); + break; + case GRPC_CHANNEL_IDLE: + case GRPC_CHANNEL_CONNECTING: + case GRPC_CHANNEL_READY: + GPR_ASSERT(rr_state_error == GRPC_ERROR_NONE); + } + if (grpc_lb_xds_trace.enabled()) { + gpr_log( + GPR_INFO, + "[xdslb %p] Setting grpclb's state to %s from new RR policy %p state.", + this, grpc_connectivity_state_name(rr_connectivity_state_), + rr_policy_.get()); + } + grpc_connectivity_state_set(&state_tracker_, rr_connectivity_state_, + rr_state_error, + "update_lb_connectivity_status_locked"); +} + +void XdsLb::OnRoundRobinConnectivityChangedLocked(void* arg, + grpc_error* error) { + XdsLb* xdslb_policy = static_cast<XdsLb*>(arg); + if (xdslb_policy->shutting_down_) { + xdslb_policy->Unref(DEBUG_LOCATION, "on_rr_connectivity_changed"); + return; + } + xdslb_policy->UpdateConnectivityStateFromRoundRobinPolicyLocked( + GRPC_ERROR_REF(error)); + // Resubscribe. Reuse the "on_rr_connectivity_changed" ref. + xdslb_policy->rr_policy_->NotifyOnStateChangeLocked( + &xdslb_policy->rr_connectivity_state_, + &xdslb_policy->on_rr_connectivity_changed_); +} + +// +// factory +// + +class XdsFactory : public LoadBalancingPolicyFactory { + public: + OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( + const LoadBalancingPolicy::Args& args) const override { + /* Count the number of gRPC-LB addresses. There must be at least one. */ + const grpc_arg* arg = + grpc_channel_args_find(args.args, GRPC_ARG_LB_ADDRESSES); + if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { + return nullptr; + } + grpc_lb_addresses* addresses = + static_cast<grpc_lb_addresses*>(arg->value.pointer.p); + size_t num_grpclb_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + } + if (num_grpclb_addrs == 0) return nullptr; + return OrphanablePtr<LoadBalancingPolicy>(New<XdsLb>(addresses, args)); + } + + const char* name() const override { return "xds"; } +}; + +} // namespace + +} // namespace grpc_core + +// +// Plugin registration +// + +namespace { + +// Only add client_load_reporting filter if the grpclb LB policy is used. +bool maybe_add_client_load_reporting_filter(grpc_channel_stack_builder* builder, + void* arg) { + const grpc_channel_args* args = + grpc_channel_stack_builder_get_channel_arguments(builder); + const grpc_arg* channel_arg = + grpc_channel_args_find(args, GRPC_ARG_LB_POLICY_NAME); + if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_STRING && + strcmp(channel_arg->value.string, "grpclb") == 0) { + return grpc_channel_stack_builder_append_filter( + builder, (const grpc_channel_filter*)arg, nullptr, nullptr); + } + return true; +} + +} // namespace + +void grpc_lb_policy_xds_init() { + grpc_core::LoadBalancingPolicyRegistry::Builder:: + RegisterLoadBalancingPolicyFactory( + grpc_core::UniquePtr<grpc_core::LoadBalancingPolicyFactory>( + grpc_core::New<grpc_core::XdsFactory>())); + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_client_load_reporting_filter, + (void*)&xds_client_load_reporting_filter); +} + +void grpc_lb_policy_xds_shutdown() {} diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds.h new file mode 100644 index 0000000000..8b20680f2d --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.h @@ -0,0 +1,36 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_H + +#include <grpc/support/port_platform.h> + +/** Channel arg indicating if a target corresponding to the address is grpclb + * loadbalancer. The type of this arg is an integer and the value is treated as + * a bool. */ +#define GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER \ + "grpc.address_is_xds_load_balancer" +/** Channel arg indicating if a target corresponding to the address is a backend + * received from a balancer. The type of this arg is an integer and the value is + * treated as a bool. */ +#define GRPC_ARG_ADDRESS_IS_BACKEND_FROM_XDS_LOAD_BALANCER \ + "grpc.address_is_backend_from_xds_load_balancer" + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_H \ + */ diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc new file mode 100644 index 0000000000..0aa145a24e --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc @@ -0,0 +1,26 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/support/port_platform.h> + +#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h" + +grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args( + grpc_channel_args* args) { + return args; +} diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h new file mode 100644 index 0000000000..32c4acc8a3 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h @@ -0,0 +1,36 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CHANNEL_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CHANNEL_H + +#include <grpc/support/port_platform.h> + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" + +/// Makes any necessary modifications to \a args for use in the xds +/// balancer channel. +/// +/// Takes ownership of \a args. +/// +/// Caller takes ownership of the returned args. +grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args( + grpc_channel_args* args); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CHANNEL_H \ + */ diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc new file mode 100644 index 0000000000..5ab72efce4 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc @@ -0,0 +1,107 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/support/port_platform.h> + +#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h" + +#include <grpc/support/alloc.h> +#include <grpc/support/string_util.h> +#include <string.h> + +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/gpr/string.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/transport/target_authority_table.h" +#include "src/core/lib/slice/slice_internal.h" + +namespace grpc_core { +namespace { + +int BalancerNameCmp(const grpc_core::UniquePtr<char>& a, + const grpc_core::UniquePtr<char>& b) { + return strcmp(a.get(), b.get()); +} + +RefCountedPtr<TargetAuthorityTable> CreateTargetAuthorityTable( + grpc_lb_addresses* addresses) { + TargetAuthorityTable::Entry* target_authority_entries = + static_cast<TargetAuthorityTable::Entry*>(gpr_zalloc( + sizeof(*target_authority_entries) * addresses->num_addresses)); + for (size_t i = 0; i < addresses->num_addresses; ++i) { + char* addr_str; + GPR_ASSERT(grpc_sockaddr_to_string( + &addr_str, &addresses->addresses[i].address, true) > 0); + target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str); + target_authority_entries[i].value.reset( + gpr_strdup(addresses->addresses[i].balancer_name)); + gpr_free(addr_str); + } + RefCountedPtr<TargetAuthorityTable> target_authority_table = + TargetAuthorityTable::Create(addresses->num_addresses, + target_authority_entries, BalancerNameCmp); + gpr_free(target_authority_entries); + return target_authority_table; +} + +} // namespace +} // namespace grpc_core + +grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args( + grpc_channel_args* args) { + const char* args_to_remove[1]; + size_t num_args_to_remove = 0; + grpc_arg args_to_add[2]; + size_t num_args_to_add = 0; + // Add arg for targets info table. + const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_LB_ADDRESSES); + GPR_ASSERT(arg != nullptr); + GPR_ASSERT(arg->type == GRPC_ARG_POINTER); + grpc_lb_addresses* addresses = + static_cast<grpc_lb_addresses*>(arg->value.pointer.p); + grpc_core::RefCountedPtr<grpc_core::TargetAuthorityTable> + target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses); + args_to_add[num_args_to_add++] = + grpc_core::CreateTargetAuthorityTableChannelArg( + target_authority_table.get()); + // Substitute the channel credentials with a version without call + // credentials: the load balancer is not necessarily trusted to handle + // bearer token credentials. + grpc_channel_credentials* channel_credentials = + grpc_channel_credentials_find_in_args(args); + grpc_channel_credentials* creds_sans_call_creds = nullptr; + if (channel_credentials != nullptr) { + creds_sans_call_creds = + grpc_channel_credentials_duplicate_without_call_credentials( + channel_credentials); + GPR_ASSERT(creds_sans_call_creds != nullptr); + args_to_remove[num_args_to_remove++] = GRPC_ARG_CHANNEL_CREDENTIALS; + args_to_add[num_args_to_add++] = + grpc_channel_credentials_to_arg(creds_sans_call_creds); + } + grpc_channel_args* result = grpc_channel_args_copy_and_add_and_remove( + args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add); + // Clean up. + grpc_channel_args_destroy(args); + if (creds_sans_call_creds != nullptr) { + grpc_channel_credentials_unref(creds_sans_call_creds); + } + return result; +} diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc new file mode 100644 index 0000000000..cdf5408be3 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc @@ -0,0 +1,85 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/support/port_platform.h> + +#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h" + +#include <grpc/support/atm.h> +#include <grpc/support/string_util.h> +#include <string.h> + +namespace grpc_core { + +void XdsLbClientStats::AddCallStarted() { + gpr_atm_full_fetch_add(&num_calls_started_, (gpr_atm)1); +} + +void XdsLbClientStats::AddCallFinished(bool finished_with_client_failed_to_send, + bool finished_known_received) { + gpr_atm_full_fetch_add(&num_calls_finished_, (gpr_atm)1); + if (finished_with_client_failed_to_send) { + gpr_atm_full_fetch_add(&num_calls_finished_with_client_failed_to_send_, + (gpr_atm)1); + } + if (finished_known_received) { + gpr_atm_full_fetch_add(&num_calls_finished_known_received_, (gpr_atm)1); + } +} + +void XdsLbClientStats::AddCallDroppedLocked(char* token) { + // Increment num_calls_started and num_calls_finished. + gpr_atm_full_fetch_add(&num_calls_started_, (gpr_atm)1); + gpr_atm_full_fetch_add(&num_calls_finished_, (gpr_atm)1); + // Record the drop. + if (drop_token_counts_ == nullptr) { + drop_token_counts_.reset(New<DroppedCallCounts>()); + } + for (size_t i = 0; i < drop_token_counts_->size(); ++i) { + if (strcmp((*drop_token_counts_)[i].token.get(), token) == 0) { + ++(*drop_token_counts_)[i].count; + return; + } + } + // Not found, so add a new entry. + drop_token_counts_->emplace_back(UniquePtr<char>(gpr_strdup(token)), 1); +} + +namespace { + +void AtomicGetAndResetCounter(int64_t* value, gpr_atm* counter) { + *value = static_cast<int64_t>(gpr_atm_full_xchg(counter, (gpr_atm)0)); +} + +} // namespace + +void XdsLbClientStats::GetLocked( + int64_t* num_calls_started, int64_t* num_calls_finished, + int64_t* num_calls_finished_with_client_failed_to_send, + int64_t* num_calls_finished_known_received, + UniquePtr<DroppedCallCounts>* drop_token_counts) { + AtomicGetAndResetCounter(num_calls_started, &num_calls_started_); + AtomicGetAndResetCounter(num_calls_finished, &num_calls_finished_); + AtomicGetAndResetCounter(num_calls_finished_with_client_failed_to_send, + &num_calls_finished_with_client_failed_to_send_); + AtomicGetAndResetCounter(num_calls_finished_known_received, + &num_calls_finished_known_received_); + *drop_token_counts = std::move(drop_token_counts_); +} + +} // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h new file mode 100644 index 0000000000..fa0b9f4b63 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h @@ -0,0 +1,72 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CLIENT_STATS_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CLIENT_STATS_H + +#include <grpc/support/port_platform.h> + +#include <grpc/support/atm.h> + +#include "src/core/lib/gprpp/inlined_vector.h" +#include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/gprpp/ref_counted.h" + +namespace grpc_core { + +class XdsLbClientStats : public RefCounted<XdsLbClientStats> { + public: + struct DropTokenCount { + UniquePtr<char> token; + int64_t count; + + DropTokenCount(UniquePtr<char> token, int64_t count) + : token(std::move(token)), count(count) {} + }; + + typedef InlinedVector<DropTokenCount, 10> DroppedCallCounts; + + XdsLbClientStats() {} + + void AddCallStarted(); + void AddCallFinished(bool finished_with_client_failed_to_send, + bool finished_known_received); + + // This method is not thread-safe; caller must synchronize. + void AddCallDroppedLocked(char* token); + + // This method is not thread-safe; caller must synchronize. + void GetLocked(int64_t* num_calls_started, int64_t* num_calls_finished, + int64_t* num_calls_finished_with_client_failed_to_send, + int64_t* num_calls_finished_known_received, + UniquePtr<DroppedCallCounts>* drop_token_counts); + + private: + // This field must only be accessed via *_locked() methods. + UniquePtr<DroppedCallCounts> drop_token_counts_; + // These fields may be accessed from multiple threads at a time. + gpr_atm num_calls_started_ = 0; + gpr_atm num_calls_finished_ = 0; + gpr_atm num_calls_finished_with_client_failed_to_send_ = 0; + gpr_atm num_calls_finished_known_received_ = 0; +}; + +} // namespace grpc_core + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CLIENT_STATS_H \ + */ diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h index c07792d8a7..62bdbf2689 100644 --- a/src/core/ext/filters/client_channel/lb_policy_factory.h +++ b/src/core/ext/filters/client_channel/lb_policy_factory.h @@ -70,16 +70,14 @@ grpc_lb_addresses* grpc_lb_addresses_create( grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses); /** Sets the value of the address at index \a index of \a addresses. - * \a address is a socket address of length \a address_len. - * Takes ownership of \a balancer_name. */ + * \a address is a socket address of length \a address_len. */ void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, const void* address, size_t address_len, bool is_balancer, const char* balancer_name, void* user_data); /** Sets the value of the address at index \a index of \a addresses from \a uri. - * Returns true upon success, false otherwise. Takes ownership of \a - * balancer_name. */ + * Returns true upon success, false otherwise. */ bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses, size_t index, const grpc_uri* uri, bool is_balancer, diff --git a/src/core/ext/filters/client_channel/parse_address.cc b/src/core/ext/filters/client_channel/parse_address.cc index b3900114ad..707beb8876 100644 --- a/src/core/ext/filters/client_channel/parse_address.cc +++ b/src/core/ext/filters/client_channel/parse_address.cc @@ -125,27 +125,41 @@ bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr, char* host_end = static_cast<char*>(gpr_memrchr(host, '%', strlen(host))); if (host_end != nullptr) { GPR_ASSERT(host_end >= host); - char host_without_scope[GRPC_INET6_ADDRSTRLEN]; + char host_without_scope[GRPC_INET6_ADDRSTRLEN + 1]; size_t host_without_scope_len = static_cast<size_t>(host_end - host); uint32_t sin6_scope_id = 0; + if (host_without_scope_len > GRPC_INET6_ADDRSTRLEN) { + if (log_errors) { + gpr_log( + GPR_ERROR, + "invalid ipv6 address length %zu. Length cannot be greater than " + "GRPC_INET6_ADDRSTRLEN i.e %d)", + host_without_scope_len, GRPC_INET6_ADDRSTRLEN); + } + goto done; + } strncpy(host_without_scope, host, host_without_scope_len); host_without_scope[host_without_scope_len] = '\0'; if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) == 0) { - gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope); + if (log_errors) { + gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope); + } goto done; } if (gpr_parse_bytes_to_uint32(host_end + 1, strlen(host) - host_without_scope_len - 1, &sin6_scope_id) == 0) { - gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1); + if (log_errors) { + gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1); + } goto done; } // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027. in6->sin6_scope_id = sin6_scope_id; } else { if (grpc_inet_pton(GRPC_AF_INET6, host, &in6->sin6_addr) == 0) { - gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host); + if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host); goto done; } } @@ -190,3 +204,12 @@ bool grpc_parse_uri(const grpc_uri* uri, grpc_resolved_address* resolved_addr) { gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme); return false; } + +uint16_t grpc_strhtons(const char* port) { + if (strcmp(port, "http") == 0) { + return htons(80); + } else if (strcmp(port, "https") == 0) { + return htons(443); + } + return htons(static_cast<unsigned short>(atoi(port))); +} diff --git a/src/core/ext/filters/client_channel/parse_address.h b/src/core/ext/filters/client_channel/parse_address.h index 9a88b66edc..c2af0e6c49 100644 --- a/src/core/ext/filters/client_channel/parse_address.h +++ b/src/core/ext/filters/client_channel/parse_address.h @@ -47,4 +47,7 @@ bool grpc_parse_ipv4_hostport(const char* hostport, grpc_resolved_address* addr, bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr, bool log_errors); +/* Converts named or numeric port to a uint16 suitable for use in a sockaddr. */ +uint16_t grpc_strhtons(const char* port); + #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H */ diff --git a/src/core/ext/filters/client_channel/resolver.h b/src/core/ext/filters/client_channel/resolver.h index 48f2e89095..e9acbb7c41 100644 --- a/src/core/ext/filters/client_channel/resolver.h +++ b/src/core/ext/filters/client_channel/resolver.h @@ -81,18 +81,7 @@ class Resolver : public InternallyRefCountedWithTracing<Resolver> { /// /// If this causes new data to become available, then the currently /// pending call to \a NextLocked() will return the new result. - /// - /// Note: Currently, all resolvers are required to return a new result - /// shortly after this method is called. For pull-based mechanisms, if - /// the implementation decides to delay querying the name service, it - /// should immediately return a new copy of the previously returned - /// result (and it can then return the updated data later, when it - /// actually does query the name service). For push-based mechanisms, - /// the implementation should immediately return a new copy of the - /// last-seen result. - /// TODO(roth): Remove this requirement once we fix pick_first to not - /// throw away unselected subchannels. - virtual void RequestReresolutionLocked() GRPC_ABSTRACT; + virtual void RequestReresolutionLocked() {} /// Resets the re-resolution backoff, if any. /// This needs to be implemented only by pull-based implementations; diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index f2bb5f3c71..dfa52867d8 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -373,13 +373,7 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { void AresDnsResolver::MaybeStartResolvingLocked() { // If there is an existing timer, the time it fires is the earliest time we // can start the next resolution. - if (have_next_resolution_timer_) { - // TODO(dgq): remove the following two lines once Pick First stops - // discarding subchannels after selecting. - ++resolved_version_; - MaybeFinishNextLocked(); - return; - } + if (have_next_resolution_timer_) return; if (last_resolution_timestamp_ >= 0) { const grpc_millis earliest_next_resolution = last_resolution_timestamp_ + min_time_between_resolutions_; @@ -401,10 +395,6 @@ void AresDnsResolver::MaybeStartResolvingLocked() { self.release(); grpc_timer_init(&next_resolution_timer_, ms_until_next_resolution, &on_next_resolution_); - // TODO(dgq): remove the following two lines once Pick First stops - // discarding subchannels after selecting. - ++resolved_version_; - MaybeFinishNextLocked(); return; } } diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc index 485998f5e4..4c795c34c8 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc @@ -87,15 +87,6 @@ typedef struct grpc_ares_hostbyname_request { static void do_basic_init(void) { gpr_mu_init(&g_init_mu); } -static uint16_t strhtons(const char* port) { - if (strcmp(port, "http") == 0) { - return htons(80); - } else if (strcmp(port, "https") == 0) { - return htons(443); - } - return htons(static_cast<unsigned short>(atoi(port))); -} - static void log_address_sorting_list(grpc_lb_addresses* lb_addrs, const char* input_output_str) { for (size_t i = 0; i < lb_addrs->num_addresses; i++) { @@ -139,12 +130,6 @@ void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs) { } } -/* Allow tests to access grpc_ares_wrapper_address_sorting_sort */ -void grpc_cares_wrapper_test_only_address_sorting_sort( - grpc_lb_addresses* lb_addrs) { - grpc_cares_wrapper_address_sorting_sort(lb_addrs); -} - static void grpc_ares_request_ref_locked(grpc_ares_request* r) { r->pending_queries++; } @@ -371,7 +356,8 @@ done: grpc_ares_request_unref_locked(r); } -static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( +static grpc_ares_request* +grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, @@ -454,12 +440,12 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( } r->pending_queries = 1; if (grpc_ares_query_ipv6()) { - hr = create_hostbyname_request_locked(r, host, strhtons(port), + hr = create_hostbyname_request_locked(r, host, grpc_strhtons(port), false /* is_balancer */); ares_gethostbyname(*channel, hr->host, AF_INET6, on_hostbyname_done_locked, hr); } - hr = create_hostbyname_request_locked(r, host, strhtons(port), + hr = create_hostbyname_request_locked(r, host, grpc_strhtons(port), false /* is_balancer */); ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_locked, hr); @@ -494,6 +480,79 @@ error_cleanup: return nullptr; } +static bool inner_resolve_as_ip_literal_locked(const char* name, + const char* default_port, + grpc_lb_addresses** addrs, + char** host, char** port, + char** hostport) { + gpr_split_host_port(name, host, port); + if (*host == nullptr) { + gpr_log(GPR_ERROR, + "Failed to parse %s to host:port while attempting to resolve as ip " + "literal.", + name); + return false; + } + if (*port == nullptr) { + if (default_port == nullptr) { + gpr_log(GPR_ERROR, + "No port or default port for %s while attempting to resolve as " + "ip literal.", + name); + return false; + } + *port = gpr_strdup(default_port); + } + grpc_resolved_address addr; + GPR_ASSERT(gpr_join_host_port(hostport, *host, atoi(*port))); + if (grpc_parse_ipv4_hostport(*hostport, &addr, false /* log errors */) || + grpc_parse_ipv6_hostport(*hostport, &addr, false /* log errors */)) { + GPR_ASSERT(*addrs == nullptr); + *addrs = grpc_lb_addresses_create(1, nullptr); + grpc_lb_addresses_set_address( + *addrs, 0, addr.addr, addr.len, false /* is_balancer */, + nullptr /* balancer_name */, nullptr /* user_data */); + return true; + } + return false; +} + +static bool resolve_as_ip_literal_locked(const char* name, + const char* default_port, + grpc_lb_addresses** addrs) { + char* host = nullptr; + char* port = nullptr; + char* hostport = nullptr; + bool out = inner_resolve_as_ip_literal_locked(name, default_port, addrs, + &host, &port, &hostport); + gpr_free(host); + gpr_free(port); + gpr_free(hostport); + return out; +} + +static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( + const char* dns_server, const char* name, const char* default_port, + grpc_pollset_set* interested_parties, grpc_closure* on_done, + grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, + grpc_combiner* combiner) { + // Early out if the target is an ipv4 or ipv6 literal. + if (resolve_as_ip_literal_locked(name, default_port, addrs)) { + GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE); + return nullptr; + } + // Early out if the target is localhost and we're on Windows. + if (grpc_ares_maybe_resolve_localhost_manually_locked(name, default_port, + addrs)) { + GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE); + return nullptr; + } + // Look up name using c-ares lib. + return grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( + dns_server, name, default_port, interested_parties, on_done, addrs, + check_grpclb, service_config_json, combiner); +} + grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, @@ -502,7 +561,9 @@ grpc_ares_request* (*grpc_dns_lookup_ares_locked)( void grpc_cancel_ares_request(grpc_ares_request* r) { if (grpc_dns_lookup_ares_locked == grpc_dns_lookup_ares_locked_impl) { - grpc_ares_ev_driver_shutdown_locked(r->ev_driver); + if (r != nullptr) { + grpc_ares_ev_driver_shutdown_locked(r->ev_driver); + } } } diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h index ca5779e1d7..1bc457d4cf 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h @@ -81,9 +81,15 @@ void grpc_ares_complete_request_locked(grpc_ares_request* request); /* E.g., return false if ipv6 is known to not be available. */ bool grpc_ares_query_ipv6(); -/* Exposed only for testing */ -void grpc_cares_wrapper_test_only_address_sorting_sort( - grpc_lb_addresses* lb_addrs); +/* Maybe (depending on the current platform) checks if "name" matches + * "localhost" and if so fills in addrs with the correct sockaddr structures. + * Returns a bool indicating whether or not such an action was performed. + * See https://github.com/grpc/grpc/issues/15158. */ +bool grpc_ares_maybe_resolve_localhost_manually_locked( + const char* name, const char* default_port, grpc_lb_addresses** addrs); + +/* Sorts destinations in lb_addrs according to RFC 6724. */ +void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs); #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \ */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc index 23c0fec74f..639eec2323 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc @@ -26,4 +26,9 @@ bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } +bool grpc_ares_maybe_resolve_localhost_manually_locked( + const char* name, const char* default_port, grpc_lb_addresses** addrs) { + return false; +} + #endif /* GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc index ee827e284e..7e34784691 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc @@ -21,9 +21,79 @@ #include "src/core/lib/iomgr/port.h" #if GRPC_ARES == 1 && defined(GPR_WINDOWS) +#include <grpc/support/string_util.h> + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/lib/gpr/host_port.h" +#include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/socket_windows.h" bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } +static bool inner_maybe_resolve_localhost_manually_locked( + const char* name, const char* default_port, grpc_lb_addresses** addrs, + char** host, char** port) { + gpr_split_host_port(name, host, port); + if (*host == nullptr) { + gpr_log(GPR_ERROR, + "Failed to parse %s into host:port during Windows localhost " + "resolution check.", + name); + return false; + } + if (*port == nullptr) { + if (default_port == nullptr) { + gpr_log(GPR_ERROR, + "No port or default port for %s during Windows localhost " + "resolution check.", + name); + return false; + } + *port = gpr_strdup(default_port); + } + if (gpr_stricmp(*host, "localhost") == 0) { + GPR_ASSERT(*addrs == nullptr); + *addrs = grpc_lb_addresses_create(2, nullptr); + uint16_t numeric_port = grpc_strhtons(*port); + // Append the ipv6 loopback address. + struct sockaddr_in6 ipv6_loopback_addr; + memset(&ipv6_loopback_addr, 0, sizeof(ipv6_loopback_addr)); + ((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1; + ipv6_loopback_addr.sin6_family = AF_INET6; + ipv6_loopback_addr.sin6_port = numeric_port; + grpc_lb_addresses_set_address( + *addrs, 0, &ipv6_loopback_addr, sizeof(ipv6_loopback_addr), + false /* is_balancer */, nullptr /* balancer_name */, + nullptr /* user_data */); + // Append the ipv4 loopback address. + struct sockaddr_in ipv4_loopback_addr; + memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr)); + ((char*)&ipv4_loopback_addr.sin_addr)[0] = 0x7f; + ((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01; + ipv4_loopback_addr.sin_family = AF_INET; + ipv4_loopback_addr.sin_port = numeric_port; + grpc_lb_addresses_set_address( + *addrs, 1, &ipv4_loopback_addr, sizeof(ipv4_loopback_addr), + false /* is_balancer */, nullptr /* balancer_name */, + nullptr /* user_data */); + // Let the address sorter figure out which one should be tried first. + grpc_cares_wrapper_address_sorting_sort(*addrs); + return true; + } + return false; +} + +bool grpc_ares_maybe_resolve_localhost_manually_locked( + const char* name, const char* default_port, grpc_lb_addresses** addrs) { + char* host = nullptr; + char* port = nullptr; + bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port, + addrs, &host, &port); + gpr_free(host); + gpr_free(port); + return out; +} + #endif /* GRPC_ARES == 1 && defined(GPR_WINDOWS) */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc index 282caf215c..65ff1ec1a5 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc @@ -247,13 +247,7 @@ void NativeDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { void NativeDnsResolver::MaybeStartResolvingLocked() { // If there is an existing timer, the time it fires is the earliest time we // can start the next resolution. - if (have_next_resolution_timer_) { - // TODO(dgq): remove the following two lines once Pick First stops - // discarding subchannels after selecting. - ++resolved_version_; - MaybeFinishNextLocked(); - return; - } + if (have_next_resolution_timer_) return; if (last_resolution_timestamp_ >= 0) { const grpc_millis earliest_next_resolution = last_resolution_timestamp_ + min_time_between_resolutions_; @@ -275,10 +269,6 @@ void NativeDnsResolver::MaybeStartResolvingLocked() { self.release(); grpc_timer_init(&next_resolution_timer_, ms_until_next_resolution, &on_next_resolution_); - // TODO(dgq): remove the following two lines once Pick First stops - // discarding subchannels after selecting. - ++resolved_version_; - MaybeFinishNextLocked(); return; } } diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc index 99a33f2277..144ac24a56 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc @@ -73,11 +73,6 @@ class FakeResolver : public Resolver { // Results to use for the pretended re-resolution in // RequestReresolutionLocked(). grpc_channel_args* reresolution_results_ = nullptr; - // TODO(juanlishen): This can go away once pick_first is changed to not throw - // away its subchannels, since that will eliminate its dependence on - // channel_saw_error_locked() causing an immediate resolver return. - // A copy of the most-recently used resolution results. - grpc_channel_args* last_used_results_ = nullptr; // pending next completion, or NULL grpc_closure* next_completion_ = nullptr; // target result address for next completion @@ -96,7 +91,6 @@ FakeResolver::FakeResolver(const ResolverArgs& args) : Resolver(args.combiner) { FakeResolver::~FakeResolver() { grpc_channel_args_destroy(next_results_); grpc_channel_args_destroy(reresolution_results_); - grpc_channel_args_destroy(last_used_results_); grpc_channel_args_destroy(channel_args_); } @@ -109,17 +103,11 @@ void FakeResolver::NextLocked(grpc_channel_args** target_result, } void FakeResolver::RequestReresolutionLocked() { - // A resolution must have been returned before an error is seen. - GPR_ASSERT(last_used_results_ != nullptr); - grpc_channel_args_destroy(next_results_); if (reresolution_results_ != nullptr) { + grpc_channel_args_destroy(next_results_); next_results_ = grpc_channel_args_copy(reresolution_results_); - } else { - // If reresolution_results is unavailable, re-resolve with the most-recently - // used results to avoid a no-op re-resolution. - next_results_ = grpc_channel_args_copy(last_used_results_); + MaybeFinishNextLocked(); } - MaybeFinishNextLocked(); } void FakeResolver::MaybeFinishNextLocked() { @@ -161,8 +149,6 @@ void FakeResolverResponseGenerator::SetResponseLocked(void* arg, FakeResolver* resolver = closure_arg->generator->resolver_; grpc_channel_args_destroy(resolver->next_results_); resolver->next_results_ = closure_arg->response; - grpc_channel_args_destroy(resolver->last_used_results_); - resolver->last_used_results_ = grpc_channel_args_copy(closure_arg->response); resolver->MaybeFinishNextLocked(); Delete(closure_arg); } diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h index e5175f9b7b..708eaf1147 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h @@ -53,7 +53,8 @@ class FakeResolverResponseGenerator // The new re-resolution response replaces any previous re-resolution // response that may have been set by a previous call. // If the re-resolution response is set to NULL, then the fake - // resolver will return the last value set via \a SetResponse(). + // resolver will not return anything when \a RequestReresolutionLocked() + // is called. void SetReresolutionResponse(grpc_channel_args* response); // Tells the resolver to return a transient failure (signalled by diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc index f74ac5aebe..801734764b 100644 --- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc @@ -50,8 +50,6 @@ class SockaddrResolver : public Resolver { void NextLocked(grpc_channel_args** result, grpc_closure* on_complete) override; - void RequestReresolutionLocked() override; - void ShutdownLocked() override; private: @@ -90,11 +88,6 @@ void SockaddrResolver::NextLocked(grpc_channel_args** target_result, MaybeFinishNextLocked(); } -void SockaddrResolver::RequestReresolutionLocked() { - published_ = false; - MaybeFinishNextLocked(); -} - void SockaddrResolver::ShutdownLocked() { if (next_completion_ != nullptr) { *target_result_ = nullptr; diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index 48c6030c89..a0a40eb2b3 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -49,6 +49,8 @@ #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/channel_init.h" #include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/transport/status_metadata.h" #define INTERNAL_REF_BITS 16 #define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1)) @@ -144,6 +146,11 @@ struct grpc_subchannel { struct grpc_subchannel_call { grpc_core::ConnectedSubchannel* connection; grpc_closure* schedule_closure_after_destroy; + // state needed to support channelz interception of recv trailing metadata. + grpc_closure recv_trailing_metadata_ready; + grpc_closure* original_recv_trailing_metadata; + grpc_metadata_batch* recv_trailing_metadata; + grpc_millis deadline; }; #define SUBCHANNEL_CALL_TO_CALL_STACK(call) \ @@ -183,7 +190,13 @@ static void connection_destroy(void* arg, grpc_error* error) { static void subchannel_destroy(void* arg, grpc_error* error) { grpc_subchannel* c = static_cast<grpc_subchannel*>(arg); - c->channelz_subchannel.reset(); + if (c->channelz_subchannel != nullptr) { + c->channelz_subchannel->AddTraceEvent( + grpc_core::channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string("Subchannel destroyed")); + c->channelz_subchannel->MarkSubchannelDestroyed(); + c->channelz_subchannel.reset(); + } gpr_free((void*)c->filters); grpc_channel_args_destroy(c->args); grpc_connectivity_state_destroy(&c->state_tracker); @@ -382,10 +395,21 @@ grpc_subchannel* grpc_subchannel_create(grpc_connector* connector, const grpc_arg* arg = grpc_channel_args_find(c->args, GRPC_ARG_ENABLE_CHANNELZ); - bool channelz_enabled = grpc_channel_arg_get_bool(arg, false); + 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_EVENT_MEMORY_PER_NODE); + const grpc_integer_options options = { + 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>(); + grpc_core::MakeRefCounted<grpc_core::channelz::SubchannelNode>( + c, channel_tracer_max_memory); + c->channelz_subchannel->AddTraceEvent( + grpc_core::channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string("Subchannel created")); } return grpc_subchannel_index_register(key, c); @@ -396,6 +420,43 @@ grpc_core::channelz::SubchannelNode* grpc_subchannel_get_channelz_node( return subchannel->channelz_subchannel.get(); } +intptr_t grpc_subchannel_get_child_socket_uuid(grpc_subchannel* subchannel) { + if (subchannel->connected_subchannel != nullptr) { + return subchannel->connected_subchannel->socket_uuid(); + } else { + return 0; + } +} + +static const char* subchannel_connectivity_state_change_string( + grpc_connectivity_state state) { + switch (state) { + case GRPC_CHANNEL_IDLE: + return "Subchannel state change to IDLE"; + case GRPC_CHANNEL_CONNECTING: + return "Subchannel state change to CONNECTING"; + case GRPC_CHANNEL_READY: + return "Subchannel state change to READY"; + case GRPC_CHANNEL_TRANSIENT_FAILURE: + return "Subchannel state change to TRANSIENT_FAILURE"; + case GRPC_CHANNEL_SHUTDOWN: + return "Subchannel state change to SHUTDOWN"; + } + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} + +static void set_subchannel_connectivity_state_locked( + grpc_subchannel* c, grpc_connectivity_state state, grpc_error* error, + const char* reason) { + if (c->channelz_subchannel != nullptr) { + c->channelz_subchannel->AddTraceEvent( + grpc_core::channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string( + subchannel_connectivity_state_change_string(state))); + } + grpc_connectivity_state_set(&c->state_tracker, state, error, reason); +} + static void continue_connect_locked(grpc_subchannel* c) { grpc_connect_in_args args; args.interested_parties = c->pollset_set; @@ -404,6 +465,8 @@ static void continue_connect_locked(grpc_subchannel* c) { c->next_attempt_deadline = c->backoff->NextAttemptTime(); args.deadline = std::max(c->next_attempt_deadline, min_deadline); args.channel_args = c->args; + set_subchannel_connectivity_state_locked(c, GRPC_CHANNEL_CONNECTING, + GRPC_ERROR_NONE, "connecting"); grpc_connector_connect(c->connector, &args, &c->connecting_result, &c->on_connected); } @@ -478,8 +541,6 @@ static void maybe_start_connecting_locked(grpc_subchannel* c) { GRPC_SUBCHANNEL_WEAK_REF(c, "connecting"); if (!c->backoff_begun) { c->backoff_begun = true; - grpc_connectivity_state_set(&c->state_tracker, GRPC_CHANNEL_CONNECTING, - GRPC_ERROR_NONE, "connecting"); continue_connect_locked(c); } else { GPR_ASSERT(!c->have_alarm); @@ -494,11 +555,6 @@ static void maybe_start_connecting_locked(grpc_subchannel* c) { } GRPC_CLOSURE_INIT(&c->on_alarm, on_alarm, c, grpc_schedule_on_exec_ctx); grpc_timer_init(&c->alarm, c->next_attempt_deadline, &c->on_alarm); - // During backoff, we prefer the connectivity state of CONNECTING instead of - // TRANSIENT_FAILURE in order to prevent triggering re-resolution - // continuously in pick_first. - grpc_connectivity_state_set(&c->state_tracker, GRPC_CHANNEL_CONNECTING, - GRPC_ERROR_NONE, "backoff"); } } @@ -560,9 +616,9 @@ static void on_connected_subchannel_connectivity_changed(void* p, connected_subchannel_watcher->connectivity_state)); } c->connected_subchannel.reset(); - grpc_connectivity_state_set(&c->state_tracker, - GRPC_CHANNEL_TRANSIENT_FAILURE, - GRPC_ERROR_REF(error), "reflect_child"); + set_subchannel_connectivity_state_locked( + c, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error), + "reflect_child"); c->backoff_begun = false; c->backoff->Reset(); maybe_start_connecting_locked(c); @@ -573,8 +629,8 @@ static void on_connected_subchannel_connectivity_changed(void* p, break; } default: { - grpc_connectivity_state_set( - &c->state_tracker, connected_subchannel_watcher->connectivity_state, + set_subchannel_connectivity_state_locked( + c, connected_subchannel_watcher->connectivity_state, GRPC_ERROR_REF(error), "reflect_child"); GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher"); c->connected_subchannel->NotifyOnStateChange( @@ -611,6 +667,7 @@ static bool publish_transport_locked(grpc_subchannel* c) { GRPC_ERROR_UNREF(error); return false; } + intptr_t socket_uuid = c->connecting_result.socket_uuid; memset(&c->connecting_result, 0, sizeof(c->connecting_result)); /* initialize state watcher */ @@ -630,8 +687,8 @@ static bool publish_transport_locked(grpc_subchannel* c) { } /* publish */ - c->connected_subchannel.reset( - grpc_core::New<grpc_core::ConnectedSubchannel>(stk)); + c->connected_subchannel.reset(grpc_core::New<grpc_core::ConnectedSubchannel>( + stk, c->channelz_subchannel, socket_uuid)); gpr_log(GPR_INFO, "New connected subchannel at %p for subchannel %p", c->connected_subchannel.get(), c); @@ -644,8 +701,8 @@ static bool publish_transport_locked(grpc_subchannel* c) { &connected_subchannel_watcher->closure); /* signal completion */ - grpc_connectivity_state_set(&c->state_tracker, GRPC_CHANNEL_READY, - GRPC_ERROR_NONE, "connected"); + set_subchannel_connectivity_state_locked(c, GRPC_CHANNEL_READY, + GRPC_ERROR_NONE, "connected"); return true; } @@ -662,8 +719,8 @@ static void on_subchannel_connected(void* arg, grpc_error* error) { } else if (c->disconnected) { GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting"); } else { - grpc_connectivity_state_set( - &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, + set_subchannel_connectivity_state_locked( + c, GRPC_CHANNEL_TRANSIENT_FAILURE, grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Connect Failed", &error, 1), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE), @@ -724,9 +781,71 @@ void grpc_subchannel_call_unref( GRPC_CALL_STACK_UNREF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON); } +// Sets *status based on md_batch and error. +static void get_call_status(grpc_subchannel_call* call, + grpc_metadata_batch* md_batch, grpc_error* error, + grpc_status_code* status) { + if (error != GRPC_ERROR_NONE) { + grpc_error_get_status(error, call->deadline, status, nullptr, nullptr, + nullptr); + } else { + if (md_batch->idx.named.grpc_status != nullptr) { + *status = grpc_get_status_code_from_metadata( + md_batch->idx.named.grpc_status->md); + } else { + *status = GRPC_STATUS_UNKNOWN; + } + } + GRPC_ERROR_UNREF(error); +} + +static void recv_trailing_metadata_ready(void* arg, grpc_error* error) { + grpc_subchannel_call* call = static_cast<grpc_subchannel_call*>(arg); + GPR_ASSERT(call->recv_trailing_metadata != nullptr); + grpc_status_code status = GRPC_STATUS_OK; + grpc_metadata_batch* md_batch = call->recv_trailing_metadata; + get_call_status(call, md_batch, GRPC_ERROR_REF(error), &status); + grpc_core::channelz::SubchannelNode* channelz_subchannel = + call->connection->channelz_subchannel(); + GPR_ASSERT(channelz_subchannel != nullptr); + if (status == GRPC_STATUS_OK) { + channelz_subchannel->RecordCallSucceeded(); + } else { + channelz_subchannel->RecordCallFailed(); + } + GRPC_CLOSURE_RUN(call->original_recv_trailing_metadata, + GRPC_ERROR_REF(error)); +} + +// If channelz is enabled, intercept recv_trailing so that we may check the +// status and associate it to a subchannel. +static void maybe_intercept_recv_trailing_metadata( + grpc_subchannel_call* call, grpc_transport_stream_op_batch* batch) { + // only intercept payloads with recv trailing. + if (!batch->recv_trailing_metadata) { + return; + } + // only add interceptor is channelz is enabled. + if (call->connection->channelz_subchannel() == nullptr) { + return; + } + GRPC_CLOSURE_INIT(&call->recv_trailing_metadata_ready, + recv_trailing_metadata_ready, call, + grpc_schedule_on_exec_ctx); + // save some state needed for the interception callback. + GPR_ASSERT(call->recv_trailing_metadata == nullptr); + call->recv_trailing_metadata = + batch->payload->recv_trailing_metadata.recv_trailing_metadata; + call->original_recv_trailing_metadata = + batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready; + batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready = + &call->recv_trailing_metadata_ready; +} + void grpc_subchannel_call_process_op(grpc_subchannel_call* call, grpc_transport_stream_op_batch* batch) { GPR_TIMER_SCOPE("grpc_subchannel_call_process_op", 0); + maybe_intercept_recv_trailing_metadata(call, batch); grpc_call_stack* call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call); grpc_call_element* top_elem = grpc_call_stack_element(call_stack, 0); GRPC_CALL_LOG_OP(GPR_INFO, top_elem, batch); @@ -775,6 +894,14 @@ void grpc_get_subchannel_address_arg(const grpc_channel_args* args, } } +const char* grpc_subchannel_get_target(grpc_subchannel* subchannel) { + const grpc_arg* addr_arg = + grpc_channel_args_find(subchannel->args, GRPC_ARG_SUBCHANNEL_ADDRESS); + const char* addr_str = grpc_channel_arg_get_string(addr_arg); + GPR_ASSERT(addr_str != nullptr); // Should have been set by LB policy. + return addr_str; +} + const char* grpc_get_subchannel_address_uri_arg(const grpc_channel_args* args) { const grpc_arg* addr_arg = grpc_channel_args_find(args, GRPC_ARG_SUBCHANNEL_ADDRESS); @@ -791,9 +918,15 @@ grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address* addr) { namespace grpc_core { -ConnectedSubchannel::ConnectedSubchannel(grpc_channel_stack* channel_stack) +ConnectedSubchannel::ConnectedSubchannel( + grpc_channel_stack* channel_stack, + grpc_core::RefCountedPtr<grpc_core::channelz::SubchannelNode> + channelz_subchannel, + intptr_t socket_uuid) : RefCountedWithTracing<ConnectedSubchannel>(&grpc_trace_stream_refcount), - channel_stack_(channel_stack) {} + channel_stack_(channel_stack), + channelz_subchannel_(std::move(channelz_subchannel)), + socket_uuid_(socket_uuid) {} ConnectedSubchannel::~ConnectedSubchannel() { GRPC_CHANNEL_STACK_UNREF(channel_stack_, "connected_subchannel_dtor"); @@ -839,6 +972,7 @@ grpc_error* ConnectedSubchannel::CreateCall(const CallArgs& args, Ref(DEBUG_LOCATION, "subchannel_call"); connection.release(); // Ref is passed to the grpc_subchannel_call object. (*call)->connection = this; + (*call)->deadline = args.deadline; const grpc_call_element_args call_args = { callstk, /* call_stack */ nullptr, /* server_transport_data */ diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h index a135035d62..c53b13e37e 100644 --- a/src/core/ext/filters/client_channel/subchannel.h +++ b/src/core/ext/filters/client_channel/subchannel.h @@ -85,7 +85,11 @@ class ConnectedSubchannel : public RefCountedWithTracing<ConnectedSubchannel> { size_t parent_data_size; }; - explicit ConnectedSubchannel(grpc_channel_stack* channel_stack); + explicit ConnectedSubchannel( + grpc_channel_stack* channel_stack, + grpc_core::RefCountedPtr<grpc_core::channelz::SubchannelNode> + channelz_subchannel, + intptr_t socket_uuid); ~ConnectedSubchannel(); grpc_channel_stack* channel_stack() { return channel_stack_; } @@ -94,9 +98,19 @@ class ConnectedSubchannel : public RefCountedWithTracing<ConnectedSubchannel> { grpc_closure* closure); void Ping(grpc_closure* on_initiate, grpc_closure* on_ack); grpc_error* CreateCall(const CallArgs& args, grpc_subchannel_call** call); + channelz::SubchannelNode* channelz_subchannel() { + return channelz_subchannel_.get(); + } + intptr_t socket_uuid() { return socket_uuid_; } private: grpc_channel_stack* channel_stack_; + // ref counted pointer to the channelz node in this connected subchannel's + // owning subchannel. + grpc_core::RefCountedPtr<grpc_core::channelz::SubchannelNode> + channelz_subchannel_; + // uuid of this subchannel's socket. 0 if this subchannel is not connected. + const intptr_t socket_uuid_; }; } // namespace grpc_core @@ -119,6 +133,8 @@ void grpc_subchannel_call_unref( grpc_core::channelz::SubchannelNode* grpc_subchannel_get_channelz_node( grpc_subchannel* subchannel); +intptr_t grpc_subchannel_get_child_socket_uuid(grpc_subchannel* subchannel); + /** Returns a pointer to the parent data associated with \a subchannel_call. The data will be of the size specified in \a parent_data_size field of the args passed to \a grpc_connected_subchannel_create_call(). */ @@ -184,6 +200,8 @@ grpc_subchannel* grpc_subchannel_create(grpc_connector* connector, void grpc_get_subchannel_address_arg(const grpc_channel_args* args, grpc_resolved_address* addr); +const char* grpc_subchannel_get_target(grpc_subchannel* subchannel); + /// Returns the URI string for the address to connect to. const char* grpc_get_subchannel_address_uri_arg(const grpc_channel_args* args); diff --git a/src/core/ext/filters/client_channel/subchannel_index.cc b/src/core/ext/filters/client_channel/subchannel_index.cc index cb02b1a748..1c23a6c4be 100644 --- a/src/core/ext/filters/client_channel/subchannel_index.cc +++ b/src/core/ext/filters/client_channel/subchannel_index.cc @@ -73,7 +73,8 @@ static grpc_subchannel_key* subchannel_key_copy(grpc_subchannel_key* k) { int grpc_subchannel_key_compare(const grpc_subchannel_key* a, const grpc_subchannel_key* b) { - if (g_force_creation) return false; + // To pretend the keys are different, return a non-zero value. + if (GPR_UNLIKELY(g_force_creation)) return 1; int c = GPR_ICMP(a->args.filter_count, b->args.filter_count); if (c != 0) return c; if (a->args.filter_count > 0) { diff --git a/src/core/ext/filters/client_channel/subchannel_index.h b/src/core/ext/filters/client_channel/subchannel_index.h index a7dae9d47d..c135613d26 100644 --- a/src/core/ext/filters/client_channel/subchannel_index.h +++ b/src/core/ext/filters/client_channel/subchannel_index.h @@ -65,13 +65,10 @@ void grpc_subchannel_index_ref(void); void grpc_subchannel_index_unref(void); /** \em TEST ONLY. - * If \a force_creation is true, all key comparisons will be false, resulting in + * If \a force_creation is true, all keys are regarded different, resulting in * new subchannels always being created. Otherwise, the keys will be compared as * usual. * - * This function is *not* threadsafe on purpose: it should *only* be used in - * test code. - * * Tests using this function \em MUST run tests with and without \a * force_creation set. */ void grpc_subchannel_index_test_only_set_force_creation(bool force_creation); diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc index 3bd3059312..d23ad67ad5 100644 --- a/src/core/ext/filters/deadline/deadline_filter.cc +++ b/src/core/ext/filters/deadline/deadline_filter.cc @@ -379,10 +379,10 @@ static bool maybe_add_deadline_filter(grpc_channel_stack_builder* builder, void grpc_deadline_filter_init(void) { grpc_channel_init_register_stage( - GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH, + GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_deadline_filter, (void*)&grpc_client_deadline_filter); grpc_channel_init_register_stage( - GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH, + GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_deadline_filter, (void*)&grpc_server_deadline_filter); } diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc index 1678051beb..cd459e47cd 100644 --- a/src/core/ext/filters/http/client/http_client_filter.cc +++ b/src/core/ext/filters/http/client/http_client_filter.cc @@ -51,12 +51,15 @@ struct call_data { grpc_linked_mdelem user_agent; // State for handling recv_initial_metadata ops. grpc_metadata_batch* recv_initial_metadata; + grpc_error* recv_initial_metadata_error; grpc_closure* original_recv_initial_metadata_ready; grpc_closure recv_initial_metadata_ready; // State for handling recv_trailing_metadata ops. grpc_metadata_batch* recv_trailing_metadata; grpc_closure* original_recv_trailing_metadata_ready; grpc_closure recv_trailing_metadata_ready; + grpc_error* recv_trailing_metadata_error; + bool seen_recv_trailing_metadata_ready; // State for handling send_message ops. grpc_transport_stream_op_batch* send_message_batch; size_t send_message_bytes_read; @@ -78,7 +81,12 @@ struct channel_data { static grpc_error* client_filter_incoming_metadata(grpc_call_element* elem, grpc_metadata_batch* b) { if (b->idx.named.status != nullptr) { - if (grpc_mdelem_eq(b->idx.named.status->md, GRPC_MDELEM_STATUS_200)) { + /* If both gRPC status and HTTP status are provided in the response, we + * should prefer the gRPC status code, as mentioned in + * https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md. + */ + if (b->idx.named.grpc_status != nullptr || + grpc_mdelem_eq(b->idx.named.status->md, GRPC_MDELEM_STATUS_200)) { grpc_metadata_batch_remove(b, b->idx.named.status); } else { char* val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.status->md), @@ -147,21 +155,39 @@ static void recv_initial_metadata_ready(void* user_data, grpc_error* error) { call_data* calld = static_cast<call_data*>(elem->call_data); if (error == GRPC_ERROR_NONE) { error = client_filter_incoming_metadata(elem, calld->recv_initial_metadata); + calld->recv_initial_metadata_error = GRPC_ERROR_REF(error); } else { GRPC_ERROR_REF(error); } - GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready, error); + grpc_closure* closure = calld->original_recv_initial_metadata_ready; + calld->original_recv_initial_metadata_ready = nullptr; + if (calld->seen_recv_trailing_metadata_ready) { + GRPC_CALL_COMBINER_START( + calld->call_combiner, &calld->recv_trailing_metadata_ready, + calld->recv_trailing_metadata_error, "continue recv_trailing_metadata"); + } + GRPC_CLOSURE_RUN(closure, error); } static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) { grpc_call_element* elem = static_cast<grpc_call_element*>(user_data); call_data* calld = static_cast<call_data*>(elem->call_data); + if (calld->original_recv_initial_metadata_ready != nullptr) { + calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error); + calld->seen_recv_trailing_metadata_ready = true; + GRPC_CALL_COMBINER_STOP(calld->call_combiner, + "deferring recv_trailing_metadata_ready until " + "after recv_initial_metadata_ready"); + return; + } if (error == GRPC_ERROR_NONE) { error = client_filter_incoming_metadata(elem, calld->recv_trailing_metadata); } else { GRPC_ERROR_REF(error); } + error = grpc_error_add_child( + error, GRPC_ERROR_REF(calld->recv_initial_metadata_error)); GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, error); } @@ -434,7 +460,10 @@ static grpc_error* init_call_elem(grpc_call_element* elem, /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, - grpc_closure* ignored) {} + grpc_closure* ignored) { + call_data* calld = static_cast<call_data*>(elem->call_data); + GRPC_ERROR_UNREF(calld->recv_initial_metadata_error); +} static grpc_mdelem scheme_from_args(const grpc_channel_args* args) { unsigned i; diff --git a/src/core/ext/filters/http/client_authority_filter.cc b/src/core/ext/filters/http/client_authority_filter.cc index 3c0ae47e8d..6383f12594 100644 --- a/src/core/ext/filters/http/client_authority_filter.cc +++ b/src/core/ext/filters/http/client_authority_filter.cc @@ -59,9 +59,8 @@ void authority_start_transport_stream_op_batch( initial_metadata->idx.named.authority == nullptr) { grpc_error* error = grpc_metadata_batch_add_head( initial_metadata, &calld->authority_storage, - grpc_mdelem_from_slices( - GRPC_MDSTR_AUTHORITY, - grpc_slice_ref_internal(chand->default_authority))); + grpc_mdelem_create(GRPC_MDSTR_AUTHORITY, chand->default_authority, + nullptr)); if (error != GRPC_ERROR_NONE) { grpc_transport_stream_op_batch_finish_with_failure(batch, error, calld->call_combiner); @@ -94,7 +93,7 @@ grpc_error* init_channel_elem(grpc_channel_element* elem, if (default_authority_arg == nullptr) { return GRPC_ERROR_CREATE_FROM_STATIC_STRING( "GRPC_ARG_DEFAULT_AUTHORITY channel arg. not found. Note that direct " - "channels must explicity specify a value for this argument."); + "channels must explicitly specify a value for this argument."); } const char* default_authority_str = grpc_channel_arg_get_string(default_authority_arg); @@ -146,12 +145,12 @@ static bool add_client_authority_filter(grpc_channel_stack_builder* builder, } void grpc_client_authority_filter_init(void) { - grpc_channel_init_register_stage( - GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH, - add_client_authority_filter, (void*)&grpc_client_authority_filter); - grpc_channel_init_register_stage( - GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH, - add_client_authority_filter, (void*)&grpc_client_authority_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, + add_client_authority_filter, + (void*)&grpc_client_authority_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + add_client_authority_filter, + (void*)&grpc_client_authority_filter); } void grpc_client_authority_filter_shutdown(void) {} diff --git a/src/core/ext/filters/http/http_filters_plugin.cc b/src/core/ext/filters/http/http_filters_plugin.cc index 38757710f3..f03fa0141d 100644 --- a/src/core/ext/filters/http/http_filters_plugin.cc +++ b/src/core/ext/filters/http/http_filters_plugin.cc @@ -18,7 +18,6 @@ #include <grpc/support/port_platform.h> -#include <limits.h> #include <string.h> #include "src/core/ext/filters/http/client/http_client_filter.h" @@ -52,15 +51,15 @@ static bool maybe_add_optional_filter(grpc_channel_stack_builder* builder, bool enable = grpc_channel_arg_get_bool( grpc_channel_args_find(channel_args, filtarg->control_channel_arg), !grpc_channel_args_want_minimal_stack(channel_args)); - return enable ? grpc_channel_stack_builder_append_filter( + return enable ? grpc_channel_stack_builder_prepend_filter( builder, filtarg->filter, nullptr, nullptr) : true; } -static bool maybe_append_required_filter(grpc_channel_stack_builder* builder, - void* arg) { +static bool maybe_add_required_filter(grpc_channel_stack_builder* builder, + void* arg) { return is_building_http_like_transport(builder) - ? grpc_channel_stack_builder_append_filter( + ? grpc_channel_stack_builder_prepend_filter( builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr) : true; @@ -68,23 +67,23 @@ static bool maybe_append_required_filter(grpc_channel_stack_builder* builder, void grpc_http_filters_init(void) { grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_HIGH, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_optional_filter, &compress_filter); grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_HIGH, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_optional_filter, &compress_filter); grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_HIGH, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_optional_filter, &compress_filter); grpc_channel_init_register_stage( - GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH, - maybe_append_required_filter, (void*)&grpc_http_client_filter); + GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_required_filter, (void*)&grpc_http_client_filter); grpc_channel_init_register_stage( - GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH, - maybe_append_required_filter, (void*)&grpc_http_client_filter); + GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_required_filter, (void*)&grpc_http_client_filter); grpc_channel_init_register_stage( - GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_HIGH, - maybe_append_required_filter, (void*)&grpc_http_server_filter); + GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_required_filter, (void*)&grpc_http_server_filter); } void grpc_http_filters_shutdown(void) {} diff --git a/src/core/ext/filters/http/server/http_server_filter.cc b/src/core/ext/filters/http/server/http_server_filter.cc index 3919447f26..436ea09d94 100644 --- a/src/core/ext/filters/http/server/http_server_filter.cc +++ b/src/core/ext/filters/http/server/http_server_filter.cc @@ -23,6 +23,7 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <string.h> +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/slice/b64.h" @@ -50,6 +51,7 @@ struct call_data { // State for intercepting recv_initial_metadata. grpc_closure recv_initial_metadata_ready; + grpc_error* recv_initial_metadata_ready_error; grpc_closure* original_recv_initial_metadata_ready; grpc_metadata_batch* recv_initial_metadata; uint32_t* recv_initial_metadata_flags; @@ -60,6 +62,16 @@ struct call_data { grpc_closure recv_message_ready; grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message; bool seen_recv_message_ready; + + // State for intercepting recv_trailing_metadata + grpc_closure recv_trailing_metadata_ready; + grpc_closure* original_recv_trailing_metadata_ready; + grpc_error* recv_trailing_metadata_ready_error; + bool seen_recv_trailing_metadata_ready; +}; + +struct channel_data { + bool surface_user_agent; }; } // namespace @@ -258,6 +270,11 @@ static grpc_error* hs_filter_incoming_metadata(grpc_call_element* elem, GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":authority"))); } + channel_data* chand = static_cast<channel_data*>(elem->channel_data); + if (!chand->surface_user_agent && b->idx.named.user_agent != nullptr) { + grpc_metadata_batch_remove(b, b->idx.named.user_agent); + } + return error; } @@ -267,6 +284,7 @@ static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err) { calld->seen_recv_initial_metadata_ready = true; if (err == GRPC_ERROR_NONE) { err = hs_filter_incoming_metadata(elem, calld->recv_initial_metadata); + calld->recv_initial_metadata_ready_error = GRPC_ERROR_REF(err); if (calld->seen_recv_message_ready) { // We've already seen the recv_message callback, but we previously // deferred it, so we need to return it here. @@ -286,6 +304,13 @@ static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err) { } else { GRPC_ERROR_REF(err); } + if (calld->seen_recv_trailing_metadata_ready) { + GRPC_CALL_COMBINER_START(calld->call_combiner, + &calld->recv_trailing_metadata_ready, + calld->recv_trailing_metadata_ready_error, + "resuming hs_recv_trailing_metadata_ready from " + "hs_recv_initial_metadata_ready"); + } GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready, err); } @@ -313,6 +338,23 @@ static void hs_recv_message_ready(void* user_data, grpc_error* err) { } } +static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err) { + grpc_call_element* elem = static_cast<grpc_call_element*>(user_data); + call_data* calld = static_cast<call_data*>(elem->call_data); + if (!calld->seen_recv_initial_metadata_ready) { + calld->recv_trailing_metadata_ready_error = GRPC_ERROR_REF(err); + calld->seen_recv_trailing_metadata_ready = true; + GRPC_CALL_COMBINER_STOP(calld->call_combiner, + "deferring hs_recv_trailing_metadata_ready until " + "ater hs_recv_initial_metadata_ready"); + return; + } + err = grpc_error_add_child( + GRPC_ERROR_REF(err), + GRPC_ERROR_REF(calld->recv_initial_metadata_ready_error)); + GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, err); +} + static grpc_error* hs_mutate_op(grpc_call_element* elem, grpc_transport_stream_op_batch* op) { /* grab pointers to our data from the call element */ @@ -357,6 +399,13 @@ static grpc_error* hs_mutate_op(grpc_call_element* elem, op->payload->recv_message.recv_message_ready = &calld->recv_message_ready; } + if (op->recv_trailing_metadata) { + calld->original_recv_trailing_metadata_ready = + op->payload->recv_trailing_metadata.recv_trailing_metadata_ready; + op->payload->recv_trailing_metadata.recv_trailing_metadata_ready = + &calld->recv_trailing_metadata_ready; + } + if (op->send_trailing_metadata) { grpc_error* error = hs_filter_outgoing_metadata( elem, op->payload->send_trailing_metadata.send_trailing_metadata); @@ -389,6 +438,9 @@ static grpc_error* hs_init_call_elem(grpc_call_element* elem, grpc_schedule_on_exec_ctx); GRPC_CLOSURE_INIT(&calld->recv_message_ready, hs_recv_message_ready, elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, + hs_recv_trailing_metadata_ready, elem, + grpc_schedule_on_exec_ctx); return GRPC_ERROR_NONE; } @@ -397,6 +449,7 @@ static void hs_destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, grpc_closure* ignored) { call_data* calld = static_cast<call_data*>(elem->call_data); + GRPC_ERROR_UNREF(calld->recv_initial_metadata_ready_error); if (calld->have_read_stream) { calld->read_stream->Orphan(); } @@ -405,7 +458,12 @@ static void hs_destroy_call_elem(grpc_call_element* elem, /* Constructor for channel_data */ static grpc_error* hs_init_channel_elem(grpc_channel_element* elem, grpc_channel_element_args* args) { + channel_data* chand = static_cast<channel_data*>(elem->channel_data); GPR_ASSERT(!args->is_last); + chand->surface_user_agent = grpc_channel_arg_get_bool( + grpc_channel_args_find(args->channel_args, + const_cast<char*>(GRPC_ARG_SURFACE_USER_AGENT)), + true); return GRPC_ERROR_NONE; } @@ -419,7 +477,7 @@ const grpc_channel_filter grpc_http_server_filter = { hs_init_call_elem, grpc_call_stack_ignore_set_pollset_or_pollset_set, hs_destroy_call_elem, - 0, + sizeof(channel_data), hs_init_channel_elem, hs_destroy_channel_elem, grpc_channel_next_get_info, diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc b/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc index 0c4ffea27b..8ac34c629f 100644 --- a/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc +++ b/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc @@ -162,9 +162,10 @@ void ServerLoadReportingCallData::GetCensusSafeClientIpString( } else if (addr->sa_family == GRPC_AF_INET6) { grpc_sockaddr_in6* addr6 = reinterpret_cast<grpc_sockaddr_in6*>(addr); *client_ip_string = static_cast<char*>(gpr_malloc(32 + 1)); - for (size_t i = 0; i < 16; ++i) { - snprintf(*client_ip_string + i * 2, 2 + 1, "%02x", - addr6->sin6_addr.__in6_u.__u6_addr8[i]); + uint32_t* addr6_next_long = reinterpret_cast<uint32_t*>(&addr6->sin6_addr); + for (size_t i = 0; i < 4; ++i) { + snprintf(*client_ip_string + 8 * i, 8 + 1, "%08x", + grpc_ntohl(*addr6_next_long++)); } *size = 32; } else { @@ -345,8 +346,7 @@ struct ServerLoadReportingFilterStaticRegistrar { if (registered) return; RegisterChannelFilter<ServerLoadReportingChannelData, ServerLoadReportingCallData>( - "server_load_reporting", GRPC_SERVER_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_LOW, true, + "server_load_reporting", GRPC_SERVER_CHANNEL, INT_MAX, MaybeAddServerLoadReportingFilter); // Access measures to ensure they are initialized. Otherwise, we can't // create any valid view before the first RPC. diff --git a/src/core/ext/filters/max_age/max_age_filter.cc b/src/core/ext/filters/max_age/max_age_filter.cc index 7db30d5b48..431472609e 100644 --- a/src/core/ext/filters/max_age/max_age_filter.cc +++ b/src/core/ext/filters/max_age/max_age_filter.cc @@ -429,8 +429,7 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem, ? GRPC_MILLIS_INF_FUTURE : DEFAULT_MAX_CONNECTION_IDLE_MS; chand->idle_state = MAX_IDLE_STATE_INIT; - gpr_atm_no_barrier_store(&chand->last_enter_idle_time_millis, - GRPC_MILLIS_INF_PAST); + gpr_atm_no_barrier_store(&chand->last_enter_idle_time_millis, GPR_ATM_MIN); for (size_t i = 0; i < args->channel_args->num_args; ++i) { if (0 == strcmp(args->channel_args->args[i].key, GRPC_ARG_MAX_CONNECTION_AGE_MS)) { @@ -536,7 +535,7 @@ static bool maybe_add_max_age_filter(grpc_channel_stack_builder* builder, void grpc_max_age_filter_init(void) { grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_LOW, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_max_age_filter, nullptr); } diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc index 1bd9cf1426..2d3b16d992 100644 --- a/src/core/ext/filters/message_size/message_size_filter.cc +++ b/src/core/ext/filters/message_size/message_size_filter.cc @@ -99,10 +99,17 @@ struct call_data { // recv_message_ready up-call on transport_stream_op, and remember to // call our next_recv_message_ready member after handling it. grpc_closure recv_message_ready; + grpc_closure recv_trailing_metadata_ready; + // The error caused by a message that is too large, or GRPC_ERROR_NONE + grpc_error* error; // Used by recv_message_ready. grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message; // Original recv_message_ready callback, invoked after our own. grpc_closure* next_recv_message_ready; + // Original recv_trailing_metadata callback, invoked after our own. + grpc_closure* original_recv_trailing_metadata_ready; + bool seen_recv_trailing_metadata; + grpc_error* recv_trailing_metadata_error; }; struct channel_data { @@ -130,18 +137,52 @@ static void recv_message_ready(void* user_data, grpc_error* error) { grpc_error* new_error = grpc_error_set_int( GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED); + GRPC_ERROR_UNREF(calld->error); if (error == GRPC_ERROR_NONE) { error = new_error; } else { error = grpc_error_add_child(error, new_error); - GRPC_ERROR_UNREF(new_error); } + calld->error = GRPC_ERROR_REF(error); gpr_free(message_string); } else { GRPC_ERROR_REF(error); } // Invoke the next callback. - GRPC_CLOSURE_RUN(calld->next_recv_message_ready, error); + grpc_closure* closure = calld->next_recv_message_ready; + calld->next_recv_message_ready = nullptr; + if (calld->seen_recv_trailing_metadata) { + /* We might potentially see another RECV_MESSAGE op. In that case, we do not + * want to run the recv_trailing_metadata_ready closure again. The newer + * RECV_MESSAGE op cannot cause any errors since the transport has already + * invoked the recv_trailing_metadata_ready closure and all further + * RECV_MESSAGE ops will get null payloads. */ + calld->seen_recv_trailing_metadata = false; + GRPC_CALL_COMBINER_START(calld->call_combiner, + &calld->recv_trailing_metadata_ready, + calld->recv_trailing_metadata_error, + "continue recv_trailing_metadata_ready"); + } + GRPC_CLOSURE_RUN(closure, error); +} + +// Callback invoked on completion of recv_trailing_metadata +// Notifies the recv_trailing_metadata batch of any message size failures +static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) { + grpc_call_element* elem = static_cast<grpc_call_element*>(user_data); + call_data* calld = static_cast<call_data*>(elem->call_data); + if (calld->next_recv_message_ready != nullptr) { + calld->seen_recv_trailing_metadata = true; + calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error); + GRPC_CALL_COMBINER_STOP(calld->call_combiner, + "deferring recv_trailing_metadata_ready until " + "after recv_message_ready"); + return; + } + error = + grpc_error_add_child(GRPC_ERROR_REF(error), GRPC_ERROR_REF(calld->error)); + // Invoke the next callback. + GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, error); } // Start transport stream op. @@ -172,6 +213,13 @@ static void start_transport_stream_op_batch( calld->recv_message = op->payload->recv_message.recv_message; op->payload->recv_message.recv_message_ready = &calld->recv_message_ready; } + // Inject callback for receiving trailing metadata. + if (op->recv_trailing_metadata) { + calld->original_recv_trailing_metadata_ready = + op->payload->recv_trailing_metadata.recv_trailing_metadata_ready; + op->payload->recv_trailing_metadata.recv_trailing_metadata_ready = + &calld->recv_trailing_metadata_ready; + } // Chain to the next filter. grpc_call_next_op(elem, op); } @@ -183,8 +231,13 @@ static grpc_error* init_call_elem(grpc_call_element* elem, call_data* calld = static_cast<call_data*>(elem->call_data); calld->call_combiner = args->call_combiner; calld->next_recv_message_ready = nullptr; + calld->original_recv_trailing_metadata_ready = nullptr; + calld->error = GRPC_ERROR_NONE; GRPC_CLOSURE_INIT(&calld->recv_message_ready, recv_message_ready, elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, + recv_trailing_metadata_ready, elem, + grpc_schedule_on_exec_ctx); // Get max sizes from channel data, then merge in per-method config values. // Note: Per-method config is only available on the client, so we // apply the max request size to the send limit and the max response @@ -213,7 +266,10 @@ static grpc_error* init_call_elem(grpc_call_element* elem, // Destructor for call_data. static void destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, - grpc_closure* ignored) {} + grpc_closure* ignored) { + call_data* calld = (call_data*)elem->call_data; + GRPC_ERROR_UNREF(calld->error); +} static int default_size(const grpc_channel_args* args, int without_minimal_stack) { @@ -311,13 +367,13 @@ static bool maybe_add_message_size_filter(grpc_channel_stack_builder* builder, void grpc_message_size_filter_init(void) { grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_LOW, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_message_size_filter, nullptr); grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_LOW, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_message_size_filter, nullptr); grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_LOW, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_message_size_filter, nullptr); } diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc index e7522ffba8..5229304fa4 100644 --- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc +++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc @@ -117,6 +117,8 @@ static void on_handshake_done(void* arg, grpc_error* error) { c->args.interested_parties); c->result->transport = grpc_create_chttp2_transport(args->args, args->endpoint, true); + c->result->socket_uuid = + grpc_chttp2_transport_get_socket_uuid(c->result->transport); GPR_ASSERT(c->result->transport); // TODO(roth): We ideally want to wait until we receive HTTP/2 // settings from the server before we consider the connection @@ -158,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->handshake_mgr); + c->args.interested_parties, 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/client/insecure/channel_create_posix.cc b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc index dfed824cd5..5bdcb387c9 100644 --- a/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc +++ b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc @@ -50,7 +50,7 @@ grpc_channel* grpc_insecure_channel_create_from_fd( GPR_ASSERT(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0); grpc_endpoint* client = grpc_tcp_client_create_from_fd( - grpc_fd_create(fd, "client", false), args, "fd-client"); + grpc_fd_create(fd, "client", true), args, "fd-client"); grpc_transport* transport = grpc_create_chttp2_transport(final_args, client, true); diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc index 3f8a26ae32..6ed88dfb5e 100644 --- a/src/core/ext/transport/chttp2/server/chttp2_server.cc +++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc @@ -53,6 +53,8 @@ typedef struct { grpc_closure tcp_server_shutdown_complete; grpc_closure* server_destroy_listener_done; grpc_handshake_manager* pending_handshake_mgrs; + grpc_core::RefCountedPtr<grpc_core::channelz::ListenSocketNode> + channelz_listen_socket; } server_state; typedef struct { @@ -67,6 +69,7 @@ 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( @@ -76,6 +79,9 @@ 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); } } @@ -133,7 +139,8 @@ static void on_handshake_done(void* arg, grpc_error* error) { grpc_create_chttp2_transport(args->args, args->endpoint, false); grpc_server_setup_transport( connection_state->svr_state->server, transport, - connection_state->accepting_pollset, args->args); + connection_state->accepting_pollset, args->args, + grpc_chttp2_transport_get_socket_uuid(transport)); // Use notify_on_receive_settings callback to enforce the // handshake deadline. connection_state->transport = @@ -189,7 +196,11 @@ 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); @@ -223,6 +234,7 @@ static void tcp_server_shutdown_complete(void* arg, grpc_error* error) { GPR_ASSERT(state->shutdown); grpc_handshake_manager_pending_list_shutdown_all( state->pending_handshake_mgrs, GRPC_ERROR_REF(error)); + state->channelz_listen_socket.reset(); gpr_mu_unlock(&state->mu); // Flush queued work before destroying handshaker factory, since that // may do a synchronous unref. @@ -262,6 +274,8 @@ grpc_error* grpc_chttp2_server_add_port(grpc_server* server, const char* addr, server_state* state = nullptr; grpc_error** errors = nullptr; size_t naddrs = 0; + const grpc_arg* arg = nullptr; + intptr_t socket_uuid = 0; *port_num = -1; @@ -323,9 +337,16 @@ grpc_error* grpc_chttp2_server_add_port(grpc_server* server, const char* addr, } grpc_resolved_addresses_destroy(resolved); + arg = grpc_channel_args_find(args, GRPC_ARG_ENABLE_CHANNELZ); + if (grpc_channel_arg_get_bool(arg, false)) { + state->channelz_listen_socket = + grpc_core::MakeRefCounted<grpc_core::channelz::ListenSocketNode>(); + socket_uuid = state->channelz_listen_socket->uuid(); + } + /* Register with the server only upon success */ grpc_server_add_listener(server, state, server_start_listener, - server_destroy_listener); + server_destroy_listener, socket_uuid); goto done; /* Error path: cleanup and return */ diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc index a0228785ee..b9024a87e2 100644 --- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc +++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc @@ -44,7 +44,7 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server, gpr_asprintf(&name, "fd:%d", fd); grpc_endpoint* server_endpoint = - grpc_tcp_create(grpc_fd_create(fd, name, false), + grpc_tcp_create(grpc_fd_create(fd, name, true), grpc_server_get_channel_args(server), name); gpr_free(name); @@ -61,7 +61,7 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server, grpc_endpoint_add_to_pollset(server_endpoint, pollsets[i]); } - grpc_server_setup_transport(server, transport, nullptr, server_args); + grpc_server_setup_transport(server, transport, nullptr, server_args, 0); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); } diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 36511fa608..8a481bb7d5 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -157,6 +157,10 @@ bool g_flow_control_enabled = true; static void destruct_transport(grpc_chttp2_transport* t) { size_t i; + if (t->channelz_socket != nullptr) { + t->channelz_socket.reset(); + } + grpc_endpoint_destroy(t->ep); grpc_slice_buffer_destroy_internal(&t->qbuf); @@ -230,35 +234,174 @@ void grpc_chttp2_ref_transport(grpc_chttp2_transport* t) { gpr_ref(&t->refs); } static const grpc_transport_vtable* get_vtable(void); -static void init_transport(grpc_chttp2_transport* t, - const grpc_channel_args* channel_args, - grpc_endpoint* ep, bool is_client) { +/* Returns whether bdp is enabled */ +static bool read_channel_args(grpc_chttp2_transport* t, + const grpc_channel_args* channel_args, + bool is_client) { + bool enable_bdp = true; + bool channelz_enabled = GRPC_ENABLE_CHANNELZ_DEFAULT; size_t i; int j; - GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) == - GRPC_CHTTP2_CLIENT_CONNECT_STRLEN); - - t->base.vtable = get_vtable(); - t->ep = ep; - /* one ref is for destroy */ - gpr_ref_init(&t->refs, 1); - t->combiner = grpc_combiner_create(); - t->peer_string = grpc_endpoint_get_peer(ep); - t->endpoint_reading = 1; - t->next_stream_id = is_client ? 1 : 2; - t->is_client = is_client; - t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; - t->is_first_frame = true; - grpc_connectivity_state_init( - &t->channel_callback.state_tracker, GRPC_CHANNEL_READY, - is_client ? "client_transport" : "server_transport"); - - grpc_slice_buffer_init(&t->qbuf); - - grpc_slice_buffer_init(&t->outbuf); - grpc_chttp2_hpack_compressor_init(&t->hpack_compressor); + for (i = 0; i < channel_args->num_args; i++) { + if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) { + const grpc_integer_options options = {-1, 0, INT_MAX}; + const int value = + grpc_channel_arg_get_integer(&channel_args->args[i], options); + if (value >= 0) { + if ((t->next_stream_id & 1) != (value & 1)) { + gpr_log(GPR_ERROR, "%s: low bit must be %d on %s", + GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, t->next_stream_id & 1, + is_client ? "client" : "server"); + } else { + t->next_stream_id = static_cast<uint32_t>(value); + } + } + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) { + const grpc_integer_options options = {-1, 0, INT_MAX}; + const int value = + grpc_channel_arg_get_integer(&channel_args->args[i], options); + if (value >= 0) { + grpc_chttp2_hpack_compressor_set_max_usable_size( + &t->hpack_compressor, static_cast<uint32_t>(value)); + } + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA)) { + t->ping_policy.max_pings_without_data = grpc_channel_arg_get_integer( + &channel_args->args[i], + {g_default_max_pings_without_data, 0, INT_MAX}); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MAX_PING_STRIKES)) { + t->ping_policy.max_ping_strikes = grpc_channel_arg_get_integer( + &channel_args->args[i], {g_default_max_ping_strikes, 0, INT_MAX}); + } else if (0 == + strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS)) { + t->ping_policy.min_sent_ping_interval_without_data = + grpc_channel_arg_get_integer( + &channel_args->args[i], + grpc_integer_options{ + g_default_min_sent_ping_interval_without_data_ms, 0, + INT_MAX}); + } else if (0 == + strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS)) { + t->ping_policy.min_recv_ping_interval_without_data = + grpc_channel_arg_get_integer( + &channel_args->args[i], + grpc_integer_options{ + g_default_min_recv_ping_interval_without_data_ms, 0, + INT_MAX}); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) { + t->write_buffer_size = static_cast<uint32_t>(grpc_channel_arg_get_integer( + &channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE})); + } else if (0 == + strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) { + enable_bdp = grpc_channel_arg_get_bool(&channel_args->args[i], true); + } else if (0 == + strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) { + const int value = grpc_channel_arg_get_integer( + &channel_args->args[i], + grpc_integer_options{t->is_client + ? g_default_client_keepalive_time_ms + : g_default_server_keepalive_time_ms, + 1, INT_MAX}); + t->keepalive_time = value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value; + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) { + const int value = grpc_channel_arg_get_integer( + &channel_args->args[i], + grpc_integer_options{t->is_client + ? g_default_client_keepalive_timeout_ms + : g_default_server_keepalive_timeout_ms, + 0, INT_MAX}); + t->keepalive_timeout = value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value; + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { + t->keepalive_permit_without_calls = static_cast<uint32_t>( + grpc_channel_arg_get_integer(&channel_args->args[i], {0, 0, 1})); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_OPTIMIZATION_TARGET)) { + if (channel_args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "%s should be a string", + GRPC_ARG_OPTIMIZATION_TARGET); + } else if (0 == strcmp(channel_args->args[i].value.string, "blend")) { + t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; + } else if (0 == strcmp(channel_args->args[i].value.string, "latency")) { + t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; + } else if (0 == + strcmp(channel_args->args[i].value.string, "throughput")) { + t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_THROUGHPUT; + } else { + gpr_log(GPR_ERROR, "%s value '%s' unknown, assuming 'blend'", + GRPC_ARG_OPTIMIZATION_TARGET, + channel_args->args[i].value.string); + } + } else if (0 == + strcmp(channel_args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) { + channelz_enabled = grpc_channel_arg_get_bool( + &channel_args->args[i], GRPC_ENABLE_CHANNELZ_DEFAULT); + } else { + static const struct { + const char* channel_arg_name; + grpc_chttp2_setting_id setting_id; + grpc_integer_options integer_options; + bool availability[2] /* server, client */; + } settings_map[] = {{GRPC_ARG_MAX_CONCURRENT_STREAMS, + GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, + {-1, 0, INT32_MAX}, + {true, false}}, + {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER, + GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, + {-1, 0, INT32_MAX}, + {true, true}}, + {GRPC_ARG_MAX_METADATA_SIZE, + GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, + {-1, 0, INT32_MAX}, + {true, true}}, + {GRPC_ARG_HTTP2_MAX_FRAME_SIZE, + GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, + {-1, 16384, 16777215}, + {true, true}}, + {GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY, + GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, + {1, 0, 1}, + {true, true}}, + {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES, + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, + {-1, 5, INT32_MAX}, + {true, true}}}; + for (j = 0; j < static_cast<int> GPR_ARRAY_SIZE(settings_map); j++) { + if (0 == strcmp(channel_args->args[i].key, + settings_map[j].channel_arg_name)) { + if (!settings_map[j].availability[is_client]) { + gpr_log(GPR_DEBUG, "%s is not available on %s", + settings_map[j].channel_arg_name, + is_client ? "clients" : "servers"); + } else { + int value = grpc_channel_arg_get_integer( + &channel_args->args[i], settings_map[j].integer_options); + if (value >= 0) { + queue_setting_update(t, settings_map[j].setting_id, + static_cast<uint32_t>(value)); + } + } + break; + } + } + } + } + if (channelz_enabled) { + t->channelz_socket = + grpc_core::MakeRefCounted<grpc_core::channelz::SocketNode>(); + } + return enable_bdp; +} +static void init_transport_closures(grpc_chttp2_transport* t) { GRPC_CLOSURE_INIT(&t->read_action_locked, read_action_locked, t, grpc_combiner_scheduler(t->combiner)); GRPC_CLOSURE_INIT(&t->benign_reclaimer_locked, benign_reclaimer_locked, t, @@ -286,6 +429,79 @@ static void init_transport(grpc_chttp2_transport* t, GRPC_CLOSURE_INIT(&t->keepalive_watchdog_fired_locked, keepalive_watchdog_fired_locked, t, grpc_combiner_scheduler(t->combiner)); +} + +static void init_transport_keepalive_settings(grpc_chttp2_transport* t) { + if (t->is_client) { + t->keepalive_time = g_default_client_keepalive_time_ms == INT_MAX + ? GRPC_MILLIS_INF_FUTURE + : g_default_client_keepalive_time_ms; + t->keepalive_timeout = g_default_client_keepalive_timeout_ms == INT_MAX + ? GRPC_MILLIS_INF_FUTURE + : g_default_client_keepalive_timeout_ms; + t->keepalive_permit_without_calls = + g_default_client_keepalive_permit_without_calls; + } else { + t->keepalive_time = g_default_server_keepalive_time_ms == INT_MAX + ? GRPC_MILLIS_INF_FUTURE + : g_default_server_keepalive_time_ms; + t->keepalive_timeout = g_default_server_keepalive_timeout_ms == INT_MAX + ? GRPC_MILLIS_INF_FUTURE + : g_default_server_keepalive_timeout_ms; + t->keepalive_permit_without_calls = + g_default_server_keepalive_permit_without_calls; + } +} + +static void configure_transport_ping_policy(grpc_chttp2_transport* t) { + t->ping_policy.max_pings_without_data = g_default_max_pings_without_data; + t->ping_policy.min_sent_ping_interval_without_data = + g_default_min_sent_ping_interval_without_data_ms; + t->ping_policy.max_ping_strikes = g_default_max_ping_strikes; + t->ping_policy.min_recv_ping_interval_without_data = + g_default_min_recv_ping_interval_without_data_ms; +} + +static void init_keepalive_pings_if_enabled(grpc_chttp2_transport* t) { + if (t->keepalive_time != GRPC_MILLIS_INF_FUTURE) { + t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING; + GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping"); + grpc_timer_init(&t->keepalive_ping_timer, + grpc_core::ExecCtx::Get()->Now() + t->keepalive_time, + &t->init_keepalive_ping_locked); + } else { + /* Use GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED to indicate there are no + inflight keeaplive timers */ + t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED; + } +} + +static void init_transport(grpc_chttp2_transport* t, + const grpc_channel_args* channel_args, + grpc_endpoint* ep, bool is_client) { + GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) == + GRPC_CHTTP2_CLIENT_CONNECT_STRLEN); + + t->base.vtable = get_vtable(); + t->ep = ep; + /* one ref is for destroy */ + gpr_ref_init(&t->refs, 1); + t->combiner = grpc_combiner_create(); + t->peer_string = grpc_endpoint_get_peer(ep); + t->endpoint_reading = 1; + t->next_stream_id = is_client ? 1 : 2; + t->is_client = is_client; + t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; + t->is_first_frame = true; + grpc_connectivity_state_init( + &t->channel_callback.state_tracker, GRPC_CHANNEL_READY, + is_client ? "client_transport" : "server_transport"); + + grpc_slice_buffer_init(&t->qbuf); + grpc_slice_buffer_init(&t->outbuf); + grpc_chttp2_hpack_compressor_init(&t->hpack_compressor); + + init_transport_closures(t); t->goaway_error = GRPC_ERROR_NONE; grpc_chttp2_goaway_parser_init(&t->goaway_parser); @@ -301,6 +517,8 @@ static void init_transport(grpc_chttp2_transport* t, grpc_chttp2_stream_map_init(&t->stream_map, 8); /* copy in initial settings to all setting sets */ + size_t i; + int j; for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) { for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) { t->settings[j][i] = grpc_chttp2_settings_parameters[i].default_value; @@ -328,191 +546,14 @@ static void init_transport(grpc_chttp2_transport* t, queue_setting_update(t, GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, 1); - t->ping_policy.max_pings_without_data = g_default_max_pings_without_data; - t->ping_policy.min_sent_ping_interval_without_data = - g_default_min_sent_ping_interval_without_data_ms; - t->ping_policy.max_ping_strikes = g_default_max_ping_strikes; - t->ping_policy.min_recv_ping_interval_without_data = - g_default_min_recv_ping_interval_without_data_ms; - - /* Keepalive setting */ - if (t->is_client) { - t->keepalive_time = g_default_client_keepalive_time_ms == INT_MAX - ? GRPC_MILLIS_INF_FUTURE - : g_default_client_keepalive_time_ms; - t->keepalive_timeout = g_default_client_keepalive_timeout_ms == INT_MAX - ? GRPC_MILLIS_INF_FUTURE - : g_default_client_keepalive_timeout_ms; - t->keepalive_permit_without_calls = - g_default_client_keepalive_permit_without_calls; - } else { - t->keepalive_time = g_default_server_keepalive_time_ms == INT_MAX - ? GRPC_MILLIS_INF_FUTURE - : g_default_server_keepalive_time_ms; - t->keepalive_timeout = g_default_server_keepalive_timeout_ms == INT_MAX - ? GRPC_MILLIS_INF_FUTURE - : g_default_server_keepalive_timeout_ms; - t->keepalive_permit_without_calls = - g_default_server_keepalive_permit_without_calls; - } + configure_transport_ping_policy(t); + init_transport_keepalive_settings(t); t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; bool enable_bdp = true; - if (channel_args) { - for (i = 0; i < channel_args->num_args; i++) { - if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) { - const grpc_integer_options options = {-1, 0, INT_MAX}; - const int value = - grpc_channel_arg_get_integer(&channel_args->args[i], options); - if (value >= 0) { - if ((t->next_stream_id & 1) != (value & 1)) { - gpr_log(GPR_ERROR, "%s: low bit must be %d on %s", - GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, - t->next_stream_id & 1, is_client ? "client" : "server"); - } else { - t->next_stream_id = static_cast<uint32_t>(value); - } - } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) { - const grpc_integer_options options = {-1, 0, INT_MAX}; - const int value = - grpc_channel_arg_get_integer(&channel_args->args[i], options); - if (value >= 0) { - grpc_chttp2_hpack_compressor_set_max_usable_size( - &t->hpack_compressor, static_cast<uint32_t>(value)); - } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA)) { - t->ping_policy.max_pings_without_data = grpc_channel_arg_get_integer( - &channel_args->args[i], - {g_default_max_pings_without_data, 0, INT_MAX}); - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_MAX_PING_STRIKES)) { - t->ping_policy.max_ping_strikes = grpc_channel_arg_get_integer( - &channel_args->args[i], {g_default_max_ping_strikes, 0, INT_MAX}); - } else if (0 == - strcmp( - channel_args->args[i].key, - GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS)) { - t->ping_policy.min_sent_ping_interval_without_data = - grpc_channel_arg_get_integer( - &channel_args->args[i], - grpc_integer_options{ - g_default_min_sent_ping_interval_without_data_ms, 0, - INT_MAX}); - } else if (0 == - strcmp( - channel_args->args[i].key, - GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS)) { - t->ping_policy.min_recv_ping_interval_without_data = - grpc_channel_arg_get_integer( - &channel_args->args[i], - grpc_integer_options{ - g_default_min_recv_ping_interval_without_data_ms, 0, - INT_MAX}); - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) { - t->write_buffer_size = - static_cast<uint32_t>(grpc_channel_arg_get_integer( - &channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE})); - } else if (0 == - strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) { - enable_bdp = grpc_channel_arg_get_bool(&channel_args->args[i], true); - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_KEEPALIVE_TIME_MS)) { - const int value = grpc_channel_arg_get_integer( - &channel_args->args[i], - grpc_integer_options{t->is_client - ? g_default_client_keepalive_time_ms - : g_default_server_keepalive_time_ms, - 1, INT_MAX}); - t->keepalive_time = value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value; - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) { - const int value = grpc_channel_arg_get_integer( - &channel_args->args[i], - grpc_integer_options{t->is_client - ? g_default_client_keepalive_timeout_ms - : g_default_server_keepalive_timeout_ms, - 0, INT_MAX}); - t->keepalive_timeout = - value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value; - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { - t->keepalive_permit_without_calls = static_cast<uint32_t>( - grpc_channel_arg_get_integer(&channel_args->args[i], {0, 0, 1})); - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_OPTIMIZATION_TARGET)) { - if (channel_args->args[i].type != GRPC_ARG_STRING) { - gpr_log(GPR_ERROR, "%s should be a string", - GRPC_ARG_OPTIMIZATION_TARGET); - } else if (0 == strcmp(channel_args->args[i].value.string, "blend")) { - t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; - } else if (0 == strcmp(channel_args->args[i].value.string, "latency")) { - t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; - } else if (0 == - strcmp(channel_args->args[i].value.string, "throughput")) { - t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_THROUGHPUT; - } else { - gpr_log(GPR_ERROR, "%s value '%s' unknown, assuming 'blend'", - GRPC_ARG_OPTIMIZATION_TARGET, - channel_args->args[i].value.string); - } - } else { - static const struct { - const char* channel_arg_name; - grpc_chttp2_setting_id setting_id; - grpc_integer_options integer_options; - bool availability[2] /* server, client */; - } settings_map[] = { - {GRPC_ARG_MAX_CONCURRENT_STREAMS, - GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, - {-1, 0, INT32_MAX}, - {true, false}}, - {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER, - GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, - {-1, 0, INT32_MAX}, - {true, true}}, - {GRPC_ARG_MAX_METADATA_SIZE, - GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, - {-1, 0, INT32_MAX}, - {true, true}}, - {GRPC_ARG_HTTP2_MAX_FRAME_SIZE, - GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, - {-1, 16384, 16777215}, - {true, true}}, - {GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY, - GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, - {1, 0, 1}, - {true, true}}, - {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES, - GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, - {-1, 5, INT32_MAX}, - {true, true}}}; - for (j = 0; j < static_cast<int> GPR_ARRAY_SIZE(settings_map); j++) { - if (0 == strcmp(channel_args->args[i].key, - settings_map[j].channel_arg_name)) { - if (!settings_map[j].availability[is_client]) { - gpr_log(GPR_DEBUG, "%s is not available on %s", - settings_map[j].channel_arg_name, - is_client ? "clients" : "servers"); - } else { - int value = grpc_channel_arg_get_integer( - &channel_args->args[i], settings_map[j].integer_options); - if (value >= 0) { - queue_setting_update(t, settings_map[j].setting_id, - static_cast<uint32_t>(value)); - } - } - break; - } - } - } - } + enable_bdp = read_channel_args(t, channel_args, is_client); } if (g_flow_control_enabled) { @@ -531,23 +572,11 @@ static void init_transport(grpc_chttp2_transport* t, t->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST; t->ping_recv_state.ping_strikes = 0; - /* Start keepalive pings */ - if (t->keepalive_time != GRPC_MILLIS_INF_FUTURE) { - t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING; - GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping"); - grpc_timer_init(&t->keepalive_ping_timer, - grpc_core::ExecCtx::Get()->Now() + t->keepalive_time, - &t->init_keepalive_ping_locked); - } else { - /* Use GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED to indicate there are no - inflight keeaplive timers */ - t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED; - } + init_keepalive_pings_if_enabled(t); if (enable_bdp) { GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); schedule_bdp_ping_locked(t); - grpc_chttp2_act_on_flowctl_action(t->flow_control->PeriodicUpdate(), t, nullptr); } @@ -704,6 +733,14 @@ static void destroy_stream_locked(void* sp, grpc_error* error) { grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp); grpc_chttp2_transport* t = s->t; + if (t->channelz_socket != nullptr) { + if ((t->is_client && s->eos_received) || (!t->is_client && s->eos_sent)) { + t->channelz_socket->RecordStreamSucceeded(); + } else { + t->channelz_socket->RecordStreamFailed(); + } + } + GPR_ASSERT((s->write_closed && s->read_closed) || s->id == 0); if (s->id != 0) { GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, s->id) == nullptr); @@ -1029,7 +1066,8 @@ static void write_action(void* gt, grpc_error* error) { grpc_endpoint_write( t->ep, &t->outbuf, GRPC_CLOSURE_INIT(&t->write_action_end_locked, write_action_end_locked, t, - grpc_combiner_scheduler(t->combiner))); + grpc_combiner_scheduler(t->combiner)), + nullptr); } /* Callback from the grpc_endpoint after bytes have been written by calling @@ -1390,6 +1428,9 @@ static void perform_stream_op_locked(void* stream_op, } if (op->send_initial_metadata) { + if (t->is_client && t->channelz_socket != nullptr) { + t->channelz_socket->RecordStreamStartedFromLocal(); + } GRPC_STATS_INC_HTTP2_OP_SEND_INITIAL_METADATA(); GPR_ASSERT(s->send_initial_metadata_finished == nullptr); on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE; @@ -1475,6 +1516,7 @@ static void perform_stream_op_locked(void* stream_op, if (op->send_message) { GRPC_STATS_INC_HTTP2_OP_SEND_MESSAGE(); + t->num_messages_in_next_write++; GRPC_STATS_INC_HTTP2_SEND_MESSAGE_SIZE( op->payload->send_message.send_message->length()); on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE; @@ -2086,8 +2128,7 @@ void grpc_chttp2_fake_status(grpc_chttp2_transport* t, grpc_chttp2_stream* s, "add_status_message", grpc_chttp2_incoming_metadata_buffer_replace_or_add( &s->metadata_buffer[1], - grpc_mdelem_from_slices(GRPC_MDSTR_GRPC_MESSAGE, - grpc_slice_ref_internal(slice)))); + grpc_mdelem_create(GRPC_MDSTR_GRPC_MESSAGE, slice, nullptr))); } s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE; grpc_chttp2_maybe_complete_recv_trailing_metadata(t, s); @@ -2690,6 +2731,9 @@ static void start_keepalive_ping_locked(void* arg, grpc_error* error) { if (error != GRPC_ERROR_NONE) { return; } + if (t->channelz_socket != nullptr) { + t->channelz_socket->RecordKeepaliveSent(); + } GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive watchdog"); grpc_timer_init(&t->keepalive_watchdog_timer, grpc_core::ExecCtx::Get()->Now() + t->keepalive_timeout, @@ -2717,10 +2761,10 @@ static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error) { if (error == GRPC_ERROR_NONE) { t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; close_transport_locked( - t, - grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "keepalive watchdog timeout"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL)); + t, grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "keepalive watchdog timeout"), + GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAVAILABLE)); } } else { /* The watchdog timer should have been cancelled by @@ -2886,17 +2930,20 @@ bool Chttp2IncomingByteStream::Next(size_t max_size_hint, } } +void Chttp2IncomingByteStream::MaybeCreateStreamDecompressionCtx() { + if (!stream_->stream_decompression_ctx) { + stream_->stream_decompression_ctx = grpc_stream_compression_context_create( + stream_->stream_decompression_method); + } +} + grpc_error* Chttp2IncomingByteStream::Pull(grpc_slice* slice) { GPR_TIMER_SCOPE("incoming_byte_stream_pull", 0); grpc_error* error; if (stream_->unprocessed_incoming_frames_buffer.length > 0) { if (!stream_->unprocessed_incoming_frames_decompressed) { bool end_of_context; - if (!stream_->stream_decompression_ctx) { - stream_->stream_decompression_ctx = - grpc_stream_compression_context_create( - stream_->stream_decompression_method); - } + MaybeCreateStreamDecompressionCtx(); if (!grpc_stream_decompress(stream_->stream_decompression_ctx, &stream_->unprocessed_incoming_frames_buffer, &stream_->decompressed_data_buffer, nullptr, @@ -3127,6 +3174,16 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream), static const grpc_transport_vtable* get_vtable(void) { return &vtable; } +intptr_t grpc_chttp2_transport_get_socket_uuid(grpc_transport* transport) { + grpc_chttp2_transport* t = + reinterpret_cast<grpc_chttp2_transport*>(transport); + if (t->channelz_socket != nullptr) { + return t->channelz_socket->uuid(); + } else { + return 0; + } +} + grpc_transport* grpc_create_chttp2_transport( const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client) { grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>( diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h index 9d55b3f4b0..e5872fee43 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.h +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h @@ -34,6 +34,8 @@ extern bool g_flow_control_enabled; grpc_transport* grpc_create_chttp2_transport( const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client); +intptr_t grpc_chttp2_transport_get_socket_uuid(grpc_transport* transport); + /// Takes ownership of \a read_buffer, which (if non-NULL) contains /// leftover bytes previously read from the endpoint (e.g., by handshakers). /// If non-null, \a notify_on_receive_settings will be scheduled when diff --git a/src/core/ext/transport/chttp2/transport/frame_data.cc b/src/core/ext/transport/chttp2/transport/frame_data.cc index f8f06f6789..933b32c03c 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.cc +++ b/src/core/ext/transport/chttp2/transport/frame_data.cc @@ -62,6 +62,7 @@ grpc_error* grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser* parser, if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) { s->received_last_frame = true; + s->eos_received = true; } else { s->received_last_frame = false; } @@ -191,6 +192,9 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( GPR_ASSERT(stream_out != nullptr); GPR_ASSERT(p->parsing_frame == nullptr); p->frame_size |= (static_cast<uint32_t>(*cur)); + if (t->channelz_socket != nullptr) { + t->channelz_socket->RecordMessageReceived(); + } p->state = GRPC_CHTTP2_DATA_FRAME; ++cur; message_flags = 0; diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc index 0eaf63f133..920d52770f 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc @@ -525,7 +525,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem, /* should this elem be in the table? */ size_t decoder_space_usage = - grpc_mdelem_get_size_in_hpack_table(elem, st->use_true_binary_metadata); + grpc_chttp2_get_size_in_hpack_table(elem, st->use_true_binary_metadata); bool should_add_elem = elem_interned && decoder_space_usage < MAX_DECODER_SPACE_USAGE && c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= @@ -688,11 +688,22 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor* c, emit_advertise_table_size_change(c, &st); } for (size_t i = 0; i < extra_headers_size; ++i) { - hpack_enc(c, *extra_headers[i], &st); + grpc_mdelem md = *extra_headers[i]; + uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(md); + if (static_index) { + emit_indexed(c, static_index, &st); + } else { + hpack_enc(c, md, &st); + } } grpc_metadata_batch_assert_ok(metadata); for (grpc_linked_mdelem* l = metadata->list.head; l; l = l->next) { - hpack_enc(c, l->md, &st); + uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md); + if (static_index) { + emit_indexed(c, static_index, &st); + } else { + hpack_enc(c, l->md, &st); + } } grpc_millis deadline = metadata->deadline; if (deadline != GRPC_MILLIS_INF_FUTURE) { diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.cc b/src/core/ext/transport/chttp2/transport/hpack_table.cc index 7929258356..fcfb01872b 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_table.cc +++ b/src/core/ext/transport/chttp2/transport/hpack_table.cc @@ -29,6 +29,7 @@ #include "src/core/lib/debug/trace.h" #include "src/core/lib/gpr/murmur_hash.h" +#include "src/core/lib/transport/static_metadata.h" extern grpc_core::TraceFlag grpc_http_trace; @@ -366,3 +367,31 @@ grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( return r; } + +static size_t get_base64_encoded_size(size_t raw_length) { + static const uint8_t tail_xtra[3] = {0, 2, 3}; + return raw_length / 3 * 4 + tail_xtra[raw_length % 3]; +} + +size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem, + bool use_true_binary_metadata) { + size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); + size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem)); + if (grpc_is_binary_header(GRPC_MDKEY(elem))) { + return overhead_and_key + (use_true_binary_metadata + ? value_len + 1 + : get_base64_encoded_size(value_len)); + } else { + return overhead_and_key + value_len; + } +} + +uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md) { + if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) { + uint8_t index = GRPC_MDELEM_DATA(md) - grpc_static_mdelem_table; + if (index < GRPC_CHTTP2_LAST_STATIC_ENTRY) { + return index + 1; // Hpack static metadata element indices start at 1 + } + } + return 0; +} diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h index 98026a4ba4..a0ffc6fab7 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_table.h +++ b/src/core/ext/transport/chttp2/transport/hpack_table.h @@ -83,6 +83,15 @@ grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl* tbl, /* add a table entry to the index */ grpc_error* grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl, grpc_mdelem md) GRPC_MUST_USE_RESULT; + +size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem, + bool use_true_binary_metadata); + +/* Returns the static hpack table index that corresponds to /a elem. Returns 0 + if /a elem is not statically stored or if it is not in the static hpack + table */ +uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md); + /* Find a key/value pair in the table... returns the index in the table of the most similar entry, or 0 if the value was not found */ typedef struct { diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index ca6e715978..ff26dd9255 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -36,6 +36,7 @@ #include "src/core/ext/transport/chttp2/transport/hpack_parser.h" #include "src/core/ext/transport/chttp2/transport/incoming_metadata.h" #include "src/core/ext/transport/chttp2/transport/stream_map.h" +#include "src/core/lib/channel/channelz.h" #include "src/core/lib/compression/stream_compression.h" #include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/iomgr/combiner.h" @@ -246,6 +247,8 @@ class Chttp2IncomingByteStream : public ByteStream { static void NextLocked(void* arg, grpc_error* error_ignored); static void OrphanLocked(void* arg, grpc_error* error_ignored); + void MaybeCreateStreamDecompressionCtx(); + grpc_chttp2_transport* transport_; // Immutable. grpc_chttp2_stream* stream_; // Immutable. @@ -469,6 +472,9 @@ struct grpc_chttp2_transport { bool keepalive_permit_without_calls; /** keep-alive state machine state */ grpc_chttp2_keepalive_state keepalive_state; + + grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode> channelz_socket; + uint32_t num_messages_in_next_write; }; typedef enum { @@ -532,6 +538,10 @@ struct grpc_chttp2_stream { /** Has trailing metadata been received. */ bool received_trailing_metadata; + /* have we sent or received the EOS bit? */ + bool eos_received; + bool eos_sent; + /** the error that resulted in this stream being read-closed */ grpc_error* read_closed_error; /** the error that resulted in this stream being write-closed */ diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc index 1e491d2ef8..f532b084c9 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.cc +++ b/src/core/ext/transport/chttp2/transport/parsing.cc @@ -409,67 +409,81 @@ static void on_initial_header(void* tp, grpc_mdelem md) { gpr_free(value); } - if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && - !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { - /* TODO(ctiller): check for a status like " 0" */ - s->seen_error = true; - } + if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) { + // We don't use grpc_mdelem_eq here to avoid executing additional + // instructions. The reasoning is if the payload is not equal, we already + // know that the metadata elements are not equal because the md is + // confirmed to be static. If we had used grpc_mdelem_eq here, then if the + // payloads are not equal, grpc_mdelem_eq executes more instructions to + // determine if they're equal or not. + if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload || + md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) { + s->seen_error = true; + } + } else { + if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && + !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { + /* TODO(ctiller): check for a status like " 0" */ + s->seen_error = true; + } - if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) { - grpc_millis* cached_timeout = - static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout)); - grpc_millis timeout; - if (cached_timeout != nullptr) { - timeout = *cached_timeout; - } else { - if (GPR_UNLIKELY( - !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) { - char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); - gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val); - gpr_free(val); - timeout = GRPC_MILLIS_INF_FUTURE; + if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) { + grpc_millis* cached_timeout = static_cast<grpc_millis*>( + grpc_mdelem_get_user_data(md, free_timeout)); + grpc_millis timeout; + if (cached_timeout != nullptr) { + timeout = *cached_timeout; + } else { + if (GPR_UNLIKELY( + !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) { + char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); + gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val); + gpr_free(val); + timeout = GRPC_MILLIS_INF_FUTURE; + } + if (GRPC_MDELEM_IS_INTERNED(md)) { + /* store the result */ + cached_timeout = + static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis))); + *cached_timeout = timeout; + grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); + } } - if (GRPC_MDELEM_IS_INTERNED(md)) { - /* store the result */ - cached_timeout = - static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis))); - *cached_timeout = timeout; - grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); + if (timeout != GRPC_MILLIS_INF_FUTURE) { + grpc_chttp2_incoming_metadata_buffer_set_deadline( + &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout); } + GRPC_MDELEM_UNREF(md); + return; } - if (timeout != GRPC_MILLIS_INF_FUTURE) { - grpc_chttp2_incoming_metadata_buffer_set_deadline( - &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout); - } + } + + const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); + const size_t metadata_size_limit = + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; + if (new_size > metadata_size_limit) { + gpr_log(GPR_DEBUG, + "received initial metadata size exceeds limit (%" PRIuPTR + " vs. %" PRIuPTR ")", + new_size, metadata_size_limit); + grpc_chttp2_cancel_stream( + t, s, + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "received initial metadata size exceeds limit"), + GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_RESOURCE_EXHAUSTED)); + grpc_chttp2_parsing_become_skip_parser(t); + s->seen_error = true; GRPC_MDELEM_UNREF(md); } else { - const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); - const size_t metadata_size_limit = - t->settings[GRPC_ACKED_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; - if (new_size > metadata_size_limit) { - gpr_log(GPR_DEBUG, - "received initial metadata size exceeds limit (%" PRIuPTR - " vs. %" PRIuPTR ")", - new_size, metadata_size_limit); - grpc_chttp2_cancel_stream( - t, s, - grpc_error_set_int( - GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "received initial metadata size exceeds limit"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); + grpc_error* error = + grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md); + if (error != GRPC_ERROR_NONE) { + grpc_chttp2_cancel_stream(t, s, error); grpc_chttp2_parsing_become_skip_parser(t); s->seen_error = true; GRPC_MDELEM_UNREF(md); - } else { - grpc_error* error = - grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md); - if (error != GRPC_ERROR_NONE) { - grpc_chttp2_cancel_stream(t, s, error); - grpc_chttp2_parsing_become_skip_parser(t); - s->seen_error = true; - GRPC_MDELEM_UNREF(md); - } } } } @@ -491,8 +505,19 @@ static void on_trailing_header(void* tp, grpc_mdelem md) { gpr_free(value); } - if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && - !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { + if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) { + // We don't use grpc_mdelem_eq here to avoid executing additional + // instructions. The reasoning is if the payload is not equal, we already + // know that the metadata elements are not equal because the md is + // confirmed to be static. If we had used grpc_mdelem_eq here, then if the + // payloads are not equal, grpc_mdelem_eq executes more instructions to + // determine if they're equal or not. + if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload || + md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) { + s->seen_error = true; + } + } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && + !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { /* TODO(ctiller): check for a status like " 0" */ s->seen_error = true; } @@ -598,6 +623,9 @@ static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t, gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted")); return init_skip_frame_parser(t, 1); } + if (t->channelz_socket != nullptr) { + t->channelz_socket->RecordStreamStartedFromRemote(); + } } else { t->incoming_stream = s; } @@ -611,6 +639,9 @@ static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t, } t->parser = grpc_chttp2_header_parser_parse; t->parser_data = &t->hpack_parser; + if (t->header_eof) { + s->eos_received = true; + } switch (s->header_frames_received) { case 0: if (t->is_client && t->header_eof) { diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc index 8b73b01dea..d533989444 100644 --- a/src/core/ext/transport/chttp2/transport/writing.cc +++ b/src/core/ext/transport/chttp2/transport/writing.cc @@ -569,6 +569,7 @@ class StreamWriteContext { void SentLastFrame() { s_->send_trailing_metadata = nullptr; s_->sent_trailing_metadata = true; + s_->eos_sent = true; if (!t_->is_client && !s_->read_closed) { grpc_slice_buffer_add( @@ -632,6 +633,11 @@ void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error* error) { GPR_TIMER_SCOPE("grpc_chttp2_end_write", 0); grpc_chttp2_stream* s; + if (t->channelz_socket != nullptr) { + t->channelz_socket->RecordMessagesSent(t->num_messages_in_next_write); + } + t->num_messages_in_next_write = 0; + while (grpc_chttp2_list_pop_writing_stream(t, &s)) { if (s->sending_bytes != 0) { update_list(t, s, static_cast<int64_t>(s->sending_bytes), diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.cc b/src/core/ext/transport/cronet/transport/cronet_transport.cc index 4a252d972d..81e2634e3a 100644 --- a/src/core/ext/transport/cronet/transport/cronet_transport.cc +++ b/src/core/ext/transport/cronet/transport/cronet_transport.cc @@ -1287,7 +1287,7 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) { grpc_error* error = GRPC_ERROR_NONE; if (stream_state->state_op_done[OP_CANCEL_ERROR]) { error = GRPC_ERROR_REF(stream_state->cancel_error); - } else if (stream_state->state_op_done[OP_FAILED]) { + } else if (stream_state->state_callback_received[OP_FAILED]) { error = make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."); } else if (oas->s->state.rs.trailing_metadata_valid) { grpc_chttp2_incoming_metadata_buffer_publish( diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc index b0ca7f8207..9dbd095843 100644 --- a/src/core/ext/transport/inproc/inproc_transport.cc +++ b/src/core/ext/transport/inproc/inproc_transport.cc @@ -1256,7 +1256,9 @@ grpc_channel* grpc_inproc_channel_create(grpc_server* server, inproc_transports_create(&server_transport, server_args, &client_transport, client_args); - grpc_server_setup_transport(server, server_transport, nullptr, server_args); + // TODO(ncteisen): design and support channelz GetSocket for inproc. + grpc_server_setup_transport(server, server_transport, nullptr, server_args, + 0); grpc_channel* channel = grpc_channel_create( "inproc", client_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport); diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc index b3443310ac..fe81acb617 100644 --- a/src/core/lib/channel/channel_trace.cc +++ b/src/core/lib/channel/channel_trace.cc @@ -41,40 +41,42 @@ namespace grpc_core { namespace channelz { -ChannelTrace::TraceEvent::TraceEvent( - Severity severity, grpc_slice data, - RefCountedPtr<ChannelNode> referenced_channel, ReferencedType type) +ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data, + RefCountedPtr<BaseNode> referenced_entity) : severity_(severity), data_(data), timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME)), next_(nullptr), - referenced_channel_(std::move(referenced_channel)), - referenced_type_(type) {} + 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; @@ -95,38 +97,30 @@ 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::AddTraceEventReferencingChannel( - Severity severity, grpc_slice data, - RefCountedPtr<ChannelNode> referenced_channel) { - if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 - // create and fill up the new event - AddTraceEventHelper(New<TraceEvent>( - severity, data, std::move(referenced_channel), ReferencedType::Channel)); -} - -void ChannelTrace::AddTraceEventReferencingSubchannel( +void ChannelTrace::AddTraceEventWithReference( Severity severity, grpc_slice data, - RefCountedPtr<ChannelNode> referenced_subchannel) { - if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 + RefCountedPtr<BaseNode> referenced_entity) { + 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_subchannel), - ReferencedType::Subchannel)); + AddTraceEventHelper( + New<TraceEvent>(severity, data, std::move(referenced_entity))); } namespace { @@ -157,45 +151,46 @@ void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const { json_iterator = grpc_json_create_child(json_iterator, json, "timestamp", gpr_format_timespec(timestamp_), GRPC_JSON_STRING, true); - if (referenced_channel_ != nullptr) { + if (referenced_entity_ != nullptr) { + const bool is_channel = + (referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel || + referenced_entity_->type() == BaseNode::EntityType::kInternalChannel); char* uuid_str; - gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_channel_->channel_uuid()); + gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_entity_->uuid()); grpc_json* child_ref = grpc_json_create_child( - json_iterator, json, - (referenced_type_ == ReferencedType::Channel) ? "channelRef" - : "subchannelRef", + json_iterator, json, is_channel ? "channelRef" : "subchannelRef", nullptr, GRPC_JSON_OBJECT, false); json_iterator = grpc_json_create_child( - nullptr, child_ref, - (referenced_type_ == ReferencedType::Channel) ? "channelId" - : "subchannelId", - uuid_str, GRPC_JSON_STRING, true); + nullptr, child_ref, is_channel ? "channelId" : "subchannelId", uuid_str, + GRPC_JSON_STRING, true); json_iterator = child_ref; } } 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); - char* num_events_logged_str; - gpr_asprintf(&num_events_logged_str, "%" PRId64, num_events_logged_); grpc_json* json_iterator = nullptr; - json_iterator = - grpc_json_create_child(json_iterator, json, "numEventsLogged", - num_events_logged_str, GRPC_JSON_STRING, true); + if (num_events_logged_ > 0) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "numEventsLogged", num_events_logged_); + } json_iterator = grpc_json_create_child( json_iterator, json, "creationTimestamp", gpr_format_timespec(time_created_), GRPC_JSON_STRING, true); - grpc_json* events = grpc_json_create_child(json_iterator, json, "events", - nullptr, GRPC_JSON_ARRAY, false); - json_iterator = nullptr; - TraceEvent* it = head_trace_; - while (it != nullptr) { - json_iterator = grpc_json_create_child(json_iterator, events, nullptr, - nullptr, GRPC_JSON_OBJECT, false); - it->RenderTraceEvent(json_iterator); - it = it->next(); + // only add in the event list if it is non-empty. + if (head_trace_ != nullptr) { + grpc_json* events = grpc_json_create_child(json_iterator, json, "events", + nullptr, GRPC_JSON_ARRAY, false); + json_iterator = nullptr; + TraceEvent* it = head_trace_; + while (it != nullptr) { + json_iterator = grpc_json_create_child(json_iterator, events, nullptr, + nullptr, GRPC_JSON_OBJECT, false); + it->RenderTraceEvent(json_iterator); + it = it->next(); + } } return json; } diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h index 596af7402f..8ff91ee8c8 100644 --- a/src/core/lib/channel/channel_trace.h +++ b/src/core/lib/channel/channel_trace.h @@ -30,14 +30,18 @@ namespace grpc_core { namespace channelz { -class ChannelNode; +namespace testing { +size_t GetSizeofTraceEvent(void); +} + +class BaseNode; // Object used to hold live data for a channel. This data is exposed via the // channelz service: // https://github.com/grpc/proposal/blob/master/A14-channelz.md class ChannelTrace { public: - ChannelTrace(size_t max_events); + ChannelTrace(size_t max_event_memory); ~ChannelTrace(); enum Severity { @@ -49,41 +53,42 @@ 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. void AddTraceEvent(Severity severity, grpc_slice data); // Adds a new trace event to the tracing object. This trace event refers to a - // an event on a child of the channel. For example, if this channel has - // created a new subchannel, then it would record that with a TraceEvent - // referencing the new subchannel. + // an event that concerns a different channelz entity. For example, if this + // 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. - void AddTraceEventReferencingChannel( - Severity severity, grpc_slice data, - RefCountedPtr<ChannelNode> referenced_channel); - void AddTraceEventReferencingSubchannel( - Severity severity, grpc_slice data, - RefCountedPtr<ChannelNode> referenced_subchannel); + // 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); // Creates and returns the raw grpc_json object, so a parent channelz // object may incorporate the json before rendering. grpc_json* RenderJson() const; private: - // Types of objects that can be references by trace events. - enum class ReferencedType { Channel, Subchannel }; + friend size_t testing::GetSizeofTraceEvent(void); + // Private class to encapsulate all the data and bookkeeping needed for a // a trace event. class TraceEvent { public: - // Constructor for a TraceEvent that references a different channel. + // Constructor for a TraceEvent that references a channel. TraceEvent(Severity severity, grpc_slice data, - RefCountedPtr<ChannelNode> referenced_channel, - ReferencedType type); + RefCountedPtr<BaseNode> referenced_entity_); // Constructor for a TraceEvent that does not reverence a different // channel. @@ -99,16 +104,16 @@ 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_; gpr_timespec timestamp_; TraceEvent* next_; // the tracer object for the (sub)channel that this trace event refers to. - RefCountedPtr<ChannelNode> referenced_channel_; - // the type that the referenced tracer points to. Unused if this trace - // does not point to any channel or subchannel - ReferencedType referenced_type_; + RefCountedPtr<BaseNode> referenced_entity_; + size_t memory_usage_; }; // TraceEvent // Internal helper to add and link in a trace event @@ -116,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 9d6002ed8a..33577d890a 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -34,40 +34,115 @@ #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/surface/server.h" #include "src/core/lib/transport/error_utils.h" namespace grpc_core { namespace channelz { -ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel) - : channel_(channel), - target_(nullptr), - channel_uuid_(-1), - is_top_level_channel_(is_top_level_channel) { - trace_.Init(channel_tracer_max_nodes); - target_ = UniquePtr<char>(grpc_channel_get_target(channel_)); - channel_uuid_ = ChannelzRegistry::RegisterChannelNode(this); - gpr_atm_no_barrier_store(&last_call_started_millis_, - (gpr_atm)ExecCtx::Get()->Now()); +BaseNode::BaseNode(EntityType type) : type_(type), uuid_(-1) { + // The registry will set uuid_ under its lock. + ChannelzRegistry::Register(this); } -ChannelNode::~ChannelNode() { - trace_.Destroy(); - ChannelzRegistry::UnregisterChannelNode(channel_uuid_); +BaseNode::~BaseNode() { ChannelzRegistry::Unregister(uuid_); } + +char* BaseNode::RenderJsonString() { + grpc_json* json = RenderJson(); + GPR_ASSERT(json != nullptr); + char* json_str = grpc_json_dump_to_string(json, 0); + grpc_json_destroy(json); + return json_str; } -void ChannelNode::RecordCallStarted() { - gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1); - gpr_atm_no_barrier_store(&last_call_started_millis_, - (gpr_atm)ExecCtx::Get()->Now()); +CallCountingHelper::CallCountingHelper() { + num_cores_ = GPR_MAX(1, gpr_cpu_num_cores()); + per_cpu_counter_data_storage_ = static_cast<AtomicCounterData*>( + gpr_zalloc(sizeof(AtomicCounterData) * num_cores_)); } -void ChannelNode::PopulateConnectivityState(grpc_json* json) {} +CallCountingHelper::~CallCountingHelper() { + gpr_free(per_cpu_counter_data_storage_); +} + +void CallCountingHelper::RecordCallStarted() { + 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 ChannelNode::PopulateChildRefs(grpc_json* json) {} +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; + CounterData data; + CollectData(&data); + if (data.calls_started != 0) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "callsStarted", data.calls_started); + } + if (data.calls_succeeded != 0) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "callsSucceeded", data.calls_succeeded); + } + if (data.calls_failed) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "callsFailed", data.calls_failed); + } + 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); + } +} + +ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, + bool is_top_level_channel) + : BaseNode(is_top_level_channel ? EntityType::kTopLevelChannel + : EntityType::kInternalChannel), + channel_(channel), + target_(UniquePtr<char>(grpc_channel_get_target(channel_))), + trace_(channel_tracer_max_nodes) {} + +ChannelNode::~ChannelNode() {} grpc_json* ChannelNode::RenderJson() { // We need to track these three json objects to build our object @@ -80,7 +155,7 @@ grpc_json* ChannelNode::RenderJson() { json = json_iterator; json_iterator = nullptr; json_iterator = grpc_json_add_number_string_child(json, json_iterator, - "channelId", channel_uuid_); + "channelId", uuid()); // reset json iterators to top level object json = top_level_json; json_iterator = nullptr; @@ -89,51 +164,28 @@ grpc_json* ChannelNode::RenderJson() { GRPC_JSON_OBJECT, false); json = data; json_iterator = nullptr; + // template method. Child classes may override this to add their specific + // functionality. PopulateConnectivityState(json); + // populate the target. GPR_ASSERT(target_.get() != nullptr); - json_iterator = grpc_json_create_child( - json_iterator, json, "target", target_.get(), GRPC_JSON_STRING, false); + grpc_json_create_child(nullptr, json, "target", target_.get(), + GRPC_JSON_STRING, false); // fill in the channel trace if applicable - grpc_json* trace = trace_->RenderJson(); - if (trace != nullptr) { - // we manually link up and fill the child since it was created for us in - // ChannelTrace::RenderJson - trace->key = "trace"; // this object is named trace in channelz.proto - json_iterator = grpc_json_link_child(json, trace, json_iterator); + grpc_json* trace_json = trace_.RenderJson(); + if (trace_json != nullptr) { + trace_json->key = "trace"; // this object is named trace in channelz.proto + grpc_json_link_child(json, trace_json, nullptr); } - // reset the parent to be the data object. - json = data; - json_iterator = nullptr; - if (calls_started_ != 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "callsStarted", calls_started_); - } - if (calls_succeeded_ != 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "callsSucceeded", calls_succeeded_); - } - if (calls_failed_) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "callsFailed", calls_failed_); - } - gpr_timespec ts = - grpc_millis_to_timespec(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); + // ask CallCountingHelper to populate trace and call count data. + call_counter_.PopulateCallCounts(json); json = top_level_json; - json_iterator = nullptr; + // template method. Child classes may override this to add their specific + // functionality. PopulateChildRefs(json); return top_level_json; } -char* ChannelNode::RenderJsonString() { - grpc_json* json = RenderJson(); - char* json_str = grpc_json_dump_to_string(json, 0); - grpc_json_destroy(json); - return json_str; -} - RefCountedPtr<ChannelNode> ChannelNode::MakeChannelNode( grpc_channel* channel, size_t channel_tracer_max_nodes, bool is_top_level_channel) { @@ -141,12 +193,202 @@ RefCountedPtr<ChannelNode> ChannelNode::MakeChannelNode( channel, channel_tracer_max_nodes, is_top_level_channel); } -SubchannelNode::SubchannelNode() { - subchannel_uuid_ = ChannelzRegistry::RegisterSubchannelNode(this); +ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes) + : BaseNode(EntityType::kServer), + server_(server), + trace_(channel_tracer_max_nodes) {} + +ServerNode::~ServerNode() {} + +char* ServerNode::RenderServerSockets(intptr_t start_socket_id) { + grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json* json = top_level_json; + grpc_json* json_iterator = nullptr; + ChildRefsList socket_refs; + // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is + // reserved). However, we want to support requests coming in with + // start_server_id=0, which signifies "give me everything." + size_t start_idx = start_socket_id == 0 ? 0 : start_socket_id - 1; + grpc_server_populate_server_sockets(server_, &socket_refs, start_idx); + if (!socket_refs.empty()) { + // create list of socket refs + grpc_json* array_parent = grpc_json_create_child( + nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false); + for (size_t i = 0; i < socket_refs.size(); ++i) { + json_iterator = + grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, + GRPC_JSON_OBJECT, false); + grpc_json_add_number_string_child(json_iterator, nullptr, "socketId", + socket_refs[i]); + } + } + // For now we do not have any pagination rules. In the future we could + // pick a constant for max_channels_sent for a GetServers request. + // Tracking: https://github.com/grpc/grpc/issues/16019. + json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr, + GRPC_JSON_TRUE, false); + char* json_str = grpc_json_dump_to_string(top_level_json, 0); + grpc_json_destroy(top_level_json); + return json_str; } -SubchannelNode::~SubchannelNode() { - ChannelzRegistry::UnregisterSubchannelNode(subchannel_uuid_); +grpc_json* ServerNode::RenderJson() { + // We need to track these three json objects to build our object + grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json* json = top_level_json; + grpc_json* json_iterator = nullptr; + // create and fill the ref child + json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr, + GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = grpc_json_add_number_string_child(json, json_iterator, + "serverId", uuid()); + // reset json iterators to top level object + json = top_level_json; + json_iterator = nullptr; + // create and fill the data child. + grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr, + GRPC_JSON_OBJECT, false); + json = data; + json_iterator = nullptr; + // fill in the channel trace if applicable + grpc_json* trace_json = trace_.RenderJson(); + if (trace_json != nullptr) { + trace_json->key = "trace"; // this object is named trace in channelz.proto + grpc_json_link_child(json, trace_json, nullptr); + } + // ask CallCountingHelper to populate trace and call count data. + call_counter_.PopulateCallCounts(json); + json = top_level_json; + ChildRefsList listen_sockets; + grpc_server_populate_listen_sockets(server_, &listen_sockets); + if (!listen_sockets.empty()) { + grpc_json* array_parent = grpc_json_create_child( + nullptr, json, "listenSocket", nullptr, GRPC_JSON_ARRAY, false); + for (size_t i = 0; i < listen_sockets.size(); ++i) { + json_iterator = + grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, + GRPC_JSON_OBJECT, false); + grpc_json_add_number_string_child(json_iterator, nullptr, "socketId", + listen_sockets[i]); + } + } + return top_level_json; +} + +SocketNode::SocketNode() : BaseNode(EntityType::kSocket) {} + +void SocketNode::RecordStreamStartedFromLocal() { + gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1)); + gpr_atm_no_barrier_store(&last_local_stream_created_millis_, + (gpr_atm)ExecCtx::Get()->Now()); +} + +void SocketNode::RecordStreamStartedFromRemote() { + gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1)); + gpr_atm_no_barrier_store(&last_remote_stream_created_millis_, + (gpr_atm)ExecCtx::Get()->Now()); +} + +void SocketNode::RecordMessagesSent(uint32_t num_sent) { + gpr_atm_no_barrier_fetch_add(&messages_sent_, static_cast<gpr_atm>(num_sent)); + gpr_atm_no_barrier_store(&last_message_sent_millis_, + (gpr_atm)ExecCtx::Get()->Now()); +} + +void SocketNode::RecordMessageReceived() { + gpr_atm_no_barrier_fetch_add(&messages_received_, static_cast<gpr_atm>(1)); + gpr_atm_no_barrier_store(&last_message_received_millis_, + (gpr_atm)ExecCtx::Get()->Now()); +} + +grpc_json* SocketNode::RenderJson() { + // We need to track these three json objects to build our object + grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json* json = top_level_json; + grpc_json* json_iterator = nullptr; + // create and fill the ref child + json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr, + GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = grpc_json_add_number_string_child(json, json_iterator, + "socketId", uuid()); + // reset json iterators to top level object + json = top_level_json; + json_iterator = nullptr; + // create and fill the data child. + grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr, + GRPC_JSON_OBJECT, false); + json = data; + json_iterator = nullptr; + gpr_timespec ts; + if (streams_started_ != 0) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "streamsStarted", streams_started_); + if (last_local_stream_created_millis_ != 0) { + ts = grpc_millis_to_timespec(last_local_stream_created_millis_, + GPR_CLOCK_REALTIME); + json_iterator = grpc_json_create_child( + json_iterator, json, "lastLocalStreamCreatedTimestamp", + gpr_format_timespec(ts), GRPC_JSON_STRING, true); + } + if (last_remote_stream_created_millis_ != 0) { + ts = grpc_millis_to_timespec(last_remote_stream_created_millis_, + GPR_CLOCK_REALTIME); + json_iterator = grpc_json_create_child( + json_iterator, json, "lastRemoteStreamCreatedTimestamp", + gpr_format_timespec(ts), GRPC_JSON_STRING, true); + } + } + if (streams_succeeded_ != 0) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "streamsSucceeded", streams_succeeded_); + } + if (streams_failed_) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "streamsFailed", streams_failed_); + } + if (messages_sent_ != 0) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "messagesSent", messages_sent_); + ts = grpc_millis_to_timespec(last_message_sent_millis_, GPR_CLOCK_REALTIME); + json_iterator = + grpc_json_create_child(json_iterator, json, "lastMessageSentTimestamp", + gpr_format_timespec(ts), GRPC_JSON_STRING, true); + } + if (messages_received_ != 0) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "messagesReceived", messages_received_); + ts = grpc_millis_to_timespec(last_message_received_millis_, + GPR_CLOCK_REALTIME); + json_iterator = grpc_json_create_child( + json_iterator, json, "lastMessageReceivedTimestamp", + gpr_format_timespec(ts), GRPC_JSON_STRING, true); + } + if (keepalives_sent_ != 0) { + json_iterator = grpc_json_add_number_string_child( + json, json_iterator, "keepAlivesSent", keepalives_sent_); + } + return top_level_json; +} + +ListenSocketNode::ListenSocketNode() : BaseNode(EntityType::kSocket) {} + +grpc_json* ListenSocketNode::RenderJson() { + // We need to track these three json objects to build our object + grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json* json = top_level_json; + grpc_json* json_iterator = nullptr; + // create and fill the ref child + json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr, + GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = grpc_json_add_number_string_child(json, json_iterator, + "socketId", uuid()); + return top_level_json; } } // namespace channelz diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 07eb73d626..88551befc8 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -24,6 +24,7 @@ #include <grpc/grpc.h> #include "src/core/lib/channel/channel_trace.h" +#include "src/core/lib/gprpp/inlined_vector.h" #include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" @@ -39,38 +40,134 @@ #define GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL \ "grpc.channelz_channel_is_internal_channel" +/** This is the default value for whether or not to enable channelz. If + * GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value. */ +#define GRPC_ENABLE_CHANNELZ_DEFAULT true + +/** 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 1024 * 4 + namespace grpc_core { + namespace channelz { +// TODO(ncteisen), this only contains the uuids of the children for now, +// since that is all that is strictly needed. In a future enhancement we will +// add human readable names as in the channelz.proto +typedef InlinedVector<intptr_t, 10> ChildRefsList; + namespace testing { +class CallCountingHelperPeer; class ChannelNodePeer; -} +} // namespace testing -class ChannelNode : public RefCounted<ChannelNode> { +// base class for all channelz entities +class BaseNode : public RefCounted<BaseNode> { public: - static RefCountedPtr<ChannelNode> MakeChannelNode( - grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel); + // There are only four high level channelz entities. However, to support + // GetTopChannelsRequest, we split the Channel entity into two different + // types. All children of BaseNode must be one of these types. + enum class EntityType { + kTopLevelChannel, + kInternalChannel, + kSubchannel, + kServer, + kSocket, + }; - void RecordCallStarted(); - void RecordCallFailed() { - gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1))); - } - void RecordCallSucceeded() { - gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1))); - } + explicit BaseNode(EntityType type); + virtual ~BaseNode(); - grpc_json* RenderJson(); + // All children must implement this function. + virtual grpc_json* RenderJson() GRPC_ABSTRACT; + + // Renders the json and returns allocated string that must be freed by the + // caller. char* RenderJsonString(); - // helper for getting and populating connectivity state. It is virtual - // because it allows the client_channel specific code to live in ext/ - // instead of lib/ - virtual void PopulateConnectivityState(grpc_json* json); + EntityType type() const { return type_; } + intptr_t uuid() const { return uuid_; } + + private: + // to allow the ChannelzRegistry to set uuid_ under its lock. + friend class ChannelzRegistry; + const EntityType type_; + intptr_t uuid_; +}; + +// This class is a helper class for channelz entities that deal with Channels, +// Subchannels, and Servers, since those have similar proto definitions. +// This class has the ability to: +// - track calls_{started,succeeded,failed} +// - track last_call_started_timestamp +// - perform rendering of the above items +class CallCountingHelper { + public: + CallCountingHelper(); + ~CallCountingHelper(); + + void RecordCallStarted(); + void RecordCallFailed(); + void RecordCallSucceeded(); + + // Common rendering of the call count data and last_call_started_timestamp. + void PopulateCallCounts(grpc_json* json); + + private: + // testing peer friend. + friend class testing::CallCountingHelperPeer; + + struct AtomicCounterData { + gpr_atm calls_started = 0; + gpr_atm calls_succeeded = 0; + gpr_atm calls_failed = 0; + gpr_atm last_call_started_millis = 0; + }; - virtual void PopulateChildRefs(grpc_json* json); + struct CounterData { + intptr_t calls_started = 0; + intptr_t calls_succeeded = 0; + intptr_t calls_failed = 0; + intptr_t last_call_started_millis = 0; + }; - ChannelTrace* trace() { return trace_.get(); } + // 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 +class ChannelNode : public BaseNode { + public: + static RefCountedPtr<ChannelNode> MakeChannelNode( + grpc_channel* channel, size_t channel_tracer_max_nodes, + bool is_top_level_channel); + + ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, + bool is_top_level_channel); + ~ChannelNode() override; + + grpc_json* RenderJson() override; + + // template methods. RenderJSON uses these methods to render its JSON + // representation. These are virtual so that children classes may provide + // their specific mechanism for populating these parts of the channelz + // object. + // + // ChannelNode does not have a notion of connectivity state or child refs, + // so it leaves these implementations blank. + // + // This is utilizing the template method design pattern. + // + // TODO(ncteisen): remove these template methods in favor of manual traversal + // and mutation of the grpc_json object. + virtual void PopulateConnectivityState(grpc_json* json) {} + virtual void PopulateChildRefs(grpc_json* json) {} void MarkChannelDestroyed() { GPR_ASSERT(channel_ != nullptr); @@ -79,47 +176,102 @@ class ChannelNode : public RefCounted<ChannelNode> { bool ChannelIsDestroyed() { return channel_ == nullptr; } - intptr_t channel_uuid() { return channel_uuid_; } - bool is_top_level_channel() { return is_top_level_channel_; } - - protected: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW - ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel); - virtual ~ChannelNode(); + // proxy methods to composed classes. + void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) { + trace_.AddTraceEvent(severity, data); + } + void AddTraceEventWithReference(ChannelTrace::Severity severity, + grpc_slice data, + RefCountedPtr<BaseNode> referenced_channel) { + trace_.AddTraceEventWithReference(severity, data, + std::move(referenced_channel)); + } + void RecordCallStarted() { call_counter_.RecordCallStarted(); } + void RecordCallFailed() { call_counter_.RecordCallFailed(); } + void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } private: - // testing peer friend. + // to allow the channel trace test to access trace_. friend class testing::ChannelNodePeer; - grpc_channel* channel_ = nullptr; UniquePtr<char> target_; - gpr_atm calls_started_ = 0; - gpr_atm calls_succeeded_ = 0; - gpr_atm calls_failed_ = 0; - gpr_atm last_call_started_millis_ = 0; - intptr_t channel_uuid_; - bool is_top_level_channel_ = true; - ManualConstructor<ChannelTrace> trace_; + CallCountingHelper call_counter_; + ChannelTrace trace_; }; -// Placeholds channelz class for subchannels. All this can do now is track its -// uuid (this information is needed by the parent channelz class). -// TODO(ncteisen): build this out to support the GetSubchannel channelz request. -class SubchannelNode : public RefCounted<SubchannelNode> { +// Handles channelz bookkeeping for servers +class ServerNode : public BaseNode { public: - SubchannelNode(); - virtual ~SubchannelNode(); + ServerNode(grpc_server* server, size_t channel_tracer_max_nodes); + ~ServerNode() override; - intptr_t subchannel_uuid() { return subchannel_uuid_; } + grpc_json* RenderJson() override; - protected: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW + char* RenderServerSockets(intptr_t start_socket_id); + + // proxy methods to composed classes. + void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) { + trace_.AddTraceEvent(severity, data); + } + void AddTraceEventWithReference(ChannelTrace::Severity severity, + grpc_slice data, + RefCountedPtr<BaseNode> referenced_channel) { + trace_.AddTraceEventWithReference(severity, data, + std::move(referenced_channel)); + } + void RecordCallStarted() { call_counter_.RecordCallStarted(); } + void RecordCallFailed() { call_counter_.RecordCallFailed(); } + void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } private: - intptr_t subchannel_uuid_; + grpc_server* server_; + CallCountingHelper call_counter_; + ChannelTrace trace_; +}; + +// Handles channelz bookkeeping for sockets +class SocketNode : public BaseNode { + public: + SocketNode(); + ~SocketNode() override {} + + grpc_json* RenderJson() override; + + void RecordStreamStartedFromLocal(); + void RecordStreamStartedFromRemote(); + void RecordStreamSucceeded() { + gpr_atm_no_barrier_fetch_add(&streams_succeeded_, static_cast<gpr_atm>(1)); + } + void RecordStreamFailed() { + gpr_atm_no_barrier_fetch_add(&streams_failed_, static_cast<gpr_atm>(1)); + } + void RecordMessagesSent(uint32_t num_sent); + void RecordMessageReceived(); + void RecordKeepaliveSent() { + gpr_atm_no_barrier_fetch_add(&keepalives_sent_, static_cast<gpr_atm>(1)); + } + + private: + gpr_atm streams_started_ = 0; + gpr_atm streams_succeeded_ = 0; + gpr_atm streams_failed_ = 0; + gpr_atm messages_sent_ = 0; + gpr_atm messages_received_ = 0; + gpr_atm keepalives_sent_ = 0; + gpr_atm last_local_stream_created_millis_ = 0; + gpr_atm last_remote_stream_created_millis_ = 0; + gpr_atm last_message_sent_millis_ = 0; + gpr_atm last_message_received_millis_ = 0; + UniquePtr<char> peer_string_; +}; + +// Handles channelz bookkeeping for listen sockets +class ListenSocketNode : public BaseNode { + public: + ListenSocketNode(); + ~ListenSocketNode() override {} + + grpc_json* RenderJson() override; }; // Creation functions diff --git a/src/core/lib/channel/channelz_registry.cc b/src/core/lib/channel/channelz_registry.cc index 38496b3d78..e90a9e1f7f 100644 --- a/src/core/lib/channel/channelz_registry.cc +++ b/src/core/lib/channel/channelz_registry.cc @@ -23,6 +23,7 @@ #include "src/core/lib/channel/channelz_registry.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/gprpp/mutex_lock.h" #include <grpc/support/alloc.h> #include <grpc/support/log.h> @@ -37,6 +38,8 @@ namespace { // singleton instance of the registry. ChannelzRegistry* g_channelz_registry = nullptr; +const int kPaginationLimit = 100; + } // anonymous namespace void ChannelzRegistry::Init() { g_channelz_registry = New<ChannelzRegistry>(); } @@ -52,54 +55,103 @@ ChannelzRegistry::ChannelzRegistry() { gpr_mu_init(&mu_); } ChannelzRegistry::~ChannelzRegistry() { gpr_mu_destroy(&mu_); } -intptr_t ChannelzRegistry::InternalRegisterEntry(const RegistryEntry& entry) { - mu_guard guard(&mu_); - entities_.push_back(entry); - intptr_t uuid = entities_.size(); - return uuid; +void ChannelzRegistry::InternalRegister(BaseNode* node) { + MutexLock lock(&mu_); + entities_.push_back(node); + node->uuid_ = ++uuid_generator_; } -void ChannelzRegistry::InternalUnregisterEntry(intptr_t uuid, EntityType type) { - GPR_ASSERT(uuid >= 1); - mu_guard guard(&mu_); - GPR_ASSERT(static_cast<size_t>(uuid) <= entities_.size()); - GPR_ASSERT(entities_[uuid - 1].type == type); - entities_[uuid - 1].object = nullptr; - entities_[uuid - 1].type = EntityType::kUnset; +void ChannelzRegistry::MaybePerformCompactionLocked() { + constexpr double kEmptinessTheshold = 1 / 3; + double emptiness_ratio = + double(num_empty_slots_) / double(entities_.capacity()); + if (emptiness_ratio > kEmptinessTheshold) { + int front = 0; + for (size_t i = 0; i < entities_.size(); ++i) { + if (entities_[i] != nullptr) { + entities_[front++] = entities_[i]; + } + } + for (int i = 0; i < num_empty_slots_; ++i) { + entities_.pop_back(); + } + num_empty_slots_ = 0; + } } -void* ChannelzRegistry::InternalGetEntry(intptr_t uuid, EntityType type) { - mu_guard guard(&mu_); - if (uuid < 1 || uuid > static_cast<intptr_t>(entities_.size())) { - return nullptr; +int ChannelzRegistry::FindByUuidLocked(intptr_t target_uuid) { + size_t left = 0; + size_t right = entities_.size() - 1; + while (left <= right) { + size_t true_middle = left + (right - left) / 2; + size_t first_non_null = true_middle; + while (first_non_null < right && entities_[first_non_null] == nullptr) { + first_non_null++; + } + if (entities_[first_non_null] == nullptr) { + right = true_middle - 1; + continue; + } + intptr_t uuid = entities_[first_non_null]->uuid(); + if (uuid == target_uuid) { + return int(first_non_null); + } + if (uuid < target_uuid) { + left = first_non_null + 1; + } else { + right = true_middle - 1; + } } - if (entities_[uuid - 1].type == type) { - return entities_[uuid - 1].object; - } else { + return -1; +} + +void ChannelzRegistry::InternalUnregister(intptr_t uuid) { + GPR_ASSERT(uuid >= 1); + MutexLock lock(&mu_); + GPR_ASSERT(uuid <= uuid_generator_); + int idx = FindByUuidLocked(uuid); + GPR_ASSERT(idx >= 0); + entities_[idx] = nullptr; + num_empty_slots_++; + MaybePerformCompactionLocked(); +} + +BaseNode* ChannelzRegistry::InternalGet(intptr_t uuid) { + MutexLock lock(&mu_); + if (uuid < 1 || uuid > uuid_generator_) { return nullptr; } + int idx = FindByUuidLocked(uuid); + return idx < 0 ? nullptr : entities_[idx]; } char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) { + MutexLock lock(&mu_); grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; grpc_json* json_iterator = nullptr; - InlinedVector<ChannelNode*, 10> top_level_channels; + InlinedVector<BaseNode*, 10> top_level_channels; // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is // reserved). However, we want to support requests coming in with // start_channel_id=0, which signifies "give me everything." Hence this // funky looking line below. size_t start_idx = start_channel_id == 0 ? 0 : start_channel_id - 1; + bool reached_pagination_limit = false; for (size_t i = start_idx; i < entities_.size(); ++i) { - if (entities_[i].type == EntityType::kChannelNode) { - ChannelNode* channel_node = - static_cast<ChannelNode*>(entities_[i].object); - if (channel_node->is_top_level_channel()) { - top_level_channels.push_back(channel_node); + if (entities_[i] != nullptr && + entities_[i]->type() == + grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel) { + // check if we are over pagination limit to determine if we need to set + // the "end" element. If we don't go through this block, we know that + // when the loop terminates, we have <= to kPaginationLimit. + if (top_level_channels.size() == kPaginationLimit) { + reached_pagination_limit = true; + break; } + top_level_channels.push_back(entities_[i]); } } - if (top_level_channels.size() > 0) { + if (!top_level_channels.empty()) { // create list of channels grpc_json* array_parent = grpc_json_create_child( nullptr, json, "channel", nullptr, GRPC_JSON_ARRAY, false); @@ -109,11 +161,54 @@ char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) { grpc_json_link_child(array_parent, channel_json, json_iterator); } } - // For now we do not have any pagination rules. In the future we could - // pick a constant for max_channels_sent for a GetTopChannels request. - // Tracking: https://github.com/grpc/grpc/issues/16019. - json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr, - GRPC_JSON_TRUE, false); + if (!reached_pagination_limit) { + grpc_json_create_child(nullptr, json, "end", nullptr, GRPC_JSON_TRUE, + false); + } + char* json_str = grpc_json_dump_to_string(top_level_json, 0); + grpc_json_destroy(top_level_json); + return json_str; +} + +char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) { + MutexLock lock(&mu_); + grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json* json = top_level_json; + grpc_json* json_iterator = nullptr; + InlinedVector<BaseNode*, 10> servers; + // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is + // reserved). However, we want to support requests coming in with + // start_server_id=0, which signifies "give me everything." + size_t start_idx = start_server_id == 0 ? 0 : start_server_id - 1; + bool reached_pagination_limit = false; + for (size_t i = start_idx; i < entities_.size(); ++i) { + if (entities_[i] != nullptr && + entities_[i]->type() == + grpc_core::channelz::BaseNode::EntityType::kServer) { + // check if we are over pagination limit to determine if we need to set + // the "end" element. If we don't go through this block, we know that + // when the loop terminates, we have <= to kPaginationLimit. + if (servers.size() == kPaginationLimit) { + reached_pagination_limit = true; + break; + } + servers.push_back(entities_[i]); + } + } + if (!servers.empty()) { + // create list of servers + grpc_json* array_parent = grpc_json_create_child( + nullptr, json, "server", nullptr, GRPC_JSON_ARRAY, false); + for (size_t i = 0; i < servers.size(); ++i) { + grpc_json* server_json = servers[i]->RenderJson(); + json_iterator = + grpc_json_link_child(array_parent, server_json, json_iterator); + } + } + if (!reached_pagination_limit) { + grpc_json_create_child(nullptr, json, "end", nullptr, GRPC_JSON_TRUE, + false); + } char* json_str = grpc_json_dump_to_string(top_level_json, 0); grpc_json_destroy(top_level_json); return json_str; @@ -127,10 +222,33 @@ char* grpc_channelz_get_top_channels(intptr_t start_channel_id) { start_channel_id); } +char* grpc_channelz_get_servers(intptr_t start_server_id) { + return grpc_core::channelz::ChannelzRegistry::GetServers(start_server_id); +} + +char* grpc_channelz_get_server_sockets(intptr_t server_id, + intptr_t start_socket_id) { + grpc_core::channelz::BaseNode* base_node = + grpc_core::channelz::ChannelzRegistry::Get(server_id); + if (base_node == nullptr || + base_node->type() != grpc_core::channelz::BaseNode::EntityType::kServer) { + return nullptr; + } + // This cast is ok since we have just checked to make sure base_node is + // actually a server node + grpc_core::channelz::ServerNode* server_node = + static_cast<grpc_core::channelz::ServerNode*>(base_node); + return server_node->RenderServerSockets(start_socket_id); +} + char* grpc_channelz_get_channel(intptr_t channel_id) { - grpc_core::channelz::ChannelNode* channel_node = - grpc_core::channelz::ChannelzRegistry::GetChannelNode(channel_id); - if (channel_node == nullptr) { + grpc_core::channelz::BaseNode* channel_node = + grpc_core::channelz::ChannelzRegistry::Get(channel_id); + if (channel_node == nullptr || + (channel_node->type() != + grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel && + channel_node->type() != + grpc_core::channelz::BaseNode::EntityType::kInternalChannel)) { return nullptr; } grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); @@ -142,3 +260,39 @@ char* grpc_channelz_get_channel(intptr_t channel_id) { grpc_json_destroy(top_level_json); return json_str; } + +char* grpc_channelz_get_subchannel(intptr_t subchannel_id) { + grpc_core::channelz::BaseNode* subchannel_node = + grpc_core::channelz::ChannelzRegistry::Get(subchannel_id); + if (subchannel_node == nullptr || + subchannel_node->type() != + grpc_core::channelz::BaseNode::EntityType::kSubchannel) { + return nullptr; + } + grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json* json = top_level_json; + grpc_json* subchannel_json = subchannel_node->RenderJson(); + subchannel_json->key = "subchannel"; + grpc_json_link_child(json, subchannel_json, nullptr); + char* json_str = grpc_json_dump_to_string(top_level_json, 0); + grpc_json_destroy(top_level_json); + return json_str; +} + +char* grpc_channelz_get_socket(intptr_t socket_id) { + grpc_core::channelz::BaseNode* socket_node = + grpc_core::channelz::ChannelzRegistry::Get(socket_id); + if (socket_node == nullptr || + socket_node->type() != + grpc_core::channelz::BaseNode::EntityType::kSocket) { + return nullptr; + } + grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json* json = top_level_json; + grpc_json* socket_json = socket_node->RenderJson(); + socket_json->key = "socket"; + grpc_json_link_child(json, socket_json, nullptr); + char* json_str = grpc_json_dump_to_string(top_level_json, 0); + grpc_json_destroy(top_level_json); + return json_str; +} diff --git a/src/core/lib/channel/channelz_registry.h b/src/core/lib/channel/channelz_registry.h index 5d7c936726..ea6ab6c8e5 100644 --- a/src/core/lib/channel/channelz_registry.h +++ b/src/core/lib/channel/channelz_registry.h @@ -30,6 +30,10 @@ namespace grpc_core { namespace channelz { +namespace testing { +class ChannelzRegistryPeer; +} + // singleton registry object to track all objects that are needed to support // channelz bookkeeping. All objects share globally distributed uuids. class ChannelzRegistry { @@ -40,32 +44,11 @@ class ChannelzRegistry { // To be called in grpc_shutdown(); static void Shutdown(); - // Register/Unregister/Get for ChannelNode - static intptr_t RegisterChannelNode(ChannelNode* channel_node) { - RegistryEntry entry(channel_node, EntityType::kChannelNode); - return Default()->InternalRegisterEntry(entry); - } - static void UnregisterChannelNode(intptr_t uuid) { - Default()->InternalUnregisterEntry(uuid, EntityType::kChannelNode); - } - static ChannelNode* GetChannelNode(intptr_t uuid) { - void* gotten = Default()->InternalGetEntry(uuid, EntityType::kChannelNode); - return gotten == nullptr ? nullptr : static_cast<ChannelNode*>(gotten); - } - - // Register/Unregister/Get for SubchannelNode - static intptr_t RegisterSubchannelNode(SubchannelNode* channel_node) { - RegistryEntry entry(channel_node, EntityType::kSubchannelNode); - return Default()->InternalRegisterEntry(entry); - } - static void UnregisterSubchannelNode(intptr_t uuid) { - Default()->InternalUnregisterEntry(uuid, EntityType::kSubchannelNode); - } - static SubchannelNode* GetSubchannelNode(intptr_t uuid) { - void* gotten = - Default()->InternalGetEntry(uuid, EntityType::kSubchannelNode); - return gotten == nullptr ? nullptr : static_cast<SubchannelNode*>(gotten); + static void Register(BaseNode* node) { + return Default()->InternalRegister(node); } + static void Unregister(intptr_t uuid) { Default()->InternalUnregister(uuid); } + static BaseNode* Get(intptr_t uuid) { return Default()->InternalGet(uuid); } // Returns the allocated JSON string that represents the proto // GetTopChannelsResponse as per channelz.proto. @@ -73,22 +56,16 @@ class ChannelzRegistry { return Default()->InternalGetTopChannels(start_channel_id); } - private: - enum class EntityType { - kChannelNode, - kSubchannelNode, - kUnset, - }; - - struct RegistryEntry { - RegistryEntry(void* object_in, EntityType type_in) - : object(object_in), type(type_in) {} - void* object; - EntityType type; - }; + // Returns the allocated JSON string that represents the proto + // GetServersResponse as per channelz.proto. + static char* GetServers(intptr_t start_server_id) { + return Default()->InternalGetServers(start_server_id); + } + private: GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE + friend class testing::ChannelzRegistryPeer; ChannelzRegistry(); ~ChannelzRegistry(); @@ -97,21 +74,31 @@ class ChannelzRegistry { static ChannelzRegistry* Default(); // globally registers an Entry. Returns its unique uuid - intptr_t InternalRegisterEntry(const RegistryEntry& entry); + void InternalRegister(BaseNode* node); // globally unregisters the object that is associated to uuid. Also does // sanity check that an object doesn't try to unregister the wrong type. - void InternalUnregisterEntry(intptr_t uuid, EntityType type); + void InternalUnregister(intptr_t uuid); // if object with uuid has previously been registered as the correct type, // returns the void* associated with that uuid. Else returns nullptr. - void* InternalGetEntry(intptr_t uuid, EntityType type); + BaseNode* InternalGet(intptr_t uuid); char* InternalGetTopChannels(intptr_t start_channel_id); + char* InternalGetServers(intptr_t start_server_id); + + // If entities_ has over a certain threshold of empty slots, it will + // compact the vector and move all used slots to the front. + void MaybePerformCompactionLocked(); + + // Performs binary search on entities_ to find the index with that uuid. + int FindByUuidLocked(intptr_t uuid); - // protects entities_ and uuid_ + // protects members gpr_mu mu_; - InlinedVector<RegistryEntry, 20> entities_; + InlinedVector<BaseNode*, 20> entities_; + intptr_t uuid_generator_ = 0; + int num_empty_slots_ = 0; }; } // namespace channelz diff --git a/src/core/lib/channel/connected_channel.cc b/src/core/lib/channel/connected_channel.cc index c78849a29b..e2ea334ded 100644 --- a/src/core/lib/channel/connected_channel.cc +++ b/src/core/lib/channel/connected_channel.cc @@ -228,8 +228,8 @@ static void bind_transport(grpc_channel_stack* channel_stack, grpc_transport_stream_size(static_cast<grpc_transport*>(t)); } -bool grpc_append_connected_filter(grpc_channel_stack_builder* builder, - void* arg_must_be_null) { +bool grpc_add_connected_filter(grpc_channel_stack_builder* builder, + void* arg_must_be_null) { GPR_ASSERT(arg_must_be_null == nullptr); grpc_transport* t = grpc_channel_stack_builder_get_transport(builder); GPR_ASSERT(t != nullptr); diff --git a/src/core/lib/channel/connected_channel.h b/src/core/lib/channel/connected_channel.h index 280daf040d..faa1c73a21 100644 --- a/src/core/lib/channel/connected_channel.h +++ b/src/core/lib/channel/connected_channel.h @@ -25,8 +25,8 @@ extern const grpc_channel_filter grpc_connected_filter; -bool grpc_append_connected_filter(grpc_channel_stack_builder* builder, - void* arg_must_be_null); +bool grpc_add_connected_filter(grpc_channel_stack_builder* builder, + void* arg_must_be_null); /* Debug helper to dig the transport stream out of a call element */ grpc_stream* grpc_connected_channel_get_stream(grpc_call_element* elem); diff --git a/src/core/lib/channel/handshaker_factory.cc b/src/core/lib/channel/handshaker_factory.cc index 4fd43635b6..8ade8fe4e2 100644 --- a/src/core/lib/channel/handshaker_factory.cc +++ b/src/core/lib/channel/handshaker_factory.cc @@ -24,11 +24,12 @@ 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, - handshake_mgr); + handshaker_factory->vtable->add_handshakers( + handshaker_factory, args, interested_parties, handshake_mgr); } } diff --git a/src/core/lib/channel/handshaker_factory.h b/src/core/lib/channel/handshaker_factory.h index 3e45fcf20e..e17a678179 100644 --- a/src/core/lib/channel/handshaker_factory.h +++ b/src/core/lib/channel/handshaker_factory.h @@ -32,6 +32,7 @@ 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; @@ -42,6 +43,7 @@ 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 eec3e1b352..fbafc43e79 100644 --- a/src/core/lib/channel/handshaker_registry.cc +++ b/src/core/lib/channel/handshaker_registry.cc @@ -51,9 +51,11 @@ 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, handshake_mgr); + grpc_handshaker_factory_add_handshakers(list->list[i], args, + interested_parties, handshake_mgr); } } @@ -91,7 +93,9 @@ 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, handshake_mgr); + &g_handshaker_factory_lists[handshaker_type], args, interested_parties, + handshake_mgr); } diff --git a/src/core/lib/channel/handshaker_registry.h b/src/core/lib/channel/handshaker_registry.h index 82ad9c5b9a..3dd4316de6 100644 --- a/src/core/lib/channel/handshaker_registry.h +++ b/src/core/lib/channel/handshaker_registry.h @@ -43,6 +43,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); #endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H */ diff --git a/src/core/lib/gpr/arena.cc b/src/core/lib/gpr/arena.cc index e30b297aea..77f9357146 100644 --- a/src/core/lib/gpr/arena.cc +++ b/src/core/lib/gpr/arena.cc @@ -77,16 +77,16 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) { // would allow us to use the alignment actually needed by the caller. typedef struct zone { - size_t size_begin; // All the space we have set aside for allocations up - // until this zone. - size_t size_end; // size_end = size_begin plus all the space we set aside for - // allocations in zone z itself. zone* next; } zone; struct gpr_arena { - gpr_atm size_so_far; + // Keep track of the total used size. We use this in our call sizing + // historesis. + gpr_atm total_used; + size_t initial_zone_size; zone initial_zone; + zone* last_zone; gpr_mu arena_growth_mutex; }; @@ -100,14 +100,15 @@ gpr_arena* gpr_arena_create(size_t initial_size) { initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size); gpr_arena* a = static_cast<gpr_arena*>(zalloc_aligned( GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size)); - a->initial_zone.size_end = initial_size; + a->initial_zone_size = initial_size; + a->last_zone = &a->initial_zone; gpr_mu_init(&a->arena_growth_mutex); return a; } size_t gpr_arena_destroy(gpr_arena* arena) { gpr_mu_destroy(&arena->arena_growth_mutex); - gpr_atm size = gpr_atm_no_barrier_load(&arena->size_so_far); + gpr_atm size = gpr_atm_no_barrier_load(&arena->total_used); zone* z = arena->initial_zone.next; gpr_free_aligned(arena); while (z) { @@ -120,55 +121,25 @@ size_t gpr_arena_destroy(gpr_arena* arena) { void* gpr_arena_alloc(gpr_arena* arena, size_t size) { size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(size); - size_t previous_size_of_arena_allocations = static_cast<size_t>( - gpr_atm_no_barrier_fetch_add(&arena->size_so_far, size)); - size_t updated_size_of_arena_allocations = - previous_size_of_arena_allocations + size; - zone* z = &arena->initial_zone; - // Check to see if the allocation isn't able to end in the initial zone. - // This statement is true only in the uncommon case because of our arena - // sizing historesis (that is, most calls should have a large enough initial - // zone and will not need to grow the arena). - if (updated_size_of_arena_allocations > z->size_end) { - // Find a zone to fit this allocation + size_t begin = gpr_atm_no_barrier_fetch_add(&arena->total_used, size); + if (begin + size <= arena->initial_zone_size) { + return reinterpret_cast<char*>(arena) + + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + begin; + } else { + // If the allocation isn't able to end in the initial zone, create a new + // zone for this allocation, and any unused space in the initial zone is + // wasted. This overflowing and wasting is uncommon because of our arena + // sizing historesis (that is, most calls should have a large enough initial + // zone and will not need to grow the arena). gpr_mu_lock(&arena->arena_growth_mutex); - while (updated_size_of_arena_allocations > z->size_end) { - if (z->next == nullptr) { - // Note that we do an extra increment of size_so_far to prevent multiple - // simultaneous callers from stepping on each other. However, this extra - // increment means some space in the arena is wasted. - // So whenever we need to allocate x bytes and there are x - n (where - // n > 0) remaining in the current zone, we will waste x bytes (x - n - // in the current zone and n in the new zone). - previous_size_of_arena_allocations = static_cast<size_t>( - gpr_atm_no_barrier_fetch_add(&arena->size_so_far, size)); - updated_size_of_arena_allocations = - previous_size_of_arena_allocations + size; - size_t next_z_size = updated_size_of_arena_allocations; - z->next = static_cast<zone*>(zalloc_aligned( - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + next_z_size)); - z->next->size_begin = z->size_end; - z->next->size_end = z->size_end + next_z_size; - } - z = z->next; - } + zone* z = static_cast<zone*>( + zalloc_aligned(GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + size)); + arena->last_zone->next = z; + arena->last_zone = z; gpr_mu_unlock(&arena->arena_growth_mutex); + return reinterpret_cast<char*>(z) + + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)); } - GPR_ASSERT(previous_size_of_arena_allocations >= z->size_begin); - GPR_ASSERT(updated_size_of_arena_allocations <= z->size_end); - // Skip the first part of the zone, which just contains tracking information. - // For the initial zone, this is the gpr_arena struct and for any other zone, - // it's the zone struct. - char* start_of_allocation_space = - (z == &arena->initial_zone) - ? reinterpret_cast<char*>(arena) + - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) - : reinterpret_cast<char*>(z) + - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)); - // previous_size_of_arena_allocations - size_begin is how many bytes have been - // allocated into the current zone - return start_of_allocation_space + previous_size_of_arena_allocations - - z->size_begin; } #endif // SIMPLE_ARENA_FOR_DEBUGGING 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/gprpp/fork.cc b/src/core/lib/gprpp/fork.cc index f6d9a87d2c..3b9c16510a 100644 --- a/src/core/lib/gprpp/fork.cc +++ b/src/core/lib/gprpp/fork.cc @@ -157,11 +157,11 @@ class ThreadState { } // namespace void Fork::GlobalInit() { - if (!overrideEnabled_) { + if (!override_enabled_) { #ifdef GRPC_ENABLE_FORK_SUPPORT - supportEnabled_ = true; + support_enabled_ = true; #else - supportEnabled_ = false; + support_enabled_ = false; #endif bool env_var_set = false; char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT"); @@ -172,7 +172,7 @@ void Fork::GlobalInit() { "False", "FALSE", "0"}; for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) { if (0 == strcmp(env, truthy[i])) { - supportEnabled_ = true; + support_enabled_ = true; env_var_set = true; break; } @@ -180,7 +180,7 @@ void Fork::GlobalInit() { if (!env_var_set) { for (size_t i = 0; i < GPR_ARRAY_SIZE(falsey); i++) { if (0 == strcmp(env, falsey[i])) { - supportEnabled_ = false; + support_enabled_ = false; env_var_set = true; break; } @@ -189,72 +189,80 @@ void Fork::GlobalInit() { gpr_free(env); } } - if (supportEnabled_) { - execCtxState_ = grpc_core::New<internal::ExecCtxState>(); - threadState_ = grpc_core::New<internal::ThreadState>(); + if (support_enabled_) { + exec_ctx_state_ = grpc_core::New<internal::ExecCtxState>(); + thread_state_ = grpc_core::New<internal::ThreadState>(); } } void Fork::GlobalShutdown() { - if (supportEnabled_) { - grpc_core::Delete(execCtxState_); - grpc_core::Delete(threadState_); + if (support_enabled_) { + grpc_core::Delete(exec_ctx_state_); + grpc_core::Delete(thread_state_); } } -bool Fork::Enabled() { return supportEnabled_; } +bool Fork::Enabled() { return support_enabled_; } // Testing Only void Fork::Enable(bool enable) { - overrideEnabled_ = true; - supportEnabled_ = enable; + override_enabled_ = true; + support_enabled_ = enable; } void Fork::IncExecCtxCount() { - if (supportEnabled_) { - execCtxState_->IncExecCtxCount(); + if (support_enabled_) { + exec_ctx_state_->IncExecCtxCount(); } } void Fork::DecExecCtxCount() { - if (supportEnabled_) { - execCtxState_->DecExecCtxCount(); + if (support_enabled_) { + exec_ctx_state_->DecExecCtxCount(); } } +void Fork::SetResetChildPollingEngineFunc( + Fork::child_postfork_func reset_child_polling_engine) { + reset_child_polling_engine_ = reset_child_polling_engine; +} +Fork::child_postfork_func Fork::GetResetChildPollingEngineFunc() { + return reset_child_polling_engine_; +} + bool Fork::BlockExecCtx() { - if (supportEnabled_) { - return execCtxState_->BlockExecCtx(); + if (support_enabled_) { + return exec_ctx_state_->BlockExecCtx(); } return false; } void Fork::AllowExecCtx() { - if (supportEnabled_) { - execCtxState_->AllowExecCtx(); + if (support_enabled_) { + exec_ctx_state_->AllowExecCtx(); } } void Fork::IncThreadCount() { - if (supportEnabled_) { - threadState_->IncThreadCount(); + if (support_enabled_) { + thread_state_->IncThreadCount(); } } void Fork::DecThreadCount() { - if (supportEnabled_) { - threadState_->DecThreadCount(); + if (support_enabled_) { + thread_state_->DecThreadCount(); } } void Fork::AwaitThreads() { - if (supportEnabled_) { - threadState_->AwaitThreads(); + if (support_enabled_) { + thread_state_->AwaitThreads(); } } -internal::ExecCtxState* Fork::execCtxState_ = nullptr; -internal::ThreadState* Fork::threadState_ = nullptr; -bool Fork::supportEnabled_ = false; -bool Fork::overrideEnabled_ = false; - +internal::ExecCtxState* Fork::exec_ctx_state_ = nullptr; +internal::ThreadState* Fork::thread_state_ = nullptr; +bool Fork::support_enabled_ = false; +bool Fork::override_enabled_ = false; +Fork::child_postfork_func Fork::reset_child_polling_engine_ = nullptr; } // namespace grpc_core diff --git a/src/core/lib/gprpp/fork.h b/src/core/lib/gprpp/fork.h index 123e22c4c6..5a7404f0d9 100644 --- a/src/core/lib/gprpp/fork.h +++ b/src/core/lib/gprpp/fork.h @@ -33,6 +33,8 @@ class ThreadState; class Fork { public: + typedef void (*child_postfork_func)(void); + static void GlobalInit(); static void GlobalShutdown(); @@ -46,6 +48,12 @@ class Fork { // Decrement the count of active ExecCtxs static void DecExecCtxCount(); + // Provide a function that will be invoked in the child's postfork handler to + // reset the polling engine's internal state. + static void SetResetChildPollingEngineFunc( + child_postfork_func reset_child_polling_engine); + static child_postfork_func GetResetChildPollingEngineFunc(); + // Check if there is a single active ExecCtx // (the one used to invoke this function). If there are more, // return false. Otherwise, return true and block creation of @@ -68,10 +76,11 @@ class Fork { static void Enable(bool enable); private: - static internal::ExecCtxState* execCtxState_; - static internal::ThreadState* threadState_; - static bool supportEnabled_; - static bool overrideEnabled_; + static internal::ExecCtxState* exec_ctx_state_; + static internal::ThreadState* thread_state_; + static bool support_enabled_; + static bool override_enabled_; + static child_postfork_func reset_child_polling_engine_; }; } // namespace grpc_core diff --git a/src/core/lib/gprpp/inlined_vector.h b/src/core/lib/gprpp/inlined_vector.h index 76e2f0a785..65c2b9634f 100644 --- a/src/core/lib/gprpp/inlined_vector.h +++ b/src/core/lib/gprpp/inlined_vector.h @@ -123,6 +123,14 @@ class InlinedVector { void push_back(T&& value) { emplace_back(std::move(value)); } + void pop_back() { + assert(!empty()); + size_t s = size(); + T& value = data()[s - 1]; + value.~T(); + size_--; + } + void copy_from(const InlinedVector& v) { // if v is allocated, copy over the buffer. if (v.dynamic_ != nullptr) { diff --git a/src/core/lib/gprpp/mutex_lock.h b/src/core/lib/gprpp/mutex_lock.h new file mode 100644 index 0000000000..54751d5fe4 --- /dev/null +++ b/src/core/lib/gprpp/mutex_lock.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_GPRPP_MUTEX_LOCK_H +#define GRPC_CORE_LIB_GPRPP_MUTEX_LOCK_H + +#include <grpc/support/port_platform.h> + +#include <grpc/support/sync.h> + +namespace grpc_core { + +class MutexLock { + public: + explicit MutexLock(gpr_mu* mu) : mu_(mu) { gpr_mu_lock(mu); } + ~MutexLock() { gpr_mu_unlock(mu_); } + + MutexLock(const MutexLock&) = delete; + MutexLock& operator=(const MutexLock&) = delete; + + private: + gpr_mu* const mu_; +}; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_GPRPP_MUTEX_LOCK_H */ diff --git a/src/core/lib/http/httpcli.cc b/src/core/lib/http/httpcli.cc index 12060074c5..3bd7a2ce59 100644 --- a/src/core/lib/http/httpcli.cc +++ b/src/core/lib/http/httpcli.cc @@ -163,7 +163,7 @@ static void done_write(void* arg, grpc_error* error) { static void start_write(internal_request* req) { grpc_slice_ref_internal(req->request_text); grpc_slice_buffer_add(&req->outgoing, req->request_text); - grpc_endpoint_write(req->ep, &req->outgoing, &req->done_write); + grpc_endpoint_write(req->ep, &req->outgoing, &req->done_write, nullptr); } static void on_handshake_done(void* arg, grpc_endpoint* ep) { diff --git a/src/core/lib/http/httpcli_security_connector.cc b/src/core/lib/http/httpcli_security_connector.cc index 50078c37a1..5a5e0b72d5 100644 --- a/src/core/lib/http/httpcli_security_connector.cc +++ b/src/core/lib/http/httpcli_security_connector.cc @@ -29,6 +29,7 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker_registry.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/security/transport/security_handshaker.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/tsi/ssl_transport_security.h" @@ -51,6 +52,7 @@ static void httpcli_ssl_destroy(grpc_security_connector* sc) { } static void httpcli_ssl_add_handshakers(grpc_channel_security_connector* sc, + grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_httpcli_ssl_channel_security_connector* c = reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc); @@ -189,7 +191,8 @@ 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, c->handshake_mgr); + grpc_handshakers_add(HANDSHAKER_CLIENT, &args, + nullptr /* interested_parties */, 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/buffer_list.cc b/src/core/lib/iomgr/buffer_list.cc new file mode 100644 index 0000000000..6ada23db1c --- /dev/null +++ b/src/core/lib/iomgr/buffer_list.cc @@ -0,0 +1,134 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/support/port_platform.h> + +#include "src/core/lib/iomgr/buffer_list.h" +#include "src/core/lib/iomgr/port.h" + +#include <grpc/support/log.h> + +#ifdef GRPC_LINUX_ERRQUEUE +#include <time.h> + +#include "src/core/lib/gprpp/memory.h" + +namespace grpc_core { +void TracedBuffer::AddNewEntry(TracedBuffer** head, uint32_t seq_no, + void* arg) { + GPR_DEBUG_ASSERT(head != nullptr); + TracedBuffer* new_elem = New<TracedBuffer>(seq_no, arg); + /* Store the current time as the sendmsg time. */ + new_elem->ts_.sendmsg_time = gpr_now(GPR_CLOCK_REALTIME); + if (*head == nullptr) { + *head = new_elem; + return; + } + /* Append at the end. */ + TracedBuffer* ptr = *head; + while (ptr->next_ != nullptr) { + ptr = ptr->next_; + } + ptr->next_ = new_elem; +} + +namespace { +/** Fills gpr_timespec gts based on values from timespec ts */ +void fill_gpr_from_timestamp(gpr_timespec* gts, const struct timespec* ts) { + gts->tv_sec = ts->tv_sec; + gts->tv_nsec = static_cast<int32_t>(ts->tv_nsec); + gts->clock_type = GPR_CLOCK_REALTIME; +} + +/** The saved callback function that will be invoked when we get all the + * timestamps that we are going to get for a TracedBuffer. */ +void (*timestamps_callback)(void*, grpc_core::Timestamps*, + grpc_error* shutdown_err); +} /* namespace */ + +void TracedBuffer::ProcessTimestamp(TracedBuffer** head, + struct sock_extended_err* serr, + struct scm_timestamping* tss) { + GPR_DEBUG_ASSERT(head != nullptr); + TracedBuffer* elem = *head; + TracedBuffer* next = nullptr; + while (elem != nullptr) { + /* The byte number refers to the sequence number of the last byte which this + * timestamp relates to. */ + if (serr->ee_data >= elem->seq_no_) { + switch (serr->ee_info) { + case SCM_TSTAMP_SCHED: + fill_gpr_from_timestamp(&(elem->ts_.scheduled_time), &(tss->ts[0])); + elem = elem->next_; + break; + case SCM_TSTAMP_SND: + fill_gpr_from_timestamp(&(elem->ts_.sent_time), &(tss->ts[0])); + elem = elem->next_; + break; + case SCM_TSTAMP_ACK: + fill_gpr_from_timestamp(&(elem->ts_.acked_time), &(tss->ts[0])); + /* Got all timestamps. Do the callback and free this TracedBuffer. + * The thing below can be passed by value if we don't want the + * restriction on the lifetime. */ + timestamps_callback(elem->arg_, &(elem->ts_), GRPC_ERROR_NONE); + next = elem->next_; + Delete<TracedBuffer>(elem); + *head = elem = next; + break; + default: + abort(); + } + } else { + break; + } + } +} + +void TracedBuffer::Shutdown(TracedBuffer** head, grpc_error* shutdown_err) { + GPR_DEBUG_ASSERT(head != nullptr); + TracedBuffer* elem = *head; + while (elem != nullptr) { + if (timestamps_callback) { + timestamps_callback(elem->arg_, &(elem->ts_), shutdown_err); + } + auto* next = elem->next_; + Delete<TracedBuffer>(elem); + elem = next; + } + *head = nullptr; + GRPC_ERROR_UNREF(shutdown_err); +} + +void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*, + grpc_core::Timestamps*, + grpc_error* error)) { + timestamps_callback = fn; +} +} /* namespace grpc_core */ + +#else /* GRPC_LINUX_ERRQUEUE */ + +namespace grpc_core { +void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*, + grpc_core::Timestamps*, + grpc_error* error)) { + gpr_log(GPR_DEBUG, "Timestamps callback is not enabled for this platform"); +} +} /* namespace grpc_core */ + +#endif /* GRPC_LINUX_ERRQUEUE */ diff --git a/src/core/lib/iomgr/buffer_list.h b/src/core/lib/iomgr/buffer_list.h new file mode 100644 index 0000000000..cbbf50a657 --- /dev/null +++ b/src/core/lib/iomgr/buffer_list.h @@ -0,0 +1,96 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_IOMGR_BUFFER_LIST_H +#define GRPC_CORE_LIB_IOMGR_BUFFER_LIST_H + +#include <grpc/support/port_platform.h> + +#include "src/core/lib/iomgr/port.h" + +#include <grpc/support/time.h> + +#include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/internal_errqueue.h" + +namespace grpc_core { +struct Timestamps { + /* TODO(yashykt): This would also need to store OPTSTAT once support is added + */ + gpr_timespec sendmsg_time; + gpr_timespec scheduled_time; + gpr_timespec sent_time; + gpr_timespec acked_time; +}; + +/** TracedBuffer is a class to keep track of timestamps for a specific buffer in + * the TCP layer. We are only tracking timestamps for Linux kernels and hence + * this class would only be used by Linux platforms. For all other platforms, + * TracedBuffer would be an empty class. + * + * The timestamps collected are according to grpc_core::Timestamps declared + * above. + * + * A TracedBuffer list is kept track of using the head element of the list. If + * the head element of the list is nullptr, then the list is empty. + */ +#ifdef GRPC_LINUX_ERRQUEUE +class TracedBuffer { + public: + /** Add a new entry in the TracedBuffer list pointed to by head. Also saves + * sendmsg_time with the current timestamp. */ + static void AddNewEntry(grpc_core::TracedBuffer** head, uint32_t seq_no, + void* arg); + + /** Processes a received timestamp based on sock_extended_err and + * scm_timestamping structures. It will invoke the timestamps callback if the + * timestamp type is SCM_TSTAMP_ACK. */ + static void ProcessTimestamp(grpc_core::TracedBuffer** head, + struct sock_extended_err* serr, + struct scm_timestamping* tss); + + /** Cleans the list by calling the callback for each traced buffer in the list + * with timestamps that it has. */ + static void Shutdown(grpc_core::TracedBuffer** head, + grpc_error* shutdown_err); + + private: + GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW + + TracedBuffer(int seq_no, void* arg) + : seq_no_(seq_no), arg_(arg), next_(nullptr) {} + + uint32_t seq_no_; /* The sequence number for the last byte in the buffer */ + void* arg_; /* The arg to pass to timestamps_callback */ + grpc_core::Timestamps ts_; /* The timestamps corresponding to this buffer */ + grpc_core::TracedBuffer* next_; /* The next TracedBuffer in the list */ +}; +#else /* GRPC_LINUX_ERRQUEUE */ +class TracedBuffer {}; +#endif /* GRPC_LINUX_ERRQUEUE */ + +/** Sets the callback function to call when timestamps for a write are + * collected. The callback does not own a reference to error. */ +void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*, + grpc_core::Timestamps*, + grpc_error* error)); + +}; /* namespace grpc_core */ + +#endif /* GRPC_CORE_LIB_IOMGR_BUFFER_LIST_H */ diff --git a/src/core/lib/iomgr/endpoint.cc b/src/core/lib/iomgr/endpoint.cc index 92e7930111..44fb47e19d 100644 --- a/src/core/lib/iomgr/endpoint.cc +++ b/src/core/lib/iomgr/endpoint.cc @@ -28,8 +28,8 @@ void grpc_endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* slices, } void grpc_endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* slices, - grpc_closure* cb) { - ep->vtable->write(ep, slices, cb); + grpc_closure* cb, void* arg) { + ep->vtable->write(ep, slices, cb, arg); } void grpc_endpoint_add_to_pollset(grpc_endpoint* ep, grpc_pollset* pollset) { diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h index 15db1649fa..1f590a80ca 100644 --- a/src/core/lib/iomgr/endpoint.h +++ b/src/core/lib/iomgr/endpoint.h @@ -33,10 +33,12 @@ typedef struct grpc_endpoint grpc_endpoint; typedef struct grpc_endpoint_vtable grpc_endpoint_vtable; +class Timestamps; struct grpc_endpoint_vtable { void (*read)(grpc_endpoint* ep, grpc_slice_buffer* slices, grpc_closure* cb); - void (*write)(grpc_endpoint* ep, grpc_slice_buffer* slices, grpc_closure* cb); + void (*write)(grpc_endpoint* ep, grpc_slice_buffer* slices, grpc_closure* cb, + void* arg); void (*add_to_pollset)(grpc_endpoint* ep, grpc_pollset* pollset); void (*add_to_pollset_set)(grpc_endpoint* ep, grpc_pollset_set* pollset); void (*delete_from_pollset_set)(grpc_endpoint* ep, grpc_pollset_set* pollset); @@ -70,9 +72,11 @@ int grpc_endpoint_get_fd(grpc_endpoint* ep); \a slices may be mutated at will by the endpoint until cb is called. No guarantee is made to the content of slices after a write EXCEPT that it is a valid slice buffer. + \a arg is platform specific. It is currently only used by TCP on linux + platforms as an argument that would be forwarded to the timestamps callback. */ void grpc_endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* slices, - grpc_closure* cb); + grpc_closure* cb, void* arg); /* Causes any pending and future read/write callbacks to run immediately with success==0 */ diff --git a/src/core/lib/iomgr/endpoint_cfstream.cc b/src/core/lib/iomgr/endpoint_cfstream.cc index c3bc0cc8fd..df2cf508c8 100644 --- a/src/core/lib/iomgr/endpoint_cfstream.cc +++ b/src/core/lib/iomgr/endpoint_cfstream.cc @@ -268,7 +268,7 @@ static void CFStreamRead(grpc_endpoint* ep, grpc_slice_buffer* slices, } static void CFStreamWrite(grpc_endpoint* ep, grpc_slice_buffer* slices, - grpc_closure* cb) { + grpc_closure* cb, void* arg) { CFStreamEndpoint* ep_impl = reinterpret_cast<CFStreamEndpoint*>(ep); if (grpc_tcp_trace.enabled()) { gpr_log(GPR_DEBUG, "CFStream endpoint:%p write (%p, %p) length:%zu", diff --git a/src/core/lib/iomgr/endpoint_pair_posix.cc b/src/core/lib/iomgr/endpoint_pair_posix.cc index 5c5c246f99..3afbfd7254 100644 --- a/src/core/lib/iomgr/endpoint_pair_posix.cc +++ b/src/core/lib/iomgr/endpoint_pair_posix.cc @@ -59,11 +59,11 @@ grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char* name, grpc_core::ExecCtx exec_ctx; gpr_asprintf(&final_name, "%s:client", name); - p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name, false), args, + p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name, true), args, "socketpair-server"); gpr_free(final_name); gpr_asprintf(&final_name, "%s:server", name); - p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name, false), args, + p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name, true), args, "socketpair-client"); gpr_free(final_name); diff --git a/src/core/lib/iomgr/error.cc b/src/core/lib/iomgr/error.cc index 90ed34da11..146a539027 100644 --- a/src/core/lib/iomgr/error.cc +++ b/src/core/lib/iomgr/error.cc @@ -454,7 +454,7 @@ typedef struct { grpc_status_code code; const char* msg; } special_error_status_map; -static special_error_status_map error_status_map[] = { +static const special_error_status_map error_status_map[] = { {GRPC_ERROR_NONE, GRPC_STATUS_OK, ""}, {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "Cancelled"}, {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"}, @@ -463,15 +463,13 @@ static special_error_status_map error_status_map[] = { bool grpc_error_get_int(grpc_error* err, grpc_error_ints which, intptr_t* p) { GPR_TIMER_SCOPE("grpc_error_get_int", 0); if (grpc_error_is_special(err)) { - if (which == GRPC_ERROR_INT_GRPC_STATUS) { - for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) { - if (error_status_map[i].error == err) { - if (p != nullptr) *p = error_status_map[i].code; - return true; - } + for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) { + if (error_status_map[i].error == err) { + if (which != GRPC_ERROR_INT_GRPC_STATUS) return false; + if (p != nullptr) *p = error_status_map[i].code; + return true; } } - return false; } uint8_t slot = err->ints[which]; if (slot != UINT8_MAX) { @@ -492,15 +490,13 @@ grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which, bool grpc_error_get_str(grpc_error* err, grpc_error_strs which, grpc_slice* str) { if (grpc_error_is_special(err)) { - if (which == GRPC_ERROR_STR_GRPC_MESSAGE) { - for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) { - if (error_status_map[i].error == err) { - *str = grpc_slice_from_static_string(error_status_map[i].msg); - return true; - } + for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) { + if (error_status_map[i].error == err) { + if (which != GRPC_ERROR_STR_GRPC_MESSAGE) return false; + *str = grpc_slice_from_static_string(error_status_map[i].msg); + return true; } } - return false; } uint8_t slot = err->strs[which]; if (slot != UINT8_MAX) { @@ -513,9 +509,24 @@ bool grpc_error_get_str(grpc_error* err, grpc_error_strs which, grpc_error* grpc_error_add_child(grpc_error* src, grpc_error* child) { GPR_TIMER_SCOPE("grpc_error_add_child", 0); - grpc_error* new_err = copy_error_and_unref(src); - internal_add_error(&new_err, child); - return new_err; + if (src != GRPC_ERROR_NONE) { + if (child == GRPC_ERROR_NONE) { + /* \a child is empty. Simply return the ref to \a src */ + return src; + } else if (child != src) { + grpc_error* new_err = copy_error_and_unref(src); + internal_add_error(&new_err, child); + return new_err; + } else { + /* \a src and \a child are the same. Drop one of the references and return + * the other */ + GRPC_ERROR_UNREF(child); + return src; + } + } else { + /* \a src is empty. Simply return the ref to \a child */ + return child; + } } static const char* no_error_string = "\"No Error\""; diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h index 27c4d22fd1..49f4029bc2 100644 --- a/src/core/lib/iomgr/error.h +++ b/src/core/lib/iomgr/error.h @@ -185,8 +185,16 @@ bool grpc_error_get_str(grpc_error* error, grpc_error_strs which, /// error occurring. Allows root causing high level errors from lower level /// errors that contributed to them. The src error takes ownership of the /// child error. +/// +/// Edge Conditions - +/// 1) If either of \a src or \a child is GRPC_ERROR_NONE, returns a reference +/// to the other argument. 2) If both \a src and \a child are GRPC_ERROR_NONE, +/// returns GRPC_ERROR_NONE. 3) If \a src and \a child point to the same error, +/// returns a single reference. (Note that, 2 references should have been +/// received to the error in this case.) grpc_error* grpc_error_add_child(grpc_error* src, grpc_error* child) GRPC_MUST_USE_RESULT; + grpc_error* grpc_os_error(const char* file, int line, int err, const char* call_name) GRPC_MUST_USE_RESULT; diff --git a/src/core/lib/iomgr/ev_epoll1_linux.cc b/src/core/lib/iomgr/ev_epoll1_linux.cc index 66e0f1fd6d..6ef889b0fe 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.cc +++ b/src/core/lib/iomgr/ev_epoll1_linux.cc @@ -131,6 +131,13 @@ static void epoll_set_shutdown() { * Fd Declarations */ +/* Only used when GRPC_ENABLE_FORK_SUPPORT=1 */ +struct grpc_fork_fd_list { + grpc_fd* fd; + grpc_fd* next; + grpc_fd* prev; +}; + struct grpc_fd { int fd; @@ -141,6 +148,9 @@ struct grpc_fd { struct grpc_fd* freelist_next; grpc_iomgr_object iomgr_object; + + /* Only used when GRPC_ENABLE_FORK_SUPPORT=1 */ + grpc_fork_fd_list* fork_fd_list; }; static void fd_global_init(void); @@ -256,9 +266,17 @@ static bool append_error(grpc_error** composite, grpc_error* error, static grpc_fd* fd_freelist = nullptr; static gpr_mu fd_freelist_mu; +/* Only used when GRPC_ENABLE_FORK_SUPPORT=1 */ +static grpc_fd* fork_fd_list_head = nullptr; +static gpr_mu fork_fd_list_mu; + static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } static void fd_global_shutdown(void) { + // TODO(guantaol): We don't have a reasonable explanation about this + // lock()/unlock() pattern. It can be a valid barrier if there is at most one + // pending lock() at this point. Otherwise, there is still a possibility of + // use-after-free race. Need to reason about the code and/or clean it up. gpr_mu_lock(&fd_freelist_mu); gpr_mu_unlock(&fd_freelist_mu); while (fd_freelist != nullptr) { @@ -269,6 +287,38 @@ static void fd_global_shutdown(void) { gpr_mu_destroy(&fd_freelist_mu); } +static void fork_fd_list_add_grpc_fd(grpc_fd* fd) { + if (grpc_core::Fork::Enabled()) { + gpr_mu_lock(&fork_fd_list_mu); + fd->fork_fd_list = + static_cast<grpc_fork_fd_list*>(gpr_malloc(sizeof(grpc_fork_fd_list))); + fd->fork_fd_list->next = fork_fd_list_head; + fd->fork_fd_list->prev = nullptr; + if (fork_fd_list_head != nullptr) { + fork_fd_list_head->fork_fd_list->prev = fd; + } + fork_fd_list_head = fd; + gpr_mu_unlock(&fork_fd_list_mu); + } +} + +static void fork_fd_list_remove_grpc_fd(grpc_fd* fd) { + if (grpc_core::Fork::Enabled()) { + gpr_mu_lock(&fork_fd_list_mu); + if (fork_fd_list_head == fd) { + fork_fd_list_head = fd->fork_fd_list->next; + } + if (fd->fork_fd_list->prev != nullptr) { + fd->fork_fd_list->prev->fork_fd_list->next = fd->fork_fd_list->next; + } + if (fd->fork_fd_list->next != nullptr) { + fd->fork_fd_list->next->fork_fd_list->prev = fd->fork_fd_list->prev; + } + gpr_free(fd->fork_fd_list); + gpr_mu_unlock(&fork_fd_list_mu); + } +} + static grpc_fd* fd_create(int fd, const char* name, bool track_err) { grpc_fd* new_fd = nullptr; @@ -295,6 +345,7 @@ static grpc_fd* fd_create(int fd, const char* name, bool track_err) { char* fd_name; gpr_asprintf(&fd_name, "%s fd=%d", name, fd); grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name); + fork_fd_list_add_grpc_fd(new_fd); #ifndef NDEBUG if (grpc_trace_fd_refcount.enabled()) { gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, new_fd, fd_name); @@ -361,6 +412,7 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd, GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_REF(error)); grpc_iomgr_unregister_object(&fd->iomgr_object); + fork_fd_list_remove_grpc_fd(fd); fd->read_closure->DestroyEvent(); fd->write_closure->DestroyEvent(); fd->error_closure->DestroyEvent(); @@ -1190,6 +1242,10 @@ static void shutdown_engine(void) { fd_global_shutdown(); pollset_global_shutdown(); epoll_set_shutdown(); + if (grpc_core::Fork::Enabled()) { + gpr_mu_destroy(&fork_fd_list_mu); + grpc_core::Fork::SetResetChildPollingEngineFunc(nullptr); + } } static const grpc_event_engine_vtable vtable = { @@ -1227,6 +1283,21 @@ static const grpc_event_engine_vtable vtable = { shutdown_engine, }; +/* Called by the child process's post-fork handler to close open fds, including + * the global epoll fd. This allows gRPC to shutdown in the child process + * without interfering with connections or RPCs ongoing in the parent. */ +static void reset_event_manager_on_fork() { + gpr_mu_lock(&fork_fd_list_mu); + while (fork_fd_list_head != nullptr) { + close(fork_fd_list_head->fd); + fork_fd_list_head->fd = -1; + fork_fd_list_head = fork_fd_list_head->fork_fd_list->next; + } + gpr_mu_unlock(&fork_fd_list_mu); + shutdown_engine(); + grpc_init_epoll1_linux(true); +} + /* It is possible that GLIBC has epoll but the underlying kernel doesn't. * Create epoll_fd (epoll_set_init() takes care of that) to make sure epoll * support is available */ @@ -1248,6 +1319,11 @@ const grpc_event_engine_vtable* grpc_init_epoll1_linux(bool explicit_request) { return nullptr; } + if (grpc_core::Fork::Enabled()) { + gpr_mu_init(&fork_fd_list_mu); + grpc_core::Fork::SetResetChildPollingEngineFunc( + reset_event_manager_on_fork); + } return &vtable; } diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index 96eae30345..06a382c556 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -46,6 +46,7 @@ #include "src/core/lib/gpr/tls.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/gprpp/manual_constructor.h" +#include "src/core/lib/gprpp/mutex_lock.h" #include "src/core/lib/iomgr/block_annotate.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/is_epollexclusive_available.h" @@ -402,6 +403,10 @@ static void unref_by(grpc_fd* fd, int n) { static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } static void fd_global_shutdown(void) { + // TODO(guantaol): We don't have a reasonable explanation about this + // lock()/unlock() pattern. It can be a valid barrier if there is at most one + // pending lock() at this point. Otherwise, there is still a possibility of + // use-after-free race. Need to reason about the code and/or clean it up. gpr_mu_lock(&fd_freelist_mu); gpr_mu_unlock(&fd_freelist_mu); while (fd_freelist != nullptr) { @@ -735,7 +740,7 @@ static void pollset_maybe_finish_shutdown(grpc_pollset* pollset) { static grpc_error* kick_one_worker(grpc_pollset_worker* specific_worker) { GPR_TIMER_SCOPE("kick_one_worker", 0); pollable* p = specific_worker->pollable_obj; - grpc_core::mu_guard lock(&p->mu); + grpc_core::MutexLock lock(&p->mu); GPR_ASSERT(specific_worker != nullptr); if (specific_worker->kicked) { if (grpc_polling_trace.enabled()) { diff --git a/src/core/lib/iomgr/ev_epollsig_linux.cc b/src/core/lib/iomgr/ev_epollsig_linux.cc deleted file mode 100644 index 5695ac795d..0000000000 --- a/src/core/lib/iomgr/ev_epollsig_linux.cc +++ /dev/null @@ -1,1743 +0,0 @@ -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include <grpc/support/port_platform.h> - -#include "src/core/lib/iomgr/port.h" - -#include <grpc/grpc_posix.h> -#include <grpc/support/log.h> - -/* This polling engine is only relevant on linux kernels supporting epoll() */ -#ifdef GRPC_LINUX_EPOLL_CREATE1 - -#include "src/core/lib/iomgr/ev_epollsig_linux.h" - -#include <assert.h> -#include <errno.h> -#include <limits.h> -#include <poll.h> -#include <pthread.h> -#include <signal.h> -#include <string.h> -#include <sys/epoll.h> -#include <sys/socket.h> -#include <unistd.h> - -#include <grpc/support/alloc.h> -#include <grpc/support/string_util.h> - -#include "src/core/lib/debug/stats.h" -#include "src/core/lib/gpr/tls.h" -#include "src/core/lib/gpr/useful.h" -#include "src/core/lib/gprpp/manual_constructor.h" -#include "src/core/lib/iomgr/block_annotate.h" -#include "src/core/lib/iomgr/ev_posix.h" -#include "src/core/lib/iomgr/iomgr_internal.h" -#include "src/core/lib/iomgr/lockfree_event.h" -#include "src/core/lib/iomgr/timer.h" -#include "src/core/lib/iomgr/wakeup_fd_posix.h" -#include "src/core/lib/profiling/timers.h" - -#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker*)1) - -#define GRPC_POLLING_TRACE(...) \ - if (grpc_polling_trace.enabled()) { \ - gpr_log(GPR_INFO, __VA_ARGS__); \ - } - -static int grpc_wakeup_signal = -1; -static bool is_grpc_wakeup_signal_initialized = false; - -/* Implements the function defined in grpc_posix.h. This function might be - * called before even calling grpc_init() to set either a different signal to - * use. If signum == -1, then the use of signals is disabled */ -void grpc_use_signal(int signum) { - grpc_wakeup_signal = signum; - is_grpc_wakeup_signal_initialized = true; - - if (grpc_wakeup_signal < 0) { - gpr_log(GPR_INFO, - "Use of signals is disabled. Epoll engine will not be used"); - } else { - gpr_log(GPR_INFO, "epoll engine will be using signal: %d", - grpc_wakeup_signal); - } -} - -struct polling_island; - -typedef enum { - POLL_OBJ_FD, - POLL_OBJ_POLLSET, - POLL_OBJ_POLLSET_SET -} poll_obj_type; - -typedef struct poll_obj { -#ifndef NDEBUG - poll_obj_type obj_type; -#endif - gpr_mu mu; - struct polling_island* pi; -} poll_obj; - -const char* poll_obj_string(poll_obj_type po_type) { - switch (po_type) { - case POLL_OBJ_FD: - return "fd"; - case POLL_OBJ_POLLSET: - return "pollset"; - case POLL_OBJ_POLLSET_SET: - return "pollset_set"; - } - - GPR_UNREACHABLE_CODE(return "UNKNOWN"); -} - - /******************************************************************************* - * Fd Declarations - */ - -#define FD_FROM_PO(po) ((grpc_fd*)(po)) - -struct grpc_fd { - poll_obj po; - - int fd; - /* refst format: - bit 0 : 1=Active / 0=Orphaned - bits 1-n : refcount - Ref/Unref by two to avoid altering the orphaned bit */ - gpr_atm refst; - - /* The fd is either closed or we relinquished control of it. In either - cases, this indicates that the 'fd' on this structure is no longer - valid */ - bool orphaned; - - grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure; - grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure; - grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure; - - struct grpc_fd* freelist_next; - grpc_closure* on_done_closure; - - grpc_iomgr_object iomgr_object; - - /* Do we need to track EPOLLERR events separately? */ - bool track_err; -}; - -/* Reference counting for fds */ -#ifndef NDEBUG -static void fd_ref(grpc_fd* fd, const char* reason, const char* file, int line); -static void fd_unref(grpc_fd* fd, const char* reason, const char* file, - int line); -#define GRPC_FD_REF(fd, reason) fd_ref(fd, reason, __FILE__, __LINE__) -#define GRPC_FD_UNREF(fd, reason) fd_unref(fd, reason, __FILE__, __LINE__) -#else -static void fd_ref(grpc_fd* fd); -static void fd_unref(grpc_fd* fd); -#define GRPC_FD_REF(fd, reason) fd_ref(fd) -#define GRPC_FD_UNREF(fd, reason) fd_unref(fd) -#endif - -static void fd_global_init(void); -static void fd_global_shutdown(void); - -/******************************************************************************* - * Polling island Declarations - */ - -#ifndef NDEBUG - -#define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__) -#define PI_UNREF(p, r) pi_unref_dbg((p), (r), __FILE__, __LINE__) - -#else - -#define PI_ADD_REF(p, r) pi_add_ref((p)) -#define PI_UNREF(p, r) pi_unref((p)) - -#endif - -/* This is also used as grpc_workqueue (by directly casing it) */ -typedef struct polling_island { - gpr_mu mu; - /* Ref count. Use PI_ADD_REF() and PI_UNREF() macros to increment/decrement - the refcount. - Once the ref count becomes zero, this structure is destroyed which means - we should ensure that there is never a scenario where a PI_ADD_REF() is - racing with a PI_UNREF() that just made the ref_count zero. */ - gpr_atm ref_count; - - /* Pointer to the polling_island this merged into. - * merged_to value is only set once in polling_island's lifetime (and that too - * only if the island is merged with another island). Because of this, we can - * use gpr_atm type here so that we can do atomic access on this and reduce - * lock contention on 'mu' mutex. - * - * Note that if this field is not NULL (i.e not 0), all the remaining fields - * (except mu and ref_count) are invalid and must be ignored. */ - gpr_atm merged_to; - - /* Number of threads currently polling on this island */ - gpr_atm poller_count; - - /* The fd of the underlying epoll set */ - int epoll_fd; - - /* The file descriptors in the epoll set */ - size_t fd_cnt; - size_t fd_capacity; - grpc_fd** fds; -} polling_island; - -/******************************************************************************* - * Pollset Declarations - */ -struct grpc_pollset_worker { - /* Thread id of this worker */ - pthread_t pt_id; - - /* Used to prevent a worker from getting kicked multiple times */ - gpr_atm is_kicked; - struct grpc_pollset_worker* next; - struct grpc_pollset_worker* prev; -}; - -struct grpc_pollset { - poll_obj po; - - grpc_pollset_worker root_worker; - bool kicked_without_pollers; - - bool shutting_down; /* Is the pollset shutting down ? */ - bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */ - grpc_closure* shutdown_done; /* Called after after shutdown is complete */ -}; - -/******************************************************************************* - * Pollset-set Declarations - */ -struct grpc_pollset_set { - poll_obj po; -}; - -/******************************************************************************* - * Common helpers - */ - -static bool append_error(grpc_error** composite, grpc_error* error, - const char* desc) { - if (error == GRPC_ERROR_NONE) return true; - if (*composite == GRPC_ERROR_NONE) { - *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc); - } - *composite = grpc_error_add_child(*composite, error); - return false; -} - -/******************************************************************************* - * Polling island Definitions - */ - -/* The wakeup fd that is used to wake up all threads in a Polling island. This - is useful in the polling island merge operation where we need to wakeup all - the threads currently polling the smaller polling island (so that they can - start polling the new/merged polling island) - - NOTE: This fd is initialized to be readable and MUST NOT be consumed i.e the - threads that woke up MUST NOT call grpc_wakeup_fd_consume_wakeup() */ -static grpc_wakeup_fd polling_island_wakeup_fd; - -/* The polling island being polled right now. - See comments in workqueue_maybe_wakeup for why this is tracked. */ -static __thread polling_island* g_current_thread_polling_island; - -/* Forward declaration */ -static void polling_island_delete(polling_island* pi); - -#ifdef GRPC_TSAN -/* Currently TSAN may incorrectly flag data races between epoll_ctl and - epoll_wait for any grpc_fd structs that are added to the epoll set via - epoll_ctl and are returned (within a very short window) via epoll_wait(). - - To work-around this race, we establish a happens-before relation between - the code just-before epoll_ctl() and the code after epoll_wait() by using - this atomic */ -gpr_atm g_epoll_sync; -#endif /* defined(GRPC_TSAN) */ - -static void pi_add_ref(polling_island* pi); -static void pi_unref(polling_island* pi); - -#ifndef NDEBUG -static void pi_add_ref_dbg(polling_island* pi, const char* reason, - const char* file, int line) { - if (grpc_polling_trace.enabled()) { - gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count); - gpr_log(GPR_INFO, - "Add ref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR - " (%s) - (%s, %d)", - pi, old_cnt, old_cnt + 1, reason, file, line); - } - pi_add_ref(pi); -} - -static void pi_unref_dbg(polling_island* pi, const char* reason, - const char* file, int line) { - if (grpc_polling_trace.enabled()) { - gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count); - gpr_log(GPR_INFO, - "Unref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR - " (%s) - (%s, %d)", - pi, old_cnt, (old_cnt - 1), reason, file, line); - } - pi_unref(pi); -} -#endif - -static void pi_add_ref(polling_island* pi) { - gpr_atm_no_barrier_fetch_add(&pi->ref_count, 1); -} - -static void pi_unref(polling_island* pi) { - /* If ref count went to zero, delete the polling island. - Note that this deletion not be done under a lock. Once the ref count goes - to zero, we are guaranteed that no one else holds a reference to the - polling island (and that there is no racing pi_add_ref() call either). - - Also, if we are deleting the polling island and the merged_to field is - non-empty, we should remove a ref to the merged_to polling island - */ - if (1 == gpr_atm_full_fetch_add(&pi->ref_count, -1)) { - polling_island* next = (polling_island*)gpr_atm_acq_load(&pi->merged_to); - polling_island_delete(pi); - if (next != nullptr) { - PI_UNREF(next, "pi_delete"); /* Recursive call */ - } - } -} - -/* The caller is expected to hold pi->mu lock before calling this function */ -static void polling_island_add_fds_locked(polling_island* pi, grpc_fd** fds, - size_t fd_count, bool add_fd_refs, - grpc_error** error) { - int err; - size_t i; - struct epoll_event ev; - char* err_msg; - const char* err_desc = "polling_island_add_fds"; - -#ifdef GRPC_TSAN - /* See the definition of g_epoll_sync for more context */ - gpr_atm_rel_store(&g_epoll_sync, (gpr_atm)0); -#endif /* defined(GRPC_TSAN) */ - - for (i = 0; i < fd_count; i++) { - ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET); - /* Use the least significant bit of ev.data.ptr to store track_err to avoid - * synchronization issues when accessing it after receiving an event */ - ev.data.ptr = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(fds[i]) | - (fds[i]->track_err ? 1 : 0)); - err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, fds[i]->fd, &ev); - - if (err < 0) { - if (errno != EEXIST) { - gpr_asprintf( - &err_msg, - "epoll_ctl (epoll_fd: %d) add fd: %d failed with error: %d (%s)", - pi->epoll_fd, fds[i]->fd, errno, strerror(errno)); - append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); - gpr_free(err_msg); - } - - continue; - } - - if (pi->fd_cnt == pi->fd_capacity) { - pi->fd_capacity = GPR_MAX(pi->fd_capacity + 8, pi->fd_cnt * 3 / 2); - pi->fds = static_cast<grpc_fd**>( - gpr_realloc(pi->fds, sizeof(grpc_fd*) * pi->fd_capacity)); - } - - pi->fds[pi->fd_cnt++] = fds[i]; - if (add_fd_refs) { - GRPC_FD_REF(fds[i], "polling_island"); - } - } -} - -/* The caller is expected to hold pi->mu before calling this */ -static void polling_island_add_wakeup_fd_locked(polling_island* pi, - grpc_wakeup_fd* wakeup_fd, - grpc_error** error) { - struct epoll_event ev; - int err; - char* err_msg; - const char* err_desc = "polling_island_add_wakeup_fd"; - - ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLET); - ev.data.ptr = wakeup_fd; - err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, - GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), &ev); - if (err < 0 && errno != EEXIST) { - gpr_asprintf(&err_msg, - "epoll_ctl (epoll_fd: %d) add wakeup fd: %d failed with " - "error: %d (%s)", - pi->epoll_fd, GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), errno, - strerror(errno)); - append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); - gpr_free(err_msg); - } -} - -/* The caller is expected to hold pi->mu lock before calling this function */ -static void polling_island_remove_all_fds_locked(polling_island* pi, - bool remove_fd_refs, - grpc_error** error) { - int err; - size_t i; - char* err_msg; - const char* err_desc = "polling_island_remove_fds"; - - for (i = 0; i < pi->fd_cnt; i++) { - err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, pi->fds[i]->fd, nullptr); - if (err < 0 && errno != ENOENT) { - gpr_asprintf(&err_msg, - "epoll_ctl (epoll_fd: %d) delete fds[%zu]: %d failed with " - "error: %d (%s)", - pi->epoll_fd, i, pi->fds[i]->fd, errno, strerror(errno)); - append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); - gpr_free(err_msg); - } - - if (remove_fd_refs) { - GRPC_FD_UNREF(pi->fds[i], "polling_island"); - } - } - - pi->fd_cnt = 0; -} - -/* The caller is expected to hold pi->mu lock before calling this function */ -static void polling_island_remove_fd_locked(polling_island* pi, grpc_fd* fd, - grpc_error** error) { - int err; - size_t i; - char* err_msg; - const char* err_desc = "polling_island_remove_fd"; - - /* If fd is already closed, then it would have been automatically been removed - from the epoll set */ - err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, fd->fd, nullptr); - if (err < 0 && errno != ENOENT) { - gpr_asprintf( - &err_msg, - "epoll_ctl (epoll_fd: %d) del fd: %d failed with error: %d (%s)", - pi->epoll_fd, fd->fd, errno, strerror(errno)); - append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); - gpr_free(err_msg); - } - - for (i = 0; i < pi->fd_cnt; i++) { - if (pi->fds[i] == fd) { - pi->fds[i] = pi->fds[--pi->fd_cnt]; - GRPC_FD_UNREF(fd, "polling_island"); - break; - } - } -} - -/* Might return NULL in case of an error */ -static polling_island* polling_island_create(grpc_fd* initial_fd, - grpc_error** error) { - polling_island* pi = nullptr; - const char* err_desc = "polling_island_create"; - - *error = GRPC_ERROR_NONE; - - pi = static_cast<polling_island*>(gpr_malloc(sizeof(*pi))); - gpr_mu_init(&pi->mu); - pi->fd_cnt = 0; - pi->fd_capacity = 0; - pi->fds = nullptr; - pi->epoll_fd = -1; - - gpr_atm_rel_store(&pi->ref_count, 0); - gpr_atm_rel_store(&pi->poller_count, 0); - gpr_atm_rel_store(&pi->merged_to, (gpr_atm) nullptr); - - pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC); - - if (pi->epoll_fd < 0) { - append_error(error, GRPC_OS_ERROR(errno, "epoll_create1"), err_desc); - goto done; - } - - if (initial_fd != nullptr) { - polling_island_add_fds_locked(pi, &initial_fd, 1, true, error); - } - -done: - if (*error != GRPC_ERROR_NONE) { - polling_island_delete(pi); - pi = nullptr; - } - return pi; -} - -static void polling_island_delete(polling_island* pi) { - GPR_ASSERT(pi->fd_cnt == 0); - - if (pi->epoll_fd >= 0) { - close(pi->epoll_fd); - } - gpr_mu_destroy(&pi->mu); - gpr_free(pi->fds); - gpr_free(pi); -} - -/* Attempts to gets the last polling island in the linked list (liked by the - * 'merged_to' field). Since this does not lock the polling island, there are no - * guarantees that the island returned is the last island */ -static polling_island* polling_island_maybe_get_latest(polling_island* pi) { - polling_island* next = (polling_island*)gpr_atm_acq_load(&pi->merged_to); - while (next != nullptr) { - pi = next; - next = (polling_island*)gpr_atm_acq_load(&pi->merged_to); - } - - return pi; -} - -/* Gets the lock on the *latest* polling island i.e the last polling island in - the linked list (linked by the 'merged_to' field). Call gpr_mu_unlock on the - returned polling island's mu. - Usage: To lock/unlock polling island "pi", do the following: - polling_island *pi_latest = polling_island_lock(pi); - ... - ... critical section .. - ... - gpr_mu_unlock(&pi_latest->mu); // NOTE: use pi_latest->mu. NOT pi->mu */ -static polling_island* polling_island_lock(polling_island* pi) { - polling_island* next = nullptr; - - while (true) { - next = (polling_island*)gpr_atm_acq_load(&pi->merged_to); - if (next == nullptr) { - /* Looks like 'pi' is the last node in the linked list but unless we check - this by holding the pi->mu lock, we cannot be sure (i.e without the - pi->mu lock, we don't prevent island merges). - To be absolutely sure, check once more by holding the pi->mu lock */ - gpr_mu_lock(&pi->mu); - next = (polling_island*)gpr_atm_acq_load(&pi->merged_to); - if (next == nullptr) { - /* pi is infact the last node and we have the pi->mu lock. we're done */ - break; - } - - /* pi->merged_to is not NULL i.e pi isn't the last node anymore. pi->mu - * isn't the lock we are interested in. Continue traversing the list */ - gpr_mu_unlock(&pi->mu); - } - - pi = next; - } - - return pi; -} - -/* Gets the lock on the *latest* polling islands in the linked lists pointed by - *p and *q (and also updates *p and *q to point to the latest polling islands) - - This function is needed because calling the following block of code to obtain - locks on polling islands (*p and *q) is prone to deadlocks. - { - polling_island_lock(*p, true); - polling_island_lock(*q, true); - } - - Usage/example: - polling_island *p1; - polling_island *p2; - .. - polling_island_lock_pair(&p1, &p2); - .. - .. Critical section with both p1 and p2 locked - .. - // Release locks: Always call polling_island_unlock_pair() to release locks - polling_island_unlock_pair(p1, p2); -*/ -static void polling_island_lock_pair(polling_island** p, polling_island** q) { - polling_island* pi_1 = *p; - polling_island* pi_2 = *q; - polling_island* next_1 = nullptr; - polling_island* next_2 = nullptr; - - /* The algorithm is simple: - - Go to the last polling islands in the linked lists *pi_1 and *pi_2 (and - keep updating pi_1 and pi_2) - - Then obtain locks on the islands by following a lock order rule of - locking polling_island with lower address first - Special case: Before obtaining the locks, check if pi_1 and pi_2 are - pointing to the same island. If that is the case, we can just call - polling_island_lock() - - After obtaining both the locks, double check that the polling islands - are still the last polling islands in their respective linked lists - (this is because there might have been polling island merges before - we got the lock) - - If the polling islands are the last islands, we are done. If not, - release the locks and continue the process from the first step */ - while (true) { - next_1 = (polling_island*)gpr_atm_acq_load(&pi_1->merged_to); - while (next_1 != nullptr) { - pi_1 = next_1; - next_1 = (polling_island*)gpr_atm_acq_load(&pi_1->merged_to); - } - - next_2 = (polling_island*)gpr_atm_acq_load(&pi_2->merged_to); - while (next_2 != nullptr) { - pi_2 = next_2; - next_2 = (polling_island*)gpr_atm_acq_load(&pi_2->merged_to); - } - - if (pi_1 == pi_2) { - pi_1 = pi_2 = polling_island_lock(pi_1); - break; - } - - if (pi_1 < pi_2) { - gpr_mu_lock(&pi_1->mu); - gpr_mu_lock(&pi_2->mu); - } else { - gpr_mu_lock(&pi_2->mu); - gpr_mu_lock(&pi_1->mu); - } - - next_1 = (polling_island*)gpr_atm_acq_load(&pi_1->merged_to); - next_2 = (polling_island*)gpr_atm_acq_load(&pi_2->merged_to); - if (next_1 == nullptr && next_2 == nullptr) { - break; - } - - gpr_mu_unlock(&pi_1->mu); - gpr_mu_unlock(&pi_2->mu); - } - - *p = pi_1; - *q = pi_2; -} - -static void polling_island_unlock_pair(polling_island* p, polling_island* q) { - if (p == q) { - gpr_mu_unlock(&p->mu); - } else { - gpr_mu_unlock(&p->mu); - gpr_mu_unlock(&q->mu); - } -} - -static polling_island* polling_island_merge(polling_island* p, - polling_island* q, - grpc_error** error) { - /* Get locks on both the polling islands */ - polling_island_lock_pair(&p, &q); - - if (p != q) { - /* Make sure that p points to the polling island with fewer fds than q */ - if (p->fd_cnt > q->fd_cnt) { - GPR_SWAP(polling_island*, p, q); - } - - /* Merge p with q i.e move all the fds from p (The one with fewer fds) to q - Note that the refcounts on the fds being moved will not change here. - This is why the last param in the following two functions is 'false') */ - polling_island_add_fds_locked(q, p->fds, p->fd_cnt, false, error); - polling_island_remove_all_fds_locked(p, false, error); - - /* Wakeup all the pollers (if any) on p so that they pickup this change */ - polling_island_add_wakeup_fd_locked(p, &polling_island_wakeup_fd, error); - - /* Add the 'merged_to' link from p --> q */ - gpr_atm_rel_store(&p->merged_to, (gpr_atm)q); - PI_ADD_REF(q, "pi_merge"); /* To account for the new incoming ref from p */ - } - /* else if p == q, nothing needs to be done */ - - polling_island_unlock_pair(p, q); - - /* Return the merged polling island (Note that no merge would have happened - if p == q which is ok) */ - return q; -} - -static grpc_error* polling_island_global_init() { - grpc_error* error = GRPC_ERROR_NONE; - - error = grpc_wakeup_fd_init(&polling_island_wakeup_fd); - if (error == GRPC_ERROR_NONE) { - error = grpc_wakeup_fd_wakeup(&polling_island_wakeup_fd); - } - - return error; -} - -static void polling_island_global_shutdown() { - grpc_wakeup_fd_destroy(&polling_island_wakeup_fd); -} - -/******************************************************************************* - * Fd Definitions - */ - -/* We need to keep a freelist not because of any concerns of malloc performance - * but instead so that implementations with multiple threads in (for example) - * epoll_wait deal with the race between pollset removal and incoming poll - * notifications. - * - * The problem is that the poller ultimately holds a reference to this - * object, so it is very difficult to know when is safe to free it, at least - * without some expensive synchronization. - * - * If we keep the object freelisted, in the worst case losing this race just - * becomes a spurious read notification on a reused fd. - */ - -/* The alarm system needs to be able to wakeup 'some poller' sometimes - * (specifically when a new alarm needs to be triggered earlier than the next - * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a - * case occurs. */ - -static grpc_fd* fd_freelist = nullptr; -static gpr_mu fd_freelist_mu; - -#ifndef NDEBUG -#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__) -#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) -static void ref_by(grpc_fd* fd, int n, const char* reason, const char* file, - int line) { - if (grpc_trace_fd_refcount.enabled()) { - gpr_log(GPR_DEBUG, - "FD %d %p ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", - fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), - gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); - } -#else -#define REF_BY(fd, n, reason) ref_by(fd, n) -#define UNREF_BY(fd, n, reason) unref_by(fd, n) -static void ref_by(grpc_fd* fd, int n) { -#endif - GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0); -} - -#ifndef NDEBUG -static void unref_by(grpc_fd* fd, int n, const char* reason, const char* file, - int line) { - if (grpc_trace_fd_refcount.enabled()) { - gpr_log(GPR_DEBUG, - "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", - fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), - gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); - } -#else -static void unref_by(grpc_fd* fd, int n) { -#endif - gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n); - if (old == n) { - /* Add the fd to the freelist */ - gpr_mu_lock(&fd_freelist_mu); - fd->freelist_next = fd_freelist; - fd_freelist = fd; - grpc_iomgr_unregister_object(&fd->iomgr_object); - - fd->read_closure->DestroyEvent(); - fd->write_closure->DestroyEvent(); - fd->error_closure->DestroyEvent(); - - gpr_mu_unlock(&fd_freelist_mu); - } else { - GPR_ASSERT(old > n); - } -} - -/* Increment refcount by two to avoid changing the orphan bit */ -#ifndef NDEBUG -static void fd_ref(grpc_fd* fd, const char* reason, const char* file, - int line) { - ref_by(fd, 2, reason, file, line); -} - -static void fd_unref(grpc_fd* fd, const char* reason, const char* file, - int line) { - unref_by(fd, 2, reason, file, line); -} -#else -static void fd_ref(grpc_fd* fd) { ref_by(fd, 2); } -static void fd_unref(grpc_fd* fd) { unref_by(fd, 2); } -#endif - -static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } - -static void fd_global_shutdown(void) { - gpr_mu_lock(&fd_freelist_mu); - gpr_mu_unlock(&fd_freelist_mu); - while (fd_freelist != nullptr) { - grpc_fd* fd = fd_freelist; - fd_freelist = fd_freelist->freelist_next; - gpr_mu_destroy(&fd->po.mu); - gpr_free(fd); - } - gpr_mu_destroy(&fd_freelist_mu); -} - -static grpc_fd* fd_create(int fd, const char* name, bool track_err) { - grpc_fd* new_fd = nullptr; - - gpr_mu_lock(&fd_freelist_mu); - if (fd_freelist != nullptr) { - new_fd = fd_freelist; - fd_freelist = fd_freelist->freelist_next; - } - gpr_mu_unlock(&fd_freelist_mu); - - if (new_fd == nullptr) { - new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd))); - gpr_mu_init(&new_fd->po.mu); - new_fd->read_closure.Init(); - new_fd->write_closure.Init(); - new_fd->error_closure.Init(); - } - - /* Note: It is not really needed to get the new_fd->po.mu lock here. If this - * is a newly created fd (or an fd we got from the freelist), no one else - * would be holding a lock to it anyway. */ - gpr_mu_lock(&new_fd->po.mu); - new_fd->po.pi = nullptr; -#ifndef NDEBUG - new_fd->po.obj_type = POLL_OBJ_FD; -#endif - - gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1); - new_fd->fd = fd; - new_fd->orphaned = false; - new_fd->read_closure->InitEvent(); - new_fd->write_closure->InitEvent(); - new_fd->error_closure->InitEvent(); - new_fd->track_err = track_err; - - new_fd->freelist_next = nullptr; - new_fd->on_done_closure = nullptr; - - gpr_mu_unlock(&new_fd->po.mu); - - char* fd_name; - gpr_asprintf(&fd_name, "%s fd=%d", name, fd); - grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name); - gpr_free(fd_name); - return new_fd; -} - -static int fd_wrapped_fd(grpc_fd* fd) { - int ret_fd = -1; - gpr_mu_lock(&fd->po.mu); - if (!fd->orphaned) { - ret_fd = fd->fd; - } - gpr_mu_unlock(&fd->po.mu); - - return ret_fd; -} - -static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd, - const char* reason) { - grpc_error* error = GRPC_ERROR_NONE; - polling_island* unref_pi = nullptr; - - gpr_mu_lock(&fd->po.mu); - fd->on_done_closure = on_done; - - /* Remove the active status but keep referenced. We want this grpc_fd struct - to be alive (and not added to freelist) until the end of this function */ - REF_BY(fd, 1, reason); - - /* Remove the fd from the polling island: - - Get a lock on the latest polling island (i.e the last island in the - linked list pointed by fd->po.pi). This is the island that - would actually contain the fd - - Remove the fd from the latest polling island - - Unlock the latest polling island - - Set fd->po.pi to NULL (but remove the ref on the polling island - before doing this.) */ - if (fd->po.pi != nullptr) { - polling_island* pi_latest = polling_island_lock(fd->po.pi); - polling_island_remove_fd_locked(pi_latest, fd, &error); - gpr_mu_unlock(&pi_latest->mu); - - unref_pi = fd->po.pi; - fd->po.pi = nullptr; - } - - /* If release_fd is not NULL, we should be relinquishing control of the file - descriptor fd->fd (but we still own the grpc_fd structure). */ - if (release_fd != nullptr) { - *release_fd = fd->fd; - } else { - close(fd->fd); - } - - fd->orphaned = true; - - GRPC_CLOSURE_SCHED(fd->on_done_closure, GRPC_ERROR_REF(error)); - - gpr_mu_unlock(&fd->po.mu); - UNREF_BY(fd, 2, reason); /* Drop the reference */ - if (unref_pi != nullptr) { - /* Unref stale polling island here, outside the fd lock above. - The polling island owns a workqueue which owns an fd, and unreffing - inside the lock can cause an eventual lock loop that makes TSAN very - unhappy. */ - PI_UNREF(unref_pi, "fd_orphan"); - } - if (error != GRPC_ERROR_NONE) { - const char* msg = grpc_error_string(error); - gpr_log(GPR_DEBUG, "fd_orphan: %s", msg); - } - GRPC_ERROR_UNREF(error); -} - -static bool fd_is_shutdown(grpc_fd* fd) { - return fd->read_closure->IsShutdown(); -} - -/* Might be called multiple times */ -static void fd_shutdown(grpc_fd* fd, grpc_error* why) { - if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) { - shutdown(fd->fd, SHUT_RDWR); - fd->write_closure->SetShutdown(GRPC_ERROR_REF(why)); - fd->error_closure->SetShutdown(GRPC_ERROR_REF(why)); - } - GRPC_ERROR_UNREF(why); -} - -static void fd_notify_on_read(grpc_fd* fd, grpc_closure* closure) { - fd->read_closure->NotifyOn(closure); -} - -static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) { - fd->write_closure->NotifyOn(closure); -} - -static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) { - fd->error_closure->NotifyOn(closure); -} - -static void fd_become_readable(grpc_fd* fd) { fd->read_closure->SetReady(); } - -static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); } - -static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); } - -/******************************************************************************* - * Pollset Definitions - */ -GPR_TLS_DECL(g_current_thread_pollset); -GPR_TLS_DECL(g_current_thread_worker); -static __thread bool g_initialized_sigmask; -static __thread sigset_t g_orig_sigmask; - -static void sig_handler(int sig_num) { -#ifdef GRPC_EPOLL_DEBUG - gpr_log(GPR_INFO, "Received signal %d", sig_num); -#endif -} - -static void poller_kick_init() { signal(grpc_wakeup_signal, sig_handler); } - -/* Global state management */ -static grpc_error* pollset_global_init(void) { - gpr_tls_init(&g_current_thread_pollset); - gpr_tls_init(&g_current_thread_worker); - poller_kick_init(); - return GRPC_ERROR_NONE; -} - -static void pollset_global_shutdown(void) { - gpr_tls_destroy(&g_current_thread_pollset); - gpr_tls_destroy(&g_current_thread_worker); -} - -static grpc_error* pollset_worker_kick(grpc_pollset_worker* worker) { - grpc_error* err = GRPC_ERROR_NONE; - - /* Kick the worker only if it was not already kicked */ - if (gpr_atm_no_barrier_cas(&worker->is_kicked, static_cast<gpr_atm>(0), - static_cast<gpr_atm>(1))) { - GRPC_POLLING_TRACE( - "pollset_worker_kick: Kicking worker: %p (thread id: %ld)", - (void*)worker, (long int)worker->pt_id); - int err_num = pthread_kill(worker->pt_id, grpc_wakeup_signal); - if (err_num != 0) { - err = GRPC_OS_ERROR(err_num, "pthread_kill"); - } - } - return err; -} - -/* Return 1 if the pollset has active threads in pollset_work (pollset must - * be locked) */ -static int pollset_has_workers(grpc_pollset* p) { - return p->root_worker.next != &p->root_worker; -} - -static void remove_worker(grpc_pollset* p, grpc_pollset_worker* worker) { - worker->prev->next = worker->next; - worker->next->prev = worker->prev; -} - -static grpc_pollset_worker* pop_front_worker(grpc_pollset* p) { - if (pollset_has_workers(p)) { - grpc_pollset_worker* w = p->root_worker.next; - remove_worker(p, w); - return w; - } else { - return nullptr; - } -} - -static void push_back_worker(grpc_pollset* p, grpc_pollset_worker* worker) { - worker->next = &p->root_worker; - worker->prev = worker->next->prev; - worker->prev->next = worker->next->prev = worker; -} - -static void push_front_worker(grpc_pollset* p, grpc_pollset_worker* worker) { - worker->prev = &p->root_worker; - worker->next = worker->prev->next; - worker->prev->next = worker->next->prev = worker; -} - -/* p->mu must be held before calling this function */ -static grpc_error* pollset_kick(grpc_pollset* p, - grpc_pollset_worker* specific_worker) { - GPR_TIMER_SCOPE("pollset_kick", 0); - grpc_error* error = GRPC_ERROR_NONE; - GRPC_STATS_INC_POLLSET_KICK(); - const char* err_desc = "Kick Failure"; - grpc_pollset_worker* worker = specific_worker; - if (worker != nullptr) { - if (worker == GRPC_POLLSET_KICK_BROADCAST) { - if (pollset_has_workers(p)) { - GPR_TIMER_SCOPE("pollset_kick.broadcast", 0); - for (worker = p->root_worker.next; worker != &p->root_worker; - worker = worker->next) { - if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) { - append_error(&error, pollset_worker_kick(worker), err_desc); - } - } - } else { - p->kicked_without_pollers = true; - } - } else { - GPR_TIMER_MARK("kicked_specifically", 0); - if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) { - append_error(&error, pollset_worker_kick(worker), err_desc); - } - } - } else if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)p) { - /* Since worker == NULL, it means that we can kick "any" worker on this - pollset 'p'. If 'p' happens to be the same pollset this thread is - currently polling (i.e in pollset_work() function), then there is no need - to kick any other worker since the current thread can just absorb the - kick. This is the reason why we enter this case only when - g_current_thread_pollset is != p */ - - GPR_TIMER_MARK("kick_anonymous", 0); - worker = pop_front_worker(p); - if (worker != nullptr) { - GPR_TIMER_MARK("finally_kick", 0); - push_back_worker(p, worker); - append_error(&error, pollset_worker_kick(worker), err_desc); - } else { - GPR_TIMER_MARK("kicked_no_pollers", 0); - p->kicked_without_pollers = true; - } - } - - GRPC_LOG_IF_ERROR("pollset_kick", GRPC_ERROR_REF(error)); - return error; -} - -static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) { - gpr_mu_init(&pollset->po.mu); - *mu = &pollset->po.mu; - pollset->po.pi = nullptr; -#ifndef NDEBUG - pollset->po.obj_type = POLL_OBJ_POLLSET; -#endif - - pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker; - pollset->kicked_without_pollers = false; - - pollset->shutting_down = false; - pollset->finish_shutdown_called = false; - pollset->shutdown_done = nullptr; -} - -static int poll_deadline_to_millis_timeout(grpc_millis millis) { - if (millis == GRPC_MILLIS_INF_FUTURE) return -1; - grpc_millis delta = millis - grpc_core::ExecCtx::Get()->Now(); - if (delta > INT_MAX) - return INT_MAX; - else if (delta < 0) - return 0; - else - return static_cast<int>(delta); -} - -static void pollset_release_polling_island(grpc_pollset* ps, - const char* reason) { - if (ps->po.pi != nullptr) { - PI_UNREF(ps->po.pi, reason); - } - ps->po.pi = nullptr; -} - -static void finish_shutdown_locked(grpc_pollset* pollset) { - /* The pollset cannot have any workers if we are at this stage */ - GPR_ASSERT(!pollset_has_workers(pollset)); - - pollset->finish_shutdown_called = true; - - /* Release the ref and set pollset->po.pi to NULL */ - pollset_release_polling_island(pollset, "ps_shutdown"); - GRPC_CLOSURE_SCHED(pollset->shutdown_done, GRPC_ERROR_NONE); -} - -/* pollset->po.mu lock must be held by the caller before calling this */ -static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) { - GPR_TIMER_SCOPE("pollset_shutdown", 0); - GPR_ASSERT(!pollset->shutting_down); - pollset->shutting_down = true; - pollset->shutdown_done = closure; - pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); - - /* If the pollset has any workers, we cannot call finish_shutdown_locked() - because it would release the underlying polling island. In such a case, we - let the last worker call finish_shutdown_locked() from pollset_work() */ - if (!pollset_has_workers(pollset)) { - GPR_ASSERT(!pollset->finish_shutdown_called); - GPR_TIMER_MARK("pollset_shutdown.finish_shutdown_locked", 0); - finish_shutdown_locked(pollset); - } -} - -/* pollset_shutdown is guaranteed to be called before pollset_destroy. So other - * than destroying the mutexes, there is nothing special that needs to be done - * here */ -static void pollset_destroy(grpc_pollset* pollset) { - GPR_ASSERT(!pollset_has_workers(pollset)); - gpr_mu_destroy(&pollset->po.mu); -} - -#define GRPC_EPOLL_MAX_EVENTS 100 -/* Note: sig_mask contains the signal mask to use *during* epoll_wait() */ -static void pollset_work_and_unlock(grpc_pollset* pollset, - grpc_pollset_worker* worker, int timeout_ms, - sigset_t* sig_mask, grpc_error** error) { - GPR_TIMER_SCOPE("pollset_work_and_unlock", 0); - struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS]; - int epoll_fd = -1; - int ep_rv; - polling_island* pi = nullptr; - char* err_msg; - const char* err_desc = "pollset_work_and_unlock"; - - /* We need to get the epoll_fd to wait on. The epoll_fd is in inside the - latest polling island pointed by pollset->po.pi - - Since epoll_fd is immutable, we can read it without obtaining the polling - island lock. There is however a possibility that the polling island (from - which we got the epoll_fd) got merged with another island while we are - in this function. This is still okay because in such a case, we will wakeup - right-away from epoll_wait() and pick up the latest polling_island the next - this function (i.e pollset_work_and_unlock()) is called */ - - if (pollset->po.pi == nullptr) { - pollset->po.pi = polling_island_create(nullptr, error); - if (pollset->po.pi == nullptr) { - return; /* Fatal error. We cannot continue */ - } - - PI_ADD_REF(pollset->po.pi, "ps"); - GRPC_POLLING_TRACE("pollset_work: pollset: %p created new pi: %p", - (void*)pollset, (void*)pollset->po.pi); - } - - pi = polling_island_maybe_get_latest(pollset->po.pi); - epoll_fd = pi->epoll_fd; - - /* Update the pollset->po.pi since the island being pointed by - pollset->po.pi maybe older than the one pointed by pi) */ - if (pollset->po.pi != pi) { - /* Always do PI_ADD_REF before PI_UNREF because PI_UNREF may cause the - polling island to be deleted */ - PI_ADD_REF(pi, "ps"); - PI_UNREF(pollset->po.pi, "ps"); - pollset->po.pi = pi; - } - - /* Add an extra ref so that the island does not get destroyed (which means - the epoll_fd won't be closed) while we are are doing an epoll_wait() on the - epoll_fd */ - PI_ADD_REF(pi, "ps_work"); - gpr_mu_unlock(&pollset->po.mu); - - gpr_atm_no_barrier_fetch_add(&pi->poller_count, 1); - g_current_thread_polling_island = pi; - - GRPC_SCHEDULING_START_BLOCKING_REGION; - GRPC_STATS_INC_SYSCALL_POLL(); - ep_rv = - epoll_pwait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms, sig_mask); - GRPC_SCHEDULING_END_BLOCKING_REGION; - if (ep_rv < 0) { - if (errno != EINTR) { - gpr_asprintf(&err_msg, - "epoll_wait() epoll fd: %d failed with error: %d (%s)", - epoll_fd, errno, strerror(errno)); - append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); - } else { - /* We were interrupted. Save an interation by doing a zero timeout - epoll_wait to see if there are any other events of interest */ - GRPC_POLLING_TRACE("pollset_work: pollset: %p, worker: %p received kick", - (void*)pollset, (void*)worker); - ep_rv = epoll_wait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0); - } - } - -#ifdef GRPC_TSAN - /* See the definition of g_poll_sync for more details */ - gpr_atm_acq_load(&g_epoll_sync); -#endif /* defined(GRPC_TSAN) */ - - for (int i = 0; i < ep_rv; ++i) { - void* data_ptr = ep_ev[i].data.ptr; - if (data_ptr == &polling_island_wakeup_fd) { - GRPC_POLLING_TRACE( - "pollset_work: pollset: %p, worker: %p polling island (epoll_fd: " - "%d) got merged", - (void*)pollset, (void*)worker, epoll_fd); - /* This means that our polling island is merged with a different - island. We do not have to do anything here since the subsequent call - to the function pollset_work_and_unlock() will pick up the correct - epoll_fd */ - } else { - grpc_fd* fd = reinterpret_cast<grpc_fd*>( - reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1)); - bool track_err = - reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1); - bool cancel = (ep_ev[i].events & EPOLLHUP) != 0; - bool error = (ep_ev[i].events & EPOLLERR) != 0; - bool read_ev = (ep_ev[i].events & (EPOLLIN | EPOLLPRI)) != 0; - bool write_ev = (ep_ev[i].events & EPOLLOUT) != 0; - bool err_fallback = error && !track_err; - - if (error && !err_fallback) { - fd_has_errors(fd); - } - if (read_ev || cancel || err_fallback) { - fd_become_readable(fd); - } - if (write_ev || cancel || err_fallback) { - fd_become_writable(fd); - } - } - } - - g_current_thread_polling_island = nullptr; - gpr_atm_no_barrier_fetch_add(&pi->poller_count, -1); - - GPR_ASSERT(pi != nullptr); - - /* Before leaving, release the extra ref we added to the polling island. It - is important to use "pi" here (i.e our old copy of pollset->po.pi - that we got before releasing the polling island lock). This is because - pollset->po.pi pointer might get udpated in other parts of the - code when there is an island merge while we are doing epoll_wait() above */ - PI_UNREF(pi, "ps_work"); -} - -/* pollset->po.mu lock must be held by the caller before calling this. - The function pollset_work() may temporarily release the lock (pollset->po.mu) - during the course of its execution but it will always re-acquire the lock and - ensure that it is held by the time the function returns */ -static grpc_error* pollset_work(grpc_pollset* pollset, - grpc_pollset_worker** worker_hdl, - grpc_millis deadline) { - GPR_TIMER_SCOPE("pollset_work", 0); - grpc_error* error = GRPC_ERROR_NONE; - int timeout_ms = poll_deadline_to_millis_timeout(deadline); - - sigset_t new_mask; - - grpc_pollset_worker worker; - worker.next = worker.prev = nullptr; - worker.pt_id = pthread_self(); - gpr_atm_no_barrier_store(&worker.is_kicked, (gpr_atm)0); - - if (worker_hdl) *worker_hdl = &worker; - - gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); - gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); - - if (pollset->kicked_without_pollers) { - /* If the pollset was kicked without pollers, pretend that the current - worker got the kick and skip polling. A kick indicates that there is some - work that needs attention like an event on the completion queue or an - alarm */ - GPR_TIMER_MARK("pollset_work.kicked_without_pollers", 0); - pollset->kicked_without_pollers = 0; - } else if (!pollset->shutting_down) { - /* We use the posix-signal with number 'grpc_wakeup_signal' for waking up - (i.e 'kicking') a worker in the pollset. A 'kick' is a way to inform the - worker that there is some pending work that needs immediate attention - (like an event on the completion queue, or a polling island merge that - results in a new epoll-fd to wait on) and that the worker should not - spend time waiting in epoll_pwait(). - - A worker can be kicked anytime from the point it is added to the pollset - via push_front_worker() (or push_back_worker()) to the point it is - removed via remove_worker(). - If the worker is kicked before/during it calls epoll_pwait(), it should - immediately exit from epoll_wait(). If the worker is kicked after it - returns from epoll_wait(), then nothing really needs to be done. - - To accomplish this, we mask 'grpc_wakeup_signal' on this thread at all - times *except* when it is in epoll_pwait(). This way, the worker never - misses acting on a kick */ - - if (!g_initialized_sigmask) { - sigemptyset(&new_mask); - sigaddset(&new_mask, grpc_wakeup_signal); - pthread_sigmask(SIG_BLOCK, &new_mask, &g_orig_sigmask); - sigdelset(&g_orig_sigmask, grpc_wakeup_signal); - g_initialized_sigmask = true; - /* new_mask: The new thread mask which blocks 'grpc_wakeup_signal'. - This is the mask used at all times *except during - epoll_wait()*" - g_orig_sigmask: The thread mask which allows 'grpc_wakeup_signal' and - this is the mask to use *during epoll_wait()* - - The new_mask is set on the worker before it is added to the pollset - (i.e before it can be kicked) */ - } - - push_front_worker(pollset, &worker); /* Add worker to pollset */ - - pollset_work_and_unlock(pollset, &worker, timeout_ms, &g_orig_sigmask, - &error); - grpc_core::ExecCtx::Get()->Flush(); - - gpr_mu_lock(&pollset->po.mu); - - /* Note: There is no need to reset worker.is_kicked to 0 since we are no - longer going to use this worker */ - remove_worker(pollset, &worker); - } - - /* If we are the last worker on the pollset (i.e pollset_has_workers() is - false at this point) and the pollset is shutting down, we may have to - finish the shutdown process by calling finish_shutdown_locked(). - See pollset_shutdown() for more details. - - Note: Continuing to access pollset here is safe; it is the caller's - responsibility to not destroy a pollset when it has outstanding calls to - pollset_work() */ - if (pollset->shutting_down && !pollset_has_workers(pollset) && - !pollset->finish_shutdown_called) { - GPR_TIMER_MARK("pollset_work.finish_shutdown_locked", 0); - finish_shutdown_locked(pollset); - - gpr_mu_unlock(&pollset->po.mu); - grpc_core::ExecCtx::Get()->Flush(); - gpr_mu_lock(&pollset->po.mu); - } - - if (worker_hdl) *worker_hdl = nullptr; - - gpr_tls_set(&g_current_thread_pollset, (intptr_t)0); - gpr_tls_set(&g_current_thread_worker, (intptr_t)0); - - GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error)); - return error; -} - -static void add_poll_object(poll_obj* bag, poll_obj_type bag_type, - poll_obj* item, poll_obj_type item_type) { - GPR_TIMER_SCOPE("add_poll_object", 0); - -#ifndef NDEBUG - GPR_ASSERT(item->obj_type == item_type); - GPR_ASSERT(bag->obj_type == bag_type); -#endif - - grpc_error* error = GRPC_ERROR_NONE; - polling_island* pi_new = nullptr; - - gpr_mu_lock(&bag->mu); - gpr_mu_lock(&item->mu); - -retry: - /* - * 1) If item->pi and bag->pi are both non-NULL and equal, do nothing - * 2) If item->pi and bag->pi are both NULL, create a new polling island (with - * a refcount of 2) and point item->pi and bag->pi to the new island - * 3) If exactly one of item->pi or bag->pi is NULL, update it to point to - * the other's non-NULL pi - * 4) Finally if item->pi and bag-pi are non-NULL and not-equal, merge the - * polling islands and update item->pi and bag->pi to point to the new - * island - */ - - /* Early out if we are trying to add an 'fd' to a 'bag' but the fd is already - * orphaned */ - if (item_type == POLL_OBJ_FD && (FD_FROM_PO(item))->orphaned) { - gpr_mu_unlock(&item->mu); - gpr_mu_unlock(&bag->mu); - return; - } - - if (item->pi == bag->pi) { - pi_new = item->pi; - if (pi_new == nullptr) { - /* GPR_ASSERT(item->pi == bag->pi == NULL) */ - - /* If we are adding an fd to a bag (i.e pollset or pollset_set), then - * we need to do some extra work to make TSAN happy */ - if (item_type == POLL_OBJ_FD) { - /* Unlock before creating a new polling island: the polling island will - create a workqueue which creates a file descriptor, and holding an fd - lock here can eventually cause a loop to appear to TSAN (making it - unhappy). We don't think it's a real loop (there's an epoch point - where that loop possibility disappears), but the advantages of - keeping TSAN happy outweigh any performance advantage we might have - by keeping the lock held. */ - gpr_mu_unlock(&item->mu); - pi_new = polling_island_create(FD_FROM_PO(item), &error); - gpr_mu_lock(&item->mu); - - /* Need to reverify any assumptions made between the initial lock and - getting to this branch: if they've changed, we need to throw away our - work and figure things out again. */ - if (item->pi != nullptr) { - GRPC_POLLING_TRACE( - "add_poll_object: Raced creating new polling island. pi_new: %p " - "(fd: %d, %s: %p)", - (void*)pi_new, FD_FROM_PO(item)->fd, poll_obj_string(bag_type), - (void*)bag); - /* No need to lock 'pi_new' here since this is a new polling island - and no one has a reference to it yet */ - polling_island_remove_all_fds_locked(pi_new, true, &error); - - /* Ref and unref so that the polling island gets deleted during unref - */ - PI_ADD_REF(pi_new, "dance_of_destruction"); - PI_UNREF(pi_new, "dance_of_destruction"); - goto retry; - } - } else { - pi_new = polling_island_create(nullptr, &error); - } - - GRPC_POLLING_TRACE( - "add_poll_object: Created new polling island. pi_new: %p (%s: %p, " - "%s: %p)", - (void*)pi_new, poll_obj_string(item_type), (void*)item, - poll_obj_string(bag_type), (void*)bag); - } else { - GRPC_POLLING_TRACE( - "add_poll_object: Same polling island. pi: %p (%s, %s)", - (void*)pi_new, poll_obj_string(item_type), poll_obj_string(bag_type)); - } - } else if (item->pi == nullptr) { - /* GPR_ASSERT(bag->pi != NULL) */ - /* Make pi_new point to latest pi*/ - pi_new = polling_island_lock(bag->pi); - - if (item_type == POLL_OBJ_FD) { - grpc_fd* fd = FD_FROM_PO(item); - polling_island_add_fds_locked(pi_new, &fd, 1, true, &error); - } - - gpr_mu_unlock(&pi_new->mu); - GRPC_POLLING_TRACE( - "add_poll_obj: item->pi was NULL. pi_new: %p (item(%s): %p, " - "bag(%s): %p)", - (void*)pi_new, poll_obj_string(item_type), (void*)item, - poll_obj_string(bag_type), (void*)bag); - } else if (bag->pi == nullptr) { - /* GPR_ASSERT(item->pi != NULL) */ - /* Make pi_new to point to latest pi */ - pi_new = polling_island_lock(item->pi); - gpr_mu_unlock(&pi_new->mu); - GRPC_POLLING_TRACE( - "add_poll_obj: bag->pi was NULL. pi_new: %p (item(%s): %p, " - "bag(%s): %p)", - (void*)pi_new, poll_obj_string(item_type), (void*)item, - poll_obj_string(bag_type), (void*)bag); - } else { - pi_new = polling_island_merge(item->pi, bag->pi, &error); - GRPC_POLLING_TRACE( - "add_poll_obj: polling islands merged. pi_new: %p (item(%s): %p, " - "bag(%s): %p)", - (void*)pi_new, poll_obj_string(item_type), (void*)item, - poll_obj_string(bag_type), (void*)bag); - } - - /* At this point, pi_new is the polling island that both item->pi and bag->pi - MUST be pointing to */ - - if (item->pi != pi_new) { - PI_ADD_REF(pi_new, poll_obj_string(item_type)); - if (item->pi != nullptr) { - PI_UNREF(item->pi, poll_obj_string(item_type)); - } - item->pi = pi_new; - } - - if (bag->pi != pi_new) { - PI_ADD_REF(pi_new, poll_obj_string(bag_type)); - if (bag->pi != nullptr) { - PI_UNREF(bag->pi, poll_obj_string(bag_type)); - } - bag->pi = pi_new; - } - - gpr_mu_unlock(&item->mu); - gpr_mu_unlock(&bag->mu); - - GRPC_LOG_IF_ERROR("add_poll_object", error); -} - -static void pollset_add_fd(grpc_pollset* pollset, grpc_fd* fd) { - add_poll_object(&pollset->po, POLL_OBJ_POLLSET, &fd->po, POLL_OBJ_FD); -} - -/******************************************************************************* - * Pollset-set Definitions - */ - -static grpc_pollset_set* pollset_set_create(void) { - grpc_pollset_set* pss = - static_cast<grpc_pollset_set*>(gpr_malloc(sizeof(*pss))); - gpr_mu_init(&pss->po.mu); - pss->po.pi = nullptr; -#ifndef NDEBUG - pss->po.obj_type = POLL_OBJ_POLLSET_SET; -#endif - return pss; -} - -static void pollset_set_destroy(grpc_pollset_set* pss) { - gpr_mu_destroy(&pss->po.mu); - - if (pss->po.pi != nullptr) { - PI_UNREF(pss->po.pi, "pss_destroy"); - } - - gpr_free(pss); -} - -static void pollset_set_add_fd(grpc_pollset_set* pss, grpc_fd* fd) { - add_poll_object(&pss->po, POLL_OBJ_POLLSET_SET, &fd->po, POLL_OBJ_FD); -} - -static void pollset_set_del_fd(grpc_pollset_set* pss, grpc_fd* fd) { - /* Nothing to do */ -} - -static void pollset_set_add_pollset(grpc_pollset_set* pss, grpc_pollset* ps) { - add_poll_object(&pss->po, POLL_OBJ_POLLSET_SET, &ps->po, POLL_OBJ_POLLSET); -} - -static void pollset_set_del_pollset(grpc_pollset_set* pss, grpc_pollset* ps) { - /* Nothing to do */ -} - -static void pollset_set_add_pollset_set(grpc_pollset_set* bag, - grpc_pollset_set* item) { - add_poll_object(&bag->po, POLL_OBJ_POLLSET_SET, &item->po, - POLL_OBJ_POLLSET_SET); -} - -static void pollset_set_del_pollset_set(grpc_pollset_set* bag, - grpc_pollset_set* item) { - /* Nothing to do */ -} - -/* Test helper functions - * */ -void* grpc_fd_get_polling_island(grpc_fd* fd) { - polling_island* pi; - - gpr_mu_lock(&fd->po.mu); - pi = fd->po.pi; - gpr_mu_unlock(&fd->po.mu); - - return pi; -} - -void* grpc_pollset_get_polling_island(grpc_pollset* ps) { - polling_island* pi; - - gpr_mu_lock(&ps->po.mu); - pi = ps->po.pi; - gpr_mu_unlock(&ps->po.mu); - - return pi; -} - -bool grpc_are_polling_islands_equal(void* p, void* q) { - polling_island* p1 = static_cast<polling_island*>(p); - polling_island* p2 = static_cast<polling_island*>(q); - - /* Note: polling_island_lock_pair() may change p1 and p2 to point to the - latest polling islands in their respective linked lists */ - polling_island_lock_pair(&p1, &p2); - polling_island_unlock_pair(p1, p2); - - return p1 == p2; -} - -/******************************************************************************* - * Event engine binding - */ - -static void shutdown_engine(void) { - fd_global_shutdown(); - pollset_global_shutdown(); - polling_island_global_shutdown(); -} - -static const grpc_event_engine_vtable vtable = { - sizeof(grpc_pollset), - true, - - fd_create, - fd_wrapped_fd, - fd_orphan, - fd_shutdown, - fd_notify_on_read, - fd_notify_on_write, - fd_notify_on_error, - fd_become_readable, - fd_become_writable, - fd_has_errors, - fd_is_shutdown, - - pollset_init, - pollset_shutdown, - pollset_destroy, - pollset_work, - pollset_kick, - pollset_add_fd, - - pollset_set_create, - pollset_set_destroy, - pollset_set_add_pollset, - pollset_set_del_pollset, - pollset_set_add_pollset_set, - pollset_set_del_pollset_set, - pollset_set_add_fd, - pollset_set_del_fd, - - shutdown_engine, -}; - -/* It is possible that GLIBC has epoll but the underlying kernel doesn't. - * Create a dummy epoll_fd to make sure epoll support is available */ -static bool is_epoll_available() { - int fd = epoll_create1(EPOLL_CLOEXEC); - if (fd < 0) { - gpr_log( - GPR_ERROR, - "epoll_create1 failed with error: %d. Not using epoll polling engine", - fd); - return false; - } - close(fd); - return true; -} - -const grpc_event_engine_vtable* grpc_init_epollsig_linux( - bool explicit_request) { - /* If use of signals is disabled, we cannot use epoll engine*/ - if (is_grpc_wakeup_signal_initialized && grpc_wakeup_signal < 0) { - gpr_log(GPR_ERROR, "Skipping epollsig because use of signals is disabled."); - return nullptr; - } - - if (!grpc_has_wakeup_fd()) { - gpr_log(GPR_ERROR, "Skipping epollsig because of no wakeup fd."); - return nullptr; - } - - if (!is_epoll_available()) { - gpr_log(GPR_ERROR, "Skipping epollsig because epoll is unavailable."); - return nullptr; - } - - if (!is_grpc_wakeup_signal_initialized) { - if (explicit_request) { - grpc_use_signal(SIGRTMIN + 6); - } else { - gpr_log(GPR_ERROR, - "Skipping epollsig because uninitialized wakeup signal."); - return nullptr; - } - } - - fd_global_init(); - - if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { - return nullptr; - } - - if (!GRPC_LOG_IF_ERROR("polling_island_global_init", - polling_island_global_init())) { - return nullptr; - } - - return &vtable; -} - -#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */ -#if defined(GRPC_POSIX_SOCKET_EV_EPOLLSIG) -#include "src/core/lib/iomgr/ev_epollsig_linux.h" -/* If GRPC_LINUX_EPOLL_CREATE1 is not defined, it means - epoll_create1 is not available. Return NULL */ -const grpc_event_engine_vtable* grpc_init_epollsig_linux( - bool explicit_request) { - return nullptr; -} -#endif /* defined(GRPC_POSIX_SOCKET) */ - -void grpc_use_signal(int signum) {} -#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */ diff --git a/src/core/lib/iomgr/ev_poll_posix.cc b/src/core/lib/iomgr/ev_poll_posix.cc index fb4c71ef71..16562538a6 100644 --- a/src/core/lib/iomgr/ev_poll_posix.cc +++ b/src/core/lib/iomgr/ev_poll_posix.cc @@ -60,6 +60,19 @@ typedef struct grpc_fd_watcher { grpc_fd* fd; } grpc_fd_watcher; +typedef struct grpc_cached_wakeup_fd grpc_cached_wakeup_fd; + +/* Only used when GRPC_ENABLE_FORK_SUPPORT=1 */ +struct grpc_fork_fd_list { + /* Only one of fd or cached_wakeup_fd will be set. The unused field will be + set to nullptr. */ + grpc_fd* fd; + grpc_cached_wakeup_fd* cached_wakeup_fd; + + grpc_fork_fd_list* next; + grpc_fork_fd_list* prev; +}; + struct grpc_fd { int fd; /* refst format: @@ -108,8 +121,18 @@ struct grpc_fd { grpc_closure* on_done_closure; grpc_iomgr_object iomgr_object; + + /* Only used when GRPC_ENABLE_FORK_SUPPORT=1 */ + grpc_fork_fd_list* fork_fd_list; }; +/* True when GRPC_ENABLE_FORK_SUPPORT=1. We do not support fork with poll-cv */ +static bool track_fds_for_fork = false; + +/* Only used when GRPC_ENABLE_FORK_SUPPORT=1 */ +static grpc_fork_fd_list* fork_fd_list_head = nullptr; +static gpr_mu fork_fd_list_mu; + /* Begin polling on an fd. Registers that the given pollset is interested in this fd - so that if read or writability interest changes, the pollset can be kicked to pick up that @@ -156,6 +179,9 @@ static void fd_unref(grpc_fd* fd); typedef struct grpc_cached_wakeup_fd { grpc_wakeup_fd fd; struct grpc_cached_wakeup_fd* next; + + /* Only used when GRPC_ENABLE_FORK_SUPPORT=1 */ + grpc_fork_fd_list* fork_fd_list; } grpc_cached_wakeup_fd; struct grpc_pollset_worker { @@ -281,9 +307,61 @@ poll_hash_table poll_cache; grpc_cv_fd_table g_cvfds; /******************************************************************************* - * fd_posix.c + * functions to track opened fds. No-ops unless track_fds_for_fork is true. */ +static void fork_fd_list_remove_node(grpc_fork_fd_list* node) { + if (track_fds_for_fork) { + gpr_mu_lock(&fork_fd_list_mu); + if (fork_fd_list_head == node) { + fork_fd_list_head = node->next; + } + if (node->prev != nullptr) { + node->prev->next = node->next; + } + if (node->next != nullptr) { + node->next->prev = node->prev; + } + gpr_free(node); + gpr_mu_unlock(&fork_fd_list_mu); + } +} + +static void fork_fd_list_add_node(grpc_fork_fd_list* node) { + gpr_mu_lock(&fork_fd_list_mu); + node->next = fork_fd_list_head; + node->prev = nullptr; + if (fork_fd_list_head != nullptr) { + fork_fd_list_head->prev = node; + } + fork_fd_list_head = node; + gpr_mu_unlock(&fork_fd_list_mu); +} + +static void fork_fd_list_add_grpc_fd(grpc_fd* fd) { + if (track_fds_for_fork) { + fd->fork_fd_list = + static_cast<grpc_fork_fd_list*>(gpr_malloc(sizeof(grpc_fork_fd_list))); + fd->fork_fd_list->fd = fd; + fd->fork_fd_list->cached_wakeup_fd = nullptr; + fork_fd_list_add_node(fd->fork_fd_list); + } +} + +static void fork_fd_list_add_wakeup_fd(grpc_cached_wakeup_fd* fd) { + if (track_fds_for_fork) { + fd->fork_fd_list = + static_cast<grpc_fork_fd_list*>(gpr_malloc(sizeof(grpc_fork_fd_list))); + fd->fork_fd_list->cached_wakeup_fd = fd; + fd->fork_fd_list->fd = nullptr; + fork_fd_list_add_node(fd->fork_fd_list); + } +} + + /******************************************************************************* + * fd_posix.c + */ + #ifndef NDEBUG #define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__) #define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) @@ -319,6 +397,7 @@ static void unref_by(grpc_fd* fd, int n) { if (old == n) { gpr_mu_destroy(&fd->mu); grpc_iomgr_unregister_object(&fd->iomgr_object); + fork_fd_list_remove_node(fd->fork_fd_list); if (fd->shutdown) GRPC_ERROR_UNREF(fd->shutdown_error); gpr_free(fd); } else { @@ -347,6 +426,7 @@ static grpc_fd* fd_create(int fd, const char* name, bool track_err) { gpr_asprintf(&name2, "%s fd=%d", name, fd); grpc_iomgr_register_object(&r->iomgr_object, name2); gpr_free(name2); + fork_fd_list_add_grpc_fd(r); return r; } @@ -822,6 +902,7 @@ static void pollset_destroy(grpc_pollset* pollset) { GPR_ASSERT(!pollset_has_workers(pollset)); while (pollset->local_wakeup_cache) { grpc_cached_wakeup_fd* next = pollset->local_wakeup_cache->next; + fork_fd_list_remove_node(pollset->local_wakeup_cache->fork_fd_list); grpc_wakeup_fd_destroy(&pollset->local_wakeup_cache->fd); gpr_free(pollset->local_wakeup_cache); pollset->local_wakeup_cache = next; @@ -895,6 +976,7 @@ static grpc_error* pollset_work(grpc_pollset* pollset, worker.wakeup_fd = static_cast<grpc_cached_wakeup_fd*>( gpr_malloc(sizeof(*worker.wakeup_fd))); error = grpc_wakeup_fd_init(&worker.wakeup_fd->fd); + fork_fd_list_add_wakeup_fd(worker.wakeup_fd); if (error != GRPC_ERROR_NONE) { GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error)); return error; @@ -1705,6 +1787,10 @@ static void shutdown_engine(void) { if (grpc_cv_wakeup_fds_enabled()) { global_cv_fd_table_shutdown(); } + if (track_fds_for_fork) { + gpr_mu_destroy(&fork_fd_list_mu); + grpc_core::Fork::SetResetChildPollingEngineFunc(nullptr); + } } static const grpc_event_engine_vtable vtable = { @@ -1742,6 +1828,26 @@ static const grpc_event_engine_vtable vtable = { shutdown_engine, }; +/* Called by the child process's post-fork handler to close open fds, including + * worker wakeup fds. This allows gRPC to shutdown in the child process without + * interfering with connections or RPCs ongoing in the parent. */ +static void reset_event_manager_on_fork() { + gpr_mu_lock(&fork_fd_list_mu); + while (fork_fd_list_head != nullptr) { + if (fork_fd_list_head->fd != nullptr) { + close(fork_fd_list_head->fd->fd); + fork_fd_list_head->fd->fd = -1; + } else { + close(fork_fd_list_head->cached_wakeup_fd->fd.read_fd); + fork_fd_list_head->cached_wakeup_fd->fd.read_fd = -1; + close(fork_fd_list_head->cached_wakeup_fd->fd.write_fd); + fork_fd_list_head->cached_wakeup_fd->fd.write_fd = -1; + } + fork_fd_list_head = fork_fd_list_head->next; + } + gpr_mu_unlock(&fork_fd_list_mu); +} + const grpc_event_engine_vtable* grpc_init_poll_posix(bool explicit_request) { if (!grpc_has_wakeup_fd()) { gpr_log(GPR_ERROR, "Skipping poll because of no wakeup fd."); @@ -1750,6 +1856,12 @@ const grpc_event_engine_vtable* grpc_init_poll_posix(bool explicit_request) { if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { return nullptr; } + if (grpc_core::Fork::Enabled()) { + track_fds_for_fork = true; + gpr_mu_init(&fork_fd_list_mu); + grpc_core::Fork::SetResetChildPollingEngineFunc( + reset_event_manager_on_fork); + } return &vtable; } diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc index b8fe017ce7..8a7dc7b004 100644 --- a/src/core/lib/iomgr/ev_posix.cc +++ b/src/core/lib/iomgr/ev_posix.cc @@ -35,7 +35,6 @@ #include "src/core/lib/gpr/useful.h" #include "src/core/lib/iomgr/ev_epoll1_linux.h" #include "src/core/lib/iomgr/ev_epollex_linux.h" -#include "src/core/lib/iomgr/ev_epollsig_linux.h" #include "src/core/lib/iomgr/ev_poll_posix.h" grpc_core::TraceFlag grpc_polling_trace(false, @@ -59,7 +58,14 @@ grpc_core::DebugOnlyTraceFlag grpc_polling_api_trace(false, "polling_api"); /** Default poll() function - a pointer so that it can be overridden by some * tests */ +#ifndef GPR_AIX grpc_poll_function_type grpc_poll_function = poll; +#else +int aix_poll(struct pollfd fds[], nfds_t nfds, int timeout) { + return poll(fds, nfds, timeout); +} +grpc_poll_function_type grpc_poll_function = aix_poll; +#endif grpc_wakeup_fd grpc_global_wakeup_fd; @@ -116,13 +122,13 @@ const grpc_event_engine_vtable* init_non_polling(bool explicit_request) { // environment variable if that variable is set (which should be a // comma-separated list of one or more event engine names) static event_engine_factory g_factories[] = { - {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr}, - {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr}, - {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux}, - {"epollsig", grpc_init_epollsig_linux}, {"poll", grpc_init_poll_posix}, - {"poll-cv", grpc_init_poll_cv_posix}, {"none", init_non_polling}, - {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr}, - {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr}, + {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr}, + {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr}, + {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux}, + {"poll", grpc_init_poll_posix}, {"poll-cv", grpc_init_poll_cv_posix}, + {"none", init_non_polling}, {ENGINE_TAIL_CUSTOM, nullptr}, + {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr}, + {ENGINE_TAIL_CUSTOM, nullptr}, }; static void add(const char* beg, const char* end, char*** ss, size_t* ns) { @@ -230,14 +236,19 @@ void grpc_event_engine_shutdown(void) { } bool grpc_event_engine_can_track_errors(void) { +/* Only track errors if platform supports errqueue. */ +#ifdef GRPC_LINUX_ERRQUEUE return g_event_engine->can_track_err; +#else + return false; +#endif /* GRPC_LINUX_ERRQUEUE */ } grpc_fd* grpc_fd_create(int fd, const char* name, bool track_err) { GRPC_POLLING_API_TRACE("fd_create(%d, %s, %d)", fd, name, track_err); GRPC_FD_TRACE("fd_create(%d, %s, %d)", fd, name, track_err); - GPR_DEBUG_ASSERT(!track_err || g_event_engine->can_track_err); - return g_event_engine->fd_create(fd, name, track_err); + return g_event_engine->fd_create(fd, name, + track_err && g_event_engine->can_track_err); } int grpc_fd_wrapped_fd(grpc_fd* fd) { diff --git a/src/core/lib/iomgr/exec_ctx.cc b/src/core/lib/iomgr/exec_ctx.cc index 5d5c355ff9..d68fa0714b 100644 --- a/src/core/lib/iomgr/exec_ctx.cc +++ b/src/core/lib/iomgr/exec_ctx.cc @@ -109,6 +109,12 @@ grpc_closure_scheduler* grpc_schedule_on_exec_ctx = &exec_ctx_scheduler; namespace grpc_core { GPR_TLS_CLASS_DEF(ExecCtx::exec_ctx_); +// WARNING: for testing purposes only! +void ExecCtx::TestOnlyGlobalInit(gpr_timespec new_val) { + g_start_time = new_val; + gpr_tls_init(&exec_ctx_); +} + void ExecCtx::GlobalInit(void) { g_start_time = gpr_now(GPR_CLOCK_MONOTONIC); gpr_tls_init(&exec_ctx_); diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h index 8ddab0d381..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 */ @@ -192,6 +187,8 @@ class ExecCtx { now_is_valid_ = true; } + static void TestOnlyGlobalInit(gpr_timespec new_val); + /** Global initialization for ExecCtx. Called by iomgr. */ static void GlobalInit(void); @@ -221,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/fork_posix.cc b/src/core/lib/iomgr/fork_posix.cc index b37384b8db..e957bad73d 100644 --- a/src/core/lib/iomgr/fork_posix.cc +++ b/src/core/lib/iomgr/fork_posix.cc @@ -25,6 +25,7 @@ #include <string.h> #include <grpc/fork.h> +#include <grpc/grpc.h> #include <grpc/support/log.h> #include "src/core/lib/gpr/env.h" @@ -34,7 +35,6 @@ #include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/timer_manager.h" #include "src/core/lib/iomgr/wakeup_fd_posix.h" -#include "src/core/lib/surface/init.h" /* * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK @@ -58,6 +58,12 @@ void grpc_prefork() { "environment variable GRPC_ENABLE_FORK_SUPPORT=1"); return; } + if (strcmp(grpc_get_poll_strategy_name(), "epoll1") != 0 && + strcmp(grpc_get_poll_strategy_name(), "poll") != 0) { + gpr_log(GPR_ERROR, + "Fork support is only compatible with the epoll1 and poll polling " + "strategies"); + } if (!grpc_core::Fork::BlockExecCtx()) { gpr_log(GPR_INFO, "Other threads are currently calling into gRPC, skipping fork() " @@ -84,6 +90,11 @@ void grpc_postfork_child() { if (!skipped_handler) { grpc_core::Fork::AllowExecCtx(); grpc_core::ExecCtx exec_ctx; + grpc_core::Fork::child_postfork_func reset_polling_engine = + grpc_core::Fork::GetResetChildPollingEngineFunc(); + if (reset_polling_engine != nullptr) { + reset_polling_engine(); + } grpc_timer_manager_set_threading(true); grpc_executor_set_threading(true); } diff --git a/src/core/lib/iomgr/ev_epollsig_linux.h b/src/core/lib/iomgr/internal_errqueue.cc index 2ba2f0a63b..99c22e9055 100644 --- a/src/core/lib/iomgr/ev_epollsig_linux.h +++ b/src/core/lib/iomgr/internal_errqueue.cc @@ -1,6 +1,6 @@ /* * - * Copyright 2015 gRPC authors. + * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,21 @@ * */ -#ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H -#define GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H - #include <grpc/support/port_platform.h> -#include "src/core/lib/iomgr/ev_posix.h" #include "src/core/lib/iomgr/port.h" -const grpc_event_engine_vtable* grpc_init_epollsig_linux(bool explicit_request); +#include "src/core/lib/iomgr/internal_errqueue.h" + +#ifdef GRPC_POSIX_SOCKET_TCP -#ifdef GRPC_LINUX_EPOLL_CREATE1 -void* grpc_fd_get_polling_island(grpc_fd* fd); -void* grpc_pollset_get_polling_island(grpc_pollset* ps); -bool grpc_are_polling_islands_equal(void* p, void* q); -#endif /* defined(GRPC_LINUX_EPOLL_CREATE1) */ +bool kernel_supports_errqueue() { +#ifdef LINUX_VERSION_CODE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) + return true; +#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(4, 0, 0) */ +#endif /* LINUX_VERSION_CODE */ + return false; +} -#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H */ +#endif /* GRPC_POSIX_SOCKET_TCP */ diff --git a/src/core/lib/iomgr/internal_errqueue.h b/src/core/lib/iomgr/internal_errqueue.h new file mode 100644 index 0000000000..9d122808f9 --- /dev/null +++ b/src/core/lib/iomgr/internal_errqueue.h @@ -0,0 +1,83 @@ +/* + * + * Copyright 2018 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. + * + */ + +/* This file contains constants defined in <linux/errqueue.h> and + * <linux/net_tstamp.h> so as to allow collecting network timestamps in the + * kernel. This file allows tcp_posix.cc to compile on platforms that do not + * have <linux/errqueue.h> and <linux/net_tstamp.h>. + */ + +#ifndef GRPC_CORE_LIB_IOMGR_INTERNAL_ERRQUEUE_H +#define GRPC_CORE_LIB_IOMGR_INTERNAL_ERRQUEUE_H + +#include <grpc/support/port_platform.h> + +#include "src/core/lib/iomgr/port.h" + +#ifdef GRPC_POSIX_SOCKET_TCP + +#include <sys/types.h> +#include <time.h> + +#ifdef GRPC_LINUX_ERRQUEUE +#include <linux/errqueue.h> +#include <linux/net_tstamp.h> +#include <sys/socket.h> +#endif /* GRPC_LINUX_ERRQUEUE */ + +namespace grpc_core { + +#ifdef GRPC_LINUX_ERRQUEUE + +/* Redefining scm_timestamping in the same way that <linux/errqueue.h> defines + * it, so that code compiles on systems that don't have it. */ +struct scm_timestamping { + struct timespec ts[3]; +}; +/* Also redefine timestamp types */ +/* The timestamp type for when the driver passed skb to NIC, or HW. */ +constexpr int SCM_TSTAMP_SND = 0; +/* The timestamp type for when data entered the packet scheduler. */ +constexpr int SCM_TSTAMP_SCHED = 1; +/* The timestamp type for when data acknowledged by peer. */ +constexpr int SCM_TSTAMP_ACK = 2; +/* Redefine required constants from <linux/net_tstamp.h> */ +constexpr uint32_t SOF_TIMESTAMPING_TX_SOFTWARE = 1u << 1; +constexpr uint32_t SOF_TIMESTAMPING_SOFTWARE = 1u << 4; +constexpr uint32_t SOF_TIMESTAMPING_OPT_ID = 1u << 7; +constexpr uint32_t SOF_TIMESTAMPING_TX_SCHED = 1u << 8; +constexpr uint32_t SOF_TIMESTAMPING_TX_ACK = 1u << 9; +constexpr uint32_t SOF_TIMESTAMPING_OPT_TSONLY = 1u << 11; + +constexpr uint32_t kTimestampingSocketOptions = SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_OPT_ID | + SOF_TIMESTAMPING_OPT_TSONLY; +constexpr uint32_t kTimestampingRecordingOptions = + SOF_TIMESTAMPING_TX_SCHED | SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_TX_ACK; +#endif /* GRPC_LINUX_ERRQUEUE */ + +/* Returns true if kernel is capable of supporting errqueue and timestamping. + * Currently allowing only linux kernels above 4.0.0 + */ +bool kernel_supports_errqueue(); +} // namespace grpc_core + +#endif /* GRPC_POSIX_SOCKET_TCP */ + +#endif /* GRPC_CORE_LIB_IOMGR_INTERNAL_ERRQUEUE_H */ diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h index 1d0ecff802..bf56a7298d 100644 --- a/src/core/lib/iomgr/port.h +++ b/src/core/lib/iomgr/port.h @@ -60,6 +60,12 @@ #define GRPC_HAVE_IP_PKTINFO 1 #define GRPC_HAVE_MSG_NOSIGNAL 1 #define GRPC_HAVE_UNIX_SOCKET 1 +#ifdef LINUX_VERSION_CODE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) +/* TODO(yashykt): Re-enable once Fathom changes are commited. +#define GRPC_LINUX_ERRQUEUE 1 */ +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */ +#endif /* LINUX_VERSION_CODE */ #define GRPC_LINUX_MULTIPOLL_WITH_EPOLL 1 #define GRPC_POSIX_FORK 1 #define GRPC_POSIX_HOST_NAME_MAX 1 @@ -77,6 +83,11 @@ #define GRPC_LINUX_SOCKETUTILS 1 #endif #endif +#ifdef LINUX_VERSION_CODE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) +#define GRPC_HAVE_TCP_USER_TIMEOUT +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) */ +#endif /* LINUX_VERSION_CODE */ #ifndef __GLIBC__ #define GRPC_LINUX_EPOLL 1 #define GRPC_LINUX_EPOLL_CREATE1 1 @@ -105,7 +116,6 @@ #define GRPC_POSIX_SOCKET_EV 1 #define GRPC_POSIX_SOCKET_EV_EPOLL1 1 #define GRPC_POSIX_SOCKET_EV_EPOLLEX 1 -#define GRPC_POSIX_SOCKET_EV_EPOLLSIG 1 #define GRPC_POSIX_SOCKET_EV_POLL 1 #define GRPC_POSIX_SOCKET_RESOLVE_ADDRESS 1 #define GRPC_POSIX_SOCKET_SOCKADDR 1 @@ -140,6 +150,18 @@ #define GRPC_POSIX_SOCKET 1 #define GRPC_POSIX_SOCKETUTILS 1 #define GRPC_POSIX_WAKEUP_FD 1 +#elif defined(GPR_SOLARIS) +#define GRPC_HAVE_UNIX_SOCKET 1 +#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1 +#define GRPC_POSIX_SOCKET 1 +#define GRPC_POSIX_SOCKETUTILS 1 +#define GRPC_POSIX_WAKEUP_FD 1 +#elif defined(GPR_AIX) +#define GRPC_HAVE_UNIX_SOCKET 1 +#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1 +#define GRPC_POSIX_SOCKET 1 +#define GRPC_POSIX_SOCKETUTILS 1 +#define GRPC_POSIX_WAKEUP_FD 1 #elif defined(GPR_NACL) #define GRPC_HAVE_ARPA_NAMESER 1 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1 @@ -161,7 +183,6 @@ #define GRPC_POSIX_SOCKET_ARES_EV_DRIVER 1 #define GRPC_POSIX_SOCKET_EV 1 #define GRPC_POSIX_SOCKET_EV_EPOLLEX 1 -#define GRPC_POSIX_SOCKET_EV_EPOLLSIG 1 #define GRPC_POSIX_SOCKET_EV_POLL 1 #define GRPC_POSIX_SOCKET_EV_EPOLL1 1 #define GRPC_POSIX_SOCKET_IOMGR 1 diff --git a/src/core/lib/iomgr/socket_mutator.cc b/src/core/lib/iomgr/socket_mutator.cc index b9b8eaf4ad..a448c9f61c 100644 --- a/src/core/lib/iomgr/socket_mutator.cc +++ b/src/core/lib/iomgr/socket_mutator.cc @@ -57,7 +57,7 @@ int grpc_socket_mutator_compare(grpc_socket_mutator* a, void grpc_socket_mutator_unref(grpc_socket_mutator* mutator) { if (gpr_unref(&mutator->refcount)) { - mutator->vtable->destory(mutator); + mutator->vtable->destroy(mutator); } } diff --git a/src/core/lib/iomgr/socket_mutator.h b/src/core/lib/iomgr/socket_mutator.h index 6c7781c51d..8742a3ba61 100644 --- a/src/core/lib/iomgr/socket_mutator.h +++ b/src/core/lib/iomgr/socket_mutator.h @@ -33,7 +33,7 @@ typedef struct { /** Compare socket mutator \a a and \a b */ int (*compare)(grpc_socket_mutator* a, grpc_socket_mutator* b); /** Destroys the socket mutator instance */ - void (*destory)(grpc_socket_mutator* mutator); + void (*destroy)(grpc_socket_mutator* mutator); } grpc_socket_mutator_vtable; /** The Socket Mutator interface allows changes on socket options */ diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc index c4b991c94d..bdfc1d70c3 100644 --- a/src/core/lib/iomgr/socket_utils_common_posix.cc +++ b/src/core/lib/iomgr/socket_utils_common_posix.cc @@ -41,6 +41,7 @@ #include <grpc/support/log.h> #include <grpc/support/sync.h> +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/sockaddr.h" @@ -222,6 +223,98 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) { return GRPC_ERROR_NONE; } +/* The default values for TCP_USER_TIMEOUT are currently configured to be in + * line with the default values of KEEPALIVE_TIMEOUT as proposed in + * https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md */ +#define DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */ +#define DEFAULT_SERVER_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */ + +static int g_default_client_tcp_user_timeout_ms = + DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS; +static int g_default_server_tcp_user_timeout_ms = + DEFAULT_SERVER_TCP_USER_TIMEOUT_MS; +static bool g_default_client_tcp_user_timeout_enabled = false; +static bool g_default_server_tcp_user_timeout_enabled = true; + +void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client) { + if (is_client) { + g_default_client_tcp_user_timeout_enabled = enable; + if (timeout > 0) { + g_default_client_tcp_user_timeout_ms = timeout; + } + } else { + g_default_server_tcp_user_timeout_enabled = enable; + if (timeout > 0) { + g_default_server_tcp_user_timeout_ms = timeout; + } + } +} + +/* Set TCP_USER_TIMEOUT */ +grpc_error* grpc_set_socket_tcp_user_timeout( + int fd, const grpc_channel_args* channel_args, bool is_client) { +#ifdef GRPC_HAVE_TCP_USER_TIMEOUT + bool enable; + int timeout; + if (is_client) { + enable = g_default_client_tcp_user_timeout_enabled; + timeout = g_default_client_tcp_user_timeout_ms; + } else { + enable = g_default_server_tcp_user_timeout_enabled; + timeout = g_default_server_tcp_user_timeout_ms; + } + if (channel_args) { + for (unsigned int i = 0; i < channel_args->num_args; i++) { + if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) { + const int value = grpc_channel_arg_get_integer( + &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX}); + /* Continue using default if value is 0 */ + if (value == 0) { + continue; + } + /* Disable if value is INT_MAX */ + enable = value != INT_MAX; + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) { + const int value = grpc_channel_arg_get_integer( + &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX}); + /* Continue using default if value is 0 */ + if (value == 0) { + continue; + } + timeout = value; + } + } + } + if (enable) { + extern grpc_core::TraceFlag grpc_tcp_trace; + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_INFO, "Enabling TCP_USER_TIMEOUT with a timeout of %d ms", + timeout); + } + int newval; + socklen_t len = sizeof(newval); + if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, + sizeof(timeout))) { + return GRPC_OS_ERROR(errno, "setsockopt(TCP_USER_TIMEOUT)"); + } + if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) { + return GRPC_OS_ERROR(errno, "getsockopt(TCP_USER_TIMEOUT)"); + } + if (newval != timeout) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Failed to set TCP_USER_TIMEOUT"); + } + } +#else + extern grpc_core::TraceFlag grpc_tcp_trace; + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform"); + } +#endif /* GRPC_HAVE_TCP_USER_TIMEOUT */ + return GRPC_ERROR_NONE; +} + /* set a socket using a grpc_socket_mutator */ grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) { GPR_ASSERT(mutator); diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h index b3fd58a530..71a304dc4e 100644 --- a/src/core/lib/iomgr/socket_utils_posix.h +++ b/src/core/lib/iomgr/socket_utils_posix.h @@ -53,6 +53,13 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency); /* set SO_REUSEPORT */ grpc_error* grpc_set_socket_reuse_port(int fd, int reuse); +/* Configure the default values for TCP_USER_TIMEOUT */ +void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client); + +/* Set TCP_USER_TIMEOUT */ +grpc_error* grpc_set_socket_tcp_user_timeout( + int fd, const grpc_channel_args* channel_args, bool is_client); + /* Returns true if this system can create AF_INET6 sockets bound to ::1. The value is probed once, and cached for the life of the process. diff --git a/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc index 296ee74311..8553ed0db4 100644 --- a/src/core/lib/iomgr/tcp_client_posix.cc +++ b/src/core/lib/iomgr/tcp_client_posix.cc @@ -76,6 +76,9 @@ static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd, if (!grpc_is_unix_socket(addr)) { err = grpc_set_socket_low_latency(fd, 1); if (err != GRPC_ERROR_NONE) goto error; + err = grpc_set_socket_tcp_user_timeout(fd, channel_args, + true /* is_client */); + if (err != GRPC_ERROR_NONE) goto error; } err = grpc_set_socket_no_sigpipe_if_possible(fd); if (err != GRPC_ERROR_NONE) goto error; @@ -279,7 +282,7 @@ grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args, } addr_str = grpc_sockaddr_to_uri(mapped_addr); gpr_asprintf(&name, "tcp-client:%s", addr_str); - *fdobj = grpc_fd_create(fd, name, false); + *fdobj = grpc_fd_create(fd, name, true); gpr_free(name); gpr_free(addr_str); return GRPC_ERROR_NONE; diff --git a/src/core/lib/iomgr/tcp_custom.cc b/src/core/lib/iomgr/tcp_custom.cc index 990e8d632b..e02a1898f2 100644 --- a/src/core/lib/iomgr/tcp_custom.cc +++ b/src/core/lib/iomgr/tcp_custom.cc @@ -221,7 +221,7 @@ static void custom_write_callback(grpc_custom_socket* socket, } static void endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* write_slices, - grpc_closure* cb) { + grpc_closure* cb, void* arg) { custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index b53ffbf01c..aa2704ce26 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -27,7 +27,9 @@ #include <errno.h> #include <limits.h> +#include <netinet/in.h> #include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> @@ -46,6 +48,7 @@ #include "src/core/lib/debug/trace.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/iomgr/buffer_list.h" #include "src/core/lib/iomgr/ev_posix.h" #include "src/core/lib/iomgr/executor.h" #include "src/core/lib/profiling/timers.h" @@ -97,17 +100,42 @@ struct grpc_tcp { grpc_closure read_done_closure; grpc_closure write_done_closure; + grpc_closure error_closure; char* peer_string; grpc_resource_user* resource_user; grpc_resource_user_slice_allocator slice_allocator; + + grpc_core::TracedBuffer* tb_head; /* List of traced buffers */ + gpr_mu tb_mu; /* Lock for access to list of traced buffers */ + + /* grpc_endpoint_write takes an argument which if non-null means that the + * transport layer wants the TCP layer to collect timestamps for this write. + * This arg is forwarded to the timestamps callback function when the ACK + * timestamp is received from the kernel. This arg is a (void *) which allows + * users of this API to pass in a pointer to any kind of structure. This + * structure could actually be a tag or any book-keeping object that the user + * can use to distinguish between different traced writes. The only + * requirement from the TCP endpoint layer is that this arg should be non-null + * if the user wants timestamps for the write. */ + void* outgoing_buffer_arg; + /* A counter which starts at 0. It is initialized the first time the socket + * options for collecting timestamps are set, and is incremented with each + * byte sent. */ + int bytes_counter; + bool socket_ts_enabled; /* True if timestamping options are set on the socket + */ + gpr_atm + stop_error_notification; /* Set to 1 if we do not want to be notified on + errors anymore */ }; struct backup_poller { gpr_mu* pollset_mu; grpc_closure run_poller; }; + } // namespace #define BACKUP_POLLER_POLLSET(b) ((grpc_pollset*)((b) + 1)) @@ -176,6 +204,13 @@ static void drop_uncovered(grpc_tcp* tcp) { GPR_ASSERT(old_count != 1); } +// gRPC API considers a Write operation to be done the moment it clears ‘flow +// control’ i.e., not necessarily sent on the wire. This means that the +// application MIGHT not call `grpc_completion_queue_next/pluck` in a timely +// manner when its `Write()` API is acked. +// +// We need to ensure that the fd is 'covered' (i.e being monitored by some +// polling thread and progress is made) and hence add it to a backup poller here static void cover_self(grpc_tcp* tcp) { backup_poller* p; gpr_atm old_count = @@ -302,6 +337,7 @@ static void tcp_free(grpc_tcp* tcp) { grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer); grpc_resource_user_unref(tcp->resource_user); gpr_free(tcp->peer_string); + gpr_mu_destroy(&tcp->tb_mu); gpr_free(tcp); } @@ -347,6 +383,10 @@ static void tcp_destroy(grpc_endpoint* ep) { grpc_network_status_unregister_endpoint(ep); grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep); grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer); + if (grpc_event_engine_can_track_errors()) { + gpr_atm_no_barrier_store(&tcp->stop_error_notification, true); + grpc_fd_set_error(tcp->em_fd); + } TCP_UNREF(tcp, "destroy"); } @@ -428,7 +468,9 @@ static void tcp_do_read(grpc_tcp* tcp) { GRPC_STATS_INC_TCP_READ_SIZE(read_bytes); add_to_estimate(tcp, static_cast<size_t>(read_bytes)); GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length); - if (static_cast<size_t>(read_bytes) < tcp->incoming_buffer->length) { + if (static_cast<size_t>(read_bytes) == tcp->incoming_buffer->length) { + finish_estimate(tcp); + } else if (static_cast<size_t>(read_bytes) < tcp->incoming_buffer->length) { grpc_slice_buffer_trim_end( tcp->incoming_buffer, tcp->incoming_buffer->length - static_cast<size_t>(read_bytes), @@ -458,7 +500,7 @@ static void tcp_read_allocation_done(void* tcpp, grpc_error* error) { static void tcp_continue_read(grpc_tcp* tcp) { size_t target_read_size = get_target_read_size(tcp); - if (tcp->incoming_buffer->length < target_read_size && + if (tcp->incoming_buffer->length < target_read_size / 2 && tcp->incoming_buffer->count < MAX_READ_IOVEC) { if (grpc_tcp_trace.enabled()) { gpr_log(GPR_INFO, "TCP:%p alloc_slices", tcp); @@ -513,6 +555,235 @@ static void tcp_read(grpc_endpoint* ep, grpc_slice_buffer* incoming_buffer, } } +/* A wrapper around sendmsg. It sends \a msg over \a fd and returns the number + * of bytes sent. */ +ssize_t tcp_send(int fd, const struct msghdr* msg) { + GPR_TIMER_SCOPE("sendmsg", 1); + ssize_t sent_length; + do { + /* TODO(klempner): Cork if this is a partial write */ + GRPC_STATS_INC_SYSCALL_WRITE(); + sent_length = sendmsg(fd, msg, SENDMSG_FLAGS); + } while (sent_length < 0 && errno == EINTR); + return sent_length; +} + +/** This is to be called if outgoing_buffer_arg is not null. On linux platforms, + * this will call sendmsg with socket options set to collect timestamps inside + * the kernel. On return, sent_length is set to the return value of the sendmsg + * call. Returns false if setting the socket options failed. This is not + * implemented for non-linux platforms currently, and crashes out. + */ +static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg, + size_t sending_length, + ssize_t* sent_length, grpc_error** error); + +/** The callback function to be invoked when we get an error on the socket. */ +static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error); + +#ifdef GRPC_LINUX_ERRQUEUE +static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg, + size_t sending_length, + ssize_t* sent_length, + grpc_error** error) { + if (!tcp->socket_ts_enabled) { + uint32_t opt = grpc_core::kTimestampingSocketOptions; + if (setsockopt(tcp->fd, SOL_SOCKET, SO_TIMESTAMPING, + static_cast<void*>(&opt), sizeof(opt)) != 0) { + *error = tcp_annotate_error(GRPC_OS_ERROR(errno, "setsockopt"), tcp); + grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer); + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_ERROR, "Failed to set timestamping options on the socket."); + } + return false; + } + tcp->bytes_counter = -1; + tcp->socket_ts_enabled = true; + } + /* Set control message to indicate that you want timestamps. */ + union { + char cmsg_buf[CMSG_SPACE(sizeof(uint32_t))]; + struct cmsghdr align; + } u; + cmsghdr* cmsg = reinterpret_cast<cmsghdr*>(u.cmsg_buf); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SO_TIMESTAMPING; + cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t)); + *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = + grpc_core::kTimestampingRecordingOptions; + msg->msg_control = u.cmsg_buf; + msg->msg_controllen = CMSG_SPACE(sizeof(uint32_t)); + + /* If there was an error on sendmsg the logic in tcp_flush will handle it. */ + ssize_t length = tcp_send(tcp->fd, msg); + *sent_length = length; + /* Only save timestamps if all the bytes were taken by sendmsg. */ + if (sending_length == static_cast<size_t>(length)) { + gpr_mu_lock(&tcp->tb_mu); + grpc_core::TracedBuffer::AddNewEntry( + &tcp->tb_head, static_cast<int>(tcp->bytes_counter + length), + tcp->outgoing_buffer_arg); + gpr_mu_unlock(&tcp->tb_mu); + tcp->outgoing_buffer_arg = nullptr; + } + return true; +} + +/** Reads \a cmsg to derive timestamps from the control messages. If a valid + * timestamp is found, the traced buffer list is updated with this timestamp. + * The caller of this function should be looping on the control messages found + * in \a msg. \a cmsg should point to the control message that the caller wants + * processed. + * On return, a pointer to a control message is returned. On the next iteration, + * CMSG_NXTHDR(msg, ret_val) should be passed as \a cmsg. */ +struct cmsghdr* process_timestamp(grpc_tcp* tcp, msghdr* msg, + struct cmsghdr* cmsg) { + auto next_cmsg = CMSG_NXTHDR(msg, cmsg); + if (next_cmsg == nullptr) { + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_ERROR, "Received timestamp without extended error"); + } + return cmsg; + } + + if (!(next_cmsg->cmsg_level == SOL_IP || next_cmsg->cmsg_level == SOL_IPV6) || + !(next_cmsg->cmsg_type == IP_RECVERR || + next_cmsg->cmsg_type == IPV6_RECVERR)) { + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_ERROR, "Unexpected control message"); + } + return cmsg; + } + + auto tss = + reinterpret_cast<struct grpc_core::scm_timestamping*>(CMSG_DATA(cmsg)); + auto serr = reinterpret_cast<struct sock_extended_err*>(CMSG_DATA(next_cmsg)); + if (serr->ee_errno != ENOMSG || + serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) { + gpr_log(GPR_ERROR, "Unexpected control message"); + return cmsg; + } + /* The error handling can potentially be done on another thread so we need + * to protect the traced buffer list. A lock free list might be better. Using + * a simple mutex for now. */ + gpr_mu_lock(&tcp->tb_mu); + grpc_core::TracedBuffer::ProcessTimestamp(&tcp->tb_head, serr, tss); + gpr_mu_unlock(&tcp->tb_mu); + return next_cmsg; +} + +/** For linux platforms, reads the socket's error queue and processes error + * messages from the queue. Returns true if all the errors processed were + * timestamps. Returns false if any of the errors were not timestamps. For + * non-linux platforms, error processing is not used/enabled currently. + */ +static bool process_errors(grpc_tcp* tcp) { + while (true) { + struct iovec iov; + iov.iov_base = nullptr; + iov.iov_len = 0; + struct msghdr msg; + msg.msg_name = nullptr; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 0; + msg.msg_flags = 0; + + union { + char rbuf[1024 /*CMSG_SPACE(sizeof(scm_timestamping)) + + CMSG_SPACE(sizeof(sock_extended_err) + sizeof(sockaddr_in))*/]; + struct cmsghdr align; + } aligned_buf; + memset(&aligned_buf, 0, sizeof(aligned_buf)); + + msg.msg_control = aligned_buf.rbuf; + msg.msg_controllen = sizeof(aligned_buf.rbuf); + + int r, saved_errno; + do { + r = recvmsg(tcp->fd, &msg, MSG_ERRQUEUE); + saved_errno = errno; + } while (r < 0 && saved_errno == EINTR); + + if (r == -1 && saved_errno == EAGAIN) { + return true; /* No more errors to process */ + } + if (r == -1) { + return false; + } + if (grpc_tcp_trace.enabled()) { + if ((msg.msg_flags & MSG_CTRUNC) == 1) { + gpr_log(GPR_INFO, "Error message was truncated."); + } + } + + if (msg.msg_controllen == 0) { + /* There was no control message found. It was probably spurious. */ + return true; + } + for (auto cmsg = CMSG_FIRSTHDR(&msg); cmsg && cmsg->cmsg_len; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_TIMESTAMPING) { + /* Got a control message that is not a timestamp. Don't know how to + * handle this. */ + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_INFO, + "unknown control message cmsg_level:%d cmsg_type:%d", + cmsg->cmsg_level, cmsg->cmsg_type); + } + return false; + } + process_timestamp(tcp, &msg, cmsg); + } + } +} + +static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) { + grpc_tcp* tcp = static_cast<grpc_tcp*>(arg); + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_INFO, "TCP:%p got_error: %s", tcp, grpc_error_string(error)); + } + + if (error != GRPC_ERROR_NONE || + static_cast<bool>(gpr_atm_acq_load(&tcp->stop_error_notification))) { + /* We aren't going to register to hear on error anymore, so it is safe to + * unref. */ + grpc_core::TracedBuffer::Shutdown(&tcp->tb_head, GRPC_ERROR_REF(error)); + TCP_UNREF(tcp, "error-tracking"); + return; + } + + /* We are still interested in collecting timestamps, so let's try reading + * them. */ + if (!process_errors(tcp)) { + /* This was not a timestamps error. This was an actual error. Set the + * read and write closures to be ready. + */ + grpc_fd_set_readable(tcp->em_fd); + grpc_fd_set_writable(tcp->em_fd); + } + GRPC_CLOSURE_INIT(&tcp->error_closure, tcp_handle_error, tcp, + grpc_schedule_on_exec_ctx); + grpc_fd_notify_on_error(tcp->em_fd, &tcp->error_closure); +} + +#else /* GRPC_LINUX_ERRQUEUE */ +static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg, + size_t sending_length, + ssize_t* sent_length, + grpc_error** error) { + gpr_log(GPR_ERROR, "Write with timestamps not supported for this platform"); + GPR_ASSERT(0); + return false; +} + +static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) { + gpr_log(GPR_ERROR, "Error handling is not supported for this platform"); + GPR_ASSERT(0); +} +#endif /* GRPC_LINUX_ERRQUEUE */ + /* returns true if done, false if pending; if returning true, *error is set */ #if defined(IOV_MAX) && IOV_MAX < 1000 #define MAX_WRITE_IOVEC IOV_MAX @@ -557,19 +828,20 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) { msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = iov_size; - msg.msg_control = nullptr; - msg.msg_controllen = 0; msg.msg_flags = 0; + if (tcp->outgoing_buffer_arg != nullptr) { + if (!tcp_write_with_timestamps(tcp, &msg, sending_length, &sent_length, + error)) + return true; /* something went wrong with timestamps */ + } else { + msg.msg_control = nullptr; + msg.msg_controllen = 0; - GRPC_STATS_INC_TCP_WRITE_SIZE(sending_length); - GRPC_STATS_INC_TCP_WRITE_IOV_SIZE(iov_size); + GRPC_STATS_INC_TCP_WRITE_SIZE(sending_length); + GRPC_STATS_INC_TCP_WRITE_IOV_SIZE(iov_size); - GPR_TIMER_SCOPE("sendmsg", 1); - do { - /* TODO(klempner): Cork if this is a partial write */ - GRPC_STATS_INC_SYSCALL_WRITE(); - sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS); - } while (sent_length < 0 && errno == EINTR); + sent_length = tcp_send(tcp->fd, &msg); + } if (sent_length < 0) { if (errno == EAGAIN) { @@ -593,6 +865,7 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) { } GPR_ASSERT(tcp->outgoing_byte_idx == 0); + tcp->bytes_counter += sent_length; trailing = sending_length - static_cast<size_t>(sent_length); while (trailing > 0) { size_t slice_length; @@ -607,7 +880,6 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) { trailing -= slice_length; } } - if (outgoing_slice_idx == tcp->outgoing_buffer->count) { *error = GRPC_ERROR_NONE; grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer); @@ -640,14 +912,13 @@ static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error) { const char* str = grpc_error_string(error); gpr_log(GPR_INFO, "write: %s", str); } - GRPC_CLOSURE_SCHED(cb, error); TCP_UNREF(tcp, "write"); } } static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf, - grpc_closure* cb) { + grpc_closure* cb, void* arg) { GPR_TIMER_SCOPE("tcp_write", 0); grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep); grpc_error* error = GRPC_ERROR_NONE; @@ -675,6 +946,10 @@ static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf, } tcp->outgoing_buffer = buf; tcp->outgoing_byte_idx = 0; + tcp->outgoing_buffer_arg = arg; + if (arg) { + GPR_ASSERT(grpc_event_engine_can_track_errors()); + } if (!tcp_flush(tcp, &error)) { TCP_REF(tcp, "write"); @@ -792,6 +1067,8 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd, tcp->bytes_read_this_round = 0; /* Will be set to false by the very first endpoint read function */ tcp->is_first_read = true; + tcp->bytes_counter = -1; + tcp->socket_ts_enabled = false; /* paired with unref in grpc_tcp_destroy */ gpr_ref_init(&tcp->refcount, 1); gpr_atm_no_barrier_store(&tcp->shutdown_count, 0); @@ -803,6 +1080,19 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd, /* Tell network status tracker about new endpoint */ grpc_network_status_register_endpoint(&tcp->base); grpc_resource_quota_unref_internal(resource_quota); + gpr_mu_init(&tcp->tb_mu); + tcp->tb_head = nullptr; + /* Start being notified on errors if event engine can track errors. */ + if (grpc_event_engine_can_track_errors()) { + /* Grab a ref to tcp so that we can safely access the tcp struct when + * processing errors. We unref when we no longer want to track errors + * separately. */ + TCP_REF(tcp, "error-tracking"); + gpr_atm_rel_store(&tcp->stop_error_notification, 0); + GRPC_CLOSURE_INIT(&tcp->error_closure, tcp_handle_error, tcp, + grpc_schedule_on_exec_ctx); + grpc_fd_notify_on_error(tcp->em_fd, &tcp->error_closure); + } return &tcp->base; } @@ -821,6 +1111,11 @@ void grpc_tcp_destroy_and_release_fd(grpc_endpoint* ep, int* fd, tcp->release_fd = fd; tcp->release_fd_cb = done; grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer); + if (grpc_event_engine_can_track_errors()) { + /* Stop errors notification. */ + gpr_atm_no_barrier_store(&tcp->stop_error_notification, true); + grpc_fd_set_error(tcp->em_fd); + } TCP_UNREF(tcp, "destroy"); } diff --git a/src/core/lib/iomgr/tcp_posix.h b/src/core/lib/iomgr/tcp_posix.h index af89bd24db..eff825cb92 100644 --- a/src/core/lib/iomgr/tcp_posix.h +++ b/src/core/lib/iomgr/tcp_posix.h @@ -31,7 +31,10 @@ #include <grpc/support/port_platform.h> +#include "src/core/lib/iomgr/port.h" + #include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/buffer_list.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/ev_posix.h" diff --git a/src/core/lib/iomgr/tcp_server_posix.cc b/src/core/lib/iomgr/tcp_server_posix.cc index 8ddf684fea..824db07fbf 100644 --- a/src/core/lib/iomgr/tcp_server_posix.cc +++ b/src/core/lib/iomgr/tcp_server_posix.cc @@ -226,7 +226,7 @@ static void on_read(void* arg, grpc_error* err) { gpr_log(GPR_INFO, "SERVER_CONNECT: incoming connection: %s", addr_str); } - grpc_fd* fdobj = grpc_fd_create(fd, name, false); + grpc_fd* fdobj = grpc_fd_create(fd, name, true); read_notifier_pollset = sp->server->pollsets[static_cast<size_t>(gpr_atm_no_barrier_fetch_add( @@ -362,7 +362,7 @@ static grpc_error* clone_port(grpc_tcp_listener* listener, unsigned count) { listener->sibling = sp; sp->server = listener->server; sp->fd = fd; - sp->emfd = grpc_fd_create(fd, name, false); + sp->emfd = grpc_fd_create(fd, name, true); memcpy(&sp->addr, &listener->addr, sizeof(grpc_resolved_address)); sp->port = port; sp->port_index = listener->port_index; diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc index b9f8145572..8d8d3f4273 100644 --- a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc +++ b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc @@ -105,7 +105,7 @@ static grpc_error* add_socket_to_server(grpc_tcp_server* s, int fd, s->tail = sp; sp->server = s; sp->fd = fd; - sp->emfd = grpc_fd_create(fd, name, false); + sp->emfd = grpc_fd_create(fd, name, true); memcpy(&sp->addr, addr, sizeof(grpc_resolved_address)); sp->port = port; sp->port_index = port_index; @@ -166,6 +166,9 @@ grpc_error* grpc_tcp_server_prepare_socket(grpc_tcp_server* s, int fd, if (err != GRPC_ERROR_NONE) goto error; err = grpc_set_socket_reuse_addr(fd, 1); if (err != GRPC_ERROR_NONE) goto error; + err = grpc_set_socket_tcp_user_timeout(fd, s->channel_args, + false /* is_client */); + if (err != GRPC_ERROR_NONE) goto error; } err = grpc_set_socket_no_sigpipe_if_possible(fd); if (err != GRPC_ERROR_NONE) goto error; diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc index b3cb442f18..64c4a56ae9 100644 --- a/src/core/lib/iomgr/tcp_windows.cc +++ b/src/core/lib/iomgr/tcp_windows.cc @@ -296,7 +296,7 @@ static void on_write(void* tcpp, grpc_error* error) { /* Initiates a write. */ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices, - grpc_closure* cb) { + grpc_closure* cb, void* arg) { grpc_tcp* tcp = (grpc_tcp*)ep; grpc_winsocket* socket = tcp->socket; grpc_winsocket_callback_info* info = &socket->write_info; diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h index 7f534476df..17e933b865 100644 --- a/src/core/lib/iomgr/timer.h +++ b/src/core/lib/iomgr/timer.h @@ -61,10 +61,11 @@ typedef struct grpc_timer_vtable { /* Initialize *timer. When expired or canceled, closure will be called with error set to indicate if it expired (GRPC_ERROR_NONE) or was canceled - (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called exactly once, and + (GRPC_ERROR_CANCELLED). *closure is guaranteed to be called exactly once, and application code should check the error to determine how it was invoked. The application callback is also responsible for maintaining information about - when to free up any user-level state. */ + when to free up any user-level state. Behavior is undefined for a deadline of + GRPC_MILLIS_INF_FUTURE. */ void grpc_timer_init(grpc_timer* timer, grpc_millis deadline, grpc_closure* closure); diff --git a/src/core/lib/iomgr/timer_generic.cc b/src/core/lib/iomgr/timer_generic.cc index 4294162af7..6a925add80 100644 --- a/src/core/lib/iomgr/timer_generic.cc +++ b/src/core/lib/iomgr/timer_generic.cc @@ -48,22 +48,22 @@ grpc_core::TraceFlag grpc_timer_trace(false, "timer"); grpc_core::TraceFlag grpc_timer_check_trace(false, "timer_check"); /* A "timer shard". Contains a 'heap' and a 'list' of timers. All timers with - * deadlines earlier than 'queue_deadline" cap are maintained in the heap and + * deadlines earlier than 'queue_deadline_cap' are maintained in the heap and * others are maintained in the list (unordered). This helps to keep the number * of elements in the heap low. * * The 'queue_deadline_cap' gets recomputed periodically based on the timer * stats maintained in 'stats' and the relevant timers are then moved from the - * 'list' to 'heap' + * 'list' to 'heap'. */ typedef struct { gpr_mu mu; grpc_time_averaged_stats stats; - /* All and only timers with deadlines <= this will be in the heap. */ + /* All and only timers with deadlines < this will be in the heap. */ grpc_millis queue_deadline_cap; - /* The deadline of the next timer due in this shard */ + /* The deadline of the next timer due in this shard. */ grpc_millis min_deadline; - /* Index of this timer_shard in the g_shard_queue */ + /* Index of this timer_shard in the g_shard_queue. */ uint32_t shard_queue_index; /* This holds all timers with deadlines < queue_deadline_cap. Timers in this list have the top bit of their deadline set to 0. */ @@ -85,7 +85,7 @@ static timer_shard** g_shard_queue; #ifndef NDEBUG -/* == Hash table for duplicate timer detection == */ +/* == DEBUG ONLY: hash table for duplicate timer detection == */ #define NUM_HASH_BUCKETS 1009 /* Prime number close to 1000 */ @@ -177,7 +177,7 @@ static void remove_from_ht(grpc_timer* t) { t->hash_table_next = nullptr; } -/* If a timer is added to a timer shard (either heap or a list), it cannot +/* If a timer is added to a timer shard (either heap or a list), it must * be pending. A timer is added to hash table only-if it is added to the * timer shard. * Therefore, if timer->pending is false, it cannot be in hash table */ @@ -256,7 +256,7 @@ static grpc_millis compute_min_deadline(timer_shard* shard) { static void timer_list_init() { uint32_t i; - g_num_shards = GPR_MIN(1, 2 * gpr_cpu_num_cores()); + g_num_shards = GPR_CLAMP(2 * gpr_cpu_num_cores(), 1, 32); g_shards = static_cast<timer_shard*>(gpr_zalloc(g_num_shards * sizeof(*g_shards))); g_shard_queue = static_cast<timer_shard**>( @@ -291,7 +291,7 @@ static void timer_list_init() { static void timer_list_shutdown() { size_t i; run_some_expired_timers( - GPR_ATM_MAX, nullptr, + GRPC_MILLIS_INF_FUTURE, nullptr, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timer list shutdown")); for (i = 0; i < g_num_shards; i++) { timer_shard* shard = &g_shards[i]; @@ -489,7 +489,7 @@ static void timer_cancel(grpc_timer* timer) { 'queue_deadline_cap') into into shard->heap. Returns 'true' if shard->heap has atleast ONE element REQUIRES: shard->mu locked */ -static int refill_heap(timer_shard* shard, grpc_millis now) { +static bool refill_heap(timer_shard* shard, grpc_millis now) { /* Compute the new queue window width and bound by the limits: */ double computed_deadline_delta = grpc_time_averaged_stats_update_average(&shard->stats) * @@ -714,9 +714,10 @@ static grpc_timer_check_result timer_check(grpc_millis* next) { #if GPR_ARCH_64 gpr_log(GPR_INFO, "TIMER CHECK BEGIN: now=%" PRId64 " next=%s tls_min=%" PRId64 - " glob_min=%" PRIdPTR, + " glob_min=%" PRId64, now, next_str, min_timer, - gpr_atm_no_barrier_load((gpr_atm*)(&g_shared_mutables.min_timer))); + static_cast<grpc_millis>(gpr_atm_no_barrier_load( + (gpr_atm*)(&g_shared_mutables.min_timer)))); #else gpr_log(GPR_INFO, "TIMER CHECK BEGIN: now=%" PRId64 " next=%s min=%" PRId64, now, next_str, min_timer); diff --git a/src/core/lib/iomgr/timer_heap.cc b/src/core/lib/iomgr/timer_heap.cc index 0c17d607eb..2c6a599149 100644 --- a/src/core/lib/iomgr/timer_heap.cc +++ b/src/core/lib/iomgr/timer_heap.cc @@ -95,7 +95,7 @@ void grpc_timer_heap_init(grpc_timer_heap* heap) { void grpc_timer_heap_destroy(grpc_timer_heap* heap) { gpr_free(heap->timers); } -int grpc_timer_heap_add(grpc_timer_heap* heap, grpc_timer* timer) { +bool grpc_timer_heap_add(grpc_timer_heap* heap, grpc_timer* timer) { if (heap->timer_count == heap->timer_capacity) { heap->timer_capacity = GPR_MAX(heap->timer_capacity + 1, heap->timer_capacity * 3 / 2); @@ -122,7 +122,7 @@ void grpc_timer_heap_remove(grpc_timer_heap* heap, grpc_timer* timer) { note_changed_priority(heap, heap->timers[i]); } -int grpc_timer_heap_is_empty(grpc_timer_heap* heap) { +bool grpc_timer_heap_is_empty(grpc_timer_heap* heap) { return heap->timer_count == 0; } diff --git a/src/core/lib/iomgr/timer_heap.h b/src/core/lib/iomgr/timer_heap.h index 503365d4cd..7b983e7133 100644 --- a/src/core/lib/iomgr/timer_heap.h +++ b/src/core/lib/iomgr/timer_heap.h @@ -29,8 +29,8 @@ typedef struct { uint32_t timer_capacity; } grpc_timer_heap; -/* return 1 if the new timer is the first timer in the heap */ -int grpc_timer_heap_add(grpc_timer_heap* heap, grpc_timer* timer); +/* return true if the new timer is the first timer in the heap */ +bool grpc_timer_heap_add(grpc_timer_heap* heap, grpc_timer* timer); void grpc_timer_heap_init(grpc_timer_heap* heap); void grpc_timer_heap_destroy(grpc_timer_heap* heap); @@ -39,6 +39,6 @@ void grpc_timer_heap_remove(grpc_timer_heap* heap, grpc_timer* timer); grpc_timer* grpc_timer_heap_top(grpc_timer_heap* heap); void grpc_timer_heap_pop(grpc_timer_heap* heap); -int grpc_timer_heap_is_empty(grpc_timer_heap* heap); +bool grpc_timer_heap_is_empty(grpc_timer_heap* heap); #endif /* GRPC_CORE_LIB_IOMGR_TIMER_HEAP_H */ diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc index 26de216671..ceba79f678 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; @@ -92,8 +100,7 @@ static void start_timer_thread_and_unlock(void) { void grpc_timer_manager_tick() { grpc_core::ExecCtx exec_ctx; - grpc_millis next = GRPC_MILLIS_INF_FUTURE; - grpc_timer_check(&next); + grpc_timer_check(nullptr); } static void run_some_timers() { @@ -102,9 +109,12 @@ static void run_some_timers() { // remove a waiter from the pool, and start another thread if necessary --g_waiter_count; if (g_waiter_count == 0 && g_threaded) { + // The number of timer threads is always increasing until all the threads + // are stopped. In rare cases, if a large number of timers fire + // simultaneously, we may end up using a large number of threads. start_timer_thread_and_unlock(); } else { - // if there's no thread waiting with a timeout, kick an existing + // if there's no thread waiting with a timeout, kick an existing untimed // waiter so that the next deadline is not missed if (!g_has_timed_waiter) { if (grpc_timer_check_trace.enabled()) { @@ -235,7 +245,7 @@ static void timer_main_loop() { gpr_log(GPR_INFO, "timers not checked: expect another thread to"); } next = GRPC_MILLIS_INF_FUTURE; - /* fall through */ + // fallthrough case GRPC_TIMERS_CHECKED_AND_EMPTY: if (!wait_until(next)) { return; @@ -284,6 +294,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 +334,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 +347,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/iomgr/timer_manager.h b/src/core/lib/iomgr/timer_manager.h index 3c4cdda2c8..00dcdc461b 100644 --- a/src/core/lib/iomgr/timer_manager.h +++ b/src/core/lib/iomgr/timer_manager.h @@ -23,8 +23,8 @@ #include <stdbool.h> -/* Timer Manager tries to keep one thread waiting for the next timeout at all - times */ +/* Timer Manager tries to keep only one thread waiting for the next timeout at + all times, and thus effectively preventing the thundering herd problem. */ void grpc_timer_manager_init(void); void grpc_timer_manager_shutdown(void); diff --git a/src/core/lib/iomgr/udp_server.cc b/src/core/lib/iomgr/udp_server.cc index bdb2d0e764..3dd7cab855 100644 --- a/src/core/lib/iomgr/udp_server.cc +++ b/src/core/lib/iomgr/udp_server.cc @@ -152,7 +152,7 @@ GrpcUdpListener::GrpcUdpListener(grpc_udp_server* server, int fd, grpc_sockaddr_to_string(&addr_str, addr, 1); gpr_asprintf(&name, "udp-server-listener:%s", addr_str); gpr_free(addr_str); - emfd_ = grpc_fd_create(fd, name, false); + emfd_ = grpc_fd_create(fd, name, true); memcpy(&addr_, addr, sizeof(grpc_resolved_address)); GPR_ASSERT(emfd_); gpr_free(name); diff --git a/src/core/lib/iomgr/wakeup_fd_eventfd.cc b/src/core/lib/iomgr/wakeup_fd_eventfd.cc index dcf7dab71f..d68c9ada1f 100644 --- a/src/core/lib/iomgr/wakeup_fd_eventfd.cc +++ b/src/core/lib/iomgr/wakeup_fd_eventfd.cc @@ -32,12 +32,11 @@ #include "src/core/lib/profiling/timers.h" static grpc_error* eventfd_create(grpc_wakeup_fd* fd_info) { - int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); - if (efd < 0) { + fd_info->read_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + fd_info->write_fd = -1; + if (fd_info->read_fd < 0) { return GRPC_OS_ERROR(errno, "eventfd"); } - fd_info->read_fd = efd; - fd_info->write_fd = -1; return GRPC_ERROR_NONE; } diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc index 0a39c6c485..118d18d119 100644 --- a/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc +++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc @@ -72,7 +72,8 @@ static void target_service_account_destroy( static const grpc_alts_credentials_options_vtable vtable = { alts_client_options_copy, alts_client_options_destroy}; -grpc_alts_credentials_options* grpc_alts_credentials_client_options_create() { +grpc_alts_credentials_options* grpc_alts_credentials_client_options_create( + void) { auto client_options = static_cast<grpc_alts_credentials_client_options*>( gpr_zalloc(sizeof(grpc_alts_credentials_client_options))); client_options->base.vtable = &vtable; diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc index 62aa7a620a..1a59c45675 100644 --- a/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc +++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc @@ -36,7 +36,8 @@ static void alts_server_options_destroy( static const grpc_alts_credentials_options_vtable vtable = { alts_server_options_copy, alts_server_options_destroy}; -grpc_alts_credentials_options* grpc_alts_credentials_server_options_create() { +grpc_alts_credentials_options* grpc_alts_credentials_server_options_create( + void) { grpc_alts_credentials_server_options* server_options = static_cast<grpc_alts_credentials_server_options*>( gpr_zalloc(sizeof(*server_options))); diff --git a/src/core/lib/security/credentials/jwt/json_token.h b/src/core/lib/security/credentials/jwt/json_token.h index d0fb4ebd0a..3ed990140d 100644 --- a/src/core/lib/security/credentials/jwt/json_token.h +++ b/src/core/lib/security/credentials/jwt/json_token.h @@ -21,6 +21,8 @@ #include <grpc/support/port_platform.h> +#include "src/core/tsi/grpc_shadow_boringssl.h" + #include <grpc/slice.h> #include <openssl/rsa.h> diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.cc b/src/core/lib/security/credentials/jwt/jwt_verifier.cc index 5c47276e32..c7d1b36ff0 100644 --- a/src/core/lib/security/credentials/jwt/jwt_verifier.cc +++ b/src/core/lib/security/credentials/jwt/jwt_verifier.cc @@ -18,6 +18,8 @@ #include <grpc/support/port_platform.h> +#include "src/core/tsi/grpc_shadow_boringssl.h" + #include "src/core/lib/security/credentials/jwt/jwt_verifier.h" #include <limits.h> diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc index 43dd68e874..44b093557f 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc @@ -235,7 +235,7 @@ static void on_oauth2_token_fetcher_http_response(void* user_data, access_token_md); } else { error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occured when fetching oauth2 token.", &error, 1); + "Error occurred when fetching oauth2 token.", &error, 1); } GRPC_CLOSURE_SCHED(pending_request->on_request_metadata, error); grpc_polling_entity_del_from_pollset_set( diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.cc b/src/core/lib/security/credentials/plugin/plugin_credentials.cc index 73946ce039..4015124298 100644 --- a/src/core/lib/security/credentials/plugin/plugin_credentials.cc +++ b/src/core/lib/security/credentials/plugin/plugin_credentials.cc @@ -102,8 +102,7 @@ static grpc_error* process_plugin_result( } else { for (size_t i = 0; i < num_md; ++i) { grpc_mdelem mdelem = - grpc_mdelem_from_slices(grpc_slice_ref_internal(md[i].key), - grpc_slice_ref_internal(md[i].value)); + grpc_mdelem_create(md[i].key, md[i].value, nullptr); grpc_credentials_mdelem_array_add(r->md_array, mdelem); GRPC_MDELEM_UNREF(mdelem); } 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 35a787871a..d38c0ff044 100644 --- a/src/core/lib/security/security_connector/alts_security_connector.cc +++ b/src/core/lib/security/security_connector/alts_security_connector.cc @@ -64,29 +64,29 @@ static void alts_server_destroy(grpc_security_connector* sc) { } static void alts_channel_add_handshakers( - grpc_channel_security_connector* sc, + grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_manager) { tsi_handshaker* handshaker = nullptr; 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, - &handshaker) == TSI_OK); + GPR_ASSERT(alts_tsi_handshaker_create( + creds->options, c->target_name, creds->handshaker_service_url, + true, interested_parties, &handshaker) == TSI_OK); grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create( handshaker, &sc->base)); } static void alts_server_add_handshakers( - grpc_server_security_connector* sc, + grpc_server_security_connector* sc, grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_manager) { tsi_handshaker* handshaker = nullptr; 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, - &handshaker) == TSI_OK); + GPR_ASSERT(alts_tsi_handshaker_create( + creds->options, nullptr, creds->handshaker_service_url, false, + interested_parties, &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/local_security_connector.cc b/src/core/lib/security/security_connector/local_security_connector.cc index c436a7906b..911013ae58 100644 --- a/src/core/lib/security/security_connector/local_security_connector.cc +++ b/src/core/lib/security/security_connector/local_security_connector.cc @@ -30,6 +30,7 @@ #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/security/credentials/local/local_credentials.h" #include "src/core/lib/security/transport/security_handshaker.h" #include "src/core/tsi/local_transport_security.h" @@ -68,7 +69,7 @@ static void local_server_destroy(grpc_security_connector* sc) { } static void local_channel_add_handshakers( - grpc_channel_security_connector* sc, + grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_manager) { tsi_handshaker* handshaker = nullptr; GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) == @@ -78,7 +79,7 @@ static void local_channel_add_handshakers( } static void local_server_add_handshakers( - grpc_server_security_connector* sc, + grpc_server_security_connector* sc, grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_manager) { tsi_handshaker* handshaker = nullptr; GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */, &handshaker) == diff --git a/src/core/lib/security/security_connector/security_connector.cc b/src/core/lib/security/security_connector/security_connector.cc index 04b4c87c71..7028ae8d16 100644 --- a/src/core/lib/security/security_connector/security_connector.cc +++ b/src/core/lib/security/security_connector/security_connector.cc @@ -59,8 +59,8 @@ static const char* installed_roots_path = /** Environment variable used as a flag to enable/disable loading system root certificates from the OS trust store. */ -#ifndef GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR -#define GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_USE_SYSTEM_SSL_ROOTS" +#ifndef GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR +#define GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_NOT_USE_SYSTEM_SSL_ROOTS" #endif #ifndef TSI_OPENSSL_ALPN_SUPPORT @@ -120,17 +120,19 @@ const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* peer, void grpc_channel_security_connector_add_handshakers( grpc_channel_security_connector* connector, + grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { if (connector != nullptr) { - connector->add_handshakers(connector, handshake_mgr); + connector->add_handshakers(connector, interested_parties, handshake_mgr); } } void grpc_server_security_connector_add_handshakers( grpc_server_security_connector* connector, + grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { if (connector != nullptr) { - connector->add_handshakers(connector, handshake_mgr); + connector->add_handshakers(connector, interested_parties, handshake_mgr); } } @@ -519,7 +521,7 @@ static void fake_channel_cancel_check_call_host( } static void fake_channel_add_handshakers( - grpc_channel_security_connector* sc, + grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_handshake_manager_add( handshake_mgr, @@ -528,6 +530,7 @@ static void fake_channel_add_handshakers( } static void fake_server_add_handshakers(grpc_server_security_connector* sc, + grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_handshake_manager_add( handshake_mgr, @@ -669,6 +672,7 @@ static void ssl_server_destroy(grpc_security_connector* sc) { } static void ssl_channel_add_handshakers(grpc_channel_security_connector* sc, + grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_ssl_channel_security_connector* c = reinterpret_cast<grpc_ssl_channel_security_connector*>(sc); @@ -779,6 +783,7 @@ static bool try_fetch_ssl_server_credentials( } static void ssl_server_add_handshakers(grpc_server_security_connector* sc, + grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr) { grpc_ssl_server_security_connector* c = reinterpret_cast<grpc_ssl_server_security_connector*>(sc); @@ -1192,10 +1197,10 @@ const char* DefaultSslRootStore::GetPemRootCerts() { grpc_slice DefaultSslRootStore::ComputePemRootCerts() { grpc_slice result = grpc_empty_slice(); - char* use_system_roots_env_value = - gpr_getenv(GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR); - const bool use_system_roots = gpr_is_true(use_system_roots_env_value); - gpr_free(use_system_roots_env_value); + char* not_use_system_roots_env_value = + gpr_getenv(GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR); + const bool not_use_system_roots = gpr_is_true(not_use_system_roots_env_value); + gpr_free(not_use_system_roots_env_value); // First try to load the roots from the environment. char* default_root_certs_path = gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR); @@ -1218,7 +1223,7 @@ grpc_slice DefaultSslRootStore::ComputePemRootCerts() { gpr_free(pem_root_certs); } // Try loading roots from OS trust store if flag is enabled. - if (GRPC_SLICE_IS_EMPTY(result) && use_system_roots) { + if (GRPC_SLICE_IS_EMPTY(result) && !not_use_system_roots) { result = LoadSystemRootCerts(); } // Fallback to roots manually shipped with gRPC. diff --git a/src/core/lib/security/security_connector/security_connector.h b/src/core/lib/security/security_connector/security_connector.h index 67a506b576..d8df3cd72f 100644 --- a/src/core/lib/security/security_connector/security_connector.h +++ b/src/core/lib/security/security_connector/security_connector.h @@ -27,6 +27,7 @@ #include "src/core/lib/channel/handshaker.h" #include "src/core/lib/iomgr/endpoint.h" +#include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/tcp_server.h" #include "src/core/tsi/ssl_transport_security.h" #include "src/core/tsi/transport_security_interface.h" @@ -125,6 +126,7 @@ struct grpc_channel_security_connector { grpc_closure* on_call_host_checked, grpc_error* error); void (*add_handshakers)(grpc_channel_security_connector* sc, + grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr); }; @@ -151,6 +153,7 @@ void grpc_channel_security_connector_cancel_check_call_host( /* Registers handshakers with \a handshake_mgr. */ void grpc_channel_security_connector_add_handshakers( grpc_channel_security_connector* connector, + grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr); /* --- server_security_connector object. --- @@ -164,6 +167,7 @@ struct grpc_server_security_connector { grpc_security_connector base; grpc_server_credentials* server_creds; void (*add_handshakers)(grpc_server_security_connector* sc, + grpc_pollset_set* interested_parties, grpc_handshake_manager* handshake_mgr); }; @@ -172,7 +176,8 @@ int grpc_server_security_connector_cmp(grpc_server_security_connector* sc1, grpc_server_security_connector* sc2); void grpc_server_security_connector_add_handshakers( - grpc_server_security_connector* sc, grpc_handshake_manager* handshake_mgr); + grpc_server_security_connector* sc, grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_mgr); /* --- Creation security connectors. --- */ diff --git a/src/core/lib/security/transport/secure_endpoint.cc b/src/core/lib/security/transport/secure_endpoint.cc index 840b2e73bc..f40f969bb7 100644 --- a/src/core/lib/security/transport/secure_endpoint.cc +++ b/src/core/lib/security/transport/secure_endpoint.cc @@ -254,7 +254,7 @@ static void flush_write_staging_buffer(secure_endpoint* ep, uint8_t** cur, } static void endpoint_write(grpc_endpoint* secure_ep, grpc_slice_buffer* slices, - grpc_closure* cb) { + grpc_closure* cb, void* arg) { GPR_TIMER_SCOPE("secure_endpoint.endpoint_write", 0); unsigned i; @@ -342,7 +342,7 @@ static void endpoint_write(grpc_endpoint* secure_ep, grpc_slice_buffer* slices, return; } - grpc_endpoint_write(ep->wrapped_ep, &ep->output_buffer, cb); + grpc_endpoint_write(ep->wrapped_ep, &ep->output_buffer, cb, arg); } static void endpoint_shutdown(grpc_endpoint* secure_ep, grpc_error* why) { diff --git a/src/core/lib/security/transport/security_handshaker.cc b/src/core/lib/security/transport/security_handshaker.cc index aff723ed04..4d6b133809 100644 --- a/src/core/lib/security/transport/security_handshaker.cc +++ b/src/core/lib/security/transport/security_handshaker.cc @@ -259,7 +259,7 @@ static grpc_error* on_handshake_next_done_locked( grpc_slice_buffer_reset_and_unref_internal(&h->outgoing); grpc_slice_buffer_add(&h->outgoing, to_send); grpc_endpoint_write(h->args->endpoint, &h->outgoing, - &h->on_handshake_data_sent_to_peer); + &h->on_handshake_data_sent_to_peer, nullptr); } else if (handshaker_result == nullptr) { // There is nothing to send, but need to read from peer. grpc_endpoint_read(h->args->endpoint, h->args->read_buffer, @@ -475,22 +475,24 @@ 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)); - grpc_channel_security_connector_add_handshakers(security_connector, - handshake_mgr); + grpc_channel_security_connector_add_handshakers( + security_connector, interested_parties, 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)); - grpc_server_security_connector_add_handshakers(security_connector, - handshake_mgr); + grpc_server_security_connector_add_handshakers( + security_connector, interested_parties, handshake_mgr); } static void handshaker_factory_destroy( diff --git a/src/core/lib/security/transport/server_auth_filter.cc b/src/core/lib/security/transport/server_auth_filter.cc index 19cbb03b63..b99fc5e178 100644 --- a/src/core/lib/security/transport/server_auth_filter.cc +++ b/src/core/lib/security/transport/server_auth_filter.cc @@ -41,6 +41,11 @@ struct call_data { grpc_transport_stream_op_batch* recv_initial_metadata_batch; grpc_closure* original_recv_initial_metadata_ready; grpc_closure recv_initial_metadata_ready; + grpc_error* recv_initial_metadata_error; + grpc_closure recv_trailing_metadata_ready; + grpc_closure* original_recv_trailing_metadata_ready; + grpc_error* recv_trailing_metadata_error; + bool seen_recv_trailing_metadata_ready; grpc_metadata_array md; const grpc_metadata* consumed_md; size_t num_consumed_md; @@ -111,7 +116,16 @@ static void on_md_processing_done_inner(grpc_call_element* elem, batch->payload->recv_initial_metadata.recv_initial_metadata, remove_consumed_md, elem, "Response metadata filtering error"); } - GRPC_CLOSURE_SCHED(calld->original_recv_initial_metadata_ready, error); + calld->recv_initial_metadata_error = GRPC_ERROR_REF(error); + grpc_closure* closure = calld->original_recv_initial_metadata_ready; + calld->original_recv_initial_metadata_ready = nullptr; + if (calld->seen_recv_trailing_metadata_ready) { + GRPC_CALL_COMBINER_START(calld->call_combiner, + &calld->recv_trailing_metadata_ready, + calld->recv_trailing_metadata_error, + "continue recv_trailing_metadata_ready"); + } + GRPC_CLOSURE_SCHED(closure, error); } // Called from application code. @@ -180,8 +194,31 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) { return; } } - GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready, - GRPC_ERROR_REF(error)); + grpc_closure* closure = calld->original_recv_initial_metadata_ready; + calld->original_recv_initial_metadata_ready = nullptr; + if (calld->seen_recv_trailing_metadata_ready) { + GRPC_CALL_COMBINER_START(calld->call_combiner, + &calld->recv_trailing_metadata_ready, + calld->recv_trailing_metadata_error, + "continue recv_trailing_metadata_ready"); + } + GRPC_CLOSURE_RUN(closure, GRPC_ERROR_REF(error)); +} + +static void recv_trailing_metadata_ready(void* user_data, grpc_error* err) { + grpc_call_element* elem = static_cast<grpc_call_element*>(user_data); + call_data* calld = static_cast<call_data*>(elem->call_data); + if (calld->original_recv_initial_metadata_ready != nullptr) { + calld->recv_trailing_metadata_error = GRPC_ERROR_REF(err); + calld->seen_recv_trailing_metadata_ready = true; + GRPC_CALL_COMBINER_STOP(calld->call_combiner, + "deferring recv_trailing_metadata_ready until " + "after recv_initial_metadata_ready"); + return; + } + err = grpc_error_add_child( + GRPC_ERROR_REF(err), GRPC_ERROR_REF(calld->recv_initial_metadata_error)); + GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, err); } static void auth_start_transport_stream_op_batch( @@ -195,6 +232,12 @@ static void auth_start_transport_stream_op_batch( batch->payload->recv_initial_metadata.recv_initial_metadata_ready = &calld->recv_initial_metadata_ready; } + if (batch->recv_trailing_metadata) { + calld->original_recv_trailing_metadata_ready = + batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready; + batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready = + &calld->recv_trailing_metadata_ready; + } grpc_call_next_op(elem, batch); } @@ -208,6 +251,9 @@ static grpc_error* init_call_elem(grpc_call_element* elem, GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, recv_initial_metadata_ready, elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, + recv_trailing_metadata_ready, elem, + grpc_schedule_on_exec_ctx); // Create server security context. Set its auth context from channel // data and save it in the call context. grpc_server_security_context* server_ctx = @@ -227,7 +273,10 @@ static grpc_error* init_call_elem(grpc_call_element* elem, /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, - grpc_closure* ignored) {} + grpc_closure* ignored) { + call_data* calld = static_cast<call_data*>(elem->call_data); + GRPC_ERROR_UNREF(calld->recv_initial_metadata_error); +} /* Constructor for channel_data */ static grpc_error* init_channel_elem(grpc_channel_element* elem, 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/call.cc b/src/core/lib/surface/call.cc index 52053e686b..a9349afa68 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -48,6 +48,7 @@ #include "src/core/lib/surface/call_test_only.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/surface/server.h" #include "src/core/lib/surface/validate_metadata.h" #include "src/core/lib/transport/error_utils.h" #include "src/core/lib/transport/metadata.h" @@ -71,46 +72,6 @@ // Used to create arena for the first call. #define ESTIMATED_MDELEM_COUNT 16 -/* Status data for a request can come from several sources; this - enumerates them all, and acts as a priority sorting for which - status to return to the application - earlier entries override - later ones */ -typedef enum { - /* Status came from the application layer overriding whatever - the wire says */ - STATUS_FROM_API_OVERRIDE = 0, - /* Status came from 'the wire' - or somewhere below the surface - layer */ - STATUS_FROM_WIRE, - /* Status was created by some internal channel stack operation: must come via - add_batch_error */ - STATUS_FROM_CORE, - /* Status was created by some surface error */ - STATUS_FROM_SURFACE, - /* Status came from the server sending status */ - STATUS_FROM_SERVER_STATUS, - STATUS_SOURCE_COUNT -} status_source; - -typedef struct { - bool is_set; - grpc_error* error; -} received_status; - -static gpr_atm pack_received_status(received_status r) { - return r.is_set ? (1 | (gpr_atm)r.error) : 0; -} - -static received_status unpack_received_status(gpr_atm atm) { - if ((atm & 1) == 0) { - return {false, GRPC_ERROR_NONE}; - } else { - return {true, (grpc_error*)(atm & ~static_cast<gpr_atm>(1))}; - } -} - -#define MAX_ERRORS_PER_BATCH 4 - typedef struct batch_control { grpc_call* call; /* Share memory for cq_completion and notify_tag as they are never needed @@ -135,10 +96,7 @@ typedef struct batch_control { grpc_closure start_batch; grpc_closure finish_batch; gpr_refcount steps_to_complete; - - grpc_error* errors[MAX_ERRORS_PER_BATCH]; - gpr_atm num_errors; - + gpr_atm batch_error; grpc_transport_stream_op_batch op; } batch_control; @@ -201,9 +159,6 @@ struct grpc_call { // A char* indicating the peer name. gpr_atm peer_string; - /* Packed received call statuses from various sources */ - gpr_atm status[STATUS_SOURCE_COUNT]; - /* Call data useful used for reporting. Only valid after the call has * completed */ grpc_call_final_info final_info; @@ -236,6 +191,7 @@ struct grpc_call { grpc_closure receiving_initial_metadata_ready; grpc_closure receiving_trailing_metadata_ready; uint32_t test_only_last_message_flags; + gpr_atm cancelled; grpc_closure release_call; @@ -247,8 +203,11 @@ struct grpc_call { } client; struct { int* cancelled; + // backpointer to owning server if this is a server side call. + grpc_server* server; } server; } final_op; + gpr_atm status_error; /* recv_state can contain one of the following values: RECV_NONE : : no initial metadata and messages received @@ -286,23 +245,15 @@ grpc_core::TraceFlag grpc_compression_trace(false, "compression"); static void execute_batch(grpc_call* call, grpc_transport_stream_op_batch* op, grpc_closure* start_batch_closure); -static void cancel_with_status(grpc_call* c, status_source source, - grpc_status_code status, + +static void cancel_with_status(grpc_call* c, grpc_status_code status, const char* description); -static void cancel_with_error(grpc_call* c, status_source source, - grpc_error* error); +static void cancel_with_error(grpc_call* c, grpc_error* error); static void destroy_call(void* call_stack, grpc_error* error); static void receiving_slice_ready(void* bctlp, grpc_error* error); -static void get_final_status( - grpc_call* call, void (*set_value)(grpc_status_code code, void* user_data), - void* set_value_user_data, grpc_slice* details, const char** error_string); -static void set_status_value_directly(grpc_status_code status, void* dest); -static void set_status_from_error(grpc_call* call, status_source source, - grpc_error* error); +static void set_final_status(grpc_call* call, grpc_error* error); static void process_data_after_md(batch_control* bctl); static void post_batch_completion(batch_control* bctl); -static void add_batch_error(batch_control* bctl, grpc_error* error, - bool has_cancelled); static void add_init_error(grpc_error** composite, grpc_error* new_err) { if (new_err == GRPC_ERROR_NONE) return; @@ -353,6 +304,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, gpr_arena_alloc(arena, GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) + channel_stack->call_stack_size)); gpr_ref_init(&call->ext_ref, 1); + gpr_atm_no_barrier_store(&call->cancelled, 0); call->arena = arena; grpc_call_combiner_init(&call->call_combiner); *out_call = call; @@ -362,14 +314,10 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, /* Always support no compression */ GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_MESSAGE_COMPRESS_NONE); call->is_client = args->server_transport_data == nullptr; - if (call->is_client) { - GRPC_STATS_INC_CLIENT_CALLS_CREATED(); - } else { - GRPC_STATS_INC_SERVER_CALLS_CREATED(); - } call->stream_op_payload.context = call->context; grpc_slice path = grpc_empty_slice(); if (call->is_client) { + GRPC_STATS_INC_CLIENT_CALLS_CREATED(); GPR_ASSERT(args->add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT); for (i = 0; i < args->add_initial_metadata_count; i++) { @@ -383,6 +331,8 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, call->send_extra_metadata_count = static_cast<int>(args->add_initial_metadata_count); } else { + GRPC_STATS_INC_SERVER_CALLS_CREATED(); + call->final_op.server.server = args->server; GPR_ASSERT(args->add_initial_metadata_count == 0); call->send_extra_metadata_count = 0; } @@ -464,10 +414,10 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, gpr_mu_unlock(&pc->child_list_mu); } if (error != GRPC_ERROR_NONE) { - cancel_with_error(call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error)); + cancel_with_error(call, GRPC_ERROR_REF(error)); } if (immediately_cancel) { - cancel_with_error(call, STATUS_FROM_API_OVERRIDE, GRPC_ERROR_CANCELLED); + cancel_with_error(call, GRPC_ERROR_CANCELLED); } if (args->cq != nullptr) { GPR_ASSERT(args->pollset_set_alternative == nullptr && @@ -486,10 +436,18 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, &call->pollent); } - grpc_core::channelz::ChannelNode* channelz_channel = - grpc_channel_get_channelz_node(call->channel); - if (channelz_channel != nullptr) { - channelz_channel->RecordCallStarted(); + if (call->is_client) { + grpc_core::channelz::ChannelNode* channelz_channel = + grpc_channel_get_channelz_node(call->channel); + if (channelz_channel != nullptr) { + channelz_channel->RecordCallStarted(); + } + } else { + grpc_core::channelz::ServerNode* channelz_server = + grpc_server_get_channelz_node(call->final_op.server.server); + if (channelz_server != nullptr) { + channelz_server->RecordCallStarted(); + } } grpc_slice_unref_internal(path); @@ -561,16 +519,15 @@ static void destroy_call(void* call, grpc_error* error) { GRPC_CQ_INTERNAL_UNREF(c->cq, "bind"); } - get_final_status(c, set_status_value_directly, &c->final_info.final_status, - nullptr, &(c->final_info.error_string)); + grpc_error* status_error = + reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&c->status_error)); + grpc_error_get_status(status_error, c->send_deadline, + &c->final_info.final_status, nullptr, nullptr, + &(c->final_info.error_string)); + GRPC_ERROR_UNREF(status_error); c->final_info.stats.latency = gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time); - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - GRPC_ERROR_UNREF( - unpack_received_status(gpr_atm_acq_load(&c->status[i])).error); - } - grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c), &c->final_info, GRPC_CLOSURE_INIT(&c->release_call, release_call, c, grpc_schedule_on_exec_ctx)); @@ -608,7 +565,7 @@ void grpc_call_unref(grpc_call* c) { bool cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) != 0 && gpr_atm_acq_load(&c->received_final_op_atm) == 0; if (cancel) { - cancel_with_error(c, STATUS_FROM_API_OVERRIDE, GRPC_ERROR_CANCELLED); + cancel_with_error(c, GRPC_ERROR_CANCELLED); } else { // Unset the call combiner cancellation closure. This has the // effect of scheduling the previously set cancellation closure, if @@ -626,8 +583,7 @@ grpc_call_error grpc_call_cancel(grpc_call* call, void* reserved) { GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved)); GPR_ASSERT(!reserved); grpc_core::ExecCtx exec_ctx; - cancel_with_error(call, STATUS_FROM_API_OVERRIDE, GRPC_ERROR_CANCELLED); - + cancel_with_error(call, GRPC_ERROR_CANCELLED); return GRPC_CALL_OK; } @@ -681,8 +637,7 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call* c, "c=%p, status=%d, description=%s, reserved=%p)", 4, (c, (int)status, description, reserved)); GPR_ASSERT(reserved == nullptr); - cancel_with_status(c, STATUS_FROM_API_OVERRIDE, status, description); - + cancel_with_status(c, status, description); return GRPC_CALL_OK; } @@ -702,15 +657,17 @@ static void done_termination(void* arg, grpc_error* error) { gpr_free(state); } -static void cancel_with_error(grpc_call* c, status_source source, - grpc_error* error) { +static void cancel_with_error(grpc_call* c, grpc_error* error) { + if (!gpr_atm_rel_cas(&c->cancelled, 0, 1)) { + GRPC_ERROR_UNREF(error); + return; + } GRPC_CALL_INTERNAL_REF(c, "termination"); // Inform the call combiner of the cancellation, so that it can cancel // any in-flight asynchronous actions that may be holding the call // combiner. This ensures that the cancel_stream batch can be sent // down the filter stack in a timely manner. grpc_call_combiner_cancel(&c->call_combiner, GRPC_ERROR_REF(error)); - set_status_from_error(c, source, GRPC_ERROR_REF(error)); cancel_state* state = static_cast<cancel_state*>(gpr_malloc(sizeof(*state))); state->call = c; GRPC_CLOSURE_INIT(&state->finish_batch, done_termination, state, @@ -733,90 +690,47 @@ static grpc_error* error_from_status(grpc_status_code status, GRPC_ERROR_INT_GRPC_STATUS, status); } -static void cancel_with_status(grpc_call* c, status_source source, - grpc_status_code status, +static void cancel_with_status(grpc_call* c, grpc_status_code status, const char* description) { - cancel_with_error(c, source, error_from_status(status, description)); -} - -/******************************************************************************* - * FINAL STATUS CODE MANIPULATION - */ - -static bool get_final_status_from( - grpc_call* call, grpc_error* error, bool allow_ok_status, - void (*set_value)(grpc_status_code code, void* user_data), - void* set_value_user_data, grpc_slice* details, const char** error_string) { - grpc_status_code code; - grpc_slice slice = grpc_empty_slice(); - grpc_error_get_status(error, call->send_deadline, &code, &slice, nullptr, - error_string); - if (code == GRPC_STATUS_OK && !allow_ok_status) { - return false; - } - - set_value(code, set_value_user_data); - if (details != nullptr) { - *details = grpc_slice_ref_internal(slice); - } - return true; + cancel_with_error(c, error_from_status(status, description)); } -static void get_final_status( - grpc_call* call, void (*set_value)(grpc_status_code code, void* user_data), - void* set_value_user_data, grpc_slice* details, const char** error_string) { - int i; - received_status status[STATUS_SOURCE_COUNT]; - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - status[i] = unpack_received_status(gpr_atm_acq_load(&call->status[i])); - } +static void set_final_status(grpc_call* call, grpc_error* error) { if (grpc_call_error_trace.enabled()) { - gpr_log(GPR_INFO, "get_final_status %s", call->is_client ? "CLI" : "SVR"); - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - if (status[i].is_set) { - gpr_log(GPR_INFO, " %d: %s", i, grpc_error_string(status[i].error)); - } - } + gpr_log(GPR_DEBUG, "set_final_status %s", call->is_client ? "CLI" : "SVR"); + gpr_log(GPR_DEBUG, "%s", grpc_error_string(error)); } - /* first search through ignoring "OK" statuses: if something went wrong, - * ensure we report it */ - for (int allow_ok_status = 0; allow_ok_status < 2; allow_ok_status++) { - /* search for the best status we can present: ideally the error we use has a - clearly defined grpc-status, and we'll prefer that. */ - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - if (status[i].is_set && - grpc_error_has_clear_grpc_status(status[i].error)) { - if (get_final_status_from(call, status[i].error, allow_ok_status != 0, - set_value, set_value_user_data, details, - error_string)) { - return; - } + if (call->is_client) { + grpc_error_get_status(error, call->send_deadline, + call->final_op.client.status, + call->final_op.client.status_details, nullptr, + call->final_op.client.error_string); + // explicitly take a ref + grpc_slice_ref_internal(*call->final_op.client.status_details); + gpr_atm_rel_store(&call->status_error, reinterpret_cast<gpr_atm>(error)); + grpc_core::channelz::ChannelNode* channelz_channel = + grpc_channel_get_channelz_node(call->channel); + if (channelz_channel != nullptr) { + if (*call->final_op.client.status != GRPC_STATUS_OK) { + channelz_channel->RecordCallFailed(); + } else { + channelz_channel->RecordCallSucceeded(); } } - /* If no clearly defined status exists, search for 'anything' */ - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - if (status[i].is_set) { - if (get_final_status_from(call, status[i].error, allow_ok_status != 0, - set_value, set_value_user_data, details, - error_string)) { - return; - } + } else { + *call->final_op.server.cancelled = + error != GRPC_ERROR_NONE || + reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&call->status_error)) != + GRPC_ERROR_NONE; + grpc_core::channelz::ServerNode* channelz_server = + grpc_server_get_channelz_node(call->final_op.server.server); + if (channelz_server != nullptr) { + if (*call->final_op.server.cancelled) { + channelz_server->RecordCallFailed(); + } else { + channelz_server->RecordCallSucceeded(); } } - } - /* If nothing exists, set some default */ - if (call->is_client) { - set_value(GRPC_STATUS_UNKNOWN, set_value_user_data); - } else { - set_value(GRPC_STATUS_OK, set_value_user_data); - } -} - -static void set_status_from_error(grpc_call* call, status_source source, - grpc_error* error) { - if (!gpr_atm_rel_cas(&call->status[source], - pack_received_status({false, GRPC_ERROR_NONE}), - pack_received_status({true, error}))) { GRPC_ERROR_UNREF(error); } } @@ -1035,6 +949,7 @@ static grpc_stream_compression_algorithm decode_stream_compression( static void publish_app_metadata(grpc_call* call, grpc_metadata_batch* b, int is_trailing) { if (b->list.count == 0) return; + if (!call->is_client && is_trailing) return; if (is_trailing && call->buffered_metadata[1] == nullptr) return; GPR_TIMER_SCOPE("publish_app_metadata", 0); grpc_metadata_array* dest; @@ -1088,9 +1003,12 @@ static void recv_initial_filter(grpc_call* call, grpc_metadata_batch* b) { publish_app_metadata(call, b, false); } -static void recv_trailing_filter(void* args, grpc_metadata_batch* b) { +static void recv_trailing_filter(void* args, grpc_metadata_batch* b, + grpc_error* batch_error) { grpc_call* call = static_cast<grpc_call*>(args); - if (b->idx.named.grpc_status != nullptr) { + if (batch_error != GRPC_ERROR_NONE) { + set_final_status(call, batch_error); + } else if (b->idx.named.grpc_status != nullptr) { grpc_status_code status_code = grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md); grpc_error* error = GRPC_ERROR_NONE; @@ -1108,8 +1026,18 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b) { error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, grpc_empty_slice()); } - set_status_from_error(call, STATUS_FROM_WIRE, error); + set_final_status(call, GRPC_ERROR_REF(error)); grpc_metadata_batch_remove(b, b->idx.named.grpc_status); + GRPC_ERROR_UNREF(error); + } else if (!call->is_client) { + set_final_status(call, GRPC_ERROR_NONE); + } else { + gpr_log(GPR_DEBUG, + "Received trailing metadata with no error and no status"); + set_final_status( + call, grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("No status received"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNKNOWN)); } publish_app_metadata(call, b, true); } @@ -1124,14 +1052,6 @@ grpc_call_stack* grpc_call_get_call_stack(grpc_call* call) { * BATCH API IMPLEMENTATION */ -static void set_status_value_directly(grpc_status_code status, void* dest) { - *static_cast<grpc_status_code*>(dest) = status; -} - -static void set_cancelled_value(grpc_status_code status, void* dest) { - *static_cast<int*>(dest) = (status != GRPC_STATUS_OK); -} - static bool are_write_flags_valid(uint32_t flags) { /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */ const uint32_t allowed_write_positions = @@ -1199,31 +1119,18 @@ static void finish_batch_completion(void* user_data, GRPC_CALL_INTERNAL_UNREF(call, "completion"); } -static grpc_error* consolidate_batch_errors(batch_control* bctl) { - size_t n = static_cast<size_t>(gpr_atm_acq_load(&bctl->num_errors)); - if (n == 0) { - return GRPC_ERROR_NONE; - } else if (n == 1) { - /* Skip creating a composite error in the case that only one error was - logged */ - grpc_error* e = bctl->errors[0]; - bctl->errors[0] = nullptr; - return e; - } else { - grpc_error* error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Call batch failed", bctl->errors, n); - for (size_t i = 0; i < n; i++) { - GRPC_ERROR_UNREF(bctl->errors[i]); - bctl->errors[i] = nullptr; - } - return error; - } +static void reset_batch_errors(batch_control* bctl) { + GRPC_ERROR_UNREF( + reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error))); + gpr_atm_rel_store(&bctl->batch_error, + reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE)); } static void post_batch_completion(batch_control* bctl) { grpc_call* next_child_call; grpc_call* call = bctl->call; - grpc_error* error = consolidate_batch_errors(bctl); + grpc_error* error = GRPC_ERROR_REF( + reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error))); if (bctl->op.send_initial_metadata) { grpc_metadata_batch_destroy( @@ -1249,8 +1156,7 @@ static void post_batch_completion(batch_control* bctl) { next_child_call = child->child->sibling_next; if (child->cancellation_is_inherited) { GRPC_CALL_INTERNAL_REF(child, "propagate_cancel"); - cancel_with_error(child, STATUS_FROM_API_OVERRIDE, - GRPC_ERROR_CANCELLED); + cancel_with_error(child, GRPC_ERROR_CANCELLED); GRPC_CALL_INTERNAL_UNREF(child, "propagate_cancel"); } child = next_child_call; @@ -1258,24 +1164,6 @@ static void post_batch_completion(batch_control* bctl) { } gpr_mu_unlock(&pc->child_list_mu); } - if (call->is_client) { - get_final_status(call, set_status_value_directly, - call->final_op.client.status, - call->final_op.client.status_details, - call->final_op.client.error_string); - } else { - get_final_status(call, set_cancelled_value, - call->final_op.server.cancelled, nullptr, nullptr); - } - grpc_core::channelz::ChannelNode* channelz_channel = - grpc_channel_get_channelz_node(call->channel); - if (channelz_channel != nullptr) { - if (*call->final_op.client.status != GRPC_STATUS_OK) { - channelz_channel->RecordCallFailed(); - } else { - channelz_channel->RecordCallSucceeded(); - } - } GRPC_ERROR_UNREF(error); error = GRPC_ERROR_NONE; } @@ -1284,9 +1172,10 @@ static void post_batch_completion(batch_control* bctl) { grpc_byte_buffer_destroy(*call->receiving_buffer); *call->receiving_buffer = nullptr; } + reset_batch_errors(bctl); if (bctl->completion_data.notify_tag.is_closure) { - /* unrefs bctl->error */ + /* unrefs error */ bctl->call = nullptr; /* This closure may be meant to be run within some combiner. Since we aren't * running in any combiner here, we need to use GRPC_CLOSURE_SCHED instead @@ -1296,7 +1185,7 @@ static void post_batch_completion(batch_control* bctl) { error); GRPC_CALL_INTERNAL_UNREF(call, "completion"); } else { - /* unrefs bctl->error */ + /* unrefs error */ grpc_cq_end_op(bctl->call->cq, bctl->completion_data.notify_tag.tag, error, finish_batch_completion, bctl, &bctl->completion_data.cq_completion); @@ -1405,8 +1294,12 @@ static void receiving_stream_ready(void* bctlp, grpc_error* error) { grpc_call* call = bctl->call; if (error != GRPC_ERROR_NONE) { call->receiving_stream.reset(); - add_batch_error(bctl, GRPC_ERROR_REF(error), true); - cancel_with_error(call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error)); + if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) == + GRPC_ERROR_NONE) { + gpr_atm_rel_store(&bctl->batch_error, + reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error))); + } + cancel_with_error(call, GRPC_ERROR_REF(error)); } /* If recv_state is RECV_NONE, we will save the batch_control * object with rel_cas, and will not use it after the cas. Its corresponding @@ -1442,8 +1335,7 @@ static void validate_filtered_metadata(batch_control* bctl) { call->incoming_stream_compression_algorithm, call->incoming_message_compression_algorithm); gpr_log(GPR_ERROR, "%s", error_msg); - cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_INTERNAL, - error_msg); + cancel_with_status(call, GRPC_STATUS_INTERNAL, error_msg); gpr_free(error_msg); } else if ( grpc_compression_algorithm_from_message_stream_compression_algorithm( @@ -1455,8 +1347,7 @@ static void validate_filtered_metadata(batch_control* bctl) { "compression (%d).", call->incoming_stream_compression_algorithm, call->incoming_message_compression_algorithm); - cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_INTERNAL, - error_msg); + cancel_with_status(call, GRPC_STATUS_INTERNAL, error_msg); gpr_free(error_msg); } else { char* error_msg = nullptr; @@ -1466,8 +1357,7 @@ static void validate_filtered_metadata(batch_control* bctl) { gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.", compression_algorithm); gpr_log(GPR_ERROR, "%s", error_msg); - cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_UNIMPLEMENTED, - error_msg); + cancel_with_status(call, GRPC_STATUS_UNIMPLEMENTED, error_msg); } else if (grpc_compression_options_is_algorithm_enabled( &compression_options, compression_algorithm) == 0) { /* check if algorithm is supported by current channel config */ @@ -1476,8 +1366,7 @@ static void validate_filtered_metadata(batch_control* bctl) { gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.", algo_name); gpr_log(GPR_ERROR, "%s", error_msg); - cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_UNIMPLEMENTED, - error_msg); + cancel_with_status(call, GRPC_STATUS_UNIMPLEMENTED, error_msg); } gpr_free(error_msg); @@ -1495,23 +1384,12 @@ static void validate_filtered_metadata(batch_control* bctl) { } } -static void add_batch_error(batch_control* bctl, grpc_error* error, - bool has_cancelled) { - if (error == GRPC_ERROR_NONE) return; - int idx = static_cast<int>(gpr_atm_full_fetch_add(&bctl->num_errors, 1)); - if (idx == 0 && !has_cancelled) { - cancel_with_error(bctl->call, STATUS_FROM_CORE, GRPC_ERROR_REF(error)); - } - bctl->errors[idx] = error; -} - static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) { batch_control* bctl = static_cast<batch_control*>(bctlp); grpc_call* call = bctl->call; GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_initial_metadata_ready"); - add_batch_error(bctl, GRPC_ERROR_REF(error), false); if (error == GRPC_ERROR_NONE) { grpc_metadata_batch* md = &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; @@ -1524,6 +1402,13 @@ static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) { if (md->deadline != GRPC_MILLIS_INF_FUTURE && !call->is_client) { call->send_deadline = md->deadline; } + } else { + if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) == + GRPC_ERROR_NONE) { + gpr_atm_rel_store(&bctl->batch_error, + reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error))); + } + cancel_with_error(call, GRPC_ERROR_REF(error)); } grpc_closure* saved_rsr_closure = nullptr; @@ -1561,10 +1446,9 @@ static void receiving_trailing_metadata_ready(void* bctlp, grpc_error* error) { batch_control* bctl = static_cast<batch_control*>(bctlp); grpc_call* call = bctl->call; GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_trailing_metadata_ready"); - add_batch_error(bctl, GRPC_ERROR_REF(error), false); grpc_metadata_batch* md = &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - recv_trailing_filter(call, md); + recv_trailing_filter(call, md, GRPC_ERROR_REF(error)); finish_batch_step(bctl); } @@ -1572,7 +1456,14 @@ static void finish_batch(void* bctlp, grpc_error* error) { batch_control* bctl = static_cast<batch_control*>(bctlp); grpc_call* call = bctl->call; GRPC_CALL_COMBINER_STOP(&call->call_combiner, "on_complete"); - add_batch_error(bctl, GRPC_ERROR_REF(error), false); + if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) == + GRPC_ERROR_NONE) { + gpr_atm_rel_store(&bctl->batch_error, + reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error))); + } + if (error != GRPC_ERROR_NONE) { + cancel_with_error(call, GRPC_ERROR_REF(error)); + } finish_batch_step(bctl); } @@ -1774,28 +1665,33 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, call->send_extra_metadata_count = 1; call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem( call->channel, op->data.send_status_from_server.status); - { - grpc_error* override_error = GRPC_ERROR_NONE; - if (op->data.send_status_from_server.status != GRPC_STATUS_OK) { - override_error = - error_from_status(op->data.send_status_from_server.status, - "Returned non-ok status"); - } - if (op->data.send_status_from_server.status_details != nullptr) { - call->send_extra_metadata[1].md = grpc_mdelem_from_slices( - GRPC_MDSTR_GRPC_MESSAGE, - grpc_slice_ref_internal( - *op->data.send_status_from_server.status_details)); - call->send_extra_metadata_count++; + grpc_error* status_error = + op->data.send_status_from_server.status == GRPC_STATUS_OK + ? GRPC_ERROR_NONE + : grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Server returned error"), + GRPC_ERROR_INT_GRPC_STATUS, + static_cast<intptr_t>( + op->data.send_status_from_server.status)); + if (op->data.send_status_from_server.status_details != nullptr) { + call->send_extra_metadata[1].md = grpc_mdelem_from_slices( + GRPC_MDSTR_GRPC_MESSAGE, + grpc_slice_ref_internal( + *op->data.send_status_from_server.status_details)); + call->send_extra_metadata_count++; + if (status_error != GRPC_ERROR_NONE) { char* msg = grpc_slice_to_c_string( GRPC_MDVALUE(call->send_extra_metadata[1].md)); - override_error = - grpc_error_set_str(override_error, GRPC_ERROR_STR_GRPC_MESSAGE, + status_error = + grpc_error_set_str(status_error, GRPC_ERROR_STR_GRPC_MESSAGE, grpc_slice_from_copied_string(msg)); gpr_free(msg); } - set_status_from_error(call, STATUS_FROM_API_OVERRIDE, override_error); } + + gpr_atm_rel_store(&call->status_error, + reinterpret_cast<gpr_atm>(status_error)); if (!prepare_application_metadata( call, static_cast<int>( @@ -1951,7 +1847,7 @@ done: return error; done_with_error: - /* reverse any mutations that occured */ + /* reverse any mutations that occurred */ if (stream_op->send_initial_metadata) { call->sent_initial_metadata = false; grpc_metadata_batch_clear(&call->metadata_batch[0][0]); diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h index b3b06059d4..b34260505a 100644 --- a/src/core/lib/surface/call.h +++ b/src/core/lib/surface/call.h @@ -33,6 +33,7 @@ typedef void (*grpc_ioreq_completion_func)(grpc_call* call, int success, typedef struct grpc_call_create_args { grpc_channel* channel; + grpc_server* server; grpc_call* parent; uint32_t propagation_mask; diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index 82635d3c21..d7095c24d4 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -100,11 +100,10 @@ grpc_channel* grpc_channel_create_with_builder( return channel; } - memset(channel, 0, sizeof(*channel)); 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 = false; + 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. @@ -142,16 +141,17 @@ 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 - const grpc_integer_options options = {0, 0, INT_MAX}; - channel_tracer_max_nodes = + 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_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 // https://github.com/grpc/grpc/issues/15986 are addressed. - channelz_enabled = grpc_channel_arg_get_bool(&args->args[i], false); + channelz_enabled = grpc_channel_arg_get_bool( + &args->args[i], GRPC_ENABLE_CHANNELZ_DEFAULT); } else if (0 == strcmp(args->args[i].key, GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC)) { GPR_ASSERT(args->args[i].type == GRPC_ARG_POINTER); @@ -166,11 +166,12 @@ grpc_channel* grpc_channel_create_with_builder( } grpc_channel_args_destroy(args); - if (channelz_enabled) { - bool is_top_level_channel = channel->is_client && !internal_channel; + // we only need to do the channelz bookkeeping for clients here. The channelz + // 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, is_top_level_channel); - channel->channelz_channel->trace()->AddTraceEvent( + channel, channel_tracer_max_memory, !internal_channel); + channel->channelz_channel->AddTraceEvent( grpc_core::channelz::ChannelTrace::Severity::Info, grpc_slice_from_static_string("Channel created")); } @@ -335,9 +336,8 @@ grpc_call* grpc_channel_create_call(grpc_channel* channel, grpc_core::ExecCtx exec_ctx; grpc_call* call = grpc_channel_create_call_internal( channel, parent_call, propagation_mask, cq, nullptr, - grpc_mdelem_from_slices(GRPC_MDSTR_PATH, grpc_slice_ref_internal(method)), - host != nullptr ? grpc_mdelem_from_slices(GRPC_MDSTR_AUTHORITY, - grpc_slice_ref_internal(*host)) + grpc_mdelem_create(GRPC_MDSTR_PATH, method, nullptr), + host != nullptr ? grpc_mdelem_create(GRPC_MDSTR_AUTHORITY, *host, nullptr) : GRPC_MDNULL, grpc_timespec_to_millis_round_up(deadline)); @@ -346,14 +346,13 @@ grpc_call* grpc_channel_create_call(grpc_channel* channel, grpc_call* grpc_channel_create_pollset_set_call( grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask, - grpc_pollset_set* pollset_set, grpc_slice method, const grpc_slice* host, - grpc_millis deadline, void* reserved) { + grpc_pollset_set* pollset_set, const grpc_slice& method, + const grpc_slice* host, grpc_millis deadline, void* reserved) { GPR_ASSERT(!reserved); return grpc_channel_create_call_internal( channel, parent_call, propagation_mask, nullptr, pollset_set, - grpc_mdelem_from_slices(GRPC_MDSTR_PATH, grpc_slice_ref_internal(method)), - host != nullptr ? grpc_mdelem_from_slices(GRPC_MDSTR_AUTHORITY, - grpc_slice_ref_internal(*host)) + grpc_mdelem_create(GRPC_MDSTR_PATH, method, nullptr), + host != nullptr ? grpc_mdelem_create(GRPC_MDSTR_AUTHORITY, *host, nullptr) : GRPC_MDNULL, deadline); } @@ -428,6 +427,9 @@ void grpc_channel_internal_unref(grpc_channel* c REF_ARG) { static void destroy_channel(void* arg, grpc_error* error) { grpc_channel* channel = static_cast<grpc_channel*>(arg); if (channel->channelz_channel != nullptr) { + channel->channelz_channel->AddTraceEvent( + grpc_core::channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string("Channel destroyed")); channel->channelz_channel->MarkChannelDestroyed(); channel->channelz_channel.reset(); } diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index e5ff2c3596..4ac76b8a29 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -45,8 +45,8 @@ grpc_channel* grpc_channel_create_with_builder( value of \a propagation_mask (see propagation_bits.h for possible values) */ grpc_call* grpc_channel_create_pollset_set_call( grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask, - grpc_pollset_set* pollset_set, grpc_slice method, const grpc_slice* host, - grpc_millis deadline, void* reserved); + grpc_pollset_set* pollset_set, const grpc_slice& method, + const grpc_slice* host, grpc_millis deadline, void* reserved); /** Get a (borrowed) pointer to this channels underlying channel stack */ grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel); diff --git a/src/core/lib/surface/channel_init.h b/src/core/lib/surface/channel_init.h index 6543796b4c..f01852473b 100644 --- a/src/core/lib/surface/channel_init.h +++ b/src/core/lib/surface/channel_init.h @@ -21,37 +21,11 @@ #include <grpc/support/port_platform.h> -#include <limits.h> - #include "src/core/lib/channel/channel_stack_builder.h" #include "src/core/lib/surface/channel_stack_type.h" #include "src/core/lib/transport/transport.h" -// Priority for channel registration functions to be used in -// grpc_channel_init_register_stage(). The priority dictates the -// order in which the registration functions run. -// -// When used to register a filter, the filter can either be appended or -// prepended, thus dictating whether the filter goes at the top or bottom of -// the stack. Higher priority functions can get closer to the top or bottom -// of the stack than lower priority functions. -enum { - // Default level. Most of filters should use this level if their location in - // the stack does not matter. - GRPC_CHANNEL_INIT_PRIORITY_LOW = 0, - // For filters that should be added after the group of filters with default - // priority, such as auth filters. - GRPC_CHANNEL_INIT_PRIORITY_MED = 10000, - // For filters that need to be close to top or bottom, such as protocol-level - // filters (client_authority, http-client, http-server). - GRPC_CHANNEL_INIT_PRIORITY_HIGH = 20000, - // For filters that need to be very close to the wire or surface, such as - // stats filters (census). - GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH = 30000, - // For things that have to happen last, such as connected channel filter or - // surface server filter. Consider as reserved for gRPC internals. - GRPC_CHANNEL_INIT_PRIORITY_MAX = INT_MAX -}; +#define GRPC_CHANNEL_INIT_BUILTIN_PRIORITY 10000 /// This module provides a way for plugins (and the grpc core library itself) /// to register mutators for channel stacks. diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc index 0769d9e4f6..b81ae73b4d 100644 --- a/src/core/lib/surface/completion_queue.cc +++ b/src/core/lib/surface/completion_queue.cc @@ -79,6 +79,7 @@ typedef struct non_polling_worker { typedef struct { gpr_mu mu; + bool kicked_without_poller; non_polling_worker* root; grpc_closure* shutdown; } non_polling_poller; @@ -103,6 +104,10 @@ static grpc_error* non_polling_poller_work(grpc_pollset* pollset, grpc_millis deadline) { non_polling_poller* npp = reinterpret_cast<non_polling_poller*>(pollset); if (npp->shutdown) return GRPC_ERROR_NONE; + if (npp->kicked_without_poller) { + npp->kicked_without_poller = false; + return GRPC_ERROR_NONE; + } non_polling_worker w; gpr_cv_init(&w.cv); if (worker != nullptr) *worker = reinterpret_cast<grpc_pollset_worker*>(&w); @@ -148,6 +153,8 @@ static grpc_error* non_polling_poller_kick( w->kicked = true; gpr_cv_signal(&w->cv); } + } else { + p->kicked_without_poller = true; } return GRPC_ERROR_NONE; } @@ -184,7 +191,8 @@ static const cq_poller_vtable g_poller_vtable_by_poller_type[] = { typedef struct cq_vtable { grpc_cq_completion_type cq_completion_type; size_t data_size; - void (*init)(void* data, grpc_core::CQCallbackInterface* shutdown_callback); + void (*init)(void* data, + grpc_experimental_completion_queue_functor* shutdown_callback); void (*shutdown)(grpc_completion_queue* cq); void (*destroy)(void* data); bool (*begin_op)(grpc_completion_queue* cq, void* tag); @@ -267,7 +275,7 @@ typedef struct cq_callback_data { bool shutdown_called; /** A callback that gets invoked when the CQ completes shutdown */ - grpc_core::CQCallbackInterface* shutdown_callback; + grpc_experimental_completion_queue_functor* shutdown_callback; } cq_callback_data; /* Completion queue structure */ @@ -333,12 +341,12 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag, gpr_timespec deadline, void* reserved); // Note that cq_init_next and cq_init_pluck do not use the shutdown_callback -static void cq_init_next(void* data, - grpc_core::CQCallbackInterface* shutdown_callback); -static void cq_init_pluck(void* data, - grpc_core::CQCallbackInterface* shutdown_callback); -static void cq_init_callback(void* data, - grpc_core::CQCallbackInterface* shutdown_callback); +static void cq_init_next( + void* data, grpc_experimental_completion_queue_functor* shutdown_callback); +static void cq_init_pluck( + void* data, grpc_experimental_completion_queue_functor* shutdown_callback); +static void cq_init_callback( + void* data, grpc_experimental_completion_queue_functor* shutdown_callback); static void cq_destroy_next(void* data); static void cq_destroy_pluck(void* data); static void cq_destroy_callback(void* data); @@ -462,7 +470,7 @@ static long cq_event_queue_num_items(grpc_cq_event_queue* q) { grpc_completion_queue* grpc_completion_queue_create_internal( grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type, - grpc_core::CQCallbackInterface* shutdown_callback) { + grpc_experimental_completion_queue_functor* shutdown_callback) { GPR_TIMER_SCOPE("grpc_completion_queue_create_internal", 0); grpc_completion_queue* cq; @@ -497,8 +505,8 @@ grpc_completion_queue* grpc_completion_queue_create_internal( return cq; } -static void cq_init_next(void* data, - grpc_core::CQCallbackInterface* shutdown_callback) { +static void cq_init_next( + void* data, grpc_experimental_completion_queue_functor* shutdown_callback) { cq_next_data* cqd = static_cast<cq_next_data*>(data); /* Initial count is dropped by grpc_completion_queue_shutdown */ gpr_atm_no_barrier_store(&cqd->pending_events, 1); @@ -513,8 +521,8 @@ static void cq_destroy_next(void* data) { cq_event_queue_destroy(&cqd->queue); } -static void cq_init_pluck(void* data, - grpc_core::CQCallbackInterface* shutdown_callback) { +static void cq_init_pluck( + void* data, grpc_experimental_completion_queue_functor* shutdown_callback) { cq_pluck_data* cqd = static_cast<cq_pluck_data*>(data); /* Initial count is dropped by grpc_completion_queue_shutdown */ gpr_atm_no_barrier_store(&cqd->pending_events, 1); @@ -532,7 +540,7 @@ static void cq_destroy_pluck(void* data) { } static void cq_init_callback( - void* data, grpc_core::CQCallbackInterface* shutdown_callback) { + void* data, grpc_experimental_completion_queue_functor* shutdown_callback) { cq_callback_data* cqd = static_cast<cq_callback_data*>(data); /* Initial count is dropped by grpc_completion_queue_shutdown */ gpr_atm_no_barrier_store(&cqd->pending_events, 1); @@ -859,7 +867,8 @@ static void cq_end_op_for_callback( GRPC_ERROR_UNREF(error); - (static_cast<grpc_core::CQCallbackInterface*>(tag))->Run(is_success); + auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(tag); + (*functor->functor_run)(functor, is_success); } void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error, @@ -1343,7 +1352,7 @@ static void cq_finish_shutdown_callback(grpc_completion_queue* cq) { GPR_ASSERT(cqd->shutdown_called); cq->poller_vtable->shutdown(POLLSET_FROM_CQ(cq), &cq->pollset_shutdown_done); - callback->Run(true); + (*callback->functor_run)(callback, true); } static void cq_shutdown_callback(grpc_completion_queue* cq) { @@ -1364,9 +1373,11 @@ static void cq_shutdown_callback(grpc_completion_queue* cq) { } cqd->shutdown_called = true; if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) { + gpr_mu_unlock(cq->mu); cq_finish_shutdown_callback(cq); + } else { + gpr_mu_unlock(cq->mu); } - gpr_mu_unlock(cq->mu); GRPC_CQ_INTERNAL_UNREF(cq, "shutting_down (callback cq)"); } diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h index a7c524d8e8..d60fe6d6ef 100644 --- a/src/core/lib/surface/completion_queue.h +++ b/src/core/lib/surface/completion_queue.h @@ -48,23 +48,6 @@ typedef struct grpc_cq_completion { uintptr_t next; } grpc_cq_completion; -/// For callback CQs, the tag that is passed in for an operation must -/// actually be a pointer to an implementation of the following class. -/// When the operation completes, the tag will be typecasted from void* -/// to grpc_core::CQCallbackInterface* and then the Run method will be -/// invoked on it. In practice, the language binding (e.g., C++ API -/// implementation) is responsible for providing and using an implementation -/// of this abstract base class. -namespace grpc_core { -class CQCallbackInterface { - public: - virtual ~CQCallbackInterface() {} - virtual void Run(bool) GRPC_ABSTRACT; - - GRPC_ABSTRACT_BASE_CLASS -}; -} // namespace grpc_core - #ifndef NDEBUG void grpc_cq_internal_ref(grpc_completion_queue* cc, const char* reason, const char* file, int line); @@ -106,6 +89,6 @@ int grpc_get_cq_poll_num(grpc_completion_queue* cc); grpc_completion_queue* grpc_completion_queue_create_internal( grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type, - grpc_core::CQCallbackInterface* shutdown_callback); + grpc_experimental_completion_queue_functor* shutdown_callback); #endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */ diff --git a/src/core/lib/surface/completion_queue_factory.cc b/src/core/lib/surface/completion_queue_factory.cc index ed92dd7eba..2616c156e4 100644 --- a/src/core/lib/surface/completion_queue_factory.cc +++ b/src/core/lib/surface/completion_queue_factory.cc @@ -31,8 +31,7 @@ static grpc_completion_queue* default_create( const grpc_completion_queue_factory* factory, const grpc_completion_queue_attributes* attr) { return grpc_completion_queue_create_internal( - attr->cq_completion_type, attr->cq_polling_type, - static_cast<grpc_core::CQCallbackInterface*>(attr->cq_shutdown_cb)); + attr->cq_completion_type, attr->cq_polling_type, attr->cq_shutdown_cb); } static grpc_completion_queue_factory_vtable default_vtable = {default_create}; @@ -73,7 +72,8 @@ grpc_completion_queue* grpc_completion_queue_create_for_pluck(void* reserved) { } grpc_completion_queue* grpc_completion_queue_create_for_callback( - void* shutdown_callback, void* reserved) { + grpc_experimental_completion_queue_functor* shutdown_callback, + void* reserved) { GPR_ASSERT(!reserved); grpc_completion_queue_attributes attr = { 2, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, shutdown_callback}; diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc index 7807b261d4..0ad82fed99 100644 --- a/src/core/lib/surface/init.cc +++ b/src/core/lib/surface/init.cc @@ -70,6 +70,11 @@ static void do_basic_init(void) { g_initializations = 0; } +static bool append_filter(grpc_channel_stack_builder* builder, void* arg) { + return grpc_channel_stack_builder_append_filter( + builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr); +} + static bool prepend_filter(grpc_channel_stack_builder* builder, void* arg) { return grpc_channel_stack_builder_prepend_filter( builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr); @@ -77,20 +82,19 @@ static bool prepend_filter(grpc_channel_stack_builder* builder, void* arg) { static void register_builtin_channel_init() { grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_MAX, - grpc_append_connected_filter, nullptr); + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + grpc_add_connected_filter, nullptr); grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_MAX, - grpc_append_connected_filter, nullptr); + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + grpc_add_connected_filter, nullptr); grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_MAX, - grpc_append_connected_filter, nullptr); + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + grpc_add_connected_filter, nullptr); grpc_channel_init_register_stage(GRPC_CLIENT_LAME_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_MAX, - prepend_filter, (void*)&grpc_lame_filter); - grpc_channel_init_register_stage( - GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, prepend_filter, - (void*)&grpc_server_top_filter); + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + append_filter, (void*)&grpc_lame_filter); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter, + (void*)&grpc_server_top_filter); } typedef struct grpc_plugin { diff --git a/src/core/lib/surface/init.h b/src/core/lib/surface/init.h index 9353208332..193f51447d 100644 --- a/src/core/lib/surface/init.h +++ b/src/core/lib/surface/init.h @@ -22,6 +22,5 @@ void grpc_register_security_filters(void); void grpc_security_pre_init(void); void grpc_security_init(void); -int grpc_is_initialized(void); #endif /* GRPC_CORE_LIB_SURFACE_INIT_H */ diff --git a/src/core/lib/surface/init_secure.cc b/src/core/lib/surface/init_secure.cc index 8058aaa804..765350cced 100644 --- a/src/core/lib/surface/init_secure.cc +++ b/src/core/lib/surface/init_secure.cc @@ -67,17 +67,14 @@ static bool maybe_prepend_server_auth_filter( } void grpc_register_security_filters(void) { - // Register the auth client with a medium priority to allow the authority + // Register the auth client with a priority < INT_MAX to allow the authority // filter -on which the auth filter depends- to be higher on the channel // stack. - grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_MED, + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX - 1, maybe_prepend_client_auth_filter, nullptr); - grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_MED, + 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, - GRPC_CHANNEL_INIT_PRIORITY_MED, + 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 cb34def740..35ab2c3bce 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -54,6 +54,7 @@ struct listener { size_t pollset_count); void (*destroy)(grpc_server* server, void* arg, grpc_closure* closure); struct listener* next; + intptr_t socket_uuid; grpc_closure destroy_done; }; @@ -104,6 +105,7 @@ struct channel_data { uint32_t registered_method_max_probes; grpc_closure finish_destroy_channel_closure; grpc_closure channel_connectivity_changed; + intptr_t socket_uuid; }; typedef struct shutdown_tag { @@ -149,10 +151,16 @@ struct call_data { grpc_closure server_on_recv_initial_metadata; grpc_closure kill_zombie_closure; grpc_closure* on_done_recv_initial_metadata; + grpc_closure recv_trailing_metadata_ready; + grpc_error* recv_initial_metadata_error; + grpc_closure* original_recv_trailing_metadata_ready; + grpc_error* recv_trailing_metadata_error; + bool seen_recv_trailing_metadata_ready; grpc_closure publish; call_data* pending_next; + grpc_call_combiner* call_combiner; }; struct request_matcher { @@ -219,6 +227,8 @@ struct grpc_server { /** when did we print the last shutdown progress message */ gpr_timespec last_shutdown_message_time; + + grpc_core::RefCountedPtr<grpc_core::channelz::ServerNode> channelz_server; }; #define SERVER_FROM_CALL_ELEM(elem) \ @@ -364,6 +374,7 @@ static void server_ref(grpc_server* server) { static void server_delete(grpc_server* server) { registered_method* rm; size_t i; + server->channelz_server.reset(); grpc_channel_args_destroy(server->channel_args); gpr_mu_destroy(&server->mu_global); gpr_mu_destroy(&server->mu_call); @@ -721,13 +732,43 @@ static void server_on_recv_initial_metadata(void* ptr, grpc_error* error) { if (calld->host_set && calld->path_set) { /* do nothing */ } else { + /* Pass the error reference to calld->recv_initial_metadata_error */ grpc_error* src_error = error; error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Missing :authority or :path", &error, 1); + "Missing :authority or :path", &src_error, 1); GRPC_ERROR_UNREF(src_error); + calld->recv_initial_metadata_error = GRPC_ERROR_REF(error); + } + grpc_closure* closure = calld->on_done_recv_initial_metadata; + calld->on_done_recv_initial_metadata = nullptr; + if (calld->seen_recv_trailing_metadata_ready) { + GRPC_CALL_COMBINER_START(calld->call_combiner, + &calld->recv_trailing_metadata_ready, + calld->recv_trailing_metadata_error, + "continue server_recv_trailing_metadata_ready"); } + GRPC_CLOSURE_RUN(closure, error); +} - GRPC_CLOSURE_RUN(calld->on_done_recv_initial_metadata, error); +static void server_recv_trailing_metadata_ready(void* user_data, + grpc_error* error) { + grpc_call_element* elem = static_cast<grpc_call_element*>(user_data); + call_data* calld = static_cast<call_data*>(elem->call_data); + if (calld->on_done_recv_initial_metadata != nullptr) { + calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error); + calld->seen_recv_trailing_metadata_ready = true; + GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, + server_recv_trailing_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + GRPC_CALL_COMBINER_STOP(calld->call_combiner, + "deferring server_recv_trailing_metadata_ready " + "until after server_on_recv_initial_metadata"); + return; + } + error = + grpc_error_add_child(GRPC_ERROR_REF(error), + GRPC_ERROR_REF(calld->recv_initial_metadata_error)); + GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, error); } static void server_mutate_op(grpc_call_element* elem, @@ -745,6 +786,12 @@ static void server_mutate_op(grpc_call_element* elem, op->payload->recv_initial_metadata.recv_flags = &calld->recv_initial_metadata_flags; } + if (op->recv_trailing_metadata) { + calld->original_recv_trailing_metadata_ready = + op->payload->recv_trailing_metadata.recv_trailing_metadata_ready; + op->payload->recv_trailing_metadata.recv_trailing_metadata_ready = + &calld->recv_trailing_metadata_ready; + } } static void server_start_transport_stream_op_batch( @@ -779,6 +826,7 @@ static void accept_stream(void* cd, grpc_transport* transport, args.channel = chand->channel; args.server_transport_data = transport_server_data; args.send_deadline = GRPC_MILLIS_INF_FUTURE; + args.server = chand->server; grpc_call* call; grpc_error* error = grpc_call_create(&args, &call); grpc_call_element* elem = @@ -824,11 +872,14 @@ static grpc_error* init_call_elem(grpc_call_element* elem, memset(calld, 0, sizeof(call_data)); calld->deadline = GRPC_MILLIS_INF_FUTURE; calld->call = grpc_call_from_top_element(elem); + calld->call_combiner = args->call_combiner; GRPC_CLOSURE_INIT(&calld->server_on_recv_initial_metadata, server_on_recv_initial_metadata, elem, grpc_schedule_on_exec_ctx); - + GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, + server_recv_trailing_metadata_ready, elem, + grpc_schedule_on_exec_ctx); server_ref(chand->server); return GRPC_ERROR_NONE; } @@ -840,7 +891,7 @@ static void destroy_call_elem(grpc_call_element* elem, call_data* calld = static_cast<call_data*>(elem->call_data); GPR_ASSERT(calld->state != PENDING); - + GRPC_ERROR_UNREF(calld->recv_initial_metadata_error); if (calld->host_set) { grpc_slice_unref_internal(calld->host); } @@ -941,6 +992,7 @@ void grpc_server_register_completion_queue(grpc_server* server, } grpc_server* grpc_server_create(const grpc_channel_args* args, void* reserved) { + grpc_core::ExecCtx exec_ctx; GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved)); grpc_server* server = @@ -957,6 +1009,21 @@ grpc_server* grpc_server_create(const grpc_channel_args* args, void* reserved) { server->channel_args = grpc_channel_args_copy(args); + 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_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>( + server, channel_tracer_max_memory); + server->channelz_server->AddTraceEvent( + grpc_core::channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string("Server created")); + } + return server; } @@ -1054,7 +1121,8 @@ void grpc_server_get_pollsets(grpc_server* server, grpc_pollset*** pollsets, void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport, grpc_pollset* accepting_pollset, - const grpc_channel_args* args) { + const grpc_channel_args* args, + intptr_t socket_uuid) { size_t num_registered_methods; size_t alloc; registered_method* rm; @@ -1074,6 +1142,7 @@ void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport, chand->server = s; server_ref(s); chand->channel = channel; + chand->socket_uuid = socket_uuid; size_t cq_idx; for (cq_idx = 0; cq_idx < s->cq_count; cq_idx++) { @@ -1148,6 +1217,29 @@ void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport, grpc_transport_perform_op(transport, op); } +void grpc_server_populate_server_sockets( + grpc_server* s, grpc_core::channelz::ChildRefsList* server_sockets, + intptr_t start_idx) { + gpr_mu_lock(&s->mu_global); + channel_data* c = nullptr; + for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) { + intptr_t socket_uuid = c->socket_uuid; + if (socket_uuid >= start_idx) { + server_sockets->push_back(socket_uuid); + } + } + gpr_mu_unlock(&s->mu_global); +} + +void grpc_server_populate_listen_sockets( + grpc_server* server, grpc_core::channelz::ChildRefsList* listen_sockets) { + gpr_mu_lock(&server->mu_global); + for (listener* l = server->listeners; l != nullptr; l = l->next) { + listen_sockets->push_back(l->socket_uuid); + } + gpr_mu_unlock(&server->mu_global); +} + void done_published_shutdown(void* done_arg, grpc_cq_completion* storage) { (void)done_arg; gpr_free(storage); @@ -1281,11 +1373,13 @@ void grpc_server_add_listener(grpc_server* server, void* arg, grpc_pollset** pollsets, size_t pollset_count), void (*destroy)(grpc_server* server, void* arg, - grpc_closure* on_done)) { + grpc_closure* on_done), + intptr_t socket_uuid) { listener* l = static_cast<listener*>(gpr_malloc(sizeof(listener))); l->arg = arg; l->start = start; l->destroy = destroy; + l->socket_uuid = socket_uuid; l->next = server->listeners; server->listeners = l; } @@ -1459,3 +1553,11 @@ int grpc_server_has_open_connections(grpc_server* server) { gpr_mu_unlock(&server->mu_global); return r; } + +grpc_core::channelz::ServerNode* grpc_server_get_channelz_node( + grpc_server* server) { + if (server == nullptr) { + return nullptr; + } + return server->channelz_server.get(); +} diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h index c617cc223e..33c205417e 100644 --- a/src/core/lib/surface/server.h +++ b/src/core/lib/surface/server.h @@ -23,6 +23,7 @@ #include <grpc/grpc.h> #include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/channel/channelz.h" #include "src/core/lib/debug/trace.h" #include "src/core/lib/transport/transport.h" @@ -38,13 +39,27 @@ void grpc_server_add_listener(grpc_server* server, void* listener, grpc_pollset** pollsets, size_t npollsets), void (*destroy)(grpc_server* server, void* arg, - grpc_closure* on_done)); + grpc_closure* on_done), + intptr_t socket_uuid); /* Setup a transport - creates a channel stack, binds the transport to the server */ void grpc_server_setup_transport(grpc_server* server, grpc_transport* transport, grpc_pollset* accepting_pollset, - const grpc_channel_args* args); + const grpc_channel_args* args, + intptr_t socket_uuid); + +/* fills in the uuids of all sockets used for connections on this server */ +void grpc_server_populate_server_sockets( + grpc_server* server, grpc_core::channelz::ChildRefsList* server_sockets, + intptr_t start_idx); + +/* fills in the uuids of all listen sockets on this server */ +void grpc_server_populate_listen_sockets( + grpc_server* server, grpc_core::channelz::ChildRefsList* listen_sockets); + +grpc_core::channelz::ServerNode* grpc_server_get_channelz_node( + grpc_server* server); const grpc_channel_args* grpc_server_get_channel_args(grpc_server* server); diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc index e92fe2c5a1..66890ce65a 100644 --- a/src/core/lib/surface/version.cc +++ b/src/core/lib/surface/version.cc @@ -23,6 +23,6 @@ #include <grpc/grpc.h> -const char* grpc_version_string(void) { return "6.0.0-dev"; } +const char* grpc_version_string(void) { return "7.0.0-dev"; } -const char* grpc_g_stands_for(void) { return "glider"; } +const char* grpc_g_stands_for(void) { return "gizmo"; } diff --git a/src/core/lib/transport/metadata.cc b/src/core/lib/transport/metadata.cc index d10194a2fe..60af22393e 100644 --- a/src/core/lib/transport/metadata.cc +++ b/src/core/lib/transport/metadata.cc @@ -237,7 +237,7 @@ static void rehash_mdtab(mdtab_shard* shard) { } grpc_mdelem grpc_mdelem_create( - grpc_slice key, grpc_slice value, + const grpc_slice& key, const grpc_slice& value, grpc_mdelem_data* compatible_external_backing_store) { if (!grpc_slice_is_interned(key) || !grpc_slice_is_interned(value)) { if (compatible_external_backing_store != nullptr) { @@ -324,7 +324,8 @@ grpc_mdelem grpc_mdelem_create( return GRPC_MAKE_MDELEM(md, GRPC_MDELEM_STORAGE_INTERNED); } -grpc_mdelem grpc_mdelem_from_slices(grpc_slice key, grpc_slice value) { +grpc_mdelem grpc_mdelem_from_slices(const grpc_slice& key, + const grpc_slice& value) { grpc_mdelem out = grpc_mdelem_create(key, value, nullptr); grpc_slice_unref_internal(key); grpc_slice_unref_internal(value); @@ -342,24 +343,6 @@ grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_metadata* metadata) { changed ? nullptr : reinterpret_cast<grpc_mdelem_data*>(metadata)); } -static size_t get_base64_encoded_size(size_t raw_length) { - static const uint8_t tail_xtra[3] = {0, 2, 3}; - return raw_length / 3 * 4 + tail_xtra[raw_length % 3]; -} - -size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem, - bool use_true_binary_metadata) { - size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); - size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem)); - if (grpc_is_binary_header(GRPC_MDKEY(elem))) { - return overhead_and_key + (use_true_binary_metadata - ? value_len + 1 - : get_base64_encoded_size(value_len)); - } else { - return overhead_and_key + value_len; - } -} - grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd DEBUG_ARGS) { switch (GRPC_MDELEM_STORAGE(gmd)) { case GRPC_MDELEM_STORAGE_EXTERNAL: diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h index 78df4bc3a3..989c7544c1 100644 --- a/src/core/lib/transport/metadata.h +++ b/src/core/lib/transport/metadata.h @@ -109,7 +109,8 @@ struct grpc_mdelem { (uintptr_t)GRPC_MDELEM_STORAGE_INTERNED_BIT)) /* Unrefs the slices. */ -grpc_mdelem grpc_mdelem_from_slices(grpc_slice key, grpc_slice value); +grpc_mdelem grpc_mdelem_from_slices(const grpc_slice& key, + const grpc_slice& value); /* Cheaply convert a grpc_metadata to a grpc_mdelem; may use the grpc_metadata object as backing storage (so lifetimes should align) */ @@ -120,14 +121,11 @@ grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_metadata* metadata); compatible_external_backing_store if it is non-NULL (in which case it's the users responsibility to ensure that it outlives usage) */ grpc_mdelem grpc_mdelem_create( - grpc_slice key, grpc_slice value, + const grpc_slice& key, const grpc_slice& value, grpc_mdelem_data* compatible_external_backing_store); bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b); -size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem, - bool use_true_binary_metadata); - /* Mutator and accessor for grpc_mdelem user data. The destructor function is used as a type tag and is checked during user_data fetch. */ void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*if_destroy_func)(void*)); diff --git a/src/core/lib/transport/metadata_batch.cc b/src/core/lib/transport/metadata_batch.cc index 49740fcd1e..928ed73cda 100644 --- a/src/core/lib/transport/metadata_batch.cc +++ b/src/core/lib/transport/metadata_batch.cc @@ -105,7 +105,7 @@ static grpc_error* maybe_link_callout(grpc_metadata_batch* batch, return GRPC_ERROR_NONE; } if (batch->idx.array[idx] == nullptr) { - if (grpc_static_callout_is_default[idx]) ++batch->list.default_count; + ++batch->list.default_count; batch->idx.array[idx] = storage; return GRPC_ERROR_NONE; } @@ -121,7 +121,7 @@ static void maybe_unlink_callout(grpc_metadata_batch* batch, if (idx == GRPC_BATCH_CALLOUTS_COUNT) { return; } - if (grpc_static_callout_is_default[idx]) --batch->list.default_count; + --batch->list.default_count; GPR_ASSERT(batch->idx.array[idx] != nullptr); batch->idx.array[idx] = nullptr; } @@ -139,6 +139,7 @@ static void link_head(grpc_mdelem_list* list, grpc_linked_mdelem* storage) { GPR_ASSERT(!GRPC_MDISNULL(storage->md)); storage->prev = nullptr; storage->next = list->head; + storage->reserved = nullptr; if (list->head != nullptr) { list->head->prev = storage; } else { diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h index 7068750b6f..0bcbb32d1f 100644 --- a/src/core/lib/transport/metadata_batch.h +++ b/src/core/lib/transport/metadata_batch.h @@ -82,6 +82,7 @@ void grpc_metadata_batch_set_value(grpc_linked_mdelem* storage, grpc_error* grpc_metadata_batch_link_head(grpc_metadata_batch* batch, grpc_linked_mdelem* storage) GRPC_MUST_USE_RESULT; + /** Add \a storage to the end of \a batch. storage->md is assumed to be valid. \a storage is owned by the caller and must survive for the @@ -100,6 +101,7 @@ grpc_error* grpc_metadata_batch_link_tail(grpc_metadata_batch* batch, grpc_error* grpc_metadata_batch_add_head( grpc_metadata_batch* batch, grpc_linked_mdelem* storage, grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT; + /** Add \a elem_to_add as the last element in \a batch, using \a storage as backing storage for the linked list element. \a storage is owned by the caller and must survive for the diff --git a/src/core/lib/transport/service_config.cc b/src/core/lib/transport/service_config.cc index e1a55d98ab..405e336028 100644 --- a/src/core/lib/transport/service_config.cc +++ b/src/core/lib/transport/service_config.cc @@ -65,8 +65,8 @@ const char* ServiceConfig::GetLoadBalancingPolicyName() const { return lb_policy_name; } -size_t ServiceConfig::CountNamesInMethodConfig(grpc_json* json) { - size_t num_names = 0; +int ServiceConfig::CountNamesInMethodConfig(grpc_json* json) { + int num_names = 0; for (grpc_json* field = json->child; field != nullptr; field = field->next) { if (field->key != nullptr && strcmp(field->key, "name") == 0) { if (field->type != GRPC_JSON_ARRAY) return -1; diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h index a65b267d46..2c0dd75845 100644 --- a/src/core/lib/transport/service_config.h +++ b/src/core/lib/transport/service_config.h @@ -103,7 +103,7 @@ class ServiceConfig { ServiceConfig(UniquePtr<char> json_string, grpc_json* json_tree); // Returns the number of names specified in the method config \a json. - static size_t CountNamesInMethodConfig(grpc_json* json); + static int CountNamesInMethodConfig(grpc_json* json); // Returns a path string for the JSON name object specified by \a json. // Returns null on error. @@ -188,9 +188,9 @@ ServiceConfig::CreateMethodConfigTable(CreateValue<T> create_value) { // Find number of entries. for (grpc_json* method = field->child; method != nullptr; method = method->next) { - size_t count = CountNamesInMethodConfig(method); + int count = CountNamesInMethodConfig(method); if (count <= 0) return nullptr; - num_entries += count; + num_entries += static_cast<size_t>(count); } // Populate method config table entries. entries = static_cast<typename SliceHashTable<RefCountedPtr<T>>::Entry*>( diff --git a/src/core/lib/transport/static_metadata.cc b/src/core/lib/transport/static_metadata.cc index 6a5144f21a..cdcb9a11d2 100644 --- a/src/core/lib/transport/static_metadata.cc +++ b/src/core/lib/transport/static_metadata.cc @@ -64,46 +64,46 @@ static uint8_t g_bytes[] = { 99, 46, 108, 98, 46, 118, 49, 46, 76, 111, 97, 100, 66, 97, 108, 97, 110, 99, 101, 114, 47, 66, 97, 108, 97, 110, 99, 101, 76, 111, 97, 100, 100, 101, 102, 108, 97, 116, 101, 103, 122, 105, 112, 115, 116, - 114, 101, 97, 109, 47, 103, 122, 105, 112, 48, 105, 100, 101, 110, 116, - 105, 116, 121, 116, 114, 97, 105, 108, 101, 114, 115, 97, 112, 112, 108, - 105, 99, 97, 116, 105, 111, 110, 47, 103, 114, 112, 99, 80, 79, 83, - 84, 50, 48, 48, 52, 48, 52, 104, 116, 116, 112, 104, 116, 116, 112, - 115, 103, 114, 112, 99, 71, 69, 84, 80, 85, 84, 47, 47, 105, 110, - 100, 101, 120, 46, 104, 116, 109, 108, 50, 48, 52, 50, 48, 54, 51, - 48, 52, 52, 48, 48, 53, 48, 48, 97, 99, 99, 101, 112, 116, 45, - 99, 104, 97, 114, 115, 101, 116, 103, 122, 105, 112, 44, 32, 100, 101, - 102, 108, 97, 116, 101, 97, 99, 99, 101, 112, 116, 45, 108, 97, 110, - 103, 117, 97, 103, 101, 97, 99, 99, 101, 112, 116, 45, 114, 97, 110, - 103, 101, 115, 97, 99, 99, 101, 112, 116, 97, 99, 99, 101, 115, 115, - 45, 99, 111, 110, 116, 114, 111, 108, 45, 97, 108, 108, 111, 119, 45, - 111, 114, 105, 103, 105, 110, 97, 103, 101, 97, 108, 108, 111, 119, 97, - 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 99, 97, 99, - 104, 101, 45, 99, 111, 110, 116, 114, 111, 108, 99, 111, 110, 116, 101, - 110, 116, 45, 100, 105, 115, 112, 111, 115, 105, 116, 105, 111, 110, 99, - 111, 110, 116, 101, 110, 116, 45, 108, 97, 110, 103, 117, 97, 103, 101, - 99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103, 116, 104, 99, - 111, 110, 116, 101, 110, 116, 45, 108, 111, 99, 97, 116, 105, 111, 110, - 99, 111, 110, 116, 101, 110, 116, 45, 114, 97, 110, 103, 101, 99, 111, - 111, 107, 105, 101, 100, 97, 116, 101, 101, 116, 97, 103, 101, 120, 112, - 101, 99, 116, 101, 120, 112, 105, 114, 101, 115, 102, 114, 111, 109, 105, - 102, 45, 109, 97, 116, 99, 104, 105, 102, 45, 109, 111, 100, 105, 102, - 105, 101, 100, 45, 115, 105, 110, 99, 101, 105, 102, 45, 110, 111, 110, - 101, 45, 109, 97, 116, 99, 104, 105, 102, 45, 114, 97, 110, 103, 101, - 105, 102, 45, 117, 110, 109, 111, 100, 105, 102, 105, 101, 100, 45, 115, - 105, 110, 99, 101, 108, 97, 115, 116, 45, 109, 111, 100, 105, 102, 105, - 101, 100, 108, 98, 45, 99, 111, 115, 116, 45, 98, 105, 110, 108, 105, - 110, 107, 108, 111, 99, 97, 116, 105, 111, 110, 109, 97, 120, 45, 102, - 111, 114, 119, 97, 114, 100, 115, 112, 114, 111, 120, 121, 45, 97, 117, - 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 112, 114, 111, 120, 121, - 45, 97, 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 114, - 97, 110, 103, 101, 114, 101, 102, 101, 114, 101, 114, 114, 101, 102, 114, - 101, 115, 104, 114, 101, 116, 114, 121, 45, 97, 102, 116, 101, 114, 115, - 101, 114, 118, 101, 114, 115, 101, 116, 45, 99, 111, 111, 107, 105, 101, - 115, 116, 114, 105, 99, 116, 45, 116, 114, 97, 110, 115, 112, 111, 114, - 116, 45, 115, 101, 99, 117, 114, 105, 116, 121, 116, 114, 97, 110, 115, - 102, 101, 114, 45, 101, 110, 99, 111, 100, 105, 110, 103, 118, 97, 114, - 121, 118, 105, 97, 119, 119, 119, 45, 97, 117, 116, 104, 101, 110, 116, - 105, 99, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, + 114, 101, 97, 109, 47, 103, 122, 105, 112, 71, 69, 84, 80, 79, 83, + 84, 47, 47, 105, 110, 100, 101, 120, 46, 104, 116, 109, 108, 104, 116, + 116, 112, 104, 116, 116, 112, 115, 50, 48, 48, 50, 48, 52, 50, 48, + 54, 51, 48, 52, 52, 48, 48, 52, 48, 52, 53, 48, 48, 97, 99, + 99, 101, 112, 116, 45, 99, 104, 97, 114, 115, 101, 116, 103, 122, 105, + 112, 44, 32, 100, 101, 102, 108, 97, 116, 101, 97, 99, 99, 101, 112, + 116, 45, 108, 97, 110, 103, 117, 97, 103, 101, 97, 99, 99, 101, 112, + 116, 45, 114, 97, 110, 103, 101, 115, 97, 99, 99, 101, 112, 116, 97, + 99, 99, 101, 115, 115, 45, 99, 111, 110, 116, 114, 111, 108, 45, 97, + 108, 108, 111, 119, 45, 111, 114, 105, 103, 105, 110, 97, 103, 101, 97, + 108, 108, 111, 119, 97, 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, + 111, 110, 99, 97, 99, 104, 101, 45, 99, 111, 110, 116, 114, 111, 108, + 99, 111, 110, 116, 101, 110, 116, 45, 100, 105, 115, 112, 111, 115, 105, + 116, 105, 111, 110, 99, 111, 110, 116, 101, 110, 116, 45, 108, 97, 110, + 103, 117, 97, 103, 101, 99, 111, 110, 116, 101, 110, 116, 45, 108, 101, + 110, 103, 116, 104, 99, 111, 110, 116, 101, 110, 116, 45, 108, 111, 99, + 97, 116, 105, 111, 110, 99, 111, 110, 116, 101, 110, 116, 45, 114, 97, + 110, 103, 101, 99, 111, 111, 107, 105, 101, 100, 97, 116, 101, 101, 116, + 97, 103, 101, 120, 112, 101, 99, 116, 101, 120, 112, 105, 114, 101, 115, + 102, 114, 111, 109, 105, 102, 45, 109, 97, 116, 99, 104, 105, 102, 45, + 109, 111, 100, 105, 102, 105, 101, 100, 45, 115, 105, 110, 99, 101, 105, + 102, 45, 110, 111, 110, 101, 45, 109, 97, 116, 99, 104, 105, 102, 45, + 114, 97, 110, 103, 101, 105, 102, 45, 117, 110, 109, 111, 100, 105, 102, + 105, 101, 100, 45, 115, 105, 110, 99, 101, 108, 97, 115, 116, 45, 109, + 111, 100, 105, 102, 105, 101, 100, 108, 105, 110, 107, 108, 111, 99, 97, + 116, 105, 111, 110, 109, 97, 120, 45, 102, 111, 114, 119, 97, 114, 100, + 115, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104, 101, 110, 116, 105, + 99, 97, 116, 101, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104, 111, + 114, 105, 122, 97, 116, 105, 111, 110, 114, 97, 110, 103, 101, 114, 101, + 102, 101, 114, 101, 114, 114, 101, 102, 114, 101, 115, 104, 114, 101, 116, + 114, 121, 45, 97, 102, 116, 101, 114, 115, 101, 114, 118, 101, 114, 115, + 101, 116, 45, 99, 111, 111, 107, 105, 101, 115, 116, 114, 105, 99, 116, + 45, 116, 114, 97, 110, 115, 112, 111, 114, 116, 45, 115, 101, 99, 117, + 114, 105, 116, 121, 116, 114, 97, 110, 115, 102, 101, 114, 45, 101, 110, + 99, 111, 100, 105, 110, 103, 118, 97, 114, 121, 118, 105, 97, 119, 119, + 119, 45, 97, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 48, + 105, 100, 101, 110, 116, 105, 116, 121, 116, 114, 97, 105, 108, 101, 114, + 115, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 103, 114, + 112, 99, 103, 114, 112, 99, 80, 85, 84, 108, 98, 45, 99, 111, 115, + 116, 45, 98, 105, 110, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44, 103, 122, 105, 112, 100, 101, 102, 108, 97, 116, 101, 44, 103, 122, 105, 112, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97, @@ -265,69 +265,69 @@ const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = { {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}, {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}, {&grpc_static_metadata_refcounts[37], {{g_bytes + 493, 11}}}, - {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}}, - {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}, - {&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}}, - {&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}}, - {&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}}, - {&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}}, - {&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}}, - {&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}}, - {&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}}, - {&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}}, - {&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}}, - {&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}}, - {&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}}, - {&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}}, - {&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}}, - {&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}}, - {&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}}, - {&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}}, - {&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}}, - {&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}}, - {&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}}, - {&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}}, - {&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}}, - {&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}}, - {&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}}, - {&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}}, - {&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}}, - {&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}}, - {&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}}, - {&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}}, - {&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}}, - {&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}}, - {&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}}, - {&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}}, - {&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}}, - {&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}}, - {&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}}, - {&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}}, - {&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}}, - {&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}}, - {&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}}, - {&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}}, - {&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}}, - {&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}}, - {&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}}, - {&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}}, - {&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}}, - {&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}}, - {&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}}, - {&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}}, - {&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}}, - {&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}}, - {&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}}, - {&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}}, - {&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}}, - {&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}}, - {&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}}, - {&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}}, - {&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}}, - {&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}}, - {&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}}, - {&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}}, - {&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}}, + {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 3}}}, + {&grpc_static_metadata_refcounts[39], {{g_bytes + 507, 4}}}, + {&grpc_static_metadata_refcounts[40], {{g_bytes + 511, 1}}}, + {&grpc_static_metadata_refcounts[41], {{g_bytes + 512, 11}}}, + {&grpc_static_metadata_refcounts[42], {{g_bytes + 523, 4}}}, + {&grpc_static_metadata_refcounts[43], {{g_bytes + 527, 5}}}, + {&grpc_static_metadata_refcounts[44], {{g_bytes + 532, 3}}}, + {&grpc_static_metadata_refcounts[45], {{g_bytes + 535, 3}}}, + {&grpc_static_metadata_refcounts[46], {{g_bytes + 538, 3}}}, + {&grpc_static_metadata_refcounts[47], {{g_bytes + 541, 3}}}, + {&grpc_static_metadata_refcounts[48], {{g_bytes + 544, 3}}}, + {&grpc_static_metadata_refcounts[49], {{g_bytes + 547, 3}}}, + {&grpc_static_metadata_refcounts[50], {{g_bytes + 550, 3}}}, + {&grpc_static_metadata_refcounts[51], {{g_bytes + 553, 14}}}, + {&grpc_static_metadata_refcounts[52], {{g_bytes + 567, 13}}}, + {&grpc_static_metadata_refcounts[53], {{g_bytes + 580, 15}}}, + {&grpc_static_metadata_refcounts[54], {{g_bytes + 595, 13}}}, + {&grpc_static_metadata_refcounts[55], {{g_bytes + 608, 6}}}, + {&grpc_static_metadata_refcounts[56], {{g_bytes + 614, 27}}}, + {&grpc_static_metadata_refcounts[57], {{g_bytes + 641, 3}}}, + {&grpc_static_metadata_refcounts[58], {{g_bytes + 644, 5}}}, + {&grpc_static_metadata_refcounts[59], {{g_bytes + 649, 13}}}, + {&grpc_static_metadata_refcounts[60], {{g_bytes + 662, 13}}}, + {&grpc_static_metadata_refcounts[61], {{g_bytes + 675, 19}}}, + {&grpc_static_metadata_refcounts[62], {{g_bytes + 694, 16}}}, + {&grpc_static_metadata_refcounts[63], {{g_bytes + 710, 14}}}, + {&grpc_static_metadata_refcounts[64], {{g_bytes + 724, 16}}}, + {&grpc_static_metadata_refcounts[65], {{g_bytes + 740, 13}}}, + {&grpc_static_metadata_refcounts[66], {{g_bytes + 753, 6}}}, + {&grpc_static_metadata_refcounts[67], {{g_bytes + 759, 4}}}, + {&grpc_static_metadata_refcounts[68], {{g_bytes + 763, 4}}}, + {&grpc_static_metadata_refcounts[69], {{g_bytes + 767, 6}}}, + {&grpc_static_metadata_refcounts[70], {{g_bytes + 773, 7}}}, + {&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 4}}}, + {&grpc_static_metadata_refcounts[72], {{g_bytes + 784, 8}}}, + {&grpc_static_metadata_refcounts[73], {{g_bytes + 792, 17}}}, + {&grpc_static_metadata_refcounts[74], {{g_bytes + 809, 13}}}, + {&grpc_static_metadata_refcounts[75], {{g_bytes + 822, 8}}}, + {&grpc_static_metadata_refcounts[76], {{g_bytes + 830, 19}}}, + {&grpc_static_metadata_refcounts[77], {{g_bytes + 849, 13}}}, + {&grpc_static_metadata_refcounts[78], {{g_bytes + 862, 4}}}, + {&grpc_static_metadata_refcounts[79], {{g_bytes + 866, 8}}}, + {&grpc_static_metadata_refcounts[80], {{g_bytes + 874, 12}}}, + {&grpc_static_metadata_refcounts[81], {{g_bytes + 886, 18}}}, + {&grpc_static_metadata_refcounts[82], {{g_bytes + 904, 19}}}, + {&grpc_static_metadata_refcounts[83], {{g_bytes + 923, 5}}}, + {&grpc_static_metadata_refcounts[84], {{g_bytes + 928, 7}}}, + {&grpc_static_metadata_refcounts[85], {{g_bytes + 935, 7}}}, + {&grpc_static_metadata_refcounts[86], {{g_bytes + 942, 11}}}, + {&grpc_static_metadata_refcounts[87], {{g_bytes + 953, 6}}}, + {&grpc_static_metadata_refcounts[88], {{g_bytes + 959, 10}}}, + {&grpc_static_metadata_refcounts[89], {{g_bytes + 969, 25}}}, + {&grpc_static_metadata_refcounts[90], {{g_bytes + 994, 17}}}, + {&grpc_static_metadata_refcounts[91], {{g_bytes + 1011, 4}}}, + {&grpc_static_metadata_refcounts[92], {{g_bytes + 1015, 3}}}, + {&grpc_static_metadata_refcounts[93], {{g_bytes + 1018, 16}}}, + {&grpc_static_metadata_refcounts[94], {{g_bytes + 1034, 1}}}, + {&grpc_static_metadata_refcounts[95], {{g_bytes + 1035, 8}}}, + {&grpc_static_metadata_refcounts[96], {{g_bytes + 1043, 8}}}, + {&grpc_static_metadata_refcounts[97], {{g_bytes + 1051, 16}}}, + {&grpc_static_metadata_refcounts[98], {{g_bytes + 1067, 4}}}, + {&grpc_static_metadata_refcounts[99], {{g_bytes + 1071, 3}}}, + {&grpc_static_metadata_refcounts[100], {{g_bytes + 1074, 11}}}, {&grpc_static_metadata_refcounts[101], {{g_bytes + 1085, 16}}}, {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}, {&grpc_static_metadata_refcounts[103], {{g_bytes + 1114, 12}}}, @@ -341,14 +341,15 @@ uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8, 2, 4, 4}; static const int8_t elems_r[] = { - 16, 11, -1, 0, 15, 2, -78, 24, 0, 18, -5, 0, 0, 0, 17, 14, -8, 0, - 0, 27, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, -64, 0, -44, -43, -70, 0, 34, 33, 33, 32, 31, 30, 29, 28, 27, - 27, 26, 25, 24, 23, 22, 21, 20, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, - 11, 14, 13, 12, 11, 10, 9, 9, 8, 7, 6, 5, 0}; + 15, 9, -8, 0, 2, -44, -78, 17, 0, 6, -8, 0, 0, 0, 6, + -5, -10, 0, 0, -2, -3, -4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -63, 0, -46, -68, -69, -53, 0, 31, 30, + 29, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 18, + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, + 2, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, -5, 0}; static uint32_t elems_phash(uint32_t i) { - i -= 50; + i -= 40; uint32_t x = i % 103; uint32_t y = i / 103; uint32_t h = x; @@ -360,28 +361,25 @@ static uint32_t elems_phash(uint32_t i) { } static const uint16_t elem_keys[] = { - 1085, 1086, 565, 1709, 1089, 262, 263, 264, 265, 266, 1716, - 153, 154, 1719, 760, 761, 50, 51, 465, 466, 467, 980, - 981, 1604, 1499, 984, 773, 2129, 2234, 6014, 1611, 6434, 1738, - 1614, 6539, 6644, 1511, 6749, 6854, 6959, 7064, 7169, 7274, 7379, - 2024, 7484, 7589, 7694, 7799, 7904, 8009, 8114, 8219, 6224, 8324, - 8429, 6329, 8534, 8639, 8744, 8849, 8954, 9059, 9164, 9269, 9374, - 1151, 1152, 1153, 1154, 9479, 9584, 9689, 9794, 9899, 10004, 1782, - 10109, 10214, 10319, 10424, 10529, 0, 0, 0, 0, 0, 344, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 253, 254, 147, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0}; + 254, 255, 256, 257, 258, 259, 260, 1085, 1086, 143, 144, 1709, + 462, 463, 1604, 40, 41, 761, 1716, 980, 981, 1611, 621, 1499, + 760, 2024, 2129, 2234, 5384, 5699, 5804, 6014, 6119, 6224, 1732, 6329, + 6434, 6539, 6644, 6749, 6854, 6959, 7064, 7169, 7274, 7379, 7484, 7589, + 5909, 5594, 7694, 7799, 7904, 8009, 8114, 8219, 8324, 8429, 8534, 8639, + 8744, 8849, 8954, 9059, 9164, 9269, 9374, 1145, 518, 9479, 204, 9584, + 9689, 1151, 1152, 1153, 1154, 1775, 9794, 1040, 1670, 10529, 0, 0, + 1782, 829, 0, 0, 0, 0, 344, 1567, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}; static const uint8_t elem_idxs[] = { - 77, 79, 6, 25, 76, 19, 20, 21, 22, 23, 84, 15, 16, 83, 1, - 2, 17, 18, 11, 12, 13, 5, 4, 38, 43, 3, 0, 50, 57, 24, - 37, 29, 26, 36, 30, 31, 7, 32, 33, 34, 35, 39, 40, 41, 72, - 42, 44, 45, 46, 47, 48, 49, 51, 27, 52, 53, 28, 54, 55, 56, - 58, 59, 60, 61, 62, 63, 78, 80, 81, 82, 64, 65, 66, 67, 68, - 69, 85, 70, 71, 73, 74, 75, 255, 255, 255, 255, 255, 14, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 9, 10, 8}; + 7, 8, 9, 10, 11, 12, 13, 77, 79, 1, 2, 71, 5, 6, 25, 3, + 4, 63, 84, 66, 65, 73, 67, 30, 62, 57, 37, 74, 14, 17, 18, 20, + 21, 22, 15, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34, 35, 36, 38, + 19, 16, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 76, 69, 56, 70, 58, 59, 78, 80, 81, 82, 83, 60, 64, + 72, 75, 255, 255, 85, 61, 255, 255, 255, 255, 0, 68}; grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) { if (a == -1 || b == -1) return GRPC_MDNULL; @@ -395,160 +393,160 @@ grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) { } grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = { - {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}}, - {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}}}, - {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}}, - {&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}}}, - {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}}, - {&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}}}, - {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}}, - {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}}, - {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}}, - {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}}, - {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}}, - {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}}, - {{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}}, - {&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}}}, - {{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}}, - {&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}}}, - {{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}}, - {&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}}}, - {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}}, - {&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}}}, - {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}}, - {&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}}}, - {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}}, - {&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}}}, - {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}}, - {&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}}}, - {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}}, - {&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}}}, {{&grpc_static_metadata_refcounts[3], {{g_bytes + 19, 10}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, {{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}}, - {&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}}}, + {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 3}}}}, {{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}}, - {&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}}}, + {&grpc_static_metadata_refcounts[39], {{g_bytes + 507, 4}}}}, {{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}}, - {&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}}}, + {&grpc_static_metadata_refcounts[40], {{g_bytes + 511, 1}}}}, {{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}}, - {&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}}}, + {&grpc_static_metadata_refcounts[41], {{g_bytes + 512, 11}}}}, + {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}}, + {&grpc_static_metadata_refcounts[42], {{g_bytes + 523, 4}}}}, + {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}}, + {&grpc_static_metadata_refcounts[43], {{g_bytes + 527, 5}}}}, {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}}, - {&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}}}, + {&grpc_static_metadata_refcounts[44], {{g_bytes + 532, 3}}}}, {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}}, - {&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}}}, + {&grpc_static_metadata_refcounts[45], {{g_bytes + 535, 3}}}}, {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}}, - {&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}}}, + {&grpc_static_metadata_refcounts[46], {{g_bytes + 538, 3}}}}, {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}}, - {&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}}}, + {&grpc_static_metadata_refcounts[47], {{g_bytes + 541, 3}}}}, {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}}, - {&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}}}, - {{&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}}, - {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}}, + {&grpc_static_metadata_refcounts[48], {{g_bytes + 544, 3}}}}, + {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}}, + {&grpc_static_metadata_refcounts[49], {{g_bytes + 547, 3}}}}, + {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}}, + {&grpc_static_metadata_refcounts[50], {{g_bytes + 550, 3}}}}, + {{&grpc_static_metadata_refcounts[51], {{g_bytes + 553, 14}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}}, - {&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}}}, - {{&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}}, + {&grpc_static_metadata_refcounts[52], {{g_bytes + 567, 13}}}}, + {{&grpc_static_metadata_refcounts[53], {{g_bytes + 580, 15}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}}, + {{&grpc_static_metadata_refcounts[54], {{g_bytes + 595, 13}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}}, + {{&grpc_static_metadata_refcounts[55], {{g_bytes + 608, 6}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}}, + {{&grpc_static_metadata_refcounts[56], {{g_bytes + 614, 27}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}}, + {{&grpc_static_metadata_refcounts[57], {{g_bytes + 641, 3}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}}, + {{&grpc_static_metadata_refcounts[58], {{g_bytes + 644, 5}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}}, + {{&grpc_static_metadata_refcounts[59], {{g_bytes + 649, 13}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}}, + {{&grpc_static_metadata_refcounts[60], {{g_bytes + 662, 13}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}}, + {{&grpc_static_metadata_refcounts[61], {{g_bytes + 675, 19}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}}, - {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}}, - {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}}, - {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}}, - {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}}, + {{&grpc_static_metadata_refcounts[62], {{g_bytes + 694, 16}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}}, + {{&grpc_static_metadata_refcounts[63], {{g_bytes + 710, 14}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}}, + {{&grpc_static_metadata_refcounts[64], {{g_bytes + 724, 16}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}}, + {{&grpc_static_metadata_refcounts[65], {{g_bytes + 740, 13}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, {{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}}, + {{&grpc_static_metadata_refcounts[66], {{g_bytes + 753, 6}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}}, + {{&grpc_static_metadata_refcounts[67], {{g_bytes + 759, 4}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}}, + {{&grpc_static_metadata_refcounts[68], {{g_bytes + 763, 4}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}}, + {{&grpc_static_metadata_refcounts[69], {{g_bytes + 767, 6}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}}, + {{&grpc_static_metadata_refcounts[70], {{g_bytes + 773, 7}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}}, + {{&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 4}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, {{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}}, + {{&grpc_static_metadata_refcounts[72], {{g_bytes + 784, 8}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}}, + {{&grpc_static_metadata_refcounts[73], {{g_bytes + 792, 17}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}}, + {{&grpc_static_metadata_refcounts[74], {{g_bytes + 809, 13}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}}, + {{&grpc_static_metadata_refcounts[75], {{g_bytes + 822, 8}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}}, + {{&grpc_static_metadata_refcounts[76], {{g_bytes + 830, 19}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}}, + {{&grpc_static_metadata_refcounts[77], {{g_bytes + 849, 13}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}}, + {{&grpc_static_metadata_refcounts[78], {{g_bytes + 862, 4}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}}, + {{&grpc_static_metadata_refcounts[79], {{g_bytes + 866, 8}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}}, + {{&grpc_static_metadata_refcounts[80], {{g_bytes + 874, 12}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}}, + {{&grpc_static_metadata_refcounts[81], {{g_bytes + 886, 18}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}}, + {{&grpc_static_metadata_refcounts[82], {{g_bytes + 904, 19}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}}, + {{&grpc_static_metadata_refcounts[83], {{g_bytes + 923, 5}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}}, + {{&grpc_static_metadata_refcounts[84], {{g_bytes + 928, 7}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}}, + {{&grpc_static_metadata_refcounts[85], {{g_bytes + 935, 7}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}}, + {{&grpc_static_metadata_refcounts[86], {{g_bytes + 942, 11}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}}, + {{&grpc_static_metadata_refcounts[87], {{g_bytes + 953, 6}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}}, + {{&grpc_static_metadata_refcounts[88], {{g_bytes + 959, 10}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}}, + {{&grpc_static_metadata_refcounts[89], {{g_bytes + 969, 25}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}}, + {{&grpc_static_metadata_refcounts[90], {{g_bytes + 994, 17}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}}, + {{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}}, + {{&grpc_static_metadata_refcounts[91], {{g_bytes + 1011, 4}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}}, + {{&grpc_static_metadata_refcounts[92], {{g_bytes + 1015, 3}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}}, + {{&grpc_static_metadata_refcounts[93], {{g_bytes + 1018, 16}}}, + {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, + {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}}, + {&grpc_static_metadata_refcounts[94], {{g_bytes + 1034, 1}}}}, + {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}}, + {&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}}}, + {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}}, + {&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}}}, + {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}}, + {&grpc_static_metadata_refcounts[95], {{g_bytes + 1035, 8}}}}, + {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}}, + {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}}, + {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}}, + {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}}, + {{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}}, + {&grpc_static_metadata_refcounts[96], {{g_bytes + 1043, 8}}}}, + {{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}}, + {&grpc_static_metadata_refcounts[97], {{g_bytes + 1051, 16}}}}, + {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}}, + {&grpc_static_metadata_refcounts[98], {{g_bytes + 1067, 4}}}}, + {{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}}, + {&grpc_static_metadata_refcounts[99], {{g_bytes + 1071, 3}}}}, + {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}}, + {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}}, + {&grpc_static_metadata_refcounts[95], {{g_bytes + 1035, 8}}}}, + {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}}, + {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}}, + {{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, - {{&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}}, + {{&grpc_static_metadata_refcounts[100], {{g_bytes + 1074, 11}}}, {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}}, {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}}, - {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}}, + {&grpc_static_metadata_refcounts[95], {{g_bytes + 1035, 8}}}}, {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}}, {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}}, {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}}, @@ -562,39 +560,12 @@ grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = { {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}}, {&grpc_static_metadata_refcounts[104], {{g_bytes + 1126, 21}}}}, {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}}, - {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}}, + {&grpc_static_metadata_refcounts[95], {{g_bytes + 1035, 8}}}}, {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}}, {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}}, {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}}, {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}}, }; -bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = { - true, // :path - true, // :method - true, // :status - true, // :authority - true, // :scheme - true, // te - true, // grpc-message - true, // grpc-status - true, // grpc-payload-bin - true, // grpc-encoding - true, // grpc-accept-encoding - true, // grpc-server-stats-bin - true, // grpc-tags-bin - true, // grpc-trace-bin - true, // content-type - true, // content-encoding - true, // accept-encoding - true, // grpc-internal-encoding-request - true, // grpc-internal-stream-encoding-request - true, // user-agent - true, // host - true, // lb-token - true, // grpc-previous-rpc-attempts - true, // grpc-retry-pushback-ms -}; - const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78, 79, 80, 81, 82}; diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h index b3a10f5873..5e57ea5741 100644 --- a/src/core/lib/transport/static_metadata.h +++ b/src/core/lib/transport/static_metadata.h @@ -113,132 +113,132 @@ extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT]; #define GRPC_MDSTR_GZIP (grpc_static_slice_table[36]) /* "stream/gzip" */ #define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[37]) -/* "0" */ -#define GRPC_MDSTR_0 (grpc_static_slice_table[38]) -/* "identity" */ -#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[39]) -/* "trailers" */ -#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[40]) -/* "application/grpc" */ -#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[41]) -/* "POST" */ -#define GRPC_MDSTR_POST (grpc_static_slice_table[42]) -/* "200" */ -#define GRPC_MDSTR_200 (grpc_static_slice_table[43]) -/* "404" */ -#define GRPC_MDSTR_404 (grpc_static_slice_table[44]) -/* "http" */ -#define GRPC_MDSTR_HTTP (grpc_static_slice_table[45]) -/* "https" */ -#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[46]) -/* "grpc" */ -#define GRPC_MDSTR_GRPC (grpc_static_slice_table[47]) /* "GET" */ -#define GRPC_MDSTR_GET (grpc_static_slice_table[48]) -/* "PUT" */ -#define GRPC_MDSTR_PUT (grpc_static_slice_table[49]) +#define GRPC_MDSTR_GET (grpc_static_slice_table[38]) +/* "POST" */ +#define GRPC_MDSTR_POST (grpc_static_slice_table[39]) /* "/" */ -#define GRPC_MDSTR_SLASH (grpc_static_slice_table[50]) +#define GRPC_MDSTR_SLASH (grpc_static_slice_table[40]) /* "/index.html" */ -#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[51]) +#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[41]) +/* "http" */ +#define GRPC_MDSTR_HTTP (grpc_static_slice_table[42]) +/* "https" */ +#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[43]) +/* "200" */ +#define GRPC_MDSTR_200 (grpc_static_slice_table[44]) /* "204" */ -#define GRPC_MDSTR_204 (grpc_static_slice_table[52]) +#define GRPC_MDSTR_204 (grpc_static_slice_table[45]) /* "206" */ -#define GRPC_MDSTR_206 (grpc_static_slice_table[53]) +#define GRPC_MDSTR_206 (grpc_static_slice_table[46]) /* "304" */ -#define GRPC_MDSTR_304 (grpc_static_slice_table[54]) +#define GRPC_MDSTR_304 (grpc_static_slice_table[47]) /* "400" */ -#define GRPC_MDSTR_400 (grpc_static_slice_table[55]) +#define GRPC_MDSTR_400 (grpc_static_slice_table[48]) +/* "404" */ +#define GRPC_MDSTR_404 (grpc_static_slice_table[49]) /* "500" */ -#define GRPC_MDSTR_500 (grpc_static_slice_table[56]) +#define GRPC_MDSTR_500 (grpc_static_slice_table[50]) /* "accept-charset" */ -#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[57]) +#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[51]) /* "gzip, deflate" */ -#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[58]) +#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[52]) /* "accept-language" */ -#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[59]) +#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[53]) /* "accept-ranges" */ -#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[60]) +#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[54]) /* "accept" */ -#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[61]) +#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[55]) /* "access-control-allow-origin" */ -#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[62]) +#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[56]) /* "age" */ -#define GRPC_MDSTR_AGE (grpc_static_slice_table[63]) +#define GRPC_MDSTR_AGE (grpc_static_slice_table[57]) /* "allow" */ -#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[64]) +#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[58]) /* "authorization" */ -#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[65]) +#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[59]) /* "cache-control" */ -#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[66]) +#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[60]) /* "content-disposition" */ -#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[67]) +#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[61]) /* "content-language" */ -#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[68]) +#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[62]) /* "content-length" */ -#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[69]) +#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[63]) /* "content-location" */ -#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[70]) +#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[64]) /* "content-range" */ -#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[71]) +#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[65]) /* "cookie" */ -#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[72]) +#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[66]) /* "date" */ -#define GRPC_MDSTR_DATE (grpc_static_slice_table[73]) +#define GRPC_MDSTR_DATE (grpc_static_slice_table[67]) /* "etag" */ -#define GRPC_MDSTR_ETAG (grpc_static_slice_table[74]) +#define GRPC_MDSTR_ETAG (grpc_static_slice_table[68]) /* "expect" */ -#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[75]) +#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[69]) /* "expires" */ -#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[76]) +#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[70]) /* "from" */ -#define GRPC_MDSTR_FROM (grpc_static_slice_table[77]) +#define GRPC_MDSTR_FROM (grpc_static_slice_table[71]) /* "if-match" */ -#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[78]) +#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[72]) /* "if-modified-since" */ -#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[79]) +#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[73]) /* "if-none-match" */ -#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[80]) +#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[74]) /* "if-range" */ -#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[81]) +#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[75]) /* "if-unmodified-since" */ -#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[82]) +#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[76]) /* "last-modified" */ -#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[83]) -/* "lb-cost-bin" */ -#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[84]) +#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[77]) /* "link" */ -#define GRPC_MDSTR_LINK (grpc_static_slice_table[85]) +#define GRPC_MDSTR_LINK (grpc_static_slice_table[78]) /* "location" */ -#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[86]) +#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[79]) /* "max-forwards" */ -#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[87]) +#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[80]) /* "proxy-authenticate" */ -#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[88]) +#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[81]) /* "proxy-authorization" */ -#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[89]) +#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[82]) /* "range" */ -#define GRPC_MDSTR_RANGE (grpc_static_slice_table[90]) +#define GRPC_MDSTR_RANGE (grpc_static_slice_table[83]) /* "referer" */ -#define GRPC_MDSTR_REFERER (grpc_static_slice_table[91]) +#define GRPC_MDSTR_REFERER (grpc_static_slice_table[84]) /* "refresh" */ -#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[92]) +#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[85]) /* "retry-after" */ -#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[93]) +#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[86]) /* "server" */ -#define GRPC_MDSTR_SERVER (grpc_static_slice_table[94]) +#define GRPC_MDSTR_SERVER (grpc_static_slice_table[87]) /* "set-cookie" */ -#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[95]) +#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[88]) /* "strict-transport-security" */ -#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[96]) +#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[89]) /* "transfer-encoding" */ -#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[97]) +#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[90]) /* "vary" */ -#define GRPC_MDSTR_VARY (grpc_static_slice_table[98]) +#define GRPC_MDSTR_VARY (grpc_static_slice_table[91]) /* "via" */ -#define GRPC_MDSTR_VIA (grpc_static_slice_table[99]) +#define GRPC_MDSTR_VIA (grpc_static_slice_table[92]) /* "www-authenticate" */ -#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[100]) +#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[93]) +/* "0" */ +#define GRPC_MDSTR_0 (grpc_static_slice_table[94]) +/* "identity" */ +#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[95]) +/* "trailers" */ +#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[96]) +/* "application/grpc" */ +#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[97]) +/* "grpc" */ +#define GRPC_MDSTR_GRPC (grpc_static_slice_table[98]) +/* "PUT" */ +#define GRPC_MDSTR_PUT (grpc_static_slice_table[99]) +/* "lb-cost-bin" */ +#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[100]) /* "identity,deflate" */ #define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[101]) /* "identity,gzip" */ @@ -262,233 +262,233 @@ extern grpc_slice_refcount #define GRPC_STATIC_MDELEM_COUNT 86 extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT]; -/* "grpc-status": "0" */ -#define GRPC_MDELEM_GRPC_STATUS_0 \ +/* ":authority": "" */ +#define GRPC_MDELEM_AUTHORITY_EMPTY \ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0], GRPC_MDELEM_STORAGE_STATIC)) -/* "grpc-status": "1" */ -#define GRPC_MDELEM_GRPC_STATUS_1 \ +/* ":method": "GET" */ +#define GRPC_MDELEM_METHOD_GET \ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1], GRPC_MDELEM_STORAGE_STATIC)) -/* "grpc-status": "2" */ -#define GRPC_MDELEM_GRPC_STATUS_2 \ +/* ":method": "POST" */ +#define GRPC_MDELEM_METHOD_POST \ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2], GRPC_MDELEM_STORAGE_STATIC)) -/* "grpc-encoding": "identity" */ -#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \ +/* ":path": "/" */ +#define GRPC_MDELEM_PATH_SLASH \ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3], GRPC_MDELEM_STORAGE_STATIC)) -/* "grpc-encoding": "gzip" */ -#define GRPC_MDELEM_GRPC_ENCODING_GZIP \ +/* ":path": "/index.html" */ +#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4], GRPC_MDELEM_STORAGE_STATIC)) -/* "grpc-encoding": "deflate" */ -#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC)) -/* "te": "trailers" */ -#define GRPC_MDELEM_TE_TRAILERS \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC)) -/* "content-type": "application/grpc" */ -#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC)) -/* ":method": "POST" */ -#define GRPC_MDELEM_METHOD_POST \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC)) -/* ":status": "200" */ -#define GRPC_MDELEM_STATUS_200 \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC)) -/* ":status": "404" */ -#define GRPC_MDELEM_STATUS_404 \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC)) /* ":scheme": "http" */ #define GRPC_MDELEM_SCHEME_HTTP \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC)) /* ":scheme": "https" */ #define GRPC_MDELEM_SCHEME_HTTPS \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC)) -/* ":scheme": "grpc" */ -#define GRPC_MDELEM_SCHEME_GRPC \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC)) -/* ":authority": "" */ -#define GRPC_MDELEM_AUTHORITY_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC)) -/* ":method": "GET" */ -#define GRPC_MDELEM_METHOD_GET \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC)) -/* ":method": "PUT" */ -#define GRPC_MDELEM_METHOD_PUT \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC)) -/* ":path": "/" */ -#define GRPC_MDELEM_PATH_SLASH \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC)) -/* ":path": "/index.html" */ -#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC)) +/* ":status": "200" */ +#define GRPC_MDELEM_STATUS_200 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "204" */ #define GRPC_MDELEM_STATUS_204 \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "206" */ #define GRPC_MDELEM_STATUS_206 \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "304" */ #define GRPC_MDELEM_STATUS_304 \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "400" */ #define GRPC_MDELEM_STATUS_400 \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC)) +/* ":status": "404" */ +#define GRPC_MDELEM_STATUS_404 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "500" */ #define GRPC_MDELEM_STATUS_500 \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-charset": "" */ #define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC)) -/* "accept-encoding": "" */ -#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-encoding": "gzip, deflate" */ #define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-language": "" */ #define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-ranges": "" */ #define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC)) /* "accept": "" */ #define GRPC_MDELEM_ACCEPT_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC)) /* "access-control-allow-origin": "" */ #define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC)) /* "age": "" */ #define GRPC_MDELEM_AGE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC)) /* "allow": "" */ #define GRPC_MDELEM_ALLOW_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC)) /* "authorization": "" */ #define GRPC_MDELEM_AUTHORIZATION_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC)) /* "cache-control": "" */ #define GRPC_MDELEM_CACHE_CONTROL_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC)) /* "content-disposition": "" */ #define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC)) -/* "content-encoding": "identity" */ -#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC)) -/* "content-encoding": "gzip" */ -#define GRPC_MDELEM_CONTENT_ENCODING_GZIP \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC)) /* "content-encoding": "" */ #define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC)) /* "content-language": "" */ #define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC)) /* "content-length": "" */ #define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC)) /* "content-location": "" */ #define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC)) /* "content-range": "" */ #define GRPC_MDELEM_CONTENT_RANGE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC)) /* "content-type": "" */ #define GRPC_MDELEM_CONTENT_TYPE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC)) /* "cookie": "" */ #define GRPC_MDELEM_COOKIE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC)) /* "date": "" */ #define GRPC_MDELEM_DATE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC)) /* "etag": "" */ #define GRPC_MDELEM_ETAG_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC)) /* "expect": "" */ #define GRPC_MDELEM_EXPECT_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC)) /* "expires": "" */ #define GRPC_MDELEM_EXPIRES_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC)) /* "from": "" */ #define GRPC_MDELEM_FROM_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC)) /* "host": "" */ #define GRPC_MDELEM_HOST_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC)) /* "if-match": "" */ #define GRPC_MDELEM_IF_MATCH_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC)) /* "if-modified-since": "" */ #define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC)) /* "if-none-match": "" */ #define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC)) /* "if-range": "" */ #define GRPC_MDELEM_IF_RANGE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC)) /* "if-unmodified-since": "" */ #define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC)) /* "last-modified": "" */ #define GRPC_MDELEM_LAST_MODIFIED_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC)) -/* "lb-token": "" */ -#define GRPC_MDELEM_LB_TOKEN_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC)) -/* "lb-cost-bin": "" */ -#define GRPC_MDELEM_LB_COST_BIN_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC)) /* "link": "" */ #define GRPC_MDELEM_LINK_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC)) /* "location": "" */ #define GRPC_MDELEM_LOCATION_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC)) /* "max-forwards": "" */ #define GRPC_MDELEM_MAX_FORWARDS_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC)) /* "proxy-authenticate": "" */ #define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC)) /* "proxy-authorization": "" */ #define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC)) /* "range": "" */ #define GRPC_MDELEM_RANGE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC)) /* "referer": "" */ #define GRPC_MDELEM_REFERER_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC)) /* "refresh": "" */ #define GRPC_MDELEM_REFRESH_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC)) /* "retry-after": "" */ #define GRPC_MDELEM_RETRY_AFTER_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC)) /* "server": "" */ #define GRPC_MDELEM_SERVER_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC)) /* "set-cookie": "" */ #define GRPC_MDELEM_SET_COOKIE_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC)) /* "strict-transport-security": "" */ #define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC)) /* "transfer-encoding": "" */ #define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC)) /* "user-agent": "" */ #define GRPC_MDELEM_USER_AGENT_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC)) /* "vary": "" */ #define GRPC_MDELEM_VARY_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC)) /* "via": "" */ #define GRPC_MDELEM_VIA_EMPTY \ - (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC)) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC)) /* "www-authenticate": "" */ #define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-status": "0" */ +#define GRPC_MDELEM_GRPC_STATUS_0 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-status": "1" */ +#define GRPC_MDELEM_GRPC_STATUS_1 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-status": "2" */ +#define GRPC_MDELEM_GRPC_STATUS_2 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-encoding": "identity" */ +#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-encoding": "gzip" */ +#define GRPC_MDELEM_GRPC_ENCODING_GZIP \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-encoding": "deflate" */ +#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC)) +/* "te": "trailers" */ +#define GRPC_MDELEM_TE_TRAILERS \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC)) +/* "content-type": "application/grpc" */ +#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC)) +/* ":scheme": "grpc" */ +#define GRPC_MDELEM_SCHEME_GRPC \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC)) +/* ":method": "PUT" */ +#define GRPC_MDELEM_METHOD_PUT \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC)) +/* "accept-encoding": "" */ +#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC)) +/* "content-encoding": "identity" */ +#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC)) +/* "content-encoding": "gzip" */ +#define GRPC_MDELEM_CONTENT_ENCODING_GZIP \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC)) +/* "lb-token": "" */ +#define GRPC_MDELEM_LB_TOKEN_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC)) +/* "lb-cost-bin": "" */ +#define GRPC_MDELEM_LB_COST_BIN_EMPTY \ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-accept-encoding": "identity" */ #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \ @@ -587,8 +587,6 @@ typedef union { GRPC_BATCH_CALLOUTS_COUNT) \ : GRPC_BATCH_CALLOUTS_COUNT) -extern bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT]; - extern const uint8_t grpc_static_accept_encoding_metadata[8]; #define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \ (GRPC_MAKE_MDELEM( \ diff --git a/src/core/tsi/alts/crypt/aes_gcm.cc b/src/core/tsi/alts/crypt/aes_gcm.cc index 02b1ac4492..c638ce76ee 100644 --- a/src/core/tsi/alts/crypt/aes_gcm.cc +++ b/src/core/tsi/alts/crypt/aes_gcm.cc @@ -18,6 +18,8 @@ #include <grpc/support/port_platform.h> +#include "src/core/tsi/grpc_shadow_boringssl.h" + #include "src/core/tsi/alts/crypt/gsec.h" #include <openssl/bio.h> diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_client.cc b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc index b5268add0d..17e8026096 100644 --- a/src/core/tsi/alts/handshaker/alts_handshaker_client.cc +++ b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc @@ -24,6 +24,7 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include "src/core/lib/slice/slice_internal.h" #include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h" const int kHandshakerClientOpNum = 4; @@ -109,7 +110,7 @@ static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) { if (ok) { buffer = grpc_raw_byte_buffer_create(&slice, 1 /* number of slices */); } - grpc_slice_unref(slice); + grpc_slice_unref_internal(slice); gpr_free(target_name); grpc_gcp_handshaker_req_destroy(req); return buffer; @@ -157,7 +158,7 @@ static grpc_byte_buffer* get_serialized_start_server( if (ok) { buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */); } - grpc_slice_unref(req_slice); + grpc_slice_unref_internal(req_slice); grpc_gcp_handshaker_req_destroy(req); return buffer; } @@ -195,7 +196,7 @@ static grpc_byte_buffer* get_serialized_next(grpc_slice* bytes_received) { if (ok) { buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */); } - grpc_slice_unref(req_slice); + grpc_slice_unref_internal(req_slice); grpc_gcp_handshaker_req_destroy(req); return buffer; } @@ -258,7 +259,7 @@ alts_handshaker_client* alts_grpc_handshaker_client_create( grpc_slice_from_static_string(ALTS_SERVICE_METHOD), &slice, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); client->base.vtable = &vtable; - grpc_slice_unref(slice); + grpc_slice_unref_internal(slice); return &client->base; } diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc b/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc index e0e4184686..d63d3538c5 100644 --- a/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc +++ b/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc @@ -20,6 +20,8 @@ #include "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h" +#include "src/core/lib/slice/slice_internal.h" + void add_repeated_field(repeated_field** head, const void* data) { repeated_field* field = static_cast<repeated_field*>(gpr_zalloc(sizeof(*field))); @@ -67,7 +69,7 @@ grpc_slice* create_slice(const char* data, size_t size) { void destroy_slice(grpc_slice* slice) { if (slice != nullptr) { - grpc_slice_unref(*slice); + grpc_slice_unref_internal(*slice); gpr_free(slice); } } diff --git a/src/core/tsi/alts/handshaker/alts_tsi_event.cc b/src/core/tsi/alts/handshaker/alts_tsi_event.cc index ec0bf12b95..cb36d5ebd1 100644 --- a/src/core/tsi/alts/handshaker/alts_tsi_event.cc +++ b/src/core/tsi/alts/handshaker/alts_tsi_event.cc @@ -24,6 +24,8 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include "src/core/lib/slice/slice_internal.h" + tsi_result alts_tsi_event_create(alts_tsi_handshaker* handshaker, tsi_handshaker_on_next_done_cb cb, void* user_data, @@ -66,8 +68,8 @@ void alts_tsi_event_destroy(alts_tsi_event* event) { grpc_byte_buffer_destroy(event->recv_buffer); grpc_metadata_array_destroy(&event->initial_metadata); grpc_metadata_array_destroy(&event->trailing_metadata); - grpc_slice_unref(event->details); - grpc_slice_unref(event->target_name); + grpc_slice_unref_internal(event->details); + grpc_slice_unref_internal(event->target_name); grpc_alts_credentials_options_destroy(event->options); gpr_free(event); } diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc index 1df1021bb1..dfdd659b87 100644 --- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc +++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc @@ -31,6 +31,7 @@ #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gprpp/thd.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/tsi/alts/frame_protector/alts_frame_protector.h" #include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" #include "src/core/tsi/alts/handshaker/alts_tsi_utils.h" @@ -182,7 +183,7 @@ static void handshaker_result_destroy(tsi_handshaker_result* self) { gpr_free(result->peer_identity); gpr_free(result->key_data); gpr_free(result->unused_bytes); - grpc_slice_unref(result->rpc_versions); + grpc_slice_unref_internal(result->rpc_versions); gpr_free(result); } @@ -269,12 +270,12 @@ static tsi_result handshaker_next( handshaker->has_sent_start_message = true; } else { if (!GRPC_SLICE_IS_EMPTY(handshaker->recv_bytes)) { - grpc_slice_unref(handshaker->recv_bytes); + grpc_slice_unref_internal(handshaker->recv_bytes); } handshaker->recv_bytes = grpc_slice_ref(slice); ok = alts_handshaker_client_next(handshaker->client, event, &slice); } - grpc_slice_unref(slice); + grpc_slice_unref_internal(slice); if (ok != TSI_OK) { gpr_log(GPR_ERROR, "Failed to schedule ALTS handshaker requests"); return ok; @@ -299,8 +300,8 @@ static void handshaker_destroy(tsi_handshaker* self) { alts_tsi_handshaker* handshaker = reinterpret_cast<alts_tsi_handshaker*>(self); alts_handshaker_client_destroy(handshaker->client); - grpc_slice_unref(handshaker->recv_bytes); - grpc_slice_unref(handshaker->target_name); + grpc_slice_unref_internal(handshaker->recv_bytes); + grpc_slice_unref_internal(handshaker->target_name); grpc_alts_credentials_options_destroy(handshaker->options); gpr_free(handshaker->buffer); gpr_free(handshaker); @@ -346,7 +347,8 @@ 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, tsi_handshaker** self) { + const char* handshaker_service_url, bool is_client, + grpc_pollset_set* interested_parties, 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 227b30ce53..48ce69b1da 100644 --- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h +++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h @@ -23,6 +23,7 @@ #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" @@ -51,6 +52,7 @@ 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. * @@ -58,7 +60,8 @@ 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, tsi_handshaker** self); + const char* handshaker_service_url, bool is_client, + grpc_pollset_set* interested_parties, tsi_handshaker** self); /** * This method handles handshaker response returned from ALTS handshaker diff --git a/src/core/tsi/alts/handshaker/alts_tsi_utils.cc b/src/core/tsi/alts/handshaker/alts_tsi_utils.cc index d9b5e6c945..1747f1ad04 100644 --- a/src/core/tsi/alts/handshaker/alts_tsi_utils.cc +++ b/src/core/tsi/alts/handshaker/alts_tsi_utils.cc @@ -22,6 +22,8 @@ #include <grpc/byte_buffer_reader.h> +#include "src/core/lib/slice/slice_internal.h" + tsi_result alts_tsi_utils_convert_to_tsi_result(grpc_status_code code) { switch (code) { case GRPC_STATUS_OK: @@ -47,7 +49,7 @@ grpc_gcp_handshaker_resp* alts_tsi_utils_deserialize_response( grpc_slice slice = grpc_byte_buffer_reader_readall(&bbr); grpc_gcp_handshaker_resp* resp = grpc_gcp_handshaker_resp_create(); bool ok = grpc_gcp_handshaker_resp_decode(slice, resp); - grpc_slice_unref(slice); + grpc_slice_unref_internal(slice); grpc_byte_buffer_reader_destroy(&bbr); if (!ok) { grpc_gcp_handshaker_resp_destroy(resp); diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc index d4fd88d1e2..e7890903d5 100644 --- a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc +++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc @@ -61,7 +61,7 @@ static tsi_result alts_grpc_privacy_integrity_protect( if (status != GRPC_STATUS_OK) { gpr_log(GPR_ERROR, "Failed to protect, %s", error_details); gpr_free(error_details); - grpc_slice_unref(protected_slice); + grpc_slice_unref_internal(protected_slice); return TSI_INTERNAL_ERROR; } grpc_slice_buffer_add(protected_slices, protected_slice); @@ -106,7 +106,7 @@ static tsi_result alts_grpc_privacy_integrity_unprotect( if (status != GRPC_STATUS_OK) { gpr_log(GPR_ERROR, "Failed to unprotect, %s", error_details); gpr_free(error_details); - grpc_slice_unref(unprotected_slice); + grpc_slice_unref_internal(unprotected_slice); return TSI_INTERNAL_ERROR; } grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb); diff --git a/src/core/tsi/alts_transport_security.cc b/src/core/tsi/alts_transport_security.cc index 2fd408103b..dac23bbf7a 100644 --- a/src/core/tsi/alts_transport_security.cc +++ b/src/core/tsi/alts_transport_security.cc @@ -45,7 +45,9 @@ void grpc_tsi_alts_signal_for_cq_destroy() { } void grpc_tsi_alts_init() { - memset(&g_alts_resource, 0, sizeof(alts_shared_resource)); + g_alts_resource.channel = nullptr; + g_alts_resource.cq = nullptr; + g_alts_resource.is_cq_drained = false; gpr_mu_init(&g_alts_resource.mu); gpr_cv_init(&g_alts_resource.cv); } diff --git a/src/core/tsi/grpc_shadow_boringssl.h b/src/core/tsi/grpc_shadow_boringssl.h new file mode 100644 index 0000000000..074be6d8d9 --- /dev/null +++ b/src/core/tsi/grpc_shadow_boringssl.h @@ -0,0 +1,3006 @@ + +/* + * + * Copyright 2018 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. + * + */ + +// This file is autogenerated from a template file. Please make +// modifications to +// `templates/src/objective-c/tsi/grpc_shadow_boringssl.h.template` +// instead. This file can be regenerated from the template by running +// `tools/buildgen/generate_projects.sh`. + +#ifndef GRPC_CORE_TSI_GRPC_SHADOW_BORINGSSL_H +#define GRPC_CORE_TSI_GRPC_SHADOW_BORINGSSL_H + +#ifdef GRPC_SHADOW_BORINGSSL_SYMBOLS + +#define BIO_f_ssl GRPC_SHADOW_BIO_f_ssl +#define BIO_set_ssl GRPC_SHADOW_BIO_set_ssl +#define SSL_CTX_add_client_custom_ext GRPC_SHADOW_SSL_CTX_add_client_custom_ext +#define SSL_CTX_add_server_custom_ext GRPC_SHADOW_SSL_CTX_add_server_custom_ext +#define DTLSv1_get_timeout GRPC_SHADOW_DTLSv1_get_timeout +#define DTLSv1_handle_timeout GRPC_SHADOW_DTLSv1_handle_timeout +#define DTLSv1_set_initial_timeout_duration GRPC_SHADOW_DTLSv1_set_initial_timeout_duration +#define SSL_CTX_set_srtp_profiles GRPC_SHADOW_SSL_CTX_set_srtp_profiles +#define SSL_CTX_set_tlsext_use_srtp GRPC_SHADOW_SSL_CTX_set_tlsext_use_srtp +#define SSL_get_selected_srtp_profile GRPC_SHADOW_SSL_get_selected_srtp_profile +#define SSL_get_srtp_profiles GRPC_SHADOW_SSL_get_srtp_profiles +#define SSL_set_srtp_profiles GRPC_SHADOW_SSL_set_srtp_profiles +#define SSL_set_tlsext_use_srtp GRPC_SHADOW_SSL_set_tlsext_use_srtp +#define DTLS_client_method GRPC_SHADOW_DTLS_client_method +#define DTLS_method GRPC_SHADOW_DTLS_method +#define DTLS_server_method GRPC_SHADOW_DTLS_server_method +#define DTLS_with_buffers_method GRPC_SHADOW_DTLS_with_buffers_method +#define DTLSv1_2_client_method GRPC_SHADOW_DTLSv1_2_client_method +#define DTLSv1_2_method GRPC_SHADOW_DTLSv1_2_method +#define DTLSv1_2_server_method GRPC_SHADOW_DTLSv1_2_server_method +#define DTLSv1_client_method GRPC_SHADOW_DTLSv1_client_method +#define DTLSv1_method GRPC_SHADOW_DTLSv1_method +#define DTLSv1_server_method GRPC_SHADOW_DTLSv1_server_method +#define SSL_SESSION_from_bytes GRPC_SHADOW_SSL_SESSION_from_bytes +#define SSL_SESSION_to_bytes GRPC_SHADOW_SSL_SESSION_to_bytes +#define SSL_SESSION_to_bytes_for_ticket GRPC_SHADOW_SSL_SESSION_to_bytes_for_ticket +#define i2d_SSL_SESSION GRPC_SHADOW_i2d_SSL_SESSION +#define SSL_CTX_set0_client_CAs GRPC_SHADOW_SSL_CTX_set0_client_CAs +#define SSL_CTX_set_cert_cb GRPC_SHADOW_SSL_CTX_set_cert_cb +#define SSL_CTX_set_chain_and_key GRPC_SHADOW_SSL_CTX_set_chain_and_key +#define SSL_CTX_set_ocsp_response GRPC_SHADOW_SSL_CTX_set_ocsp_response +#define SSL_CTX_set_signed_cert_timestamp_list GRPC_SHADOW_SSL_CTX_set_signed_cert_timestamp_list +#define SSL_CTX_use_certificate_ASN1 GRPC_SHADOW_SSL_CTX_use_certificate_ASN1 +#define SSL_get0_peer_certificates GRPC_SHADOW_SSL_get0_peer_certificates +#define SSL_get0_server_requested_CAs GRPC_SHADOW_SSL_get0_server_requested_CAs +#define SSL_set0_client_CAs GRPC_SHADOW_SSL_set0_client_CAs +#define SSL_set_cert_cb GRPC_SHADOW_SSL_set_cert_cb +#define SSL_set_chain_and_key GRPC_SHADOW_SSL_set_chain_and_key +#define SSL_set_ocsp_response GRPC_SHADOW_SSL_set_ocsp_response +#define SSL_set_signed_cert_timestamp_list GRPC_SHADOW_SSL_set_signed_cert_timestamp_list +#define SSL_use_certificate_ASN1 GRPC_SHADOW_SSL_use_certificate_ASN1 +#define SSL_CIPHER_description GRPC_SHADOW_SSL_CIPHER_description +#define SSL_CIPHER_get_auth_nid GRPC_SHADOW_SSL_CIPHER_get_auth_nid +#define SSL_CIPHER_get_bits GRPC_SHADOW_SSL_CIPHER_get_bits +#define SSL_CIPHER_get_cipher_nid GRPC_SHADOW_SSL_CIPHER_get_cipher_nid +#define SSL_CIPHER_get_digest_nid GRPC_SHADOW_SSL_CIPHER_get_digest_nid +#define SSL_CIPHER_get_id GRPC_SHADOW_SSL_CIPHER_get_id +#define SSL_CIPHER_get_kx_name GRPC_SHADOW_SSL_CIPHER_get_kx_name +#define SSL_CIPHER_get_kx_nid GRPC_SHADOW_SSL_CIPHER_get_kx_nid +#define SSL_CIPHER_get_max_version GRPC_SHADOW_SSL_CIPHER_get_max_version +#define SSL_CIPHER_get_min_version GRPC_SHADOW_SSL_CIPHER_get_min_version +#define SSL_CIPHER_get_name GRPC_SHADOW_SSL_CIPHER_get_name +#define SSL_CIPHER_get_prf_nid GRPC_SHADOW_SSL_CIPHER_get_prf_nid +#define SSL_CIPHER_get_rfc_name GRPC_SHADOW_SSL_CIPHER_get_rfc_name +#define SSL_CIPHER_get_version GRPC_SHADOW_SSL_CIPHER_get_version +#define SSL_CIPHER_is_aead GRPC_SHADOW_SSL_CIPHER_is_aead +#define SSL_CIPHER_is_block_cipher GRPC_SHADOW_SSL_CIPHER_is_block_cipher +#define SSL_CIPHER_standard_name GRPC_SHADOW_SSL_CIPHER_standard_name +#define SSL_COMP_add_compression_method GRPC_SHADOW_SSL_COMP_add_compression_method +#define SSL_COMP_free_compression_methods GRPC_SHADOW_SSL_COMP_free_compression_methods +#define SSL_COMP_get0_name GRPC_SHADOW_SSL_COMP_get0_name +#define SSL_COMP_get_compression_methods GRPC_SHADOW_SSL_COMP_get_compression_methods +#define SSL_COMP_get_id GRPC_SHADOW_SSL_COMP_get_id +#define SSL_COMP_get_name GRPC_SHADOW_SSL_COMP_get_name +#define SSL_get_cipher_by_value GRPC_SHADOW_SSL_get_cipher_by_value +#define SSL_CTX_get_default_passwd_cb GRPC_SHADOW_SSL_CTX_get_default_passwd_cb +#define SSL_CTX_get_default_passwd_cb_userdata GRPC_SHADOW_SSL_CTX_get_default_passwd_cb_userdata +#define SSL_CTX_set_default_passwd_cb GRPC_SHADOW_SSL_CTX_set_default_passwd_cb +#define SSL_CTX_set_default_passwd_cb_userdata GRPC_SHADOW_SSL_CTX_set_default_passwd_cb_userdata +#define SSL_CTX_use_PrivateKey_file GRPC_SHADOW_SSL_CTX_use_PrivateKey_file +#define SSL_CTX_use_RSAPrivateKey_file GRPC_SHADOW_SSL_CTX_use_RSAPrivateKey_file +#define SSL_CTX_use_certificate_chain_file GRPC_SHADOW_SSL_CTX_use_certificate_chain_file +#define SSL_CTX_use_certificate_file GRPC_SHADOW_SSL_CTX_use_certificate_file +#define SSL_add_file_cert_subjects_to_stack GRPC_SHADOW_SSL_add_file_cert_subjects_to_stack +#define SSL_load_client_CA_file GRPC_SHADOW_SSL_load_client_CA_file +#define SSL_use_PrivateKey_file GRPC_SHADOW_SSL_use_PrivateKey_file +#define SSL_use_RSAPrivateKey_file GRPC_SHADOW_SSL_use_RSAPrivateKey_file +#define SSL_use_certificate_file GRPC_SHADOW_SSL_use_certificate_file +#define SSL_get_curve_name GRPC_SHADOW_SSL_get_curve_name +#define ERR_load_SSL_strings GRPC_SHADOW_ERR_load_SSL_strings +#define OPENSSL_init_ssl GRPC_SHADOW_OPENSSL_init_ssl +#define SSL_CTX_check_private_key GRPC_SHADOW_SSL_CTX_check_private_key +#define SSL_CTX_cipher_in_group GRPC_SHADOW_SSL_CTX_cipher_in_group +#define SSL_CTX_clear_mode GRPC_SHADOW_SSL_CTX_clear_mode +#define SSL_CTX_clear_options GRPC_SHADOW_SSL_CTX_clear_options +#define SSL_CTX_enable_ocsp_stapling GRPC_SHADOW_SSL_CTX_enable_ocsp_stapling +#define SSL_CTX_enable_signed_cert_timestamps GRPC_SHADOW_SSL_CTX_enable_signed_cert_timestamps +#define SSL_CTX_enable_tls_channel_id GRPC_SHADOW_SSL_CTX_enable_tls_channel_id +#define SSL_CTX_free GRPC_SHADOW_SSL_CTX_free +#define SSL_CTX_get0_privatekey GRPC_SHADOW_SSL_CTX_get0_privatekey +#define SSL_CTX_get_ciphers GRPC_SHADOW_SSL_CTX_get_ciphers +#define SSL_CTX_get_ex_data GRPC_SHADOW_SSL_CTX_get_ex_data +#define SSL_CTX_get_ex_new_index GRPC_SHADOW_SSL_CTX_get_ex_new_index +#define SSL_CTX_get_keylog_callback GRPC_SHADOW_SSL_CTX_get_keylog_callback +#define SSL_CTX_get_max_cert_list GRPC_SHADOW_SSL_CTX_get_max_cert_list +#define SSL_CTX_get_mode GRPC_SHADOW_SSL_CTX_get_mode +#define SSL_CTX_get_options GRPC_SHADOW_SSL_CTX_get_options +#define SSL_CTX_get_quiet_shutdown GRPC_SHADOW_SSL_CTX_get_quiet_shutdown +#define SSL_CTX_get_read_ahead GRPC_SHADOW_SSL_CTX_get_read_ahead +#define SSL_CTX_get_session_cache_mode GRPC_SHADOW_SSL_CTX_get_session_cache_mode +#define SSL_CTX_get_tlsext_ticket_keys GRPC_SHADOW_SSL_CTX_get_tlsext_ticket_keys +#define SSL_CTX_need_tmp_RSA GRPC_SHADOW_SSL_CTX_need_tmp_RSA +#define SSL_CTX_new GRPC_SHADOW_SSL_CTX_new +#define SSL_CTX_sess_accept GRPC_SHADOW_SSL_CTX_sess_accept +#define SSL_CTX_sess_accept_good GRPC_SHADOW_SSL_CTX_sess_accept_good +#define SSL_CTX_sess_accept_renegotiate GRPC_SHADOW_SSL_CTX_sess_accept_renegotiate +#define SSL_CTX_sess_cache_full GRPC_SHADOW_SSL_CTX_sess_cache_full +#define SSL_CTX_sess_cb_hits GRPC_SHADOW_SSL_CTX_sess_cb_hits +#define SSL_CTX_sess_connect GRPC_SHADOW_SSL_CTX_sess_connect +#define SSL_CTX_sess_connect_good GRPC_SHADOW_SSL_CTX_sess_connect_good +#define SSL_CTX_sess_connect_renegotiate GRPC_SHADOW_SSL_CTX_sess_connect_renegotiate +#define SSL_CTX_sess_get_cache_size GRPC_SHADOW_SSL_CTX_sess_get_cache_size +#define SSL_CTX_sess_hits GRPC_SHADOW_SSL_CTX_sess_hits +#define SSL_CTX_sess_misses GRPC_SHADOW_SSL_CTX_sess_misses +#define SSL_CTX_sess_number GRPC_SHADOW_SSL_CTX_sess_number +#define SSL_CTX_sess_set_cache_size GRPC_SHADOW_SSL_CTX_sess_set_cache_size +#define SSL_CTX_sess_timeouts GRPC_SHADOW_SSL_CTX_sess_timeouts +#define SSL_CTX_set0_buffer_pool GRPC_SHADOW_SSL_CTX_set0_buffer_pool +#define SSL_CTX_set1_curves GRPC_SHADOW_SSL_CTX_set1_curves +#define SSL_CTX_set1_curves_list GRPC_SHADOW_SSL_CTX_set1_curves_list +#define SSL_CTX_set1_tls_channel_id GRPC_SHADOW_SSL_CTX_set1_tls_channel_id +#define SSL_CTX_set_allow_unknown_alpn_protos GRPC_SHADOW_SSL_CTX_set_allow_unknown_alpn_protos +#define SSL_CTX_set_alpn_protos GRPC_SHADOW_SSL_CTX_set_alpn_protos +#define SSL_CTX_set_alpn_select_cb GRPC_SHADOW_SSL_CTX_set_alpn_select_cb +#define SSL_CTX_set_cipher_list GRPC_SHADOW_SSL_CTX_set_cipher_list +#define SSL_CTX_set_current_time_cb GRPC_SHADOW_SSL_CTX_set_current_time_cb +#define SSL_CTX_set_custom_verify GRPC_SHADOW_SSL_CTX_set_custom_verify +#define SSL_CTX_set_dos_protection_cb GRPC_SHADOW_SSL_CTX_set_dos_protection_cb +#define SSL_CTX_set_early_data_enabled GRPC_SHADOW_SSL_CTX_set_early_data_enabled +#define SSL_CTX_set_ex_data GRPC_SHADOW_SSL_CTX_set_ex_data +#define SSL_CTX_set_false_start_allowed_without_alpn GRPC_SHADOW_SSL_CTX_set_false_start_allowed_without_alpn +#define SSL_CTX_set_grease_enabled GRPC_SHADOW_SSL_CTX_set_grease_enabled +#define SSL_CTX_set_keylog_callback GRPC_SHADOW_SSL_CTX_set_keylog_callback +#define SSL_CTX_set_max_cert_list GRPC_SHADOW_SSL_CTX_set_max_cert_list +#define SSL_CTX_set_max_send_fragment GRPC_SHADOW_SSL_CTX_set_max_send_fragment +#define SSL_CTX_set_mode GRPC_SHADOW_SSL_CTX_set_mode +#define SSL_CTX_set_msg_callback GRPC_SHADOW_SSL_CTX_set_msg_callback +#define SSL_CTX_set_msg_callback_arg GRPC_SHADOW_SSL_CTX_set_msg_callback_arg +#define SSL_CTX_set_next_proto_select_cb GRPC_SHADOW_SSL_CTX_set_next_proto_select_cb +#define SSL_CTX_set_next_protos_advertised_cb GRPC_SHADOW_SSL_CTX_set_next_protos_advertised_cb +#define SSL_CTX_set_options GRPC_SHADOW_SSL_CTX_set_options +#define SSL_CTX_set_psk_client_callback GRPC_SHADOW_SSL_CTX_set_psk_client_callback +#define SSL_CTX_set_psk_server_callback GRPC_SHADOW_SSL_CTX_set_psk_server_callback +#define SSL_CTX_set_quiet_shutdown GRPC_SHADOW_SSL_CTX_set_quiet_shutdown +#define SSL_CTX_set_read_ahead GRPC_SHADOW_SSL_CTX_set_read_ahead +#define SSL_CTX_set_retain_only_sha256_of_client_certs GRPC_SHADOW_SSL_CTX_set_retain_only_sha256_of_client_certs +#define SSL_CTX_set_select_certificate_cb GRPC_SHADOW_SSL_CTX_set_select_certificate_cb +#define SSL_CTX_set_session_cache_mode GRPC_SHADOW_SSL_CTX_set_session_cache_mode +#define SSL_CTX_set_session_id_context GRPC_SHADOW_SSL_CTX_set_session_id_context +#define SSL_CTX_set_strict_cipher_list GRPC_SHADOW_SSL_CTX_set_strict_cipher_list +#define SSL_CTX_set_ticket_aead_method GRPC_SHADOW_SSL_CTX_set_ticket_aead_method +#define SSL_CTX_set_tls13_variant GRPC_SHADOW_SSL_CTX_set_tls13_variant +#define SSL_CTX_set_tls_channel_id_enabled GRPC_SHADOW_SSL_CTX_set_tls_channel_id_enabled +#define SSL_CTX_set_tlsext_servername_arg GRPC_SHADOW_SSL_CTX_set_tlsext_servername_arg +#define SSL_CTX_set_tlsext_servername_callback GRPC_SHADOW_SSL_CTX_set_tlsext_servername_callback +#define SSL_CTX_set_tlsext_ticket_key_cb GRPC_SHADOW_SSL_CTX_set_tlsext_ticket_key_cb +#define SSL_CTX_set_tlsext_ticket_keys GRPC_SHADOW_SSL_CTX_set_tlsext_ticket_keys +#define SSL_CTX_set_tmp_dh GRPC_SHADOW_SSL_CTX_set_tmp_dh +#define SSL_CTX_set_tmp_dh_callback GRPC_SHADOW_SSL_CTX_set_tmp_dh_callback +#define SSL_CTX_set_tmp_ecdh GRPC_SHADOW_SSL_CTX_set_tmp_ecdh +#define SSL_CTX_set_tmp_rsa GRPC_SHADOW_SSL_CTX_set_tmp_rsa +#define SSL_CTX_set_tmp_rsa_callback GRPC_SHADOW_SSL_CTX_set_tmp_rsa_callback +#define SSL_CTX_up_ref GRPC_SHADOW_SSL_CTX_up_ref +#define SSL_CTX_use_psk_identity_hint GRPC_SHADOW_SSL_CTX_use_psk_identity_hint +#define SSL_accept GRPC_SHADOW_SSL_accept +#define SSL_cache_hit GRPC_SHADOW_SSL_cache_hit +#define SSL_certs_clear GRPC_SHADOW_SSL_certs_clear +#define SSL_check_private_key GRPC_SHADOW_SSL_check_private_key +#define SSL_clear GRPC_SHADOW_SSL_clear +#define SSL_clear_mode GRPC_SHADOW_SSL_clear_mode +#define SSL_clear_options GRPC_SHADOW_SSL_clear_options +#define SSL_connect GRPC_SHADOW_SSL_connect +#define SSL_cutthrough_complete GRPC_SHADOW_SSL_cutthrough_complete +#define SSL_do_handshake GRPC_SHADOW_SSL_do_handshake +#define SSL_dummy_pq_padding_used GRPC_SHADOW_SSL_dummy_pq_padding_used +#define SSL_early_data_accepted GRPC_SHADOW_SSL_early_data_accepted +#define SSL_enable_ocsp_stapling GRPC_SHADOW_SSL_enable_ocsp_stapling +#define SSL_enable_signed_cert_timestamps GRPC_SHADOW_SSL_enable_signed_cert_timestamps +#define SSL_enable_tls_channel_id GRPC_SHADOW_SSL_enable_tls_channel_id +#define SSL_free GRPC_SHADOW_SSL_free +#define SSL_get0_alpn_selected GRPC_SHADOW_SSL_get0_alpn_selected +#define SSL_get0_certificate_types GRPC_SHADOW_SSL_get0_certificate_types +#define SSL_get0_next_proto_negotiated GRPC_SHADOW_SSL_get0_next_proto_negotiated +#define SSL_get0_ocsp_response GRPC_SHADOW_SSL_get0_ocsp_response +#define SSL_get0_session_id_context GRPC_SHADOW_SSL_get0_session_id_context +#define SSL_get0_signed_cert_timestamp_list GRPC_SHADOW_SSL_get0_signed_cert_timestamp_list +#define SSL_get_SSL_CTX GRPC_SHADOW_SSL_get_SSL_CTX +#define SSL_get_cipher_list GRPC_SHADOW_SSL_get_cipher_list +#define SSL_get_ciphers GRPC_SHADOW_SSL_get_ciphers +#define SSL_get_client_random GRPC_SHADOW_SSL_get_client_random +#define SSL_get_current_cipher GRPC_SHADOW_SSL_get_current_cipher +#define SSL_get_current_compression GRPC_SHADOW_SSL_get_current_compression +#define SSL_get_current_expansion GRPC_SHADOW_SSL_get_current_expansion +#define SSL_get_curve_id GRPC_SHADOW_SSL_get_curve_id +#define SSL_get_default_timeout GRPC_SHADOW_SSL_get_default_timeout +#define SSL_get_error GRPC_SHADOW_SSL_get_error +#define SSL_get_ex_data GRPC_SHADOW_SSL_get_ex_data +#define SSL_get_ex_new_index GRPC_SHADOW_SSL_get_ex_new_index +#define SSL_get_extms_support GRPC_SHADOW_SSL_get_extms_support +#define SSL_get_fd GRPC_SHADOW_SSL_get_fd +#define SSL_get_finished GRPC_SHADOW_SSL_get_finished +#define SSL_get_info_callback GRPC_SHADOW_SSL_get_info_callback +#define SSL_get_ivs GRPC_SHADOW_SSL_get_ivs +#define SSL_get_max_cert_list GRPC_SHADOW_SSL_get_max_cert_list +#define SSL_get_mode GRPC_SHADOW_SSL_get_mode +#define SSL_get_negotiated_token_binding_param GRPC_SHADOW_SSL_get_negotiated_token_binding_param +#define SSL_get_options GRPC_SHADOW_SSL_get_options +#define SSL_get_peer_finished GRPC_SHADOW_SSL_get_peer_finished +#define SSL_get_peer_quic_transport_params GRPC_SHADOW_SSL_get_peer_quic_transport_params +#define SSL_get_peer_signature_algorithm GRPC_SHADOW_SSL_get_peer_signature_algorithm +#define SSL_get_pending_cipher GRPC_SHADOW_SSL_get_pending_cipher +#define SSL_get_privatekey GRPC_SHADOW_SSL_get_privatekey +#define SSL_get_psk_identity GRPC_SHADOW_SSL_get_psk_identity +#define SSL_get_psk_identity_hint GRPC_SHADOW_SSL_get_psk_identity_hint +#define SSL_get_quiet_shutdown GRPC_SHADOW_SSL_get_quiet_shutdown +#define SSL_get_rbio GRPC_SHADOW_SSL_get_rbio +#define SSL_get_read_ahead GRPC_SHADOW_SSL_get_read_ahead +#define SSL_get_read_sequence GRPC_SHADOW_SSL_get_read_sequence +#define SSL_get_rfd GRPC_SHADOW_SSL_get_rfd +#define SSL_get_secure_renegotiation_support GRPC_SHADOW_SSL_get_secure_renegotiation_support +#define SSL_get_server_random GRPC_SHADOW_SSL_get_server_random +#define SSL_get_server_tmp_key GRPC_SHADOW_SSL_get_server_tmp_key +#define SSL_get_servername GRPC_SHADOW_SSL_get_servername +#define SSL_get_servername_type GRPC_SHADOW_SSL_get_servername_type +#define SSL_get_shared_ciphers GRPC_SHADOW_SSL_get_shared_ciphers +#define SSL_get_shutdown GRPC_SHADOW_SSL_get_shutdown +#define SSL_get_structure_sizes GRPC_SHADOW_SSL_get_structure_sizes +#define SSL_get_ticket_age_skew GRPC_SHADOW_SSL_get_ticket_age_skew +#define SSL_get_tls_channel_id GRPC_SHADOW_SSL_get_tls_channel_id +#define SSL_get_tls_unique GRPC_SHADOW_SSL_get_tls_unique +#define SSL_get_verify_mode GRPC_SHADOW_SSL_get_verify_mode +#define SSL_get_wbio GRPC_SHADOW_SSL_get_wbio +#define SSL_get_wfd GRPC_SHADOW_SSL_get_wfd +#define SSL_get_write_sequence GRPC_SHADOW_SSL_get_write_sequence +#define SSL_in_early_data GRPC_SHADOW_SSL_in_early_data +#define SSL_in_false_start GRPC_SHADOW_SSL_in_false_start +#define SSL_in_init GRPC_SHADOW_SSL_in_init +#define SSL_is_draft_downgrade GRPC_SHADOW_SSL_is_draft_downgrade +#define SSL_is_dtls GRPC_SHADOW_SSL_is_dtls +#define SSL_is_init_finished GRPC_SHADOW_SSL_is_init_finished +#define SSL_is_server GRPC_SHADOW_SSL_is_server +#define SSL_is_token_binding_negotiated GRPC_SHADOW_SSL_is_token_binding_negotiated +#define SSL_library_init GRPC_SHADOW_SSL_library_init +#define SSL_load_error_strings GRPC_SHADOW_SSL_load_error_strings +#define SSL_need_tmp_RSA GRPC_SHADOW_SSL_need_tmp_RSA +#define SSL_new GRPC_SHADOW_SSL_new +#define SSL_num_renegotiations GRPC_SHADOW_SSL_num_renegotiations +#define SSL_peek GRPC_SHADOW_SSL_peek +#define SSL_pending GRPC_SHADOW_SSL_pending +#define SSL_read GRPC_SHADOW_SSL_read +#define SSL_renegotiate GRPC_SHADOW_SSL_renegotiate +#define SSL_renegotiate_pending GRPC_SHADOW_SSL_renegotiate_pending +#define SSL_reset_early_data_reject GRPC_SHADOW_SSL_reset_early_data_reject +#define SSL_select_next_proto GRPC_SHADOW_SSL_select_next_proto +#define SSL_send_fatal_alert GRPC_SHADOW_SSL_send_fatal_alert +#define SSL_session_reused GRPC_SHADOW_SSL_session_reused +#define SSL_set0_rbio GRPC_SHADOW_SSL_set0_rbio +#define SSL_set0_wbio GRPC_SHADOW_SSL_set0_wbio +#define SSL_set1_curves GRPC_SHADOW_SSL_set1_curves +#define SSL_set1_curves_list GRPC_SHADOW_SSL_set1_curves_list +#define SSL_set1_tls_channel_id GRPC_SHADOW_SSL_set1_tls_channel_id +#define SSL_set_SSL_CTX GRPC_SHADOW_SSL_set_SSL_CTX +#define SSL_set_accept_state GRPC_SHADOW_SSL_set_accept_state +#define SSL_set_alpn_protos GRPC_SHADOW_SSL_set_alpn_protos +#define SSL_set_bio GRPC_SHADOW_SSL_set_bio +#define SSL_set_cipher_list GRPC_SHADOW_SSL_set_cipher_list +#define SSL_set_connect_state GRPC_SHADOW_SSL_set_connect_state +#define SSL_set_custom_verify GRPC_SHADOW_SSL_set_custom_verify +#define SSL_set_dummy_pq_padding_size GRPC_SHADOW_SSL_set_dummy_pq_padding_size +#define SSL_set_early_data_enabled GRPC_SHADOW_SSL_set_early_data_enabled +#define SSL_set_ex_data GRPC_SHADOW_SSL_set_ex_data +#define SSL_set_fd GRPC_SHADOW_SSL_set_fd +#define SSL_set_info_callback GRPC_SHADOW_SSL_set_info_callback +#define SSL_set_max_cert_list GRPC_SHADOW_SSL_set_max_cert_list +#define SSL_set_max_send_fragment GRPC_SHADOW_SSL_set_max_send_fragment +#define SSL_set_mode GRPC_SHADOW_SSL_set_mode +#define SSL_set_msg_callback GRPC_SHADOW_SSL_set_msg_callback +#define SSL_set_msg_callback_arg GRPC_SHADOW_SSL_set_msg_callback_arg +#define SSL_set_mtu GRPC_SHADOW_SSL_set_mtu +#define SSL_set_options GRPC_SHADOW_SSL_set_options +#define SSL_set_psk_client_callback GRPC_SHADOW_SSL_set_psk_client_callback +#define SSL_set_psk_server_callback GRPC_SHADOW_SSL_set_psk_server_callback +#define SSL_set_quic_transport_params GRPC_SHADOW_SSL_set_quic_transport_params +#define SSL_set_quiet_shutdown GRPC_SHADOW_SSL_set_quiet_shutdown +#define SSL_set_read_ahead GRPC_SHADOW_SSL_set_read_ahead +#define SSL_set_renegotiate_mode GRPC_SHADOW_SSL_set_renegotiate_mode +#define SSL_set_retain_only_sha256_of_client_certs GRPC_SHADOW_SSL_set_retain_only_sha256_of_client_certs +#define SSL_set_rfd GRPC_SHADOW_SSL_set_rfd +#define SSL_set_session_id_context GRPC_SHADOW_SSL_set_session_id_context +#define SSL_set_shutdown GRPC_SHADOW_SSL_set_shutdown +#define SSL_set_state GRPC_SHADOW_SSL_set_state +#define SSL_set_strict_cipher_list GRPC_SHADOW_SSL_set_strict_cipher_list +#define SSL_set_tls13_variant GRPC_SHADOW_SSL_set_tls13_variant +#define SSL_set_tls_channel_id_enabled GRPC_SHADOW_SSL_set_tls_channel_id_enabled +#define SSL_set_tlsext_host_name GRPC_SHADOW_SSL_set_tlsext_host_name +#define SSL_set_tmp_dh GRPC_SHADOW_SSL_set_tmp_dh +#define SSL_set_tmp_dh_callback GRPC_SHADOW_SSL_set_tmp_dh_callback +#define SSL_set_tmp_ecdh GRPC_SHADOW_SSL_set_tmp_ecdh +#define SSL_set_tmp_rsa GRPC_SHADOW_SSL_set_tmp_rsa +#define SSL_set_tmp_rsa_callback GRPC_SHADOW_SSL_set_tmp_rsa_callback +#define SSL_set_token_binding_params GRPC_SHADOW_SSL_set_token_binding_params +#define SSL_set_wfd GRPC_SHADOW_SSL_set_wfd +#define SSL_shutdown GRPC_SHADOW_SSL_shutdown +#define SSL_state GRPC_SHADOW_SSL_state +#define SSL_total_renegotiations GRPC_SHADOW_SSL_total_renegotiations +#define SSL_use_psk_identity_hint GRPC_SHADOW_SSL_use_psk_identity_hint +#define SSL_want GRPC_SHADOW_SSL_want +#define SSL_write GRPC_SHADOW_SSL_write +#define SSL_CTX_set_private_key_method GRPC_SHADOW_SSL_CTX_set_private_key_method +#define SSL_CTX_set_signing_algorithm_prefs GRPC_SHADOW_SSL_CTX_set_signing_algorithm_prefs +#define SSL_CTX_set_verify_algorithm_prefs GRPC_SHADOW_SSL_CTX_set_verify_algorithm_prefs +#define SSL_CTX_use_PrivateKey GRPC_SHADOW_SSL_CTX_use_PrivateKey +#define SSL_CTX_use_PrivateKey_ASN1 GRPC_SHADOW_SSL_CTX_use_PrivateKey_ASN1 +#define SSL_CTX_use_RSAPrivateKey GRPC_SHADOW_SSL_CTX_use_RSAPrivateKey +#define SSL_CTX_use_RSAPrivateKey_ASN1 GRPC_SHADOW_SSL_CTX_use_RSAPrivateKey_ASN1 +#define SSL_get_signature_algorithm_digest GRPC_SHADOW_SSL_get_signature_algorithm_digest +#define SSL_get_signature_algorithm_key_type GRPC_SHADOW_SSL_get_signature_algorithm_key_type +#define SSL_get_signature_algorithm_name GRPC_SHADOW_SSL_get_signature_algorithm_name +#define SSL_is_signature_algorithm_rsa_pss GRPC_SHADOW_SSL_is_signature_algorithm_rsa_pss +#define SSL_set_private_key_method GRPC_SHADOW_SSL_set_private_key_method +#define SSL_set_signing_algorithm_prefs GRPC_SHADOW_SSL_set_signing_algorithm_prefs +#define SSL_use_PrivateKey GRPC_SHADOW_SSL_use_PrivateKey +#define SSL_use_PrivateKey_ASN1 GRPC_SHADOW_SSL_use_PrivateKey_ASN1 +#define SSL_use_RSAPrivateKey GRPC_SHADOW_SSL_use_RSAPrivateKey +#define SSL_use_RSAPrivateKey_ASN1 GRPC_SHADOW_SSL_use_RSAPrivateKey_ASN1 +#define SSL_CTX_add_session GRPC_SHADOW_SSL_CTX_add_session +#define SSL_CTX_flush_sessions GRPC_SHADOW_SSL_CTX_flush_sessions +#define SSL_CTX_get_channel_id_cb GRPC_SHADOW_SSL_CTX_get_channel_id_cb +#define SSL_CTX_get_info_callback GRPC_SHADOW_SSL_CTX_get_info_callback +#define SSL_CTX_get_timeout GRPC_SHADOW_SSL_CTX_get_timeout +#define SSL_CTX_remove_session GRPC_SHADOW_SSL_CTX_remove_session +#define SSL_CTX_sess_get_get_cb GRPC_SHADOW_SSL_CTX_sess_get_get_cb +#define SSL_CTX_sess_get_new_cb GRPC_SHADOW_SSL_CTX_sess_get_new_cb +#define SSL_CTX_sess_get_remove_cb GRPC_SHADOW_SSL_CTX_sess_get_remove_cb +#define SSL_CTX_sess_set_get_cb GRPC_SHADOW_SSL_CTX_sess_set_get_cb +#define SSL_CTX_sess_set_new_cb GRPC_SHADOW_SSL_CTX_sess_set_new_cb +#define SSL_CTX_sess_set_remove_cb GRPC_SHADOW_SSL_CTX_sess_set_remove_cb +#define SSL_CTX_set_channel_id_cb GRPC_SHADOW_SSL_CTX_set_channel_id_cb +#define SSL_CTX_set_info_callback GRPC_SHADOW_SSL_CTX_set_info_callback +#define SSL_CTX_set_session_psk_dhe_timeout GRPC_SHADOW_SSL_CTX_set_session_psk_dhe_timeout +#define SSL_CTX_set_timeout GRPC_SHADOW_SSL_CTX_set_timeout +#define SSL_SESSION_free GRPC_SHADOW_SSL_SESSION_free +#define SSL_SESSION_get0_peer GRPC_SHADOW_SSL_SESSION_get0_peer +#define SSL_SESSION_get0_ticket GRPC_SHADOW_SSL_SESSION_get0_ticket +#define SSL_SESSION_get_ex_data GRPC_SHADOW_SSL_SESSION_get_ex_data +#define SSL_SESSION_get_ex_new_index GRPC_SHADOW_SSL_SESSION_get_ex_new_index +#define SSL_SESSION_get_id GRPC_SHADOW_SSL_SESSION_get_id +#define SSL_SESSION_get_master_key GRPC_SHADOW_SSL_SESSION_get_master_key +#define SSL_SESSION_get_ticket_lifetime_hint GRPC_SHADOW_SSL_SESSION_get_ticket_lifetime_hint +#define SSL_SESSION_get_time GRPC_SHADOW_SSL_SESSION_get_time +#define SSL_SESSION_get_timeout GRPC_SHADOW_SSL_SESSION_get_timeout +#define SSL_SESSION_has_ticket GRPC_SHADOW_SSL_SESSION_has_ticket +#define SSL_SESSION_is_resumable GRPC_SHADOW_SSL_SESSION_is_resumable +#define SSL_SESSION_new GRPC_SHADOW_SSL_SESSION_new +#define SSL_SESSION_set1_id_context GRPC_SHADOW_SSL_SESSION_set1_id_context +#define SSL_SESSION_set_ex_data GRPC_SHADOW_SSL_SESSION_set_ex_data +#define SSL_SESSION_set_time GRPC_SHADOW_SSL_SESSION_set_time +#define SSL_SESSION_set_timeout GRPC_SHADOW_SSL_SESSION_set_timeout +#define SSL_SESSION_should_be_single_use GRPC_SHADOW_SSL_SESSION_should_be_single_use +#define SSL_SESSION_up_ref GRPC_SHADOW_SSL_SESSION_up_ref +#define SSL_get1_session GRPC_SHADOW_SSL_get1_session +#define SSL_get_session GRPC_SHADOW_SSL_get_session +#define SSL_magic_pending_session_ptr GRPC_SHADOW_SSL_magic_pending_session_ptr +#define SSL_set_session GRPC_SHADOW_SSL_set_session +#define SSL_alert_desc_string GRPC_SHADOW_SSL_alert_desc_string +#define SSL_alert_desc_string_long GRPC_SHADOW_SSL_alert_desc_string_long +#define SSL_alert_type_string GRPC_SHADOW_SSL_alert_type_string +#define SSL_alert_type_string_long GRPC_SHADOW_SSL_alert_type_string_long +#define SSL_state_string GRPC_SHADOW_SSL_state_string +#define SSL_state_string_long GRPC_SHADOW_SSL_state_string_long +#define SSL_CTX_set_max_proto_version GRPC_SHADOW_SSL_CTX_set_max_proto_version +#define SSL_CTX_set_min_proto_version GRPC_SHADOW_SSL_CTX_set_min_proto_version +#define SSL_SESSION_get_protocol_version GRPC_SHADOW_SSL_SESSION_get_protocol_version +#define SSL_SESSION_get_version GRPC_SHADOW_SSL_SESSION_get_version +#define SSL_SESSION_set_protocol_version GRPC_SHADOW_SSL_SESSION_set_protocol_version +#define SSL_get_version GRPC_SHADOW_SSL_get_version +#define SSL_set_max_proto_version GRPC_SHADOW_SSL_set_max_proto_version +#define SSL_set_min_proto_version GRPC_SHADOW_SSL_set_min_proto_version +#define SSL_version GRPC_SHADOW_SSL_version +#define PEM_read_SSL_SESSION GRPC_SHADOW_PEM_read_SSL_SESSION +#define PEM_read_bio_SSL_SESSION GRPC_SHADOW_PEM_read_bio_SSL_SESSION +#define PEM_write_SSL_SESSION GRPC_SHADOW_PEM_write_SSL_SESSION +#define PEM_write_bio_SSL_SESSION GRPC_SHADOW_PEM_write_bio_SSL_SESSION +#define SSL_CTX_add0_chain_cert GRPC_SHADOW_SSL_CTX_add0_chain_cert +#define SSL_CTX_add1_chain_cert GRPC_SHADOW_SSL_CTX_add1_chain_cert +#define SSL_CTX_add_client_CA GRPC_SHADOW_SSL_CTX_add_client_CA +#define SSL_CTX_add_extra_chain_cert GRPC_SHADOW_SSL_CTX_add_extra_chain_cert +#define SSL_CTX_clear_chain_certs GRPC_SHADOW_SSL_CTX_clear_chain_certs +#define SSL_CTX_clear_extra_chain_certs GRPC_SHADOW_SSL_CTX_clear_extra_chain_certs +#define SSL_CTX_get0_certificate GRPC_SHADOW_SSL_CTX_get0_certificate +#define SSL_CTX_get0_chain_certs GRPC_SHADOW_SSL_CTX_get0_chain_certs +#define SSL_CTX_get0_param GRPC_SHADOW_SSL_CTX_get0_param +#define SSL_CTX_get_cert_store GRPC_SHADOW_SSL_CTX_get_cert_store +#define SSL_CTX_get_client_CA_list GRPC_SHADOW_SSL_CTX_get_client_CA_list +#define SSL_CTX_get_extra_chain_certs GRPC_SHADOW_SSL_CTX_get_extra_chain_certs +#define SSL_CTX_get_verify_callback GRPC_SHADOW_SSL_CTX_get_verify_callback +#define SSL_CTX_get_verify_depth GRPC_SHADOW_SSL_CTX_get_verify_depth +#define SSL_CTX_get_verify_mode GRPC_SHADOW_SSL_CTX_get_verify_mode +#define SSL_CTX_load_verify_locations GRPC_SHADOW_SSL_CTX_load_verify_locations +#define SSL_CTX_set0_chain GRPC_SHADOW_SSL_CTX_set0_chain +#define SSL_CTX_set0_verify_cert_store GRPC_SHADOW_SSL_CTX_set0_verify_cert_store +#define SSL_CTX_set1_chain GRPC_SHADOW_SSL_CTX_set1_chain +#define SSL_CTX_set1_param GRPC_SHADOW_SSL_CTX_set1_param +#define SSL_CTX_set1_verify_cert_store GRPC_SHADOW_SSL_CTX_set1_verify_cert_store +#define SSL_CTX_set_cert_store GRPC_SHADOW_SSL_CTX_set_cert_store +#define SSL_CTX_set_cert_verify_callback GRPC_SHADOW_SSL_CTX_set_cert_verify_callback +#define SSL_CTX_set_client_CA_list GRPC_SHADOW_SSL_CTX_set_client_CA_list +#define SSL_CTX_set_client_cert_cb GRPC_SHADOW_SSL_CTX_set_client_cert_cb +#define SSL_CTX_set_default_verify_paths GRPC_SHADOW_SSL_CTX_set_default_verify_paths +#define SSL_CTX_set_purpose GRPC_SHADOW_SSL_CTX_set_purpose +#define SSL_CTX_set_trust GRPC_SHADOW_SSL_CTX_set_trust +#define SSL_CTX_set_verify GRPC_SHADOW_SSL_CTX_set_verify +#define SSL_CTX_set_verify_depth GRPC_SHADOW_SSL_CTX_set_verify_depth +#define SSL_CTX_use_certificate GRPC_SHADOW_SSL_CTX_use_certificate +#define SSL_add0_chain_cert GRPC_SHADOW_SSL_add0_chain_cert +#define SSL_add1_chain_cert GRPC_SHADOW_SSL_add1_chain_cert +#define SSL_add_client_CA GRPC_SHADOW_SSL_add_client_CA +#define SSL_alert_from_verify_result GRPC_SHADOW_SSL_alert_from_verify_result +#define SSL_clear_chain_certs GRPC_SHADOW_SSL_clear_chain_certs +#define SSL_dup_CA_list GRPC_SHADOW_SSL_dup_CA_list +#define SSL_get0_chain_certs GRPC_SHADOW_SSL_get0_chain_certs +#define SSL_get0_param GRPC_SHADOW_SSL_get0_param +#define SSL_get_certificate GRPC_SHADOW_SSL_get_certificate +#define SSL_get_client_CA_list GRPC_SHADOW_SSL_get_client_CA_list +#define SSL_get_ex_data_X509_STORE_CTX_idx GRPC_SHADOW_SSL_get_ex_data_X509_STORE_CTX_idx +#define SSL_get_peer_cert_chain GRPC_SHADOW_SSL_get_peer_cert_chain +#define SSL_get_peer_certificate GRPC_SHADOW_SSL_get_peer_certificate +#define SSL_get_peer_full_cert_chain GRPC_SHADOW_SSL_get_peer_full_cert_chain +#define SSL_get_verify_callback GRPC_SHADOW_SSL_get_verify_callback +#define SSL_get_verify_depth GRPC_SHADOW_SSL_get_verify_depth +#define SSL_get_verify_result GRPC_SHADOW_SSL_get_verify_result +#define SSL_set0_chain GRPC_SHADOW_SSL_set0_chain +#define SSL_set0_verify_cert_store GRPC_SHADOW_SSL_set0_verify_cert_store +#define SSL_set1_chain GRPC_SHADOW_SSL_set1_chain +#define SSL_set1_param GRPC_SHADOW_SSL_set1_param +#define SSL_set1_verify_cert_store GRPC_SHADOW_SSL_set1_verify_cert_store +#define SSL_set_client_CA_list GRPC_SHADOW_SSL_set_client_CA_list +#define SSL_set_purpose GRPC_SHADOW_SSL_set_purpose +#define SSL_set_trust GRPC_SHADOW_SSL_set_trust +#define SSL_set_verify GRPC_SHADOW_SSL_set_verify +#define SSL_set_verify_depth GRPC_SHADOW_SSL_set_verify_depth +#define SSL_set_verify_result GRPC_SHADOW_SSL_set_verify_result +#define SSL_use_certificate GRPC_SHADOW_SSL_use_certificate +#define d2i_SSL_SESSION GRPC_SHADOW_d2i_SSL_SESSION +#define d2i_SSL_SESSION_bio GRPC_SHADOW_d2i_SSL_SESSION_bio +#define i2d_SSL_SESSION_bio GRPC_SHADOW_i2d_SSL_SESSION_bio +#define SSL_export_early_keying_material GRPC_SHADOW_SSL_export_early_keying_material +#define SSL_export_keying_material GRPC_SHADOW_SSL_export_keying_material +#define SSL_generate_key_block GRPC_SHADOW_SSL_generate_key_block +#define SSL_get_key_block_len GRPC_SHADOW_SSL_get_key_block_len +#define SSL_CTX_set_ed25519_enabled GRPC_SHADOW_SSL_CTX_set_ed25519_enabled +#define SSL_early_callback_ctx_extension_get GRPC_SHADOW_SSL_early_callback_ctx_extension_get +#define SSL_extension_supported GRPC_SHADOW_SSL_extension_supported +#define SSLv23_client_method GRPC_SHADOW_SSLv23_client_method +#define SSLv23_method GRPC_SHADOW_SSLv23_method +#define SSLv23_server_method GRPC_SHADOW_SSLv23_server_method +#define TLS_client_method GRPC_SHADOW_TLS_client_method +#define TLS_method GRPC_SHADOW_TLS_method +#define TLS_server_method GRPC_SHADOW_TLS_server_method +#define TLS_with_buffers_method GRPC_SHADOW_TLS_with_buffers_method +#define TLSv1_1_client_method GRPC_SHADOW_TLSv1_1_client_method +#define TLSv1_1_method GRPC_SHADOW_TLSv1_1_method +#define TLSv1_1_server_method GRPC_SHADOW_TLSv1_1_server_method +#define TLSv1_2_client_method GRPC_SHADOW_TLSv1_2_client_method +#define TLSv1_2_method GRPC_SHADOW_TLSv1_2_method +#define TLSv1_2_server_method GRPC_SHADOW_TLSv1_2_server_method +#define TLSv1_client_method GRPC_SHADOW_TLSv1_client_method +#define TLSv1_method GRPC_SHADOW_TLSv1_method +#define TLSv1_server_method GRPC_SHADOW_TLSv1_server_method +#define SSL_max_seal_overhead GRPC_SHADOW_SSL_max_seal_overhead +#define OPENSSL_cpuid_setup GRPC_SHADOW_OPENSSL_cpuid_setup +#define CRYPTO_has_asm GRPC_SHADOW_CRYPTO_has_asm +#define CRYPTO_is_confidential_build GRPC_SHADOW_CRYPTO_is_confidential_build +#define CRYPTO_library_init GRPC_SHADOW_CRYPTO_library_init +#define CRYPTO_malloc_init GRPC_SHADOW_CRYPTO_malloc_init +#define ENGINE_load_builtin_engines GRPC_SHADOW_ENGINE_load_builtin_engines +#define ENGINE_register_all_complete GRPC_SHADOW_ENGINE_register_all_complete +#define OPENSSL_ia32cap_P GRPC_SHADOW_OPENSSL_ia32cap_P +#define OPENSSL_init_crypto GRPC_SHADOW_OPENSSL_init_crypto +#define OPENSSL_load_builtin_modules GRPC_SHADOW_OPENSSL_load_builtin_modules +#define OpenSSL_version GRPC_SHADOW_OpenSSL_version +#define OpenSSL_version_num GRPC_SHADOW_OpenSSL_version_num +#define SSLeay GRPC_SHADOW_SSLeay +#define SSLeay_version GRPC_SHADOW_SSLeay_version +#define CRYPTO_cleanup_all_ex_data GRPC_SHADOW_CRYPTO_cleanup_all_ex_data +#define CRYPTO_free_ex_data GRPC_SHADOW_CRYPTO_free_ex_data +#define CRYPTO_get_ex_data GRPC_SHADOW_CRYPTO_get_ex_data +#define CRYPTO_get_ex_new_index GRPC_SHADOW_CRYPTO_get_ex_new_index +#define CRYPTO_new_ex_data GRPC_SHADOW_CRYPTO_new_ex_data +#define CRYPTO_set_ex_data GRPC_SHADOW_CRYPTO_set_ex_data +#define BIO_snprintf GRPC_SHADOW_BIO_snprintf +#define BIO_vsnprintf GRPC_SHADOW_BIO_vsnprintf +#define CRYPTO_memcmp GRPC_SHADOW_CRYPTO_memcmp +#define OPENSSL_cleanse GRPC_SHADOW_OPENSSL_cleanse +#define OPENSSL_free GRPC_SHADOW_OPENSSL_free +#define OPENSSL_hash32 GRPC_SHADOW_OPENSSL_hash32 +#define OPENSSL_malloc GRPC_SHADOW_OPENSSL_malloc +#define OPENSSL_realloc GRPC_SHADOW_OPENSSL_realloc +#define OPENSSL_strcasecmp GRPC_SHADOW_OPENSSL_strcasecmp +#define OPENSSL_strdup GRPC_SHADOW_OPENSSL_strdup +#define OPENSSL_strncasecmp GRPC_SHADOW_OPENSSL_strncasecmp +#define OPENSSL_strnlen GRPC_SHADOW_OPENSSL_strnlen +#define OPENSSL_tolower GRPC_SHADOW_OPENSSL_tolower +#define CRYPTO_refcount_dec_and_test_zero GRPC_SHADOW_CRYPTO_refcount_dec_and_test_zero +#define CRYPTO_refcount_inc GRPC_SHADOW_CRYPTO_refcount_inc +#define CRYPTO_THREADID_current GRPC_SHADOW_CRYPTO_THREADID_current +#define CRYPTO_THREADID_set_callback GRPC_SHADOW_CRYPTO_THREADID_set_callback +#define CRYPTO_THREADID_set_numeric GRPC_SHADOW_CRYPTO_THREADID_set_numeric +#define CRYPTO_THREADID_set_pointer GRPC_SHADOW_CRYPTO_THREADID_set_pointer +#define CRYPTO_get_dynlock_create_callback GRPC_SHADOW_CRYPTO_get_dynlock_create_callback +#define CRYPTO_get_dynlock_destroy_callback GRPC_SHADOW_CRYPTO_get_dynlock_destroy_callback +#define CRYPTO_get_dynlock_lock_callback GRPC_SHADOW_CRYPTO_get_dynlock_lock_callback +#define CRYPTO_get_lock_name GRPC_SHADOW_CRYPTO_get_lock_name +#define CRYPTO_get_locking_callback GRPC_SHADOW_CRYPTO_get_locking_callback +#define CRYPTO_num_locks GRPC_SHADOW_CRYPTO_num_locks +#define CRYPTO_set_add_lock_callback GRPC_SHADOW_CRYPTO_set_add_lock_callback +#define CRYPTO_set_dynlock_create_callback GRPC_SHADOW_CRYPTO_set_dynlock_create_callback +#define CRYPTO_set_dynlock_destroy_callback GRPC_SHADOW_CRYPTO_set_dynlock_destroy_callback +#define CRYPTO_set_dynlock_lock_callback GRPC_SHADOW_CRYPTO_set_dynlock_lock_callback +#define CRYPTO_set_id_callback GRPC_SHADOW_CRYPTO_set_id_callback +#define CRYPTO_set_locking_callback GRPC_SHADOW_CRYPTO_set_locking_callback +#define CRYPTO_MUTEX_cleanup GRPC_SHADOW_CRYPTO_MUTEX_cleanup +#define CRYPTO_MUTEX_init GRPC_SHADOW_CRYPTO_MUTEX_init +#define CRYPTO_MUTEX_lock_read GRPC_SHADOW_CRYPTO_MUTEX_lock_read +#define CRYPTO_MUTEX_lock_write GRPC_SHADOW_CRYPTO_MUTEX_lock_write +#define CRYPTO_MUTEX_unlock_read GRPC_SHADOW_CRYPTO_MUTEX_unlock_read +#define CRYPTO_MUTEX_unlock_write GRPC_SHADOW_CRYPTO_MUTEX_unlock_write +#define CRYPTO_STATIC_MUTEX_lock_read GRPC_SHADOW_CRYPTO_STATIC_MUTEX_lock_read +#define CRYPTO_STATIC_MUTEX_lock_write GRPC_SHADOW_CRYPTO_STATIC_MUTEX_lock_write +#define CRYPTO_STATIC_MUTEX_unlock_read GRPC_SHADOW_CRYPTO_STATIC_MUTEX_unlock_read +#define CRYPTO_STATIC_MUTEX_unlock_write GRPC_SHADOW_CRYPTO_STATIC_MUTEX_unlock_write +#define CRYPTO_get_thread_local GRPC_SHADOW_CRYPTO_get_thread_local +#define CRYPTO_once GRPC_SHADOW_CRYPTO_once +#define CRYPTO_set_thread_local GRPC_SHADOW_CRYPTO_set_thread_local +#define sk_deep_copy GRPC_SHADOW_sk_deep_copy +#define sk_delete GRPC_SHADOW_sk_delete +#define sk_delete_ptr GRPC_SHADOW_sk_delete_ptr +#define sk_dup GRPC_SHADOW_sk_dup +#define sk_find GRPC_SHADOW_sk_find +#define sk_free GRPC_SHADOW_sk_free +#define sk_insert GRPC_SHADOW_sk_insert +#define sk_is_sorted GRPC_SHADOW_sk_is_sorted +#define sk_new GRPC_SHADOW_sk_new +#define sk_new_null GRPC_SHADOW_sk_new_null +#define sk_num GRPC_SHADOW_sk_num +#define sk_pop GRPC_SHADOW_sk_pop +#define sk_pop_free GRPC_SHADOW_sk_pop_free +#define sk_push GRPC_SHADOW_sk_push +#define sk_set GRPC_SHADOW_sk_set +#define sk_set_cmp_func GRPC_SHADOW_sk_set_cmp_func +#define sk_shift GRPC_SHADOW_sk_shift +#define sk_sort GRPC_SHADOW_sk_sort +#define sk_value GRPC_SHADOW_sk_value +#define sk_zero GRPC_SHADOW_sk_zero +#define lh_delete GRPC_SHADOW_lh_delete +#define lh_doall GRPC_SHADOW_lh_doall +#define lh_doall_arg GRPC_SHADOW_lh_doall_arg +#define lh_free GRPC_SHADOW_lh_free +#define lh_insert GRPC_SHADOW_lh_insert +#define lh_new GRPC_SHADOW_lh_new +#define lh_num_items GRPC_SHADOW_lh_num_items +#define lh_retrieve GRPC_SHADOW_lh_retrieve +#define lh_strhash GRPC_SHADOW_lh_strhash +#define ERR_SAVE_STATE_free GRPC_SHADOW_ERR_SAVE_STATE_free +#define ERR_add_error_data GRPC_SHADOW_ERR_add_error_data +#define ERR_add_error_dataf GRPC_SHADOW_ERR_add_error_dataf +#define ERR_clear_error GRPC_SHADOW_ERR_clear_error +#define ERR_clear_system_error GRPC_SHADOW_ERR_clear_system_error +#define ERR_error_string GRPC_SHADOW_ERR_error_string +#define ERR_error_string_n GRPC_SHADOW_ERR_error_string_n +#define ERR_free_strings GRPC_SHADOW_ERR_free_strings +#define ERR_func_error_string GRPC_SHADOW_ERR_func_error_string +#define ERR_get_error GRPC_SHADOW_ERR_get_error +#define ERR_get_error_line GRPC_SHADOW_ERR_get_error_line +#define ERR_get_error_line_data GRPC_SHADOW_ERR_get_error_line_data +#define ERR_get_next_error_library GRPC_SHADOW_ERR_get_next_error_library +#define ERR_lib_error_string GRPC_SHADOW_ERR_lib_error_string +#define ERR_load_BIO_strings GRPC_SHADOW_ERR_load_BIO_strings +#define ERR_load_ERR_strings GRPC_SHADOW_ERR_load_ERR_strings +#define ERR_load_crypto_strings GRPC_SHADOW_ERR_load_crypto_strings +#define ERR_peek_error GRPC_SHADOW_ERR_peek_error +#define ERR_peek_error_line GRPC_SHADOW_ERR_peek_error_line +#define ERR_peek_error_line_data GRPC_SHADOW_ERR_peek_error_line_data +#define ERR_peek_last_error GRPC_SHADOW_ERR_peek_last_error +#define ERR_peek_last_error_line GRPC_SHADOW_ERR_peek_last_error_line +#define ERR_peek_last_error_line_data GRPC_SHADOW_ERR_peek_last_error_line_data +#define ERR_pop_to_mark GRPC_SHADOW_ERR_pop_to_mark +#define ERR_print_errors_cb GRPC_SHADOW_ERR_print_errors_cb +#define ERR_print_errors_fp GRPC_SHADOW_ERR_print_errors_fp +#define ERR_put_error GRPC_SHADOW_ERR_put_error +#define ERR_reason_error_string GRPC_SHADOW_ERR_reason_error_string +#define ERR_remove_state GRPC_SHADOW_ERR_remove_state +#define ERR_remove_thread_state GRPC_SHADOW_ERR_remove_thread_state +#define ERR_restore_state GRPC_SHADOW_ERR_restore_state +#define ERR_save_state GRPC_SHADOW_ERR_save_state +#define ERR_set_mark GRPC_SHADOW_ERR_set_mark +#define kOpenSSLReasonStringData GRPC_SHADOW_kOpenSSLReasonStringData +#define kOpenSSLReasonValues GRPC_SHADOW_kOpenSSLReasonValues +#define kOpenSSLReasonValuesLen GRPC_SHADOW_kOpenSSLReasonValuesLen +#define EVP_DecodeBase64 GRPC_SHADOW_EVP_DecodeBase64 +#define EVP_DecodeBlock GRPC_SHADOW_EVP_DecodeBlock +#define EVP_DecodeFinal GRPC_SHADOW_EVP_DecodeFinal +#define EVP_DecodeInit GRPC_SHADOW_EVP_DecodeInit +#define EVP_DecodeUpdate GRPC_SHADOW_EVP_DecodeUpdate +#define EVP_DecodedLength GRPC_SHADOW_EVP_DecodedLength +#define EVP_EncodeBlock GRPC_SHADOW_EVP_EncodeBlock +#define EVP_EncodeFinal GRPC_SHADOW_EVP_EncodeFinal +#define EVP_EncodeInit GRPC_SHADOW_EVP_EncodeInit +#define EVP_EncodeUpdate GRPC_SHADOW_EVP_EncodeUpdate +#define EVP_EncodedLength GRPC_SHADOW_EVP_EncodedLength +#define CBB_finish_i2d GRPC_SHADOW_CBB_finish_i2d +#define CBS_asn1_ber_to_der GRPC_SHADOW_CBS_asn1_ber_to_der +#define CBS_get_asn1_implicit_string GRPC_SHADOW_CBS_get_asn1_implicit_string +#define CBS_asn1_bitstring_has_bit GRPC_SHADOW_CBS_asn1_bitstring_has_bit +#define CBS_asn1_oid_to_text GRPC_SHADOW_CBS_asn1_oid_to_text +#define CBS_contains_zero_byte GRPC_SHADOW_CBS_contains_zero_byte +#define CBS_copy_bytes GRPC_SHADOW_CBS_copy_bytes +#define CBS_data GRPC_SHADOW_CBS_data +#define CBS_get_any_asn1 GRPC_SHADOW_CBS_get_any_asn1 +#define CBS_get_any_asn1_element GRPC_SHADOW_CBS_get_any_asn1_element +#define CBS_get_any_ber_asn1_element GRPC_SHADOW_CBS_get_any_ber_asn1_element +#define CBS_get_asn1 GRPC_SHADOW_CBS_get_asn1 +#define CBS_get_asn1_bool GRPC_SHADOW_CBS_get_asn1_bool +#define CBS_get_asn1_element GRPC_SHADOW_CBS_get_asn1_element +#define CBS_get_asn1_uint64 GRPC_SHADOW_CBS_get_asn1_uint64 +#define CBS_get_bytes GRPC_SHADOW_CBS_get_bytes +#define CBS_get_last_u8 GRPC_SHADOW_CBS_get_last_u8 +#define CBS_get_optional_asn1 GRPC_SHADOW_CBS_get_optional_asn1 +#define CBS_get_optional_asn1_bool GRPC_SHADOW_CBS_get_optional_asn1_bool +#define CBS_get_optional_asn1_octet_string GRPC_SHADOW_CBS_get_optional_asn1_octet_string +#define CBS_get_optional_asn1_uint64 GRPC_SHADOW_CBS_get_optional_asn1_uint64 +#define CBS_get_u16 GRPC_SHADOW_CBS_get_u16 +#define CBS_get_u16_length_prefixed GRPC_SHADOW_CBS_get_u16_length_prefixed +#define CBS_get_u24 GRPC_SHADOW_CBS_get_u24 +#define CBS_get_u24_length_prefixed GRPC_SHADOW_CBS_get_u24_length_prefixed +#define CBS_get_u32 GRPC_SHADOW_CBS_get_u32 +#define CBS_get_u8 GRPC_SHADOW_CBS_get_u8 +#define CBS_get_u8_length_prefixed GRPC_SHADOW_CBS_get_u8_length_prefixed +#define CBS_init GRPC_SHADOW_CBS_init +#define CBS_is_valid_asn1_bitstring GRPC_SHADOW_CBS_is_valid_asn1_bitstring +#define CBS_len GRPC_SHADOW_CBS_len +#define CBS_mem_equal GRPC_SHADOW_CBS_mem_equal +#define CBS_peek_asn1_tag GRPC_SHADOW_CBS_peek_asn1_tag +#define CBS_skip GRPC_SHADOW_CBS_skip +#define CBS_stow GRPC_SHADOW_CBS_stow +#define CBS_strdup GRPC_SHADOW_CBS_strdup +#define CBB_add_asn1 GRPC_SHADOW_CBB_add_asn1 +#define CBB_add_asn1_bool GRPC_SHADOW_CBB_add_asn1_bool +#define CBB_add_asn1_octet_string GRPC_SHADOW_CBB_add_asn1_octet_string +#define CBB_add_asn1_oid_from_text GRPC_SHADOW_CBB_add_asn1_oid_from_text +#define CBB_add_asn1_uint64 GRPC_SHADOW_CBB_add_asn1_uint64 +#define CBB_add_bytes GRPC_SHADOW_CBB_add_bytes +#define CBB_add_space GRPC_SHADOW_CBB_add_space +#define CBB_add_u16 GRPC_SHADOW_CBB_add_u16 +#define CBB_add_u16_length_prefixed GRPC_SHADOW_CBB_add_u16_length_prefixed +#define CBB_add_u24 GRPC_SHADOW_CBB_add_u24 +#define CBB_add_u24_length_prefixed GRPC_SHADOW_CBB_add_u24_length_prefixed +#define CBB_add_u32 GRPC_SHADOW_CBB_add_u32 +#define CBB_add_u8 GRPC_SHADOW_CBB_add_u8 +#define CBB_add_u8_length_prefixed GRPC_SHADOW_CBB_add_u8_length_prefixed +#define CBB_cleanup GRPC_SHADOW_CBB_cleanup +#define CBB_data GRPC_SHADOW_CBB_data +#define CBB_did_write GRPC_SHADOW_CBB_did_write +#define CBB_discard_child GRPC_SHADOW_CBB_discard_child +#define CBB_finish GRPC_SHADOW_CBB_finish +#define CBB_flush GRPC_SHADOW_CBB_flush +#define CBB_flush_asn1_set_of GRPC_SHADOW_CBB_flush_asn1_set_of +#define CBB_init GRPC_SHADOW_CBB_init +#define CBB_init_fixed GRPC_SHADOW_CBB_init_fixed +#define CBB_len GRPC_SHADOW_CBB_len +#define CBB_reserve GRPC_SHADOW_CBB_reserve +#define CBB_zero GRPC_SHADOW_CBB_zero +#define CRYPTO_BUFFER_POOL_free GRPC_SHADOW_CRYPTO_BUFFER_POOL_free +#define CRYPTO_BUFFER_POOL_new GRPC_SHADOW_CRYPTO_BUFFER_POOL_new +#define CRYPTO_BUFFER_data GRPC_SHADOW_CRYPTO_BUFFER_data +#define CRYPTO_BUFFER_free GRPC_SHADOW_CRYPTO_BUFFER_free +#define CRYPTO_BUFFER_init_CBS GRPC_SHADOW_CRYPTO_BUFFER_init_CBS +#define CRYPTO_BUFFER_len GRPC_SHADOW_CRYPTO_BUFFER_len +#define CRYPTO_BUFFER_new GRPC_SHADOW_CRYPTO_BUFFER_new +#define CRYPTO_BUFFER_new_from_CBS GRPC_SHADOW_CRYPTO_BUFFER_new_from_CBS +#define CRYPTO_BUFFER_up_ref GRPC_SHADOW_CRYPTO_BUFFER_up_ref +#define AES_cbc_encrypt GRPC_SHADOW_AES_cbc_encrypt +#define AES_cfb128_encrypt GRPC_SHADOW_AES_cfb128_encrypt +#define AES_ctr128_encrypt GRPC_SHADOW_AES_ctr128_encrypt +#define AES_decrypt GRPC_SHADOW_AES_decrypt +#define AES_ecb_encrypt GRPC_SHADOW_AES_ecb_encrypt +#define AES_encrypt GRPC_SHADOW_AES_encrypt +#define AES_ofb128_encrypt GRPC_SHADOW_AES_ofb128_encrypt +#define AES_set_decrypt_key GRPC_SHADOW_AES_set_decrypt_key +#define AES_set_encrypt_key GRPC_SHADOW_AES_set_encrypt_key +#define AES_unwrap_key GRPC_SHADOW_AES_unwrap_key +#define AES_wrap_key GRPC_SHADOW_AES_wrap_key +#define BN_BLINDING_convert GRPC_SHADOW_BN_BLINDING_convert +#define BN_BLINDING_free GRPC_SHADOW_BN_BLINDING_free +#define BN_BLINDING_invert GRPC_SHADOW_BN_BLINDING_invert +#define BN_BLINDING_new GRPC_SHADOW_BN_BLINDING_new +#define BN_CTX_end GRPC_SHADOW_BN_CTX_end +#define BN_CTX_free GRPC_SHADOW_BN_CTX_free +#define BN_CTX_get GRPC_SHADOW_BN_CTX_get +#define BN_CTX_new GRPC_SHADOW_BN_CTX_new +#define BN_CTX_start GRPC_SHADOW_BN_CTX_start +#define BN_GENCB_call GRPC_SHADOW_BN_GENCB_call +#define BN_GENCB_set GRPC_SHADOW_BN_GENCB_set +#define BN_MONT_CTX_copy GRPC_SHADOW_BN_MONT_CTX_copy +#define BN_MONT_CTX_free GRPC_SHADOW_BN_MONT_CTX_free +#define BN_MONT_CTX_new GRPC_SHADOW_BN_MONT_CTX_new +#define BN_MONT_CTX_new_for_modulus GRPC_SHADOW_BN_MONT_CTX_new_for_modulus +#define BN_MONT_CTX_set GRPC_SHADOW_BN_MONT_CTX_set +#define BN_MONT_CTX_set_locked GRPC_SHADOW_BN_MONT_CTX_set_locked +#define BN_abs_is_word GRPC_SHADOW_BN_abs_is_word +#define BN_add GRPC_SHADOW_BN_add +#define BN_add_word GRPC_SHADOW_BN_add_word +#define BN_bin2bn GRPC_SHADOW_BN_bin2bn +#define BN_bn2bin GRPC_SHADOW_BN_bn2bin +#define BN_bn2bin_padded GRPC_SHADOW_BN_bn2bin_padded +#define BN_bn2le_padded GRPC_SHADOW_BN_bn2le_padded +#define BN_clear GRPC_SHADOW_BN_clear +#define BN_clear_bit GRPC_SHADOW_BN_clear_bit +#define BN_clear_free GRPC_SHADOW_BN_clear_free +#define BN_cmp GRPC_SHADOW_BN_cmp +#define BN_cmp_word GRPC_SHADOW_BN_cmp_word +#define BN_copy GRPC_SHADOW_BN_copy +#define BN_count_low_zero_bits GRPC_SHADOW_BN_count_low_zero_bits +#define BN_div GRPC_SHADOW_BN_div +#define BN_div_word GRPC_SHADOW_BN_div_word +#define BN_dup GRPC_SHADOW_BN_dup +#define BN_enhanced_miller_rabin_primality_test GRPC_SHADOW_BN_enhanced_miller_rabin_primality_test +#define BN_equal_consttime GRPC_SHADOW_BN_equal_consttime +#define BN_exp GRPC_SHADOW_BN_exp +#define BN_free GRPC_SHADOW_BN_free +#define BN_from_montgomery GRPC_SHADOW_BN_from_montgomery +#define BN_gcd GRPC_SHADOW_BN_gcd +#define BN_generate_prime_ex GRPC_SHADOW_BN_generate_prime_ex +#define BN_get_u64 GRPC_SHADOW_BN_get_u64 +#define BN_get_word GRPC_SHADOW_BN_get_word +#define BN_init GRPC_SHADOW_BN_init +#define BN_is_bit_set GRPC_SHADOW_BN_is_bit_set +#define BN_is_negative GRPC_SHADOW_BN_is_negative +#define BN_is_odd GRPC_SHADOW_BN_is_odd +#define BN_is_one GRPC_SHADOW_BN_is_one +#define BN_is_pow2 GRPC_SHADOW_BN_is_pow2 +#define BN_is_prime_ex GRPC_SHADOW_BN_is_prime_ex +#define BN_is_prime_fasttest_ex GRPC_SHADOW_BN_is_prime_fasttest_ex +#define BN_is_word GRPC_SHADOW_BN_is_word +#define BN_is_zero GRPC_SHADOW_BN_is_zero +#define BN_le2bn GRPC_SHADOW_BN_le2bn +#define BN_lshift GRPC_SHADOW_BN_lshift +#define BN_lshift1 GRPC_SHADOW_BN_lshift1 +#define BN_mask_bits GRPC_SHADOW_BN_mask_bits +#define BN_mod_add GRPC_SHADOW_BN_mod_add +#define BN_mod_add_quick GRPC_SHADOW_BN_mod_add_quick +#define BN_mod_exp GRPC_SHADOW_BN_mod_exp +#define BN_mod_exp2_mont GRPC_SHADOW_BN_mod_exp2_mont +#define BN_mod_exp_mont GRPC_SHADOW_BN_mod_exp_mont +#define BN_mod_exp_mont_consttime GRPC_SHADOW_BN_mod_exp_mont_consttime +#define BN_mod_exp_mont_word GRPC_SHADOW_BN_mod_exp_mont_word +#define BN_mod_inverse GRPC_SHADOW_BN_mod_inverse +#define BN_mod_inverse_blinded GRPC_SHADOW_BN_mod_inverse_blinded +#define BN_mod_inverse_odd GRPC_SHADOW_BN_mod_inverse_odd +#define BN_mod_lshift GRPC_SHADOW_BN_mod_lshift +#define BN_mod_lshift1 GRPC_SHADOW_BN_mod_lshift1 +#define BN_mod_lshift1_quick GRPC_SHADOW_BN_mod_lshift1_quick +#define BN_mod_lshift_quick GRPC_SHADOW_BN_mod_lshift_quick +#define BN_mod_mul GRPC_SHADOW_BN_mod_mul +#define BN_mod_mul_montgomery GRPC_SHADOW_BN_mod_mul_montgomery +#define BN_mod_pow2 GRPC_SHADOW_BN_mod_pow2 +#define BN_mod_sqr GRPC_SHADOW_BN_mod_sqr +#define BN_mod_sqrt GRPC_SHADOW_BN_mod_sqrt +#define BN_mod_sub GRPC_SHADOW_BN_mod_sub +#define BN_mod_sub_quick GRPC_SHADOW_BN_mod_sub_quick +#define BN_mod_word GRPC_SHADOW_BN_mod_word +#define BN_mul GRPC_SHADOW_BN_mul +#define BN_mul_word GRPC_SHADOW_BN_mul_word +#define BN_new GRPC_SHADOW_BN_new +#define BN_nnmod GRPC_SHADOW_BN_nnmod +#define BN_nnmod_pow2 GRPC_SHADOW_BN_nnmod_pow2 +#define BN_num_bits GRPC_SHADOW_BN_num_bits +#define BN_num_bits_word GRPC_SHADOW_BN_num_bits_word +#define BN_num_bytes GRPC_SHADOW_BN_num_bytes +#define BN_one GRPC_SHADOW_BN_one +#define BN_primality_test GRPC_SHADOW_BN_primality_test +#define BN_pseudo_rand GRPC_SHADOW_BN_pseudo_rand +#define BN_pseudo_rand_range GRPC_SHADOW_BN_pseudo_rand_range +#define BN_rand GRPC_SHADOW_BN_rand +#define BN_rand_range GRPC_SHADOW_BN_rand_range +#define BN_rand_range_ex GRPC_SHADOW_BN_rand_range_ex +#define BN_rshift GRPC_SHADOW_BN_rshift +#define BN_rshift1 GRPC_SHADOW_BN_rshift1 +#define BN_set_bit GRPC_SHADOW_BN_set_bit +#define BN_set_negative GRPC_SHADOW_BN_set_negative +#define BN_set_u64 GRPC_SHADOW_BN_set_u64 +#define BN_set_word GRPC_SHADOW_BN_set_word +#define BN_sqr GRPC_SHADOW_BN_sqr +#define BN_sqrt GRPC_SHADOW_BN_sqrt +#define BN_sub GRPC_SHADOW_BN_sub +#define BN_sub_word GRPC_SHADOW_BN_sub_word +#define BN_to_montgomery GRPC_SHADOW_BN_to_montgomery +#define BN_uadd GRPC_SHADOW_BN_uadd +#define BN_ucmp GRPC_SHADOW_BN_ucmp +#define BN_usub GRPC_SHADOW_BN_usub +#define BN_value_one GRPC_SHADOW_BN_value_one +#define BN_zero GRPC_SHADOW_BN_zero +#define BORINGSSL_self_test GRPC_SHADOW_BORINGSSL_self_test +#define CRYPTO_POLYVAL_finish GRPC_SHADOW_CRYPTO_POLYVAL_finish +#define CRYPTO_POLYVAL_init GRPC_SHADOW_CRYPTO_POLYVAL_init +#define CRYPTO_POLYVAL_update_blocks GRPC_SHADOW_CRYPTO_POLYVAL_update_blocks +#define CRYPTO_cbc128_decrypt GRPC_SHADOW_CRYPTO_cbc128_decrypt +#define CRYPTO_cbc128_encrypt GRPC_SHADOW_CRYPTO_cbc128_encrypt +#define CRYPTO_ccm128_decrypt GRPC_SHADOW_CRYPTO_ccm128_decrypt +#define CRYPTO_ccm128_encrypt GRPC_SHADOW_CRYPTO_ccm128_encrypt +#define CRYPTO_ccm128_init GRPC_SHADOW_CRYPTO_ccm128_init +#define CRYPTO_ccm128_max_input GRPC_SHADOW_CRYPTO_ccm128_max_input +#define CRYPTO_cfb128_1_encrypt GRPC_SHADOW_CRYPTO_cfb128_1_encrypt +#define CRYPTO_cfb128_8_encrypt GRPC_SHADOW_CRYPTO_cfb128_8_encrypt +#define CRYPTO_cfb128_encrypt GRPC_SHADOW_CRYPTO_cfb128_encrypt +#define CRYPTO_ctr128_encrypt GRPC_SHADOW_CRYPTO_ctr128_encrypt +#define CRYPTO_ctr128_encrypt_ctr32 GRPC_SHADOW_CRYPTO_ctr128_encrypt_ctr32 +#define CRYPTO_gcm128_aad GRPC_SHADOW_CRYPTO_gcm128_aad +#define CRYPTO_gcm128_decrypt GRPC_SHADOW_CRYPTO_gcm128_decrypt +#define CRYPTO_gcm128_decrypt_ctr32 GRPC_SHADOW_CRYPTO_gcm128_decrypt_ctr32 +#define CRYPTO_gcm128_encrypt GRPC_SHADOW_CRYPTO_gcm128_encrypt +#define CRYPTO_gcm128_encrypt_ctr32 GRPC_SHADOW_CRYPTO_gcm128_encrypt_ctr32 +#define CRYPTO_gcm128_finish GRPC_SHADOW_CRYPTO_gcm128_finish +#define CRYPTO_gcm128_init GRPC_SHADOW_CRYPTO_gcm128_init +#define CRYPTO_gcm128_setiv GRPC_SHADOW_CRYPTO_gcm128_setiv +#define CRYPTO_gcm128_tag GRPC_SHADOW_CRYPTO_gcm128_tag +#define CRYPTO_ghash_init GRPC_SHADOW_CRYPTO_ghash_init +#define CRYPTO_ofb128_encrypt GRPC_SHADOW_CRYPTO_ofb128_encrypt +#define CRYPTO_sysrand GRPC_SHADOW_CRYPTO_sysrand +#define CRYPTO_tls1_prf GRPC_SHADOW_CRYPTO_tls1_prf +#define CTR_DRBG_clear GRPC_SHADOW_CTR_DRBG_clear +#define CTR_DRBG_generate GRPC_SHADOW_CTR_DRBG_generate +#define CTR_DRBG_init GRPC_SHADOW_CTR_DRBG_init +#define CTR_DRBG_reseed GRPC_SHADOW_CTR_DRBG_reseed +#define DES_decrypt3 GRPC_SHADOW_DES_decrypt3 +#define DES_ecb3_encrypt GRPC_SHADOW_DES_ecb3_encrypt +#define DES_ecb_encrypt GRPC_SHADOW_DES_ecb_encrypt +#define DES_ede2_cbc_encrypt GRPC_SHADOW_DES_ede2_cbc_encrypt +#define DES_ede3_cbc_encrypt GRPC_SHADOW_DES_ede3_cbc_encrypt +#define DES_encrypt3 GRPC_SHADOW_DES_encrypt3 +#define DES_ncbc_encrypt GRPC_SHADOW_DES_ncbc_encrypt +#define DES_set_key GRPC_SHADOW_DES_set_key +#define DES_set_key_unchecked GRPC_SHADOW_DES_set_key_unchecked +#define DES_set_odd_parity GRPC_SHADOW_DES_set_odd_parity +#define ECDSA_SIG_free GRPC_SHADOW_ECDSA_SIG_free +#define ECDSA_SIG_get0 GRPC_SHADOW_ECDSA_SIG_get0 +#define ECDSA_SIG_new GRPC_SHADOW_ECDSA_SIG_new +#define ECDSA_SIG_set0 GRPC_SHADOW_ECDSA_SIG_set0 +#define ECDSA_do_sign GRPC_SHADOW_ECDSA_do_sign +#define ECDSA_do_verify GRPC_SHADOW_ECDSA_do_verify +#define EC_GFp_mont_method GRPC_SHADOW_EC_GFp_mont_method +#define EC_GFp_nistp224_method GRPC_SHADOW_EC_GFp_nistp224_method +#define EC_GFp_nistp256_method GRPC_SHADOW_EC_GFp_nistp256_method +#define EC_GFp_nistz256_method GRPC_SHADOW_EC_GFp_nistz256_method +#define EC_GROUP_cmp GRPC_SHADOW_EC_GROUP_cmp +#define EC_GROUP_dup GRPC_SHADOW_EC_GROUP_dup +#define EC_GROUP_free GRPC_SHADOW_EC_GROUP_free +#define EC_GROUP_get0_generator GRPC_SHADOW_EC_GROUP_get0_generator +#define EC_GROUP_get0_order GRPC_SHADOW_EC_GROUP_get0_order +#define EC_GROUP_get_cofactor GRPC_SHADOW_EC_GROUP_get_cofactor +#define EC_GROUP_get_curve_GFp GRPC_SHADOW_EC_GROUP_get_curve_GFp +#define EC_GROUP_get_curve_name GRPC_SHADOW_EC_GROUP_get_curve_name +#define EC_GROUP_get_degree GRPC_SHADOW_EC_GROUP_get_degree +#define EC_GROUP_get_order GRPC_SHADOW_EC_GROUP_get_order +#define EC_GROUP_method_of GRPC_SHADOW_EC_GROUP_method_of +#define EC_GROUP_new_by_curve_name GRPC_SHADOW_EC_GROUP_new_by_curve_name +#define EC_GROUP_new_curve_GFp GRPC_SHADOW_EC_GROUP_new_curve_GFp +#define EC_GROUP_set_asn1_flag GRPC_SHADOW_EC_GROUP_set_asn1_flag +#define EC_GROUP_set_generator GRPC_SHADOW_EC_GROUP_set_generator +#define EC_GROUP_set_point_conversion_form GRPC_SHADOW_EC_GROUP_set_point_conversion_form +#define EC_KEY_check_fips GRPC_SHADOW_EC_KEY_check_fips +#define EC_KEY_check_key GRPC_SHADOW_EC_KEY_check_key +#define EC_KEY_dup GRPC_SHADOW_EC_KEY_dup +#define EC_KEY_free GRPC_SHADOW_EC_KEY_free +#define EC_KEY_generate_key GRPC_SHADOW_EC_KEY_generate_key +#define EC_KEY_generate_key_fips GRPC_SHADOW_EC_KEY_generate_key_fips +#define EC_KEY_get0_group GRPC_SHADOW_EC_KEY_get0_group +#define EC_KEY_get0_private_key GRPC_SHADOW_EC_KEY_get0_private_key +#define EC_KEY_get0_public_key GRPC_SHADOW_EC_KEY_get0_public_key +#define EC_KEY_get_conv_form GRPC_SHADOW_EC_KEY_get_conv_form +#define EC_KEY_get_enc_flags GRPC_SHADOW_EC_KEY_get_enc_flags +#define EC_KEY_get_ex_data GRPC_SHADOW_EC_KEY_get_ex_data +#define EC_KEY_get_ex_new_index GRPC_SHADOW_EC_KEY_get_ex_new_index +#define EC_KEY_is_opaque GRPC_SHADOW_EC_KEY_is_opaque +#define EC_KEY_new GRPC_SHADOW_EC_KEY_new +#define EC_KEY_new_by_curve_name GRPC_SHADOW_EC_KEY_new_by_curve_name +#define EC_KEY_new_method GRPC_SHADOW_EC_KEY_new_method +#define EC_KEY_set_asn1_flag GRPC_SHADOW_EC_KEY_set_asn1_flag +#define EC_KEY_set_conv_form GRPC_SHADOW_EC_KEY_set_conv_form +#define EC_KEY_set_enc_flags GRPC_SHADOW_EC_KEY_set_enc_flags +#define EC_KEY_set_ex_data GRPC_SHADOW_EC_KEY_set_ex_data +#define EC_KEY_set_group GRPC_SHADOW_EC_KEY_set_group +#define EC_KEY_set_private_key GRPC_SHADOW_EC_KEY_set_private_key +#define EC_KEY_set_public_key GRPC_SHADOW_EC_KEY_set_public_key +#define EC_KEY_set_public_key_affine_coordinates GRPC_SHADOW_EC_KEY_set_public_key_affine_coordinates +#define EC_KEY_up_ref GRPC_SHADOW_EC_KEY_up_ref +#define EC_METHOD_get_field_type GRPC_SHADOW_EC_METHOD_get_field_type +#define EC_POINT_add GRPC_SHADOW_EC_POINT_add +#define EC_POINT_clear_free GRPC_SHADOW_EC_POINT_clear_free +#define EC_POINT_cmp GRPC_SHADOW_EC_POINT_cmp +#define EC_POINT_copy GRPC_SHADOW_EC_POINT_copy +#define EC_POINT_dbl GRPC_SHADOW_EC_POINT_dbl +#define EC_POINT_dup GRPC_SHADOW_EC_POINT_dup +#define EC_POINT_free GRPC_SHADOW_EC_POINT_free +#define EC_POINT_get_affine_coordinates_GFp GRPC_SHADOW_EC_POINT_get_affine_coordinates_GFp +#define EC_POINT_invert GRPC_SHADOW_EC_POINT_invert +#define EC_POINT_is_at_infinity GRPC_SHADOW_EC_POINT_is_at_infinity +#define EC_POINT_is_on_curve GRPC_SHADOW_EC_POINT_is_on_curve +#define EC_POINT_make_affine GRPC_SHADOW_EC_POINT_make_affine +#define EC_POINT_mul GRPC_SHADOW_EC_POINT_mul +#define EC_POINT_new GRPC_SHADOW_EC_POINT_new +#define EC_POINT_oct2point GRPC_SHADOW_EC_POINT_oct2point +#define EC_POINT_point2oct GRPC_SHADOW_EC_POINT_point2oct +#define EC_POINT_set_affine_coordinates_GFp GRPC_SHADOW_EC_POINT_set_affine_coordinates_GFp +#define EC_POINT_set_compressed_coordinates_GFp GRPC_SHADOW_EC_POINT_set_compressed_coordinates_GFp +#define EC_POINT_set_to_infinity GRPC_SHADOW_EC_POINT_set_to_infinity +#define EC_POINTs_make_affine GRPC_SHADOW_EC_POINTs_make_affine +#define EC_get_builtin_curves GRPC_SHADOW_EC_get_builtin_curves +#define EVP_AEAD_CTX_aead GRPC_SHADOW_EVP_AEAD_CTX_aead +#define EVP_AEAD_CTX_cleanup GRPC_SHADOW_EVP_AEAD_CTX_cleanup +#define EVP_AEAD_CTX_free GRPC_SHADOW_EVP_AEAD_CTX_free +#define EVP_AEAD_CTX_get_iv GRPC_SHADOW_EVP_AEAD_CTX_get_iv +#define EVP_AEAD_CTX_init GRPC_SHADOW_EVP_AEAD_CTX_init +#define EVP_AEAD_CTX_init_with_direction GRPC_SHADOW_EVP_AEAD_CTX_init_with_direction +#define EVP_AEAD_CTX_new GRPC_SHADOW_EVP_AEAD_CTX_new +#define EVP_AEAD_CTX_open GRPC_SHADOW_EVP_AEAD_CTX_open +#define EVP_AEAD_CTX_open_gather GRPC_SHADOW_EVP_AEAD_CTX_open_gather +#define EVP_AEAD_CTX_seal GRPC_SHADOW_EVP_AEAD_CTX_seal +#define EVP_AEAD_CTX_seal_scatter GRPC_SHADOW_EVP_AEAD_CTX_seal_scatter +#define EVP_AEAD_CTX_tag_len GRPC_SHADOW_EVP_AEAD_CTX_tag_len +#define EVP_AEAD_CTX_zero GRPC_SHADOW_EVP_AEAD_CTX_zero +#define EVP_AEAD_key_length GRPC_SHADOW_EVP_AEAD_key_length +#define EVP_AEAD_max_overhead GRPC_SHADOW_EVP_AEAD_max_overhead +#define EVP_AEAD_max_tag_len GRPC_SHADOW_EVP_AEAD_max_tag_len +#define EVP_AEAD_nonce_length GRPC_SHADOW_EVP_AEAD_nonce_length +#define EVP_CIPHER_CTX_block_size GRPC_SHADOW_EVP_CIPHER_CTX_block_size +#define EVP_CIPHER_CTX_cipher GRPC_SHADOW_EVP_CIPHER_CTX_cipher +#define EVP_CIPHER_CTX_cleanup GRPC_SHADOW_EVP_CIPHER_CTX_cleanup +#define EVP_CIPHER_CTX_copy GRPC_SHADOW_EVP_CIPHER_CTX_copy +#define EVP_CIPHER_CTX_ctrl GRPC_SHADOW_EVP_CIPHER_CTX_ctrl +#define EVP_CIPHER_CTX_flags GRPC_SHADOW_EVP_CIPHER_CTX_flags +#define EVP_CIPHER_CTX_free GRPC_SHADOW_EVP_CIPHER_CTX_free +#define EVP_CIPHER_CTX_get_app_data GRPC_SHADOW_EVP_CIPHER_CTX_get_app_data +#define EVP_CIPHER_CTX_init GRPC_SHADOW_EVP_CIPHER_CTX_init +#define EVP_CIPHER_CTX_iv_length GRPC_SHADOW_EVP_CIPHER_CTX_iv_length +#define EVP_CIPHER_CTX_key_length GRPC_SHADOW_EVP_CIPHER_CTX_key_length +#define EVP_CIPHER_CTX_mode GRPC_SHADOW_EVP_CIPHER_CTX_mode +#define EVP_CIPHER_CTX_new GRPC_SHADOW_EVP_CIPHER_CTX_new +#define EVP_CIPHER_CTX_nid GRPC_SHADOW_EVP_CIPHER_CTX_nid +#define EVP_CIPHER_CTX_reset GRPC_SHADOW_EVP_CIPHER_CTX_reset +#define EVP_CIPHER_CTX_set_app_data GRPC_SHADOW_EVP_CIPHER_CTX_set_app_data +#define EVP_CIPHER_CTX_set_flags GRPC_SHADOW_EVP_CIPHER_CTX_set_flags +#define EVP_CIPHER_CTX_set_key_length GRPC_SHADOW_EVP_CIPHER_CTX_set_key_length +#define EVP_CIPHER_CTX_set_padding GRPC_SHADOW_EVP_CIPHER_CTX_set_padding +#define EVP_CIPHER_block_size GRPC_SHADOW_EVP_CIPHER_block_size +#define EVP_CIPHER_flags GRPC_SHADOW_EVP_CIPHER_flags +#define EVP_CIPHER_iv_length GRPC_SHADOW_EVP_CIPHER_iv_length +#define EVP_CIPHER_key_length GRPC_SHADOW_EVP_CIPHER_key_length +#define EVP_CIPHER_mode GRPC_SHADOW_EVP_CIPHER_mode +#define EVP_CIPHER_nid GRPC_SHADOW_EVP_CIPHER_nid +#define EVP_Cipher GRPC_SHADOW_EVP_Cipher +#define EVP_CipherFinal_ex GRPC_SHADOW_EVP_CipherFinal_ex +#define EVP_CipherInit GRPC_SHADOW_EVP_CipherInit +#define EVP_CipherInit_ex GRPC_SHADOW_EVP_CipherInit_ex +#define EVP_CipherUpdate GRPC_SHADOW_EVP_CipherUpdate +#define EVP_DecryptFinal_ex GRPC_SHADOW_EVP_DecryptFinal_ex +#define EVP_DecryptInit GRPC_SHADOW_EVP_DecryptInit +#define EVP_DecryptInit_ex GRPC_SHADOW_EVP_DecryptInit_ex +#define EVP_DecryptUpdate GRPC_SHADOW_EVP_DecryptUpdate +#define EVP_Digest GRPC_SHADOW_EVP_Digest +#define EVP_DigestFinal GRPC_SHADOW_EVP_DigestFinal +#define EVP_DigestFinal_ex GRPC_SHADOW_EVP_DigestFinal_ex +#define EVP_DigestInit GRPC_SHADOW_EVP_DigestInit +#define EVP_DigestInit_ex GRPC_SHADOW_EVP_DigestInit_ex +#define EVP_DigestUpdate GRPC_SHADOW_EVP_DigestUpdate +#define EVP_EncryptFinal_ex GRPC_SHADOW_EVP_EncryptFinal_ex +#define EVP_EncryptInit GRPC_SHADOW_EVP_EncryptInit +#define EVP_EncryptInit_ex GRPC_SHADOW_EVP_EncryptInit_ex +#define EVP_EncryptUpdate GRPC_SHADOW_EVP_EncryptUpdate +#define EVP_MD_CTX_block_size GRPC_SHADOW_EVP_MD_CTX_block_size +#define EVP_MD_CTX_cleanup GRPC_SHADOW_EVP_MD_CTX_cleanup +#define EVP_MD_CTX_copy GRPC_SHADOW_EVP_MD_CTX_copy +#define EVP_MD_CTX_copy_ex GRPC_SHADOW_EVP_MD_CTX_copy_ex +#define EVP_MD_CTX_create GRPC_SHADOW_EVP_MD_CTX_create +#define EVP_MD_CTX_destroy GRPC_SHADOW_EVP_MD_CTX_destroy +#define EVP_MD_CTX_free GRPC_SHADOW_EVP_MD_CTX_free +#define EVP_MD_CTX_init GRPC_SHADOW_EVP_MD_CTX_init +#define EVP_MD_CTX_md GRPC_SHADOW_EVP_MD_CTX_md +#define EVP_MD_CTX_new GRPC_SHADOW_EVP_MD_CTX_new +#define EVP_MD_CTX_reset GRPC_SHADOW_EVP_MD_CTX_reset +#define EVP_MD_CTX_size GRPC_SHADOW_EVP_MD_CTX_size +#define EVP_MD_CTX_type GRPC_SHADOW_EVP_MD_CTX_type +#define EVP_MD_block_size GRPC_SHADOW_EVP_MD_block_size +#define EVP_MD_flags GRPC_SHADOW_EVP_MD_flags +#define EVP_MD_size GRPC_SHADOW_EVP_MD_size +#define EVP_MD_type GRPC_SHADOW_EVP_MD_type +#define EVP_add_cipher_alias GRPC_SHADOW_EVP_add_cipher_alias +#define EVP_add_digest GRPC_SHADOW_EVP_add_digest +#define EVP_aead_aes_128_gcm GRPC_SHADOW_EVP_aead_aes_128_gcm +#define EVP_aead_aes_128_gcm_tls12 GRPC_SHADOW_EVP_aead_aes_128_gcm_tls12 +#define EVP_aead_aes_256_gcm GRPC_SHADOW_EVP_aead_aes_256_gcm +#define EVP_aead_aes_256_gcm_tls12 GRPC_SHADOW_EVP_aead_aes_256_gcm_tls12 +#define EVP_aes_128_cbc GRPC_SHADOW_EVP_aes_128_cbc +#define EVP_aes_128_ctr GRPC_SHADOW_EVP_aes_128_ctr +#define EVP_aes_128_ecb GRPC_SHADOW_EVP_aes_128_ecb +#define EVP_aes_128_gcm GRPC_SHADOW_EVP_aes_128_gcm +#define EVP_aes_128_ofb GRPC_SHADOW_EVP_aes_128_ofb +#define EVP_aes_192_cbc GRPC_SHADOW_EVP_aes_192_cbc +#define EVP_aes_192_ctr GRPC_SHADOW_EVP_aes_192_ctr +#define EVP_aes_192_ecb GRPC_SHADOW_EVP_aes_192_ecb +#define EVP_aes_192_gcm GRPC_SHADOW_EVP_aes_192_gcm +#define EVP_aes_256_cbc GRPC_SHADOW_EVP_aes_256_cbc +#define EVP_aes_256_ctr GRPC_SHADOW_EVP_aes_256_ctr +#define EVP_aes_256_ecb GRPC_SHADOW_EVP_aes_256_ecb +#define EVP_aes_256_gcm GRPC_SHADOW_EVP_aes_256_gcm +#define EVP_aes_256_ofb GRPC_SHADOW_EVP_aes_256_ofb +#define EVP_des_cbc GRPC_SHADOW_EVP_des_cbc +#define EVP_des_ecb GRPC_SHADOW_EVP_des_ecb +#define EVP_des_ede GRPC_SHADOW_EVP_des_ede +#define EVP_des_ede3 GRPC_SHADOW_EVP_des_ede3 +#define EVP_des_ede3_cbc GRPC_SHADOW_EVP_des_ede3_cbc +#define EVP_des_ede_cbc GRPC_SHADOW_EVP_des_ede_cbc +#define EVP_has_aes_hardware GRPC_SHADOW_EVP_has_aes_hardware +#define EVP_md4 GRPC_SHADOW_EVP_md4 +#define EVP_md5 GRPC_SHADOW_EVP_md5 +#define EVP_md5_sha1 GRPC_SHADOW_EVP_md5_sha1 +#define EVP_sha1 GRPC_SHADOW_EVP_sha1 +#define EVP_sha224 GRPC_SHADOW_EVP_sha224 +#define EVP_sha256 GRPC_SHADOW_EVP_sha256 +#define EVP_sha384 GRPC_SHADOW_EVP_sha384 +#define EVP_sha512 GRPC_SHADOW_EVP_sha512 +#define HMAC GRPC_SHADOW_HMAC +#define HMAC_CTX_cleanup GRPC_SHADOW_HMAC_CTX_cleanup +#define HMAC_CTX_copy GRPC_SHADOW_HMAC_CTX_copy +#define HMAC_CTX_copy_ex GRPC_SHADOW_HMAC_CTX_copy_ex +#define HMAC_CTX_free GRPC_SHADOW_HMAC_CTX_free +#define HMAC_CTX_init GRPC_SHADOW_HMAC_CTX_init +#define HMAC_CTX_new GRPC_SHADOW_HMAC_CTX_new +#define HMAC_CTX_reset GRPC_SHADOW_HMAC_CTX_reset +#define HMAC_Final GRPC_SHADOW_HMAC_Final +#define HMAC_Init GRPC_SHADOW_HMAC_Init +#define HMAC_Init_ex GRPC_SHADOW_HMAC_Init_ex +#define HMAC_Update GRPC_SHADOW_HMAC_Update +#define HMAC_size GRPC_SHADOW_HMAC_size +#define MD4 GRPC_SHADOW_MD4 +#define MD4_Final GRPC_SHADOW_MD4_Final +#define MD4_Init GRPC_SHADOW_MD4_Init +#define MD4_Transform GRPC_SHADOW_MD4_Transform +#define MD4_Update GRPC_SHADOW_MD4_Update +#define MD5 GRPC_SHADOW_MD5 +#define MD5_Final GRPC_SHADOW_MD5_Final +#define MD5_Init GRPC_SHADOW_MD5_Init +#define MD5_Transform GRPC_SHADOW_MD5_Transform +#define MD5_Update GRPC_SHADOW_MD5_Update +#define OPENSSL_built_in_curves GRPC_SHADOW_OPENSSL_built_in_curves +#define RAND_bytes GRPC_SHADOW_RAND_bytes +#define RAND_bytes_with_additional_data GRPC_SHADOW_RAND_bytes_with_additional_data +#define RAND_pseudo_bytes GRPC_SHADOW_RAND_pseudo_bytes +#define RAND_set_urandom_fd GRPC_SHADOW_RAND_set_urandom_fd +#define RSAZ_1024_mod_exp_avx2 GRPC_SHADOW_RSAZ_1024_mod_exp_avx2 +#define RSA_add_pkcs1_prefix GRPC_SHADOW_RSA_add_pkcs1_prefix +#define RSA_bits GRPC_SHADOW_RSA_bits +#define RSA_blinding_on GRPC_SHADOW_RSA_blinding_on +#define RSA_check_fips GRPC_SHADOW_RSA_check_fips +#define RSA_check_key GRPC_SHADOW_RSA_check_key +#define RSA_decrypt GRPC_SHADOW_RSA_decrypt +#define RSA_default_method GRPC_SHADOW_RSA_default_method +#define RSA_encrypt GRPC_SHADOW_RSA_encrypt +#define RSA_flags GRPC_SHADOW_RSA_flags +#define RSA_free GRPC_SHADOW_RSA_free +#define RSA_generate_key_ex GRPC_SHADOW_RSA_generate_key_ex +#define RSA_generate_key_fips GRPC_SHADOW_RSA_generate_key_fips +#define RSA_get0_crt_params GRPC_SHADOW_RSA_get0_crt_params +#define RSA_get0_factors GRPC_SHADOW_RSA_get0_factors +#define RSA_get0_key GRPC_SHADOW_RSA_get0_key +#define RSA_get_ex_data GRPC_SHADOW_RSA_get_ex_data +#define RSA_get_ex_new_index GRPC_SHADOW_RSA_get_ex_new_index +#define RSA_is_opaque GRPC_SHADOW_RSA_is_opaque +#define RSA_new GRPC_SHADOW_RSA_new +#define RSA_new_method GRPC_SHADOW_RSA_new_method +#define RSA_padding_add_PKCS1_OAEP_mgf1 GRPC_SHADOW_RSA_padding_add_PKCS1_OAEP_mgf1 +#define RSA_padding_add_PKCS1_PSS_mgf1 GRPC_SHADOW_RSA_padding_add_PKCS1_PSS_mgf1 +#define RSA_padding_add_PKCS1_type_1 GRPC_SHADOW_RSA_padding_add_PKCS1_type_1 +#define RSA_padding_add_PKCS1_type_2 GRPC_SHADOW_RSA_padding_add_PKCS1_type_2 +#define RSA_padding_add_none GRPC_SHADOW_RSA_padding_add_none +#define RSA_padding_check_PKCS1_OAEP_mgf1 GRPC_SHADOW_RSA_padding_check_PKCS1_OAEP_mgf1 +#define RSA_padding_check_PKCS1_type_1 GRPC_SHADOW_RSA_padding_check_PKCS1_type_1 +#define RSA_padding_check_PKCS1_type_2 GRPC_SHADOW_RSA_padding_check_PKCS1_type_2 +#define RSA_private_decrypt GRPC_SHADOW_RSA_private_decrypt +#define RSA_private_encrypt GRPC_SHADOW_RSA_private_encrypt +#define RSA_private_transform GRPC_SHADOW_RSA_private_transform +#define RSA_public_decrypt GRPC_SHADOW_RSA_public_decrypt +#define RSA_public_encrypt GRPC_SHADOW_RSA_public_encrypt +#define RSA_set0_crt_params GRPC_SHADOW_RSA_set0_crt_params +#define RSA_set0_factors GRPC_SHADOW_RSA_set0_factors +#define RSA_set0_key GRPC_SHADOW_RSA_set0_key +#define RSA_set_ex_data GRPC_SHADOW_RSA_set_ex_data +#define RSA_sign GRPC_SHADOW_RSA_sign +#define RSA_sign_pss_mgf1 GRPC_SHADOW_RSA_sign_pss_mgf1 +#define RSA_sign_raw GRPC_SHADOW_RSA_sign_raw +#define RSA_size GRPC_SHADOW_RSA_size +#define RSA_up_ref GRPC_SHADOW_RSA_up_ref +#define RSA_verify GRPC_SHADOW_RSA_verify +#define RSA_verify_PKCS1_PSS_mgf1 GRPC_SHADOW_RSA_verify_PKCS1_PSS_mgf1 +#define RSA_verify_pss_mgf1 GRPC_SHADOW_RSA_verify_pss_mgf1 +#define RSA_verify_raw GRPC_SHADOW_RSA_verify_raw +#define SHA1 GRPC_SHADOW_SHA1 +#define SHA1_Final GRPC_SHADOW_SHA1_Final +#define SHA1_Init GRPC_SHADOW_SHA1_Init +#define SHA1_Transform GRPC_SHADOW_SHA1_Transform +#define SHA1_Update GRPC_SHADOW_SHA1_Update +#define SHA224 GRPC_SHADOW_SHA224 +#define SHA224_Final GRPC_SHADOW_SHA224_Final +#define SHA224_Init GRPC_SHADOW_SHA224_Init +#define SHA224_Update GRPC_SHADOW_SHA224_Update +#define SHA256 GRPC_SHADOW_SHA256 +#define SHA256_Final GRPC_SHADOW_SHA256_Final +#define SHA256_Init GRPC_SHADOW_SHA256_Init +#define SHA256_Transform GRPC_SHADOW_SHA256_Transform +#define SHA256_Update GRPC_SHADOW_SHA256_Update +#define SHA384 GRPC_SHADOW_SHA384 +#define SHA384_Final GRPC_SHADOW_SHA384_Final +#define SHA384_Init GRPC_SHADOW_SHA384_Init +#define SHA384_Update GRPC_SHADOW_SHA384_Update +#define SHA512 GRPC_SHADOW_SHA512 +#define SHA512_Final GRPC_SHADOW_SHA512_Final +#define SHA512_Init GRPC_SHADOW_SHA512_Init +#define SHA512_Transform GRPC_SHADOW_SHA512_Transform +#define SHA512_Update GRPC_SHADOW_SHA512_Update +#define aes_ctr_set_key GRPC_SHADOW_aes_ctr_set_key +#define bn_abs_sub_consttime GRPC_SHADOW_bn_abs_sub_consttime +#define bn_add_words GRPC_SHADOW_bn_add_words +#define bn_copy_words GRPC_SHADOW_bn_copy_words +#define bn_div_consttime GRPC_SHADOW_bn_div_consttime +#define bn_expand GRPC_SHADOW_bn_expand +#define bn_fits_in_words GRPC_SHADOW_bn_fits_in_words +#define bn_from_montgomery_small GRPC_SHADOW_bn_from_montgomery_small +#define bn_in_range_words GRPC_SHADOW_bn_in_range_words +#define bn_is_bit_set_words GRPC_SHADOW_bn_is_bit_set_words +#define bn_is_relatively_prime GRPC_SHADOW_bn_is_relatively_prime +#define bn_jacobi GRPC_SHADOW_bn_jacobi +#define bn_lcm_consttime GRPC_SHADOW_bn_lcm_consttime +#define bn_less_than_montgomery_R GRPC_SHADOW_bn_less_than_montgomery_R +#define bn_less_than_words GRPC_SHADOW_bn_less_than_words +#define bn_minimal_width GRPC_SHADOW_bn_minimal_width +#define bn_mod_add_consttime GRPC_SHADOW_bn_mod_add_consttime +#define bn_mod_exp_base_2_consttime GRPC_SHADOW_bn_mod_exp_base_2_consttime +#define bn_mod_exp_mont_small GRPC_SHADOW_bn_mod_exp_mont_small +#define bn_mod_inverse_consttime GRPC_SHADOW_bn_mod_inverse_consttime +#define bn_mod_inverse_prime GRPC_SHADOW_bn_mod_inverse_prime +#define bn_mod_inverse_prime_mont_small GRPC_SHADOW_bn_mod_inverse_prime_mont_small +#define bn_mod_inverse_secret_prime GRPC_SHADOW_bn_mod_inverse_secret_prime +#define bn_mod_lshift1_consttime GRPC_SHADOW_bn_mod_lshift1_consttime +#define bn_mod_lshift_consttime GRPC_SHADOW_bn_mod_lshift_consttime +#define bn_mod_mul_montgomery_small GRPC_SHADOW_bn_mod_mul_montgomery_small +#define bn_mod_sub_consttime GRPC_SHADOW_bn_mod_sub_consttime +#define bn_mod_u16_consttime GRPC_SHADOW_bn_mod_u16_consttime +#define bn_mont_n0 GRPC_SHADOW_bn_mont_n0 +#define bn_mul_add_words GRPC_SHADOW_bn_mul_add_words +#define bn_mul_comba4 GRPC_SHADOW_bn_mul_comba4 +#define bn_mul_comba8 GRPC_SHADOW_bn_mul_comba8 +#define bn_mul_consttime GRPC_SHADOW_bn_mul_consttime +#define bn_mul_small GRPC_SHADOW_bn_mul_small +#define bn_mul_words GRPC_SHADOW_bn_mul_words +#define bn_odd_number_is_obviously_composite GRPC_SHADOW_bn_odd_number_is_obviously_composite +#define bn_one_to_montgomery GRPC_SHADOW_bn_one_to_montgomery +#define bn_one_to_montgomery_small GRPC_SHADOW_bn_one_to_montgomery_small +#define bn_rand_range_words GRPC_SHADOW_bn_rand_range_words +#define bn_rand_secret_range GRPC_SHADOW_bn_rand_secret_range +#define bn_resize_words GRPC_SHADOW_bn_resize_words +#define bn_rshift1_words GRPC_SHADOW_bn_rshift1_words +#define bn_rshift_secret_shift GRPC_SHADOW_bn_rshift_secret_shift +#define bn_select_words GRPC_SHADOW_bn_select_words +#define bn_set_minimal_width GRPC_SHADOW_bn_set_minimal_width +#define bn_set_words GRPC_SHADOW_bn_set_words +#define bn_sqr_comba4 GRPC_SHADOW_bn_sqr_comba4 +#define bn_sqr_comba8 GRPC_SHADOW_bn_sqr_comba8 +#define bn_sqr_consttime GRPC_SHADOW_bn_sqr_consttime +#define bn_sqr_small GRPC_SHADOW_bn_sqr_small +#define bn_sqr_words GRPC_SHADOW_bn_sqr_words +#define bn_sub_words GRPC_SHADOW_bn_sub_words +#define bn_to_montgomery_small GRPC_SHADOW_bn_to_montgomery_small +#define bn_uadd_consttime GRPC_SHADOW_bn_uadd_consttime +#define bn_usub_consttime GRPC_SHADOW_bn_usub_consttime +#define bn_wexpand GRPC_SHADOW_bn_wexpand +#define crypto_gcm_clmul_enabled GRPC_SHADOW_crypto_gcm_clmul_enabled +#define ec_GFp_mont_field_decode GRPC_SHADOW_ec_GFp_mont_field_decode +#define ec_GFp_mont_field_encode GRPC_SHADOW_ec_GFp_mont_field_encode +#define ec_GFp_mont_field_mul GRPC_SHADOW_ec_GFp_mont_field_mul +#define ec_GFp_mont_field_sqr GRPC_SHADOW_ec_GFp_mont_field_sqr +#define ec_GFp_mont_group_finish GRPC_SHADOW_ec_GFp_mont_group_finish +#define ec_GFp_mont_group_init GRPC_SHADOW_ec_GFp_mont_group_init +#define ec_GFp_mont_group_set_curve GRPC_SHADOW_ec_GFp_mont_group_set_curve +#define ec_GFp_nistp_recode_scalar_bits GRPC_SHADOW_ec_GFp_nistp_recode_scalar_bits +#define ec_GFp_simple_add GRPC_SHADOW_ec_GFp_simple_add +#define ec_GFp_simple_cmp GRPC_SHADOW_ec_GFp_simple_cmp +#define ec_GFp_simple_dbl GRPC_SHADOW_ec_GFp_simple_dbl +#define ec_GFp_simple_field_mul GRPC_SHADOW_ec_GFp_simple_field_mul +#define ec_GFp_simple_field_sqr GRPC_SHADOW_ec_GFp_simple_field_sqr +#define ec_GFp_simple_group_finish GRPC_SHADOW_ec_GFp_simple_group_finish +#define ec_GFp_simple_group_get_curve GRPC_SHADOW_ec_GFp_simple_group_get_curve +#define ec_GFp_simple_group_get_degree GRPC_SHADOW_ec_GFp_simple_group_get_degree +#define ec_GFp_simple_group_init GRPC_SHADOW_ec_GFp_simple_group_init +#define ec_GFp_simple_group_set_curve GRPC_SHADOW_ec_GFp_simple_group_set_curve +#define ec_GFp_simple_invert GRPC_SHADOW_ec_GFp_simple_invert +#define ec_GFp_simple_is_at_infinity GRPC_SHADOW_ec_GFp_simple_is_at_infinity +#define ec_GFp_simple_is_on_curve GRPC_SHADOW_ec_GFp_simple_is_on_curve +#define ec_GFp_simple_make_affine GRPC_SHADOW_ec_GFp_simple_make_affine +#define ec_GFp_simple_point_copy GRPC_SHADOW_ec_GFp_simple_point_copy +#define ec_GFp_simple_point_finish GRPC_SHADOW_ec_GFp_simple_point_finish +#define ec_GFp_simple_point_init GRPC_SHADOW_ec_GFp_simple_point_init +#define ec_GFp_simple_point_set_affine_coordinates GRPC_SHADOW_ec_GFp_simple_point_set_affine_coordinates +#define ec_GFp_simple_point_set_to_infinity GRPC_SHADOW_ec_GFp_simple_point_set_to_infinity +#define ec_GFp_simple_points_make_affine GRPC_SHADOW_ec_GFp_simple_points_make_affine +#define ec_bignum_to_scalar GRPC_SHADOW_ec_bignum_to_scalar +#define ec_bignum_to_scalar_unchecked GRPC_SHADOW_ec_bignum_to_scalar_unchecked +#define ec_compute_wNAF GRPC_SHADOW_ec_compute_wNAF +#define ec_group_new GRPC_SHADOW_ec_group_new +#define ec_point_mul_scalar GRPC_SHADOW_ec_point_mul_scalar +#define ec_point_mul_scalar_public GRPC_SHADOW_ec_point_mul_scalar_public +#define ec_random_nonzero_scalar GRPC_SHADOW_ec_random_nonzero_scalar +#define ec_wNAF_mul GRPC_SHADOW_ec_wNAF_mul +#define kBoringSSLRSASqrtTwo GRPC_SHADOW_kBoringSSLRSASqrtTwo +#define kBoringSSLRSASqrtTwoLen GRPC_SHADOW_kBoringSSLRSASqrtTwoLen +#define md4_block_data_order GRPC_SHADOW_md4_block_data_order +#define rsa_default_decrypt GRPC_SHADOW_rsa_default_decrypt +#define rsa_default_private_transform GRPC_SHADOW_rsa_default_private_transform +#define rsa_default_sign_raw GRPC_SHADOW_rsa_default_sign_raw +#define rsa_default_size GRPC_SHADOW_rsa_default_size +#define FIPS_mode GRPC_SHADOW_FIPS_mode +#define aesni_gcm_decrypt GRPC_SHADOW_aesni_gcm_decrypt +#define aesni_gcm_encrypt GRPC_SHADOW_aesni_gcm_encrypt +#define aesni_cbc_encrypt GRPC_SHADOW_aesni_cbc_encrypt +#define aesni_ccm64_decrypt_blocks GRPC_SHADOW_aesni_ccm64_decrypt_blocks +#define aesni_ccm64_encrypt_blocks GRPC_SHADOW_aesni_ccm64_encrypt_blocks +#define aesni_ctr32_encrypt_blocks GRPC_SHADOW_aesni_ctr32_encrypt_blocks +#define aesni_decrypt GRPC_SHADOW_aesni_decrypt +#define aesni_ecb_encrypt GRPC_SHADOW_aesni_ecb_encrypt +#define aesni_encrypt GRPC_SHADOW_aesni_encrypt +#define aesni_ocb_decrypt GRPC_SHADOW_aesni_ocb_decrypt +#define aesni_ocb_encrypt GRPC_SHADOW_aesni_ocb_encrypt +#define aesni_set_decrypt_key GRPC_SHADOW_aesni_set_decrypt_key +#define aesni_set_encrypt_key GRPC_SHADOW_aesni_set_encrypt_key +#define aesni_xts_decrypt GRPC_SHADOW_aesni_xts_decrypt +#define aesni_xts_encrypt GRPC_SHADOW_aesni_xts_encrypt +#define asm_AES_cbc_encrypt GRPC_SHADOW_asm_AES_cbc_encrypt +#define asm_AES_decrypt GRPC_SHADOW_asm_AES_decrypt +#define asm_AES_encrypt GRPC_SHADOW_asm_AES_encrypt +#define asm_AES_set_decrypt_key GRPC_SHADOW_asm_AES_set_decrypt_key +#define asm_AES_set_encrypt_key GRPC_SHADOW_asm_AES_set_encrypt_key +#define bsaes_cbc_encrypt GRPC_SHADOW_bsaes_cbc_encrypt +#define bsaes_ctr32_encrypt_blocks GRPC_SHADOW_bsaes_ctr32_encrypt_blocks +#define bsaes_xts_decrypt GRPC_SHADOW_bsaes_xts_decrypt +#define bsaes_xts_encrypt GRPC_SHADOW_bsaes_xts_encrypt +#define gcm_ghash_4bit GRPC_SHADOW_gcm_ghash_4bit +#define gcm_ghash_avx GRPC_SHADOW_gcm_ghash_avx +#define gcm_ghash_clmul GRPC_SHADOW_gcm_ghash_clmul +#define gcm_gmult_4bit GRPC_SHADOW_gcm_gmult_4bit +#define gcm_gmult_avx GRPC_SHADOW_gcm_gmult_avx +#define gcm_gmult_clmul GRPC_SHADOW_gcm_gmult_clmul +#define gcm_init_avx GRPC_SHADOW_gcm_init_avx +#define gcm_init_clmul GRPC_SHADOW_gcm_init_clmul +#define md5_block_asm_data_order GRPC_SHADOW_md5_block_asm_data_order +#define ecp_nistz256_avx2_select_w7 GRPC_SHADOW_ecp_nistz256_avx2_select_w7 +#define ecp_nistz256_mul_mont GRPC_SHADOW_ecp_nistz256_mul_mont +#define ecp_nistz256_neg GRPC_SHADOW_ecp_nistz256_neg +#define ecp_nistz256_point_add GRPC_SHADOW_ecp_nistz256_point_add +#define ecp_nistz256_point_add_affine GRPC_SHADOW_ecp_nistz256_point_add_affine +#define ecp_nistz256_point_double GRPC_SHADOW_ecp_nistz256_point_double +#define ecp_nistz256_select_w5 GRPC_SHADOW_ecp_nistz256_select_w5 +#define ecp_nistz256_select_w7 GRPC_SHADOW_ecp_nistz256_select_w7 +#define ecp_nistz256_sqr_mont GRPC_SHADOW_ecp_nistz256_sqr_mont +#define CRYPTO_rdrand GRPC_SHADOW_CRYPTO_rdrand +#define CRYPTO_rdrand_multiple8_buf GRPC_SHADOW_CRYPTO_rdrand_multiple8_buf +#define rsaz_1024_gather5_avx2 GRPC_SHADOW_rsaz_1024_gather5_avx2 +#define rsaz_1024_mul_avx2 GRPC_SHADOW_rsaz_1024_mul_avx2 +#define rsaz_1024_norm2red_avx2 GRPC_SHADOW_rsaz_1024_norm2red_avx2 +#define rsaz_1024_red2norm_avx2 GRPC_SHADOW_rsaz_1024_red2norm_avx2 +#define rsaz_1024_scatter5_avx2 GRPC_SHADOW_rsaz_1024_scatter5_avx2 +#define rsaz_1024_sqr_avx2 GRPC_SHADOW_rsaz_1024_sqr_avx2 +#define rsaz_avx2_eligible GRPC_SHADOW_rsaz_avx2_eligible +#define sha1_block_data_order GRPC_SHADOW_sha1_block_data_order +#define sha256_block_data_order GRPC_SHADOW_sha256_block_data_order +#define sha512_block_data_order GRPC_SHADOW_sha512_block_data_order +#define vpaes_cbc_encrypt GRPC_SHADOW_vpaes_cbc_encrypt +#define vpaes_decrypt GRPC_SHADOW_vpaes_decrypt +#define vpaes_encrypt GRPC_SHADOW_vpaes_encrypt +#define vpaes_set_decrypt_key GRPC_SHADOW_vpaes_set_decrypt_key +#define vpaes_set_encrypt_key GRPC_SHADOW_vpaes_set_encrypt_key +#define bn_from_montgomery GRPC_SHADOW_bn_from_montgomery +#define bn_gather5 GRPC_SHADOW_bn_gather5 +#define bn_mul_mont_gather5 GRPC_SHADOW_bn_mul_mont_gather5 +#define bn_power5 GRPC_SHADOW_bn_power5 +#define bn_scatter5 GRPC_SHADOW_bn_scatter5 +#define bn_sqr8x_internal GRPC_SHADOW_bn_sqr8x_internal +#define bn_mul_mont GRPC_SHADOW_bn_mul_mont +#define EVP_get_digestbyname GRPC_SHADOW_EVP_get_digestbyname +#define EVP_get_digestbynid GRPC_SHADOW_EVP_get_digestbynid +#define EVP_get_digestbyobj GRPC_SHADOW_EVP_get_digestbyobj +#define EVP_marshal_digest_algorithm GRPC_SHADOW_EVP_marshal_digest_algorithm +#define EVP_parse_digest_algorithm GRPC_SHADOW_EVP_parse_digest_algorithm +#define EVP_get_cipherbyname GRPC_SHADOW_EVP_get_cipherbyname +#define EVP_get_cipherbynid GRPC_SHADOW_EVP_get_cipherbynid +#define EVP_BytesToKey GRPC_SHADOW_EVP_BytesToKey +#define EVP_enc_null GRPC_SHADOW_EVP_enc_null +#define EVP_rc2_40_cbc GRPC_SHADOW_EVP_rc2_40_cbc +#define EVP_rc2_cbc GRPC_SHADOW_EVP_rc2_cbc +#define EVP_rc4 GRPC_SHADOW_EVP_rc4 +#define EVP_aead_aes_128_gcm_siv GRPC_SHADOW_EVP_aead_aes_128_gcm_siv +#define EVP_aead_aes_256_gcm_siv GRPC_SHADOW_EVP_aead_aes_256_gcm_siv +#define EVP_aead_aes_128_ctr_hmac_sha256 GRPC_SHADOW_EVP_aead_aes_128_ctr_hmac_sha256 +#define EVP_aead_aes_256_ctr_hmac_sha256 GRPC_SHADOW_EVP_aead_aes_256_ctr_hmac_sha256 +#define EVP_aead_aes_128_ccm_bluetooth GRPC_SHADOW_EVP_aead_aes_128_ccm_bluetooth +#define EVP_aead_aes_128_ccm_bluetooth_8 GRPC_SHADOW_EVP_aead_aes_128_ccm_bluetooth_8 +#define EVP_aead_chacha20_poly1305 GRPC_SHADOW_EVP_aead_chacha20_poly1305 +#define EVP_tls_cbc_copy_mac GRPC_SHADOW_EVP_tls_cbc_copy_mac +#define EVP_tls_cbc_digest_record GRPC_SHADOW_EVP_tls_cbc_digest_record +#define EVP_tls_cbc_record_digest_supported GRPC_SHADOW_EVP_tls_cbc_record_digest_supported +#define EVP_tls_cbc_remove_padding GRPC_SHADOW_EVP_tls_cbc_remove_padding +#define EVP_aead_aes_128_cbc_sha1_tls GRPC_SHADOW_EVP_aead_aes_128_cbc_sha1_tls +#define EVP_aead_aes_128_cbc_sha1_tls_implicit_iv GRPC_SHADOW_EVP_aead_aes_128_cbc_sha1_tls_implicit_iv +#define EVP_aead_aes_128_cbc_sha256_tls GRPC_SHADOW_EVP_aead_aes_128_cbc_sha256_tls +#define EVP_aead_aes_256_cbc_sha1_tls GRPC_SHADOW_EVP_aead_aes_256_cbc_sha1_tls +#define EVP_aead_aes_256_cbc_sha1_tls_implicit_iv GRPC_SHADOW_EVP_aead_aes_256_cbc_sha1_tls_implicit_iv +#define EVP_aead_aes_256_cbc_sha256_tls GRPC_SHADOW_EVP_aead_aes_256_cbc_sha256_tls +#define EVP_aead_aes_256_cbc_sha384_tls GRPC_SHADOW_EVP_aead_aes_256_cbc_sha384_tls +#define EVP_aead_des_ede3_cbc_sha1_tls GRPC_SHADOW_EVP_aead_des_ede3_cbc_sha1_tls +#define EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv GRPC_SHADOW_EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv +#define EVP_aead_null_sha1_tls GRPC_SHADOW_EVP_aead_null_sha1_tls +#define EVP_aead_aes_128_cbc_sha1_ssl3 GRPC_SHADOW_EVP_aead_aes_128_cbc_sha1_ssl3 +#define EVP_aead_aes_256_cbc_sha1_ssl3 GRPC_SHADOW_EVP_aead_aes_256_cbc_sha1_ssl3 +#define EVP_aead_des_ede3_cbc_sha1_ssl3 GRPC_SHADOW_EVP_aead_des_ede3_cbc_sha1_ssl3 +#define EVP_aead_null_sha1_ssl3 GRPC_SHADOW_EVP_aead_null_sha1_ssl3 +#define aes128gcmsiv_aes_ks GRPC_SHADOW_aes128gcmsiv_aes_ks +#define aes128gcmsiv_aes_ks_enc_x1 GRPC_SHADOW_aes128gcmsiv_aes_ks_enc_x1 +#define aes128gcmsiv_dec GRPC_SHADOW_aes128gcmsiv_dec +#define aes128gcmsiv_ecb_enc_block GRPC_SHADOW_aes128gcmsiv_ecb_enc_block +#define aes128gcmsiv_enc_msg_x4 GRPC_SHADOW_aes128gcmsiv_enc_msg_x4 +#define aes128gcmsiv_enc_msg_x8 GRPC_SHADOW_aes128gcmsiv_enc_msg_x8 +#define aes128gcmsiv_kdf GRPC_SHADOW_aes128gcmsiv_kdf +#define aes256gcmsiv_aes_ks GRPC_SHADOW_aes256gcmsiv_aes_ks +#define aes256gcmsiv_aes_ks_enc_x1 GRPC_SHADOW_aes256gcmsiv_aes_ks_enc_x1 +#define aes256gcmsiv_dec GRPC_SHADOW_aes256gcmsiv_dec +#define aes256gcmsiv_ecb_enc_block GRPC_SHADOW_aes256gcmsiv_ecb_enc_block +#define aes256gcmsiv_enc_msg_x4 GRPC_SHADOW_aes256gcmsiv_enc_msg_x4 +#define aes256gcmsiv_enc_msg_x8 GRPC_SHADOW_aes256gcmsiv_enc_msg_x8 +#define aes256gcmsiv_kdf GRPC_SHADOW_aes256gcmsiv_kdf +#define aesgcmsiv_htable6_init GRPC_SHADOW_aesgcmsiv_htable6_init +#define aesgcmsiv_htable_init GRPC_SHADOW_aesgcmsiv_htable_init +#define aesgcmsiv_htable_polyval GRPC_SHADOW_aesgcmsiv_htable_polyval +#define aesgcmsiv_polyval_horner GRPC_SHADOW_aesgcmsiv_polyval_horner +#define chacha20_poly1305_open GRPC_SHADOW_chacha20_poly1305_open +#define chacha20_poly1305_seal GRPC_SHADOW_chacha20_poly1305_seal +#define RC4 GRPC_SHADOW_RC4 +#define RC4_set_key GRPC_SHADOW_RC4_set_key +#define CONF_VALUE_new GRPC_SHADOW_CONF_VALUE_new +#define CONF_modules_free GRPC_SHADOW_CONF_modules_free +#define CONF_modules_load_file GRPC_SHADOW_CONF_modules_load_file +#define CONF_parse_list GRPC_SHADOW_CONF_parse_list +#define NCONF_free GRPC_SHADOW_NCONF_free +#define NCONF_get_section GRPC_SHADOW_NCONF_get_section +#define NCONF_get_string GRPC_SHADOW_NCONF_get_string +#define NCONF_load GRPC_SHADOW_NCONF_load +#define NCONF_load_bio GRPC_SHADOW_NCONF_load_bio +#define NCONF_new GRPC_SHADOW_NCONF_new +#define OPENSSL_config GRPC_SHADOW_OPENSSL_config +#define OPENSSL_no_config GRPC_SHADOW_OPENSSL_no_config +#define CRYPTO_chacha_20 GRPC_SHADOW_CRYPTO_chacha_20 +#define ChaCha20_ctr32 GRPC_SHADOW_ChaCha20_ctr32 +#define CRYPTO_poly1305_finish GRPC_SHADOW_CRYPTO_poly1305_finish +#define CRYPTO_poly1305_init GRPC_SHADOW_CRYPTO_poly1305_init +#define CRYPTO_poly1305_update GRPC_SHADOW_CRYPTO_poly1305_update +#define SPAKE2_CTX_free GRPC_SHADOW_SPAKE2_CTX_free +#define SPAKE2_CTX_new GRPC_SHADOW_SPAKE2_CTX_new +#define SPAKE2_generate_msg GRPC_SHADOW_SPAKE2_generate_msg +#define SPAKE2_process_msg GRPC_SHADOW_SPAKE2_process_msg +#define ED25519_keypair GRPC_SHADOW_ED25519_keypair +#define ED25519_keypair_from_seed GRPC_SHADOW_ED25519_keypair_from_seed +#define ED25519_sign GRPC_SHADOW_ED25519_sign +#define ED25519_verify GRPC_SHADOW_ED25519_verify +#define X25519 GRPC_SHADOW_X25519 +#define X25519_keypair GRPC_SHADOW_X25519_keypair +#define X25519_public_from_private GRPC_SHADOW_X25519_public_from_private +#define x25519_ge_add GRPC_SHADOW_x25519_ge_add +#define x25519_ge_frombytes_vartime GRPC_SHADOW_x25519_ge_frombytes_vartime +#define x25519_ge_p1p1_to_p2 GRPC_SHADOW_x25519_ge_p1p1_to_p2 +#define x25519_ge_p1p1_to_p3 GRPC_SHADOW_x25519_ge_p1p1_to_p3 +#define x25519_ge_p3_to_cached GRPC_SHADOW_x25519_ge_p3_to_cached +#define x25519_ge_scalarmult GRPC_SHADOW_x25519_ge_scalarmult +#define x25519_ge_scalarmult_base GRPC_SHADOW_x25519_ge_scalarmult_base +#define x25519_ge_scalarmult_small_precomp GRPC_SHADOW_x25519_ge_scalarmult_small_precomp +#define x25519_ge_sub GRPC_SHADOW_x25519_ge_sub +#define x25519_ge_tobytes GRPC_SHADOW_x25519_ge_tobytes +#define x25519_sc_reduce GRPC_SHADOW_x25519_sc_reduce +#define BUF_MEM_append GRPC_SHADOW_BUF_MEM_append +#define BUF_MEM_free GRPC_SHADOW_BUF_MEM_free +#define BUF_MEM_grow GRPC_SHADOW_BUF_MEM_grow +#define BUF_MEM_grow_clean GRPC_SHADOW_BUF_MEM_grow_clean +#define BUF_MEM_new GRPC_SHADOW_BUF_MEM_new +#define BUF_MEM_reserve GRPC_SHADOW_BUF_MEM_reserve +#define BUF_memdup GRPC_SHADOW_BUF_memdup +#define BUF_strdup GRPC_SHADOW_BUF_strdup +#define BUF_strlcat GRPC_SHADOW_BUF_strlcat +#define BUF_strlcpy GRPC_SHADOW_BUF_strlcpy +#define BUF_strndup GRPC_SHADOW_BUF_strndup +#define BUF_strnlen GRPC_SHADOW_BUF_strnlen +#define BN_marshal_asn1 GRPC_SHADOW_BN_marshal_asn1 +#define BN_parse_asn1_unsigned GRPC_SHADOW_BN_parse_asn1_unsigned +#define BN_asc2bn GRPC_SHADOW_BN_asc2bn +#define BN_bn2cbb_padded GRPC_SHADOW_BN_bn2cbb_padded +#define BN_bn2dec GRPC_SHADOW_BN_bn2dec +#define BN_bn2hex GRPC_SHADOW_BN_bn2hex +#define BN_bn2mpi GRPC_SHADOW_BN_bn2mpi +#define BN_dec2bn GRPC_SHADOW_BN_dec2bn +#define BN_hex2bn GRPC_SHADOW_BN_hex2bn +#define BN_mpi2bn GRPC_SHADOW_BN_mpi2bn +#define BN_print GRPC_SHADOW_BN_print +#define BN_print_fp GRPC_SHADOW_BN_print_fp +#define BIO_callback_ctrl GRPC_SHADOW_BIO_callback_ctrl +#define BIO_clear_flags GRPC_SHADOW_BIO_clear_flags +#define BIO_clear_retry_flags GRPC_SHADOW_BIO_clear_retry_flags +#define BIO_copy_next_retry GRPC_SHADOW_BIO_copy_next_retry +#define BIO_ctrl GRPC_SHADOW_BIO_ctrl +#define BIO_ctrl_pending GRPC_SHADOW_BIO_ctrl_pending +#define BIO_eof GRPC_SHADOW_BIO_eof +#define BIO_find_type GRPC_SHADOW_BIO_find_type +#define BIO_flush GRPC_SHADOW_BIO_flush +#define BIO_free GRPC_SHADOW_BIO_free +#define BIO_free_all GRPC_SHADOW_BIO_free_all +#define BIO_get_data GRPC_SHADOW_BIO_get_data +#define BIO_get_init GRPC_SHADOW_BIO_get_init +#define BIO_get_new_index GRPC_SHADOW_BIO_get_new_index +#define BIO_get_retry_flags GRPC_SHADOW_BIO_get_retry_flags +#define BIO_get_retry_reason GRPC_SHADOW_BIO_get_retry_reason +#define BIO_get_shutdown GRPC_SHADOW_BIO_get_shutdown +#define BIO_gets GRPC_SHADOW_BIO_gets +#define BIO_indent GRPC_SHADOW_BIO_indent +#define BIO_int_ctrl GRPC_SHADOW_BIO_int_ctrl +#define BIO_meth_free GRPC_SHADOW_BIO_meth_free +#define BIO_meth_new GRPC_SHADOW_BIO_meth_new +#define BIO_meth_set_create GRPC_SHADOW_BIO_meth_set_create +#define BIO_meth_set_ctrl GRPC_SHADOW_BIO_meth_set_ctrl +#define BIO_meth_set_destroy GRPC_SHADOW_BIO_meth_set_destroy +#define BIO_meth_set_gets GRPC_SHADOW_BIO_meth_set_gets +#define BIO_meth_set_puts GRPC_SHADOW_BIO_meth_set_puts +#define BIO_meth_set_read GRPC_SHADOW_BIO_meth_set_read +#define BIO_meth_set_write GRPC_SHADOW_BIO_meth_set_write +#define BIO_method_type GRPC_SHADOW_BIO_method_type +#define BIO_new GRPC_SHADOW_BIO_new +#define BIO_next GRPC_SHADOW_BIO_next +#define BIO_number_read GRPC_SHADOW_BIO_number_read +#define BIO_number_written GRPC_SHADOW_BIO_number_written +#define BIO_pending GRPC_SHADOW_BIO_pending +#define BIO_pop GRPC_SHADOW_BIO_pop +#define BIO_ptr_ctrl GRPC_SHADOW_BIO_ptr_ctrl +#define BIO_push GRPC_SHADOW_BIO_push +#define BIO_puts GRPC_SHADOW_BIO_puts +#define BIO_read GRPC_SHADOW_BIO_read +#define BIO_read_asn1 GRPC_SHADOW_BIO_read_asn1 +#define BIO_reset GRPC_SHADOW_BIO_reset +#define BIO_set_close GRPC_SHADOW_BIO_set_close +#define BIO_set_data GRPC_SHADOW_BIO_set_data +#define BIO_set_flags GRPC_SHADOW_BIO_set_flags +#define BIO_set_init GRPC_SHADOW_BIO_set_init +#define BIO_set_retry_read GRPC_SHADOW_BIO_set_retry_read +#define BIO_set_retry_special GRPC_SHADOW_BIO_set_retry_special +#define BIO_set_retry_write GRPC_SHADOW_BIO_set_retry_write +#define BIO_set_shutdown GRPC_SHADOW_BIO_set_shutdown +#define BIO_set_write_buffer_size GRPC_SHADOW_BIO_set_write_buffer_size +#define BIO_should_io_special GRPC_SHADOW_BIO_should_io_special +#define BIO_should_read GRPC_SHADOW_BIO_should_read +#define BIO_should_retry GRPC_SHADOW_BIO_should_retry +#define BIO_should_write GRPC_SHADOW_BIO_should_write +#define BIO_test_flags GRPC_SHADOW_BIO_test_flags +#define BIO_up_ref GRPC_SHADOW_BIO_up_ref +#define BIO_vfree GRPC_SHADOW_BIO_vfree +#define BIO_wpending GRPC_SHADOW_BIO_wpending +#define BIO_write GRPC_SHADOW_BIO_write +#define ERR_print_errors GRPC_SHADOW_ERR_print_errors +#define BIO_get_mem_data GRPC_SHADOW_BIO_get_mem_data +#define BIO_get_mem_ptr GRPC_SHADOW_BIO_get_mem_ptr +#define BIO_mem_contents GRPC_SHADOW_BIO_mem_contents +#define BIO_new_mem_buf GRPC_SHADOW_BIO_new_mem_buf +#define BIO_s_mem GRPC_SHADOW_BIO_s_mem +#define BIO_set_mem_buf GRPC_SHADOW_BIO_set_mem_buf +#define BIO_set_mem_eof_return GRPC_SHADOW_BIO_set_mem_eof_return +#define BIO_do_connect GRPC_SHADOW_BIO_do_connect +#define BIO_new_connect GRPC_SHADOW_BIO_new_connect +#define BIO_s_connect GRPC_SHADOW_BIO_s_connect +#define BIO_set_conn_hostname GRPC_SHADOW_BIO_set_conn_hostname +#define BIO_set_conn_int_port GRPC_SHADOW_BIO_set_conn_int_port +#define BIO_set_conn_port GRPC_SHADOW_BIO_set_conn_port +#define BIO_set_nbio GRPC_SHADOW_BIO_set_nbio +#define BIO_get_fd GRPC_SHADOW_BIO_get_fd +#define BIO_new_fd GRPC_SHADOW_BIO_new_fd +#define BIO_s_fd GRPC_SHADOW_BIO_s_fd +#define BIO_set_fd GRPC_SHADOW_BIO_set_fd +#define bio_fd_should_retry GRPC_SHADOW_bio_fd_should_retry +#define BIO_append_filename GRPC_SHADOW_BIO_append_filename +#define BIO_get_fp GRPC_SHADOW_BIO_get_fp +#define BIO_new_file GRPC_SHADOW_BIO_new_file +#define BIO_new_fp GRPC_SHADOW_BIO_new_fp +#define BIO_read_filename GRPC_SHADOW_BIO_read_filename +#define BIO_rw_filename GRPC_SHADOW_BIO_rw_filename +#define BIO_s_file GRPC_SHADOW_BIO_s_file +#define BIO_set_fp GRPC_SHADOW_BIO_set_fp +#define BIO_write_filename GRPC_SHADOW_BIO_write_filename +#define BIO_hexdump GRPC_SHADOW_BIO_hexdump +#define BIO_ctrl_get_read_request GRPC_SHADOW_BIO_ctrl_get_read_request +#define BIO_ctrl_get_write_guarantee GRPC_SHADOW_BIO_ctrl_get_write_guarantee +#define BIO_new_bio_pair GRPC_SHADOW_BIO_new_bio_pair +#define BIO_shutdown_wr GRPC_SHADOW_BIO_shutdown_wr +#define BIO_printf GRPC_SHADOW_BIO_printf +#define BIO_new_socket GRPC_SHADOW_BIO_new_socket +#define BIO_s_socket GRPC_SHADOW_BIO_s_socket +#define bio_clear_socket_error GRPC_SHADOW_bio_clear_socket_error +#define bio_ip_and_port_to_socket_and_addr GRPC_SHADOW_bio_ip_and_port_to_socket_and_addr +#define bio_sock_error GRPC_SHADOW_bio_sock_error +#define bio_socket_nbio GRPC_SHADOW_bio_socket_nbio +#define RAND_enable_fork_unsafe_buffering GRPC_SHADOW_RAND_enable_fork_unsafe_buffering +#define rand_fork_unsafe_buffering_enabled GRPC_SHADOW_rand_fork_unsafe_buffering_enabled +#define RAND_SSLeay GRPC_SHADOW_RAND_SSLeay +#define RAND_add GRPC_SHADOW_RAND_add +#define RAND_cleanup GRPC_SHADOW_RAND_cleanup +#define RAND_egd GRPC_SHADOW_RAND_egd +#define RAND_file_name GRPC_SHADOW_RAND_file_name +#define RAND_get_rand_method GRPC_SHADOW_RAND_get_rand_method +#define RAND_load_file GRPC_SHADOW_RAND_load_file +#define RAND_poll GRPC_SHADOW_RAND_poll +#define RAND_seed GRPC_SHADOW_RAND_seed +#define RAND_set_rand_method GRPC_SHADOW_RAND_set_rand_method +#define RAND_status GRPC_SHADOW_RAND_status +#define OBJ_cbs2nid GRPC_SHADOW_OBJ_cbs2nid +#define OBJ_cmp GRPC_SHADOW_OBJ_cmp +#define OBJ_create GRPC_SHADOW_OBJ_create +#define OBJ_dup GRPC_SHADOW_OBJ_dup +#define OBJ_get0_data GRPC_SHADOW_OBJ_get0_data +#define OBJ_length GRPC_SHADOW_OBJ_length +#define OBJ_ln2nid GRPC_SHADOW_OBJ_ln2nid +#define OBJ_nid2cbb GRPC_SHADOW_OBJ_nid2cbb +#define OBJ_nid2ln GRPC_SHADOW_OBJ_nid2ln +#define OBJ_nid2obj GRPC_SHADOW_OBJ_nid2obj +#define OBJ_nid2sn GRPC_SHADOW_OBJ_nid2sn +#define OBJ_obj2nid GRPC_SHADOW_OBJ_obj2nid +#define OBJ_obj2txt GRPC_SHADOW_OBJ_obj2txt +#define OBJ_sn2nid GRPC_SHADOW_OBJ_sn2nid +#define OBJ_txt2nid GRPC_SHADOW_OBJ_txt2nid +#define OBJ_txt2obj GRPC_SHADOW_OBJ_txt2obj +#define OBJ_find_sigid_algs GRPC_SHADOW_OBJ_find_sigid_algs +#define OBJ_find_sigid_by_algs GRPC_SHADOW_OBJ_find_sigid_by_algs +#define ASN1_BIT_STRING_check GRPC_SHADOW_ASN1_BIT_STRING_check +#define ASN1_BIT_STRING_get_bit GRPC_SHADOW_ASN1_BIT_STRING_get_bit +#define ASN1_BIT_STRING_set GRPC_SHADOW_ASN1_BIT_STRING_set +#define ASN1_BIT_STRING_set_bit GRPC_SHADOW_ASN1_BIT_STRING_set_bit +#define c2i_ASN1_BIT_STRING GRPC_SHADOW_c2i_ASN1_BIT_STRING +#define i2c_ASN1_BIT_STRING GRPC_SHADOW_i2c_ASN1_BIT_STRING +#define d2i_ASN1_BOOLEAN GRPC_SHADOW_d2i_ASN1_BOOLEAN +#define i2d_ASN1_BOOLEAN GRPC_SHADOW_i2d_ASN1_BOOLEAN +#define ASN1_d2i_bio GRPC_SHADOW_ASN1_d2i_bio +#define ASN1_d2i_fp GRPC_SHADOW_ASN1_d2i_fp +#define ASN1_item_d2i_bio GRPC_SHADOW_ASN1_item_d2i_bio +#define ASN1_item_d2i_fp GRPC_SHADOW_ASN1_item_d2i_fp +#define ASN1_dup GRPC_SHADOW_ASN1_dup +#define ASN1_item_dup GRPC_SHADOW_ASN1_item_dup +#define ASN1_ENUMERATED_get GRPC_SHADOW_ASN1_ENUMERATED_get +#define ASN1_ENUMERATED_set GRPC_SHADOW_ASN1_ENUMERATED_set +#define ASN1_ENUMERATED_to_BN GRPC_SHADOW_ASN1_ENUMERATED_to_BN +#define BN_to_ASN1_ENUMERATED GRPC_SHADOW_BN_to_ASN1_ENUMERATED +#define ASN1_GENERALIZEDTIME_adj GRPC_SHADOW_ASN1_GENERALIZEDTIME_adj +#define ASN1_GENERALIZEDTIME_check GRPC_SHADOW_ASN1_GENERALIZEDTIME_check +#define ASN1_GENERALIZEDTIME_set GRPC_SHADOW_ASN1_GENERALIZEDTIME_set +#define ASN1_GENERALIZEDTIME_set_string GRPC_SHADOW_ASN1_GENERALIZEDTIME_set_string +#define asn1_generalizedtime_to_tm GRPC_SHADOW_asn1_generalizedtime_to_tm +#define ASN1_i2d_bio GRPC_SHADOW_ASN1_i2d_bio +#define ASN1_i2d_fp GRPC_SHADOW_ASN1_i2d_fp +#define ASN1_item_i2d_bio GRPC_SHADOW_ASN1_item_i2d_bio +#define ASN1_item_i2d_fp GRPC_SHADOW_ASN1_item_i2d_fp +#define ASN1_INTEGER_cmp GRPC_SHADOW_ASN1_INTEGER_cmp +#define ASN1_INTEGER_dup GRPC_SHADOW_ASN1_INTEGER_dup +#define ASN1_INTEGER_get GRPC_SHADOW_ASN1_INTEGER_get +#define ASN1_INTEGER_set GRPC_SHADOW_ASN1_INTEGER_set +#define ASN1_INTEGER_set_uint64 GRPC_SHADOW_ASN1_INTEGER_set_uint64 +#define ASN1_INTEGER_to_BN GRPC_SHADOW_ASN1_INTEGER_to_BN +#define BN_to_ASN1_INTEGER GRPC_SHADOW_BN_to_ASN1_INTEGER +#define c2i_ASN1_INTEGER GRPC_SHADOW_c2i_ASN1_INTEGER +#define d2i_ASN1_UINTEGER GRPC_SHADOW_d2i_ASN1_UINTEGER +#define i2c_ASN1_INTEGER GRPC_SHADOW_i2c_ASN1_INTEGER +#define ASN1_mbstring_copy GRPC_SHADOW_ASN1_mbstring_copy +#define ASN1_mbstring_ncopy GRPC_SHADOW_ASN1_mbstring_ncopy +#define ASN1_OBJECT_create GRPC_SHADOW_ASN1_OBJECT_create +#define ASN1_OBJECT_free GRPC_SHADOW_ASN1_OBJECT_free +#define ASN1_OBJECT_new GRPC_SHADOW_ASN1_OBJECT_new +#define c2i_ASN1_OBJECT GRPC_SHADOW_c2i_ASN1_OBJECT +#define d2i_ASN1_OBJECT GRPC_SHADOW_d2i_ASN1_OBJECT +#define i2a_ASN1_OBJECT GRPC_SHADOW_i2a_ASN1_OBJECT +#define i2d_ASN1_OBJECT GRPC_SHADOW_i2d_ASN1_OBJECT +#define i2t_ASN1_OBJECT GRPC_SHADOW_i2t_ASN1_OBJECT +#define ASN1_OCTET_STRING_cmp GRPC_SHADOW_ASN1_OCTET_STRING_cmp +#define ASN1_OCTET_STRING_dup GRPC_SHADOW_ASN1_OCTET_STRING_dup +#define ASN1_OCTET_STRING_set GRPC_SHADOW_ASN1_OCTET_STRING_set +#define ASN1_PRINTABLE_type GRPC_SHADOW_ASN1_PRINTABLE_type +#define ASN1_STRING_TABLE_add GRPC_SHADOW_ASN1_STRING_TABLE_add +#define ASN1_STRING_TABLE_cleanup GRPC_SHADOW_ASN1_STRING_TABLE_cleanup +#define ASN1_STRING_TABLE_get GRPC_SHADOW_ASN1_STRING_TABLE_get +#define ASN1_STRING_get_default_mask GRPC_SHADOW_ASN1_STRING_get_default_mask +#define ASN1_STRING_set_by_NID GRPC_SHADOW_ASN1_STRING_set_by_NID +#define ASN1_STRING_set_default_mask GRPC_SHADOW_ASN1_STRING_set_default_mask +#define ASN1_STRING_set_default_mask_asc GRPC_SHADOW_ASN1_STRING_set_default_mask_asc +#define ASN1_TIME_adj GRPC_SHADOW_ASN1_TIME_adj +#define ASN1_TIME_check GRPC_SHADOW_ASN1_TIME_check +#define ASN1_TIME_diff GRPC_SHADOW_ASN1_TIME_diff +#define ASN1_TIME_free GRPC_SHADOW_ASN1_TIME_free +#define ASN1_TIME_it GRPC_SHADOW_ASN1_TIME_it +#define ASN1_TIME_new GRPC_SHADOW_ASN1_TIME_new +#define ASN1_TIME_set GRPC_SHADOW_ASN1_TIME_set +#define ASN1_TIME_set_string GRPC_SHADOW_ASN1_TIME_set_string +#define ASN1_TIME_to_generalizedtime GRPC_SHADOW_ASN1_TIME_to_generalizedtime +#define d2i_ASN1_TIME GRPC_SHADOW_d2i_ASN1_TIME +#define i2d_ASN1_TIME GRPC_SHADOW_i2d_ASN1_TIME +#define ASN1_TYPE_cmp GRPC_SHADOW_ASN1_TYPE_cmp +#define ASN1_TYPE_get GRPC_SHADOW_ASN1_TYPE_get +#define ASN1_TYPE_set GRPC_SHADOW_ASN1_TYPE_set +#define ASN1_TYPE_set1 GRPC_SHADOW_ASN1_TYPE_set1 +#define ASN1_UTCTIME_adj GRPC_SHADOW_ASN1_UTCTIME_adj +#define ASN1_UTCTIME_check GRPC_SHADOW_ASN1_UTCTIME_check +#define ASN1_UTCTIME_cmp_time_t GRPC_SHADOW_ASN1_UTCTIME_cmp_time_t +#define ASN1_UTCTIME_set GRPC_SHADOW_ASN1_UTCTIME_set +#define ASN1_UTCTIME_set_string GRPC_SHADOW_ASN1_UTCTIME_set_string +#define asn1_utctime_to_tm GRPC_SHADOW_asn1_utctime_to_tm +#define UTF8_getc GRPC_SHADOW_UTF8_getc +#define UTF8_putc GRPC_SHADOW_UTF8_putc +#define ASN1_STRING_cmp GRPC_SHADOW_ASN1_STRING_cmp +#define ASN1_STRING_copy GRPC_SHADOW_ASN1_STRING_copy +#define ASN1_STRING_data GRPC_SHADOW_ASN1_STRING_data +#define ASN1_STRING_dup GRPC_SHADOW_ASN1_STRING_dup +#define ASN1_STRING_free GRPC_SHADOW_ASN1_STRING_free +#define ASN1_STRING_get0_data GRPC_SHADOW_ASN1_STRING_get0_data +#define ASN1_STRING_length GRPC_SHADOW_ASN1_STRING_length +#define ASN1_STRING_length_set GRPC_SHADOW_ASN1_STRING_length_set +#define ASN1_STRING_new GRPC_SHADOW_ASN1_STRING_new +#define ASN1_STRING_set GRPC_SHADOW_ASN1_STRING_set +#define ASN1_STRING_set0 GRPC_SHADOW_ASN1_STRING_set0 +#define ASN1_STRING_type GRPC_SHADOW_ASN1_STRING_type +#define ASN1_STRING_type_new GRPC_SHADOW_ASN1_STRING_type_new +#define ASN1_get_object GRPC_SHADOW_ASN1_get_object +#define ASN1_object_size GRPC_SHADOW_ASN1_object_size +#define ASN1_put_eoc GRPC_SHADOW_ASN1_put_eoc +#define ASN1_put_object GRPC_SHADOW_ASN1_put_object +#define ASN1_tag2str GRPC_SHADOW_ASN1_tag2str +#define ASN1_item_pack GRPC_SHADOW_ASN1_item_pack +#define ASN1_item_unpack GRPC_SHADOW_ASN1_item_unpack +#define i2a_ASN1_ENUMERATED GRPC_SHADOW_i2a_ASN1_ENUMERATED +#define i2a_ASN1_INTEGER GRPC_SHADOW_i2a_ASN1_INTEGER +#define i2a_ASN1_STRING GRPC_SHADOW_i2a_ASN1_STRING +#define ASN1_item_d2i GRPC_SHADOW_ASN1_item_d2i +#define ASN1_item_ex_d2i GRPC_SHADOW_ASN1_item_ex_d2i +#define ASN1_tag2bit GRPC_SHADOW_ASN1_tag2bit +#define asn1_ex_c2i GRPC_SHADOW_asn1_ex_c2i +#define ASN1_item_ex_i2d GRPC_SHADOW_ASN1_item_ex_i2d +#define ASN1_item_i2d GRPC_SHADOW_ASN1_item_i2d +#define ASN1_item_ndef_i2d GRPC_SHADOW_ASN1_item_ndef_i2d +#define asn1_ex_i2c GRPC_SHADOW_asn1_ex_i2c +#define ASN1_item_ex_free GRPC_SHADOW_ASN1_item_ex_free +#define ASN1_item_free GRPC_SHADOW_ASN1_item_free +#define ASN1_primitive_free GRPC_SHADOW_ASN1_primitive_free +#define ASN1_template_free GRPC_SHADOW_ASN1_template_free +#define asn1_item_combine_free GRPC_SHADOW_asn1_item_combine_free +#define ASN1_item_ex_new GRPC_SHADOW_ASN1_item_ex_new +#define ASN1_item_new GRPC_SHADOW_ASN1_item_new +#define ASN1_primitive_new GRPC_SHADOW_ASN1_primitive_new +#define ASN1_template_new GRPC_SHADOW_ASN1_template_new +#define ASN1_ANY_it GRPC_SHADOW_ASN1_ANY_it +#define ASN1_BIT_STRING_free GRPC_SHADOW_ASN1_BIT_STRING_free +#define ASN1_BIT_STRING_it GRPC_SHADOW_ASN1_BIT_STRING_it +#define ASN1_BIT_STRING_new GRPC_SHADOW_ASN1_BIT_STRING_new +#define ASN1_BMPSTRING_free GRPC_SHADOW_ASN1_BMPSTRING_free +#define ASN1_BMPSTRING_it GRPC_SHADOW_ASN1_BMPSTRING_it +#define ASN1_BMPSTRING_new GRPC_SHADOW_ASN1_BMPSTRING_new +#define ASN1_BOOLEAN_it GRPC_SHADOW_ASN1_BOOLEAN_it +#define ASN1_ENUMERATED_free GRPC_SHADOW_ASN1_ENUMERATED_free +#define ASN1_ENUMERATED_it GRPC_SHADOW_ASN1_ENUMERATED_it +#define ASN1_ENUMERATED_new GRPC_SHADOW_ASN1_ENUMERATED_new +#define ASN1_FBOOLEAN_it GRPC_SHADOW_ASN1_FBOOLEAN_it +#define ASN1_GENERALIZEDTIME_free GRPC_SHADOW_ASN1_GENERALIZEDTIME_free +#define ASN1_GENERALIZEDTIME_it GRPC_SHADOW_ASN1_GENERALIZEDTIME_it +#define ASN1_GENERALIZEDTIME_new GRPC_SHADOW_ASN1_GENERALIZEDTIME_new +#define ASN1_GENERALSTRING_free GRPC_SHADOW_ASN1_GENERALSTRING_free +#define ASN1_GENERALSTRING_it GRPC_SHADOW_ASN1_GENERALSTRING_it +#define ASN1_GENERALSTRING_new GRPC_SHADOW_ASN1_GENERALSTRING_new +#define ASN1_IA5STRING_free GRPC_SHADOW_ASN1_IA5STRING_free +#define ASN1_IA5STRING_it GRPC_SHADOW_ASN1_IA5STRING_it +#define ASN1_IA5STRING_new GRPC_SHADOW_ASN1_IA5STRING_new +#define ASN1_INTEGER_free GRPC_SHADOW_ASN1_INTEGER_free +#define ASN1_INTEGER_it GRPC_SHADOW_ASN1_INTEGER_it +#define ASN1_INTEGER_new GRPC_SHADOW_ASN1_INTEGER_new +#define ASN1_NULL_free GRPC_SHADOW_ASN1_NULL_free +#define ASN1_NULL_it GRPC_SHADOW_ASN1_NULL_it +#define ASN1_NULL_new GRPC_SHADOW_ASN1_NULL_new +#define ASN1_OBJECT_it GRPC_SHADOW_ASN1_OBJECT_it +#define ASN1_OCTET_STRING_NDEF_it GRPC_SHADOW_ASN1_OCTET_STRING_NDEF_it +#define ASN1_OCTET_STRING_free GRPC_SHADOW_ASN1_OCTET_STRING_free +#define ASN1_OCTET_STRING_it GRPC_SHADOW_ASN1_OCTET_STRING_it +#define ASN1_OCTET_STRING_new GRPC_SHADOW_ASN1_OCTET_STRING_new +#define ASN1_PRINTABLESTRING_free GRPC_SHADOW_ASN1_PRINTABLESTRING_free +#define ASN1_PRINTABLESTRING_it GRPC_SHADOW_ASN1_PRINTABLESTRING_it +#define ASN1_PRINTABLESTRING_new GRPC_SHADOW_ASN1_PRINTABLESTRING_new +#define ASN1_PRINTABLE_free GRPC_SHADOW_ASN1_PRINTABLE_free +#define ASN1_PRINTABLE_it GRPC_SHADOW_ASN1_PRINTABLE_it +#define ASN1_PRINTABLE_new GRPC_SHADOW_ASN1_PRINTABLE_new +#define ASN1_SEQUENCE_ANY_it GRPC_SHADOW_ASN1_SEQUENCE_ANY_it +#define ASN1_SEQUENCE_it GRPC_SHADOW_ASN1_SEQUENCE_it +#define ASN1_SET_ANY_it GRPC_SHADOW_ASN1_SET_ANY_it +#define ASN1_T61STRING_free GRPC_SHADOW_ASN1_T61STRING_free +#define ASN1_T61STRING_it GRPC_SHADOW_ASN1_T61STRING_it +#define ASN1_T61STRING_new GRPC_SHADOW_ASN1_T61STRING_new +#define ASN1_TBOOLEAN_it GRPC_SHADOW_ASN1_TBOOLEAN_it +#define ASN1_TYPE_free GRPC_SHADOW_ASN1_TYPE_free +#define ASN1_TYPE_new GRPC_SHADOW_ASN1_TYPE_new +#define ASN1_UNIVERSALSTRING_free GRPC_SHADOW_ASN1_UNIVERSALSTRING_free +#define ASN1_UNIVERSALSTRING_it GRPC_SHADOW_ASN1_UNIVERSALSTRING_it +#define ASN1_UNIVERSALSTRING_new GRPC_SHADOW_ASN1_UNIVERSALSTRING_new +#define ASN1_UTCTIME_free GRPC_SHADOW_ASN1_UTCTIME_free +#define ASN1_UTCTIME_it GRPC_SHADOW_ASN1_UTCTIME_it +#define ASN1_UTCTIME_new GRPC_SHADOW_ASN1_UTCTIME_new +#define ASN1_UTF8STRING_free GRPC_SHADOW_ASN1_UTF8STRING_free +#define ASN1_UTF8STRING_it GRPC_SHADOW_ASN1_UTF8STRING_it +#define ASN1_UTF8STRING_new GRPC_SHADOW_ASN1_UTF8STRING_new +#define ASN1_VISIBLESTRING_free GRPC_SHADOW_ASN1_VISIBLESTRING_free +#define ASN1_VISIBLESTRING_it GRPC_SHADOW_ASN1_VISIBLESTRING_it +#define ASN1_VISIBLESTRING_new GRPC_SHADOW_ASN1_VISIBLESTRING_new +#define DIRECTORYSTRING_free GRPC_SHADOW_DIRECTORYSTRING_free +#define DIRECTORYSTRING_it GRPC_SHADOW_DIRECTORYSTRING_it +#define DIRECTORYSTRING_new GRPC_SHADOW_DIRECTORYSTRING_new +#define DISPLAYTEXT_free GRPC_SHADOW_DISPLAYTEXT_free +#define DISPLAYTEXT_it GRPC_SHADOW_DISPLAYTEXT_it +#define DISPLAYTEXT_new GRPC_SHADOW_DISPLAYTEXT_new +#define d2i_ASN1_BIT_STRING GRPC_SHADOW_d2i_ASN1_BIT_STRING +#define d2i_ASN1_BMPSTRING GRPC_SHADOW_d2i_ASN1_BMPSTRING +#define d2i_ASN1_ENUMERATED GRPC_SHADOW_d2i_ASN1_ENUMERATED +#define d2i_ASN1_GENERALIZEDTIME GRPC_SHADOW_d2i_ASN1_GENERALIZEDTIME +#define d2i_ASN1_GENERALSTRING GRPC_SHADOW_d2i_ASN1_GENERALSTRING +#define d2i_ASN1_IA5STRING GRPC_SHADOW_d2i_ASN1_IA5STRING +#define d2i_ASN1_INTEGER GRPC_SHADOW_d2i_ASN1_INTEGER +#define d2i_ASN1_NULL GRPC_SHADOW_d2i_ASN1_NULL +#define d2i_ASN1_OCTET_STRING GRPC_SHADOW_d2i_ASN1_OCTET_STRING +#define d2i_ASN1_PRINTABLE GRPC_SHADOW_d2i_ASN1_PRINTABLE +#define d2i_ASN1_PRINTABLESTRING GRPC_SHADOW_d2i_ASN1_PRINTABLESTRING +#define d2i_ASN1_SEQUENCE_ANY GRPC_SHADOW_d2i_ASN1_SEQUENCE_ANY +#define d2i_ASN1_SET_ANY GRPC_SHADOW_d2i_ASN1_SET_ANY +#define d2i_ASN1_T61STRING GRPC_SHADOW_d2i_ASN1_T61STRING +#define d2i_ASN1_TYPE GRPC_SHADOW_d2i_ASN1_TYPE +#define d2i_ASN1_UNIVERSALSTRING GRPC_SHADOW_d2i_ASN1_UNIVERSALSTRING +#define d2i_ASN1_UTCTIME GRPC_SHADOW_d2i_ASN1_UTCTIME +#define d2i_ASN1_UTF8STRING GRPC_SHADOW_d2i_ASN1_UTF8STRING +#define d2i_ASN1_VISIBLESTRING GRPC_SHADOW_d2i_ASN1_VISIBLESTRING +#define d2i_DIRECTORYSTRING GRPC_SHADOW_d2i_DIRECTORYSTRING +#define d2i_DISPLAYTEXT GRPC_SHADOW_d2i_DISPLAYTEXT +#define i2d_ASN1_BIT_STRING GRPC_SHADOW_i2d_ASN1_BIT_STRING +#define i2d_ASN1_BMPSTRING GRPC_SHADOW_i2d_ASN1_BMPSTRING +#define i2d_ASN1_ENUMERATED GRPC_SHADOW_i2d_ASN1_ENUMERATED +#define i2d_ASN1_GENERALIZEDTIME GRPC_SHADOW_i2d_ASN1_GENERALIZEDTIME +#define i2d_ASN1_GENERALSTRING GRPC_SHADOW_i2d_ASN1_GENERALSTRING +#define i2d_ASN1_IA5STRING GRPC_SHADOW_i2d_ASN1_IA5STRING +#define i2d_ASN1_INTEGER GRPC_SHADOW_i2d_ASN1_INTEGER +#define i2d_ASN1_NULL GRPC_SHADOW_i2d_ASN1_NULL +#define i2d_ASN1_OCTET_STRING GRPC_SHADOW_i2d_ASN1_OCTET_STRING +#define i2d_ASN1_PRINTABLE GRPC_SHADOW_i2d_ASN1_PRINTABLE +#define i2d_ASN1_PRINTABLESTRING GRPC_SHADOW_i2d_ASN1_PRINTABLESTRING +#define i2d_ASN1_SEQUENCE_ANY GRPC_SHADOW_i2d_ASN1_SEQUENCE_ANY +#define i2d_ASN1_SET_ANY GRPC_SHADOW_i2d_ASN1_SET_ANY +#define i2d_ASN1_T61STRING GRPC_SHADOW_i2d_ASN1_T61STRING +#define i2d_ASN1_TYPE GRPC_SHADOW_i2d_ASN1_TYPE +#define i2d_ASN1_UNIVERSALSTRING GRPC_SHADOW_i2d_ASN1_UNIVERSALSTRING +#define i2d_ASN1_UTCTIME GRPC_SHADOW_i2d_ASN1_UTCTIME +#define i2d_ASN1_UTF8STRING GRPC_SHADOW_i2d_ASN1_UTF8STRING +#define i2d_ASN1_VISIBLESTRING GRPC_SHADOW_i2d_ASN1_VISIBLESTRING +#define i2d_DIRECTORYSTRING GRPC_SHADOW_i2d_DIRECTORYSTRING +#define i2d_DISPLAYTEXT GRPC_SHADOW_i2d_DISPLAYTEXT +#define asn1_do_adb GRPC_SHADOW_asn1_do_adb +#define asn1_enc_free GRPC_SHADOW_asn1_enc_free +#define asn1_enc_init GRPC_SHADOW_asn1_enc_init +#define asn1_enc_restore GRPC_SHADOW_asn1_enc_restore +#define asn1_enc_save GRPC_SHADOW_asn1_enc_save +#define asn1_get_choice_selector GRPC_SHADOW_asn1_get_choice_selector +#define asn1_get_field_ptr GRPC_SHADOW_asn1_get_field_ptr +#define asn1_refcount_dec_and_test_zero GRPC_SHADOW_asn1_refcount_dec_and_test_zero +#define asn1_refcount_set_one GRPC_SHADOW_asn1_refcount_set_one +#define asn1_set_choice_selector GRPC_SHADOW_asn1_set_choice_selector +#define OPENSSL_gmtime GRPC_SHADOW_OPENSSL_gmtime +#define OPENSSL_gmtime_adj GRPC_SHADOW_OPENSSL_gmtime_adj +#define OPENSSL_gmtime_diff GRPC_SHADOW_OPENSSL_gmtime_diff +#define ENGINE_free GRPC_SHADOW_ENGINE_free +#define ENGINE_get_ECDSA_method GRPC_SHADOW_ENGINE_get_ECDSA_method +#define ENGINE_get_RSA_method GRPC_SHADOW_ENGINE_get_RSA_method +#define ENGINE_new GRPC_SHADOW_ENGINE_new +#define ENGINE_set_ECDSA_method GRPC_SHADOW_ENGINE_set_ECDSA_method +#define ENGINE_set_RSA_method GRPC_SHADOW_ENGINE_set_RSA_method +#define METHOD_ref GRPC_SHADOW_METHOD_ref +#define METHOD_unref GRPC_SHADOW_METHOD_unref +#define DH_compute_key GRPC_SHADOW_DH_compute_key +#define DH_free GRPC_SHADOW_DH_free +#define DH_generate_key GRPC_SHADOW_DH_generate_key +#define DH_generate_parameters_ex GRPC_SHADOW_DH_generate_parameters_ex +#define DH_get0_key GRPC_SHADOW_DH_get0_key +#define DH_get0_pqg GRPC_SHADOW_DH_get0_pqg +#define DH_get_ex_data GRPC_SHADOW_DH_get_ex_data +#define DH_get_ex_new_index GRPC_SHADOW_DH_get_ex_new_index +#define DH_new GRPC_SHADOW_DH_new +#define DH_num_bits GRPC_SHADOW_DH_num_bits +#define DH_set0_key GRPC_SHADOW_DH_set0_key +#define DH_set0_pqg GRPC_SHADOW_DH_set0_pqg +#define DH_set_ex_data GRPC_SHADOW_DH_set_ex_data +#define DH_size GRPC_SHADOW_DH_size +#define DH_up_ref GRPC_SHADOW_DH_up_ref +#define DHparams_dup GRPC_SHADOW_DHparams_dup +#define BN_get_rfc3526_prime_1536 GRPC_SHADOW_BN_get_rfc3526_prime_1536 +#define DH_check GRPC_SHADOW_DH_check +#define DH_check_pub_key GRPC_SHADOW_DH_check_pub_key +#define DH_marshal_parameters GRPC_SHADOW_DH_marshal_parameters +#define DH_parse_parameters GRPC_SHADOW_DH_parse_parameters +#define d2i_DHparams GRPC_SHADOW_d2i_DHparams +#define i2d_DHparams GRPC_SHADOW_i2d_DHparams +#define DSA_SIG_free GRPC_SHADOW_DSA_SIG_free +#define DSA_SIG_new GRPC_SHADOW_DSA_SIG_new +#define DSA_check_signature GRPC_SHADOW_DSA_check_signature +#define DSA_do_check_signature GRPC_SHADOW_DSA_do_check_signature +#define DSA_do_sign GRPC_SHADOW_DSA_do_sign +#define DSA_do_verify GRPC_SHADOW_DSA_do_verify +#define DSA_dup_DH GRPC_SHADOW_DSA_dup_DH +#define DSA_free GRPC_SHADOW_DSA_free +#define DSA_generate_key GRPC_SHADOW_DSA_generate_key +#define DSA_generate_parameters_ex GRPC_SHADOW_DSA_generate_parameters_ex +#define DSA_get0_key GRPC_SHADOW_DSA_get0_key +#define DSA_get0_pqg GRPC_SHADOW_DSA_get0_pqg +#define DSA_get_ex_data GRPC_SHADOW_DSA_get_ex_data +#define DSA_get_ex_new_index GRPC_SHADOW_DSA_get_ex_new_index +#define DSA_new GRPC_SHADOW_DSA_new +#define DSA_set0_key GRPC_SHADOW_DSA_set0_key +#define DSA_set0_pqg GRPC_SHADOW_DSA_set0_pqg +#define DSA_set_ex_data GRPC_SHADOW_DSA_set_ex_data +#define DSA_sign GRPC_SHADOW_DSA_sign +#define DSA_size GRPC_SHADOW_DSA_size +#define DSA_up_ref GRPC_SHADOW_DSA_up_ref +#define DSA_verify GRPC_SHADOW_DSA_verify +#define DSAparams_dup GRPC_SHADOW_DSAparams_dup +#define DSA_SIG_marshal GRPC_SHADOW_DSA_SIG_marshal +#define DSA_SIG_parse GRPC_SHADOW_DSA_SIG_parse +#define DSA_marshal_parameters GRPC_SHADOW_DSA_marshal_parameters +#define DSA_marshal_private_key GRPC_SHADOW_DSA_marshal_private_key +#define DSA_marshal_public_key GRPC_SHADOW_DSA_marshal_public_key +#define DSA_parse_parameters GRPC_SHADOW_DSA_parse_parameters +#define DSA_parse_private_key GRPC_SHADOW_DSA_parse_private_key +#define DSA_parse_public_key GRPC_SHADOW_DSA_parse_public_key +#define d2i_DSAPrivateKey GRPC_SHADOW_d2i_DSAPrivateKey +#define d2i_DSAPublicKey GRPC_SHADOW_d2i_DSAPublicKey +#define d2i_DSA_SIG GRPC_SHADOW_d2i_DSA_SIG +#define d2i_DSAparams GRPC_SHADOW_d2i_DSAparams +#define i2d_DSAPrivateKey GRPC_SHADOW_i2d_DSAPrivateKey +#define i2d_DSAPublicKey GRPC_SHADOW_i2d_DSAPublicKey +#define i2d_DSA_SIG GRPC_SHADOW_i2d_DSA_SIG +#define i2d_DSAparams GRPC_SHADOW_i2d_DSAparams +#define RSAPrivateKey_dup GRPC_SHADOW_RSAPrivateKey_dup +#define RSAPublicKey_dup GRPC_SHADOW_RSAPublicKey_dup +#define RSA_marshal_private_key GRPC_SHADOW_RSA_marshal_private_key +#define RSA_marshal_public_key GRPC_SHADOW_RSA_marshal_public_key +#define RSA_parse_private_key GRPC_SHADOW_RSA_parse_private_key +#define RSA_parse_public_key GRPC_SHADOW_RSA_parse_public_key +#define RSA_private_key_from_bytes GRPC_SHADOW_RSA_private_key_from_bytes +#define RSA_private_key_to_bytes GRPC_SHADOW_RSA_private_key_to_bytes +#define RSA_public_key_from_bytes GRPC_SHADOW_RSA_public_key_from_bytes +#define RSA_public_key_to_bytes GRPC_SHADOW_RSA_public_key_to_bytes +#define d2i_RSAPrivateKey GRPC_SHADOW_d2i_RSAPrivateKey +#define d2i_RSAPublicKey GRPC_SHADOW_d2i_RSAPublicKey +#define i2d_RSAPrivateKey GRPC_SHADOW_i2d_RSAPrivateKey +#define i2d_RSAPublicKey GRPC_SHADOW_i2d_RSAPublicKey +#define EC_KEY_marshal_curve_name GRPC_SHADOW_EC_KEY_marshal_curve_name +#define EC_KEY_marshal_private_key GRPC_SHADOW_EC_KEY_marshal_private_key +#define EC_KEY_parse_curve_name GRPC_SHADOW_EC_KEY_parse_curve_name +#define EC_KEY_parse_parameters GRPC_SHADOW_EC_KEY_parse_parameters +#define EC_KEY_parse_private_key GRPC_SHADOW_EC_KEY_parse_private_key +#define EC_POINT_point2cbb GRPC_SHADOW_EC_POINT_point2cbb +#define d2i_ECParameters GRPC_SHADOW_d2i_ECParameters +#define d2i_ECPrivateKey GRPC_SHADOW_d2i_ECPrivateKey +#define i2d_ECParameters GRPC_SHADOW_i2d_ECParameters +#define i2d_ECPrivateKey GRPC_SHADOW_i2d_ECPrivateKey +#define i2o_ECPublicKey GRPC_SHADOW_i2o_ECPublicKey +#define o2i_ECPublicKey GRPC_SHADOW_o2i_ECPublicKey +#define ECDH_compute_key GRPC_SHADOW_ECDH_compute_key +#define ECDSA_SIG_from_bytes GRPC_SHADOW_ECDSA_SIG_from_bytes +#define ECDSA_SIG_marshal GRPC_SHADOW_ECDSA_SIG_marshal +#define ECDSA_SIG_max_len GRPC_SHADOW_ECDSA_SIG_max_len +#define ECDSA_SIG_parse GRPC_SHADOW_ECDSA_SIG_parse +#define ECDSA_SIG_to_bytes GRPC_SHADOW_ECDSA_SIG_to_bytes +#define ECDSA_sign GRPC_SHADOW_ECDSA_sign +#define ECDSA_size GRPC_SHADOW_ECDSA_size +#define ECDSA_verify GRPC_SHADOW_ECDSA_verify +#define d2i_ECDSA_SIG GRPC_SHADOW_d2i_ECDSA_SIG +#define i2d_ECDSA_SIG GRPC_SHADOW_i2d_ECDSA_SIG +#define AES_CMAC GRPC_SHADOW_AES_CMAC +#define CMAC_CTX_free GRPC_SHADOW_CMAC_CTX_free +#define CMAC_CTX_new GRPC_SHADOW_CMAC_CTX_new +#define CMAC_Final GRPC_SHADOW_CMAC_Final +#define CMAC_Init GRPC_SHADOW_CMAC_Init +#define CMAC_Reset GRPC_SHADOW_CMAC_Reset +#define CMAC_Update GRPC_SHADOW_CMAC_Update +#define EVP_DigestSign GRPC_SHADOW_EVP_DigestSign +#define EVP_DigestSignFinal GRPC_SHADOW_EVP_DigestSignFinal +#define EVP_DigestSignInit GRPC_SHADOW_EVP_DigestSignInit +#define EVP_DigestSignUpdate GRPC_SHADOW_EVP_DigestSignUpdate +#define EVP_DigestVerify GRPC_SHADOW_EVP_DigestVerify +#define EVP_DigestVerifyFinal GRPC_SHADOW_EVP_DigestVerifyFinal +#define EVP_DigestVerifyInit GRPC_SHADOW_EVP_DigestVerifyInit +#define EVP_DigestVerifyUpdate GRPC_SHADOW_EVP_DigestVerifyUpdate +#define EVP_PKEY_CTX_get_signature_md GRPC_SHADOW_EVP_PKEY_CTX_get_signature_md +#define EVP_PKEY_CTX_set_signature_md GRPC_SHADOW_EVP_PKEY_CTX_set_signature_md +#define EVP_PKEY_assign GRPC_SHADOW_EVP_PKEY_assign +#define EVP_PKEY_assign_DSA GRPC_SHADOW_EVP_PKEY_assign_DSA +#define EVP_PKEY_assign_EC_KEY GRPC_SHADOW_EVP_PKEY_assign_EC_KEY +#define EVP_PKEY_assign_RSA GRPC_SHADOW_EVP_PKEY_assign_RSA +#define EVP_PKEY_bits GRPC_SHADOW_EVP_PKEY_bits +#define EVP_PKEY_cmp GRPC_SHADOW_EVP_PKEY_cmp +#define EVP_PKEY_cmp_parameters GRPC_SHADOW_EVP_PKEY_cmp_parameters +#define EVP_PKEY_copy_parameters GRPC_SHADOW_EVP_PKEY_copy_parameters +#define EVP_PKEY_free GRPC_SHADOW_EVP_PKEY_free +#define EVP_PKEY_get0_DH GRPC_SHADOW_EVP_PKEY_get0_DH +#define EVP_PKEY_get0_DSA GRPC_SHADOW_EVP_PKEY_get0_DSA +#define EVP_PKEY_get0_EC_KEY GRPC_SHADOW_EVP_PKEY_get0_EC_KEY +#define EVP_PKEY_get0_RSA GRPC_SHADOW_EVP_PKEY_get0_RSA +#define EVP_PKEY_get1_DSA GRPC_SHADOW_EVP_PKEY_get1_DSA +#define EVP_PKEY_get1_EC_KEY GRPC_SHADOW_EVP_PKEY_get1_EC_KEY +#define EVP_PKEY_get1_RSA GRPC_SHADOW_EVP_PKEY_get1_RSA +#define EVP_PKEY_id GRPC_SHADOW_EVP_PKEY_id +#define EVP_PKEY_is_opaque GRPC_SHADOW_EVP_PKEY_is_opaque +#define EVP_PKEY_missing_parameters GRPC_SHADOW_EVP_PKEY_missing_parameters +#define EVP_PKEY_new GRPC_SHADOW_EVP_PKEY_new +#define EVP_PKEY_set1_DSA GRPC_SHADOW_EVP_PKEY_set1_DSA +#define EVP_PKEY_set1_EC_KEY GRPC_SHADOW_EVP_PKEY_set1_EC_KEY +#define EVP_PKEY_set1_RSA GRPC_SHADOW_EVP_PKEY_set1_RSA +#define EVP_PKEY_set_type GRPC_SHADOW_EVP_PKEY_set_type +#define EVP_PKEY_size GRPC_SHADOW_EVP_PKEY_size +#define EVP_PKEY_type GRPC_SHADOW_EVP_PKEY_type +#define EVP_PKEY_up_ref GRPC_SHADOW_EVP_PKEY_up_ref +#define EVP_cleanup GRPC_SHADOW_EVP_cleanup +#define OPENSSL_add_all_algorithms_conf GRPC_SHADOW_OPENSSL_add_all_algorithms_conf +#define OpenSSL_add_all_algorithms GRPC_SHADOW_OpenSSL_add_all_algorithms +#define OpenSSL_add_all_ciphers GRPC_SHADOW_OpenSSL_add_all_ciphers +#define OpenSSL_add_all_digests GRPC_SHADOW_OpenSSL_add_all_digests +#define EVP_marshal_private_key GRPC_SHADOW_EVP_marshal_private_key +#define EVP_marshal_public_key GRPC_SHADOW_EVP_marshal_public_key +#define EVP_parse_private_key GRPC_SHADOW_EVP_parse_private_key +#define EVP_parse_public_key GRPC_SHADOW_EVP_parse_public_key +#define d2i_AutoPrivateKey GRPC_SHADOW_d2i_AutoPrivateKey +#define d2i_PrivateKey GRPC_SHADOW_d2i_PrivateKey +#define i2d_PublicKey GRPC_SHADOW_i2d_PublicKey +#define EVP_PKEY_CTX_ctrl GRPC_SHADOW_EVP_PKEY_CTX_ctrl +#define EVP_PKEY_CTX_dup GRPC_SHADOW_EVP_PKEY_CTX_dup +#define EVP_PKEY_CTX_free GRPC_SHADOW_EVP_PKEY_CTX_free +#define EVP_PKEY_CTX_get0_pkey GRPC_SHADOW_EVP_PKEY_CTX_get0_pkey +#define EVP_PKEY_CTX_new GRPC_SHADOW_EVP_PKEY_CTX_new +#define EVP_PKEY_CTX_new_id GRPC_SHADOW_EVP_PKEY_CTX_new_id +#define EVP_PKEY_decrypt GRPC_SHADOW_EVP_PKEY_decrypt +#define EVP_PKEY_decrypt_init GRPC_SHADOW_EVP_PKEY_decrypt_init +#define EVP_PKEY_derive GRPC_SHADOW_EVP_PKEY_derive +#define EVP_PKEY_derive_init GRPC_SHADOW_EVP_PKEY_derive_init +#define EVP_PKEY_derive_set_peer GRPC_SHADOW_EVP_PKEY_derive_set_peer +#define EVP_PKEY_encrypt GRPC_SHADOW_EVP_PKEY_encrypt +#define EVP_PKEY_encrypt_init GRPC_SHADOW_EVP_PKEY_encrypt_init +#define EVP_PKEY_keygen GRPC_SHADOW_EVP_PKEY_keygen +#define EVP_PKEY_keygen_init GRPC_SHADOW_EVP_PKEY_keygen_init +#define EVP_PKEY_sign GRPC_SHADOW_EVP_PKEY_sign +#define EVP_PKEY_sign_init GRPC_SHADOW_EVP_PKEY_sign_init +#define EVP_PKEY_verify GRPC_SHADOW_EVP_PKEY_verify +#define EVP_PKEY_verify_init GRPC_SHADOW_EVP_PKEY_verify_init +#define EVP_PKEY_verify_recover GRPC_SHADOW_EVP_PKEY_verify_recover +#define EVP_PKEY_verify_recover_init GRPC_SHADOW_EVP_PKEY_verify_recover_init +#define dsa_asn1_meth GRPC_SHADOW_dsa_asn1_meth +#define ec_pkey_meth GRPC_SHADOW_ec_pkey_meth +#define ec_asn1_meth GRPC_SHADOW_ec_asn1_meth +#define ed25519_pkey_meth GRPC_SHADOW_ed25519_pkey_meth +#define EVP_PKEY_new_ed25519_private GRPC_SHADOW_EVP_PKEY_new_ed25519_private +#define EVP_PKEY_new_ed25519_public GRPC_SHADOW_EVP_PKEY_new_ed25519_public +#define ed25519_asn1_meth GRPC_SHADOW_ed25519_asn1_meth +#define EVP_PKEY_CTX_get0_rsa_oaep_label GRPC_SHADOW_EVP_PKEY_CTX_get0_rsa_oaep_label +#define EVP_PKEY_CTX_get_rsa_mgf1_md GRPC_SHADOW_EVP_PKEY_CTX_get_rsa_mgf1_md +#define EVP_PKEY_CTX_get_rsa_oaep_md GRPC_SHADOW_EVP_PKEY_CTX_get_rsa_oaep_md +#define EVP_PKEY_CTX_get_rsa_padding GRPC_SHADOW_EVP_PKEY_CTX_get_rsa_padding +#define EVP_PKEY_CTX_get_rsa_pss_saltlen GRPC_SHADOW_EVP_PKEY_CTX_get_rsa_pss_saltlen +#define EVP_PKEY_CTX_set0_rsa_oaep_label GRPC_SHADOW_EVP_PKEY_CTX_set0_rsa_oaep_label +#define EVP_PKEY_CTX_set_rsa_keygen_bits GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_keygen_bits +#define EVP_PKEY_CTX_set_rsa_keygen_pubexp GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_keygen_pubexp +#define EVP_PKEY_CTX_set_rsa_mgf1_md GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_mgf1_md +#define EVP_PKEY_CTX_set_rsa_oaep_md GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_oaep_md +#define EVP_PKEY_CTX_set_rsa_padding GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_padding +#define EVP_PKEY_CTX_set_rsa_pss_saltlen GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_pss_saltlen +#define rsa_pkey_meth GRPC_SHADOW_rsa_pkey_meth +#define rsa_asn1_meth GRPC_SHADOW_rsa_asn1_meth +#define PKCS5_PBKDF2_HMAC GRPC_SHADOW_PKCS5_PBKDF2_HMAC +#define PKCS5_PBKDF2_HMAC_SHA1 GRPC_SHADOW_PKCS5_PBKDF2_HMAC_SHA1 +#define EVP_PKEY_print_params GRPC_SHADOW_EVP_PKEY_print_params +#define EVP_PKEY_print_private GRPC_SHADOW_EVP_PKEY_print_private +#define EVP_PKEY_print_public GRPC_SHADOW_EVP_PKEY_print_public +#define EVP_PBE_scrypt GRPC_SHADOW_EVP_PBE_scrypt +#define EVP_SignFinal GRPC_SHADOW_EVP_SignFinal +#define EVP_SignInit GRPC_SHADOW_EVP_SignInit +#define EVP_SignInit_ex GRPC_SHADOW_EVP_SignInit_ex +#define EVP_SignUpdate GRPC_SHADOW_EVP_SignUpdate +#define EVP_VerifyFinal GRPC_SHADOW_EVP_VerifyFinal +#define EVP_VerifyInit GRPC_SHADOW_EVP_VerifyInit +#define EVP_VerifyInit_ex GRPC_SHADOW_EVP_VerifyInit_ex +#define EVP_VerifyUpdate GRPC_SHADOW_EVP_VerifyUpdate +#define HKDF GRPC_SHADOW_HKDF +#define HKDF_expand GRPC_SHADOW_HKDF_expand +#define HKDF_extract GRPC_SHADOW_HKDF_extract +#define PEM_read_DSAPrivateKey GRPC_SHADOW_PEM_read_DSAPrivateKey +#define PEM_read_DSA_PUBKEY GRPC_SHADOW_PEM_read_DSA_PUBKEY +#define PEM_read_DSAparams GRPC_SHADOW_PEM_read_DSAparams +#define PEM_read_ECPrivateKey GRPC_SHADOW_PEM_read_ECPrivateKey +#define PEM_read_EC_PUBKEY GRPC_SHADOW_PEM_read_EC_PUBKEY +#define PEM_read_PUBKEY GRPC_SHADOW_PEM_read_PUBKEY +#define PEM_read_RSAPrivateKey GRPC_SHADOW_PEM_read_RSAPrivateKey +#define PEM_read_RSAPublicKey GRPC_SHADOW_PEM_read_RSAPublicKey +#define PEM_read_RSA_PUBKEY GRPC_SHADOW_PEM_read_RSA_PUBKEY +#define PEM_read_X509_CRL GRPC_SHADOW_PEM_read_X509_CRL +#define PEM_read_X509_REQ GRPC_SHADOW_PEM_read_X509_REQ +#define PEM_read_bio_DSAPrivateKey GRPC_SHADOW_PEM_read_bio_DSAPrivateKey +#define PEM_read_bio_DSA_PUBKEY GRPC_SHADOW_PEM_read_bio_DSA_PUBKEY +#define PEM_read_bio_DSAparams GRPC_SHADOW_PEM_read_bio_DSAparams +#define PEM_read_bio_ECPrivateKey GRPC_SHADOW_PEM_read_bio_ECPrivateKey +#define PEM_read_bio_EC_PUBKEY GRPC_SHADOW_PEM_read_bio_EC_PUBKEY +#define PEM_read_bio_PUBKEY GRPC_SHADOW_PEM_read_bio_PUBKEY +#define PEM_read_bio_RSAPrivateKey GRPC_SHADOW_PEM_read_bio_RSAPrivateKey +#define PEM_read_bio_RSAPublicKey GRPC_SHADOW_PEM_read_bio_RSAPublicKey +#define PEM_read_bio_RSA_PUBKEY GRPC_SHADOW_PEM_read_bio_RSA_PUBKEY +#define PEM_read_bio_X509_CRL GRPC_SHADOW_PEM_read_bio_X509_CRL +#define PEM_read_bio_X509_REQ GRPC_SHADOW_PEM_read_bio_X509_REQ +#define PEM_write_DHparams GRPC_SHADOW_PEM_write_DHparams +#define PEM_write_DSAPrivateKey GRPC_SHADOW_PEM_write_DSAPrivateKey +#define PEM_write_DSA_PUBKEY GRPC_SHADOW_PEM_write_DSA_PUBKEY +#define PEM_write_DSAparams GRPC_SHADOW_PEM_write_DSAparams +#define PEM_write_ECPrivateKey GRPC_SHADOW_PEM_write_ECPrivateKey +#define PEM_write_EC_PUBKEY GRPC_SHADOW_PEM_write_EC_PUBKEY +#define PEM_write_PUBKEY GRPC_SHADOW_PEM_write_PUBKEY +#define PEM_write_RSAPrivateKey GRPC_SHADOW_PEM_write_RSAPrivateKey +#define PEM_write_RSAPublicKey GRPC_SHADOW_PEM_write_RSAPublicKey +#define PEM_write_RSA_PUBKEY GRPC_SHADOW_PEM_write_RSA_PUBKEY +#define PEM_write_X509_CRL GRPC_SHADOW_PEM_write_X509_CRL +#define PEM_write_X509_REQ GRPC_SHADOW_PEM_write_X509_REQ +#define PEM_write_X509_REQ_NEW GRPC_SHADOW_PEM_write_X509_REQ_NEW +#define PEM_write_bio_DHparams GRPC_SHADOW_PEM_write_bio_DHparams +#define PEM_write_bio_DSAPrivateKey GRPC_SHADOW_PEM_write_bio_DSAPrivateKey +#define PEM_write_bio_DSA_PUBKEY GRPC_SHADOW_PEM_write_bio_DSA_PUBKEY +#define PEM_write_bio_DSAparams GRPC_SHADOW_PEM_write_bio_DSAparams +#define PEM_write_bio_ECPrivateKey GRPC_SHADOW_PEM_write_bio_ECPrivateKey +#define PEM_write_bio_EC_PUBKEY GRPC_SHADOW_PEM_write_bio_EC_PUBKEY +#define PEM_write_bio_PUBKEY GRPC_SHADOW_PEM_write_bio_PUBKEY +#define PEM_write_bio_RSAPrivateKey GRPC_SHADOW_PEM_write_bio_RSAPrivateKey +#define PEM_write_bio_RSAPublicKey GRPC_SHADOW_PEM_write_bio_RSAPublicKey +#define PEM_write_bio_RSA_PUBKEY GRPC_SHADOW_PEM_write_bio_RSA_PUBKEY +#define PEM_write_bio_X509_CRL GRPC_SHADOW_PEM_write_bio_X509_CRL +#define PEM_write_bio_X509_REQ GRPC_SHADOW_PEM_write_bio_X509_REQ +#define PEM_write_bio_X509_REQ_NEW GRPC_SHADOW_PEM_write_bio_X509_REQ_NEW +#define PEM_X509_INFO_read GRPC_SHADOW_PEM_X509_INFO_read +#define PEM_X509_INFO_read_bio GRPC_SHADOW_PEM_X509_INFO_read_bio +#define PEM_X509_INFO_write_bio GRPC_SHADOW_PEM_X509_INFO_write_bio +#define PEM_ASN1_read GRPC_SHADOW_PEM_ASN1_read +#define PEM_ASN1_write GRPC_SHADOW_PEM_ASN1_write +#define PEM_ASN1_write_bio GRPC_SHADOW_PEM_ASN1_write_bio +#define PEM_bytes_read_bio GRPC_SHADOW_PEM_bytes_read_bio +#define PEM_def_callback GRPC_SHADOW_PEM_def_callback +#define PEM_dek_info GRPC_SHADOW_PEM_dek_info +#define PEM_do_header GRPC_SHADOW_PEM_do_header +#define PEM_get_EVP_CIPHER_INFO GRPC_SHADOW_PEM_get_EVP_CIPHER_INFO +#define PEM_proc_type GRPC_SHADOW_PEM_proc_type +#define PEM_read GRPC_SHADOW_PEM_read +#define PEM_read_bio GRPC_SHADOW_PEM_read_bio +#define PEM_write GRPC_SHADOW_PEM_write +#define PEM_write_bio GRPC_SHADOW_PEM_write_bio +#define PEM_ASN1_read_bio GRPC_SHADOW_PEM_ASN1_read_bio +#define PEM_read_PKCS8 GRPC_SHADOW_PEM_read_PKCS8 +#define PEM_read_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_PEM_read_PKCS8_PRIV_KEY_INFO +#define PEM_read_bio_PKCS8 GRPC_SHADOW_PEM_read_bio_PKCS8 +#define PEM_read_bio_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_PEM_read_bio_PKCS8_PRIV_KEY_INFO +#define PEM_write_PKCS8 GRPC_SHADOW_PEM_write_PKCS8 +#define PEM_write_PKCS8PrivateKey GRPC_SHADOW_PEM_write_PKCS8PrivateKey +#define PEM_write_PKCS8PrivateKey_nid GRPC_SHADOW_PEM_write_PKCS8PrivateKey_nid +#define PEM_write_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_PEM_write_PKCS8_PRIV_KEY_INFO +#define PEM_write_bio_PKCS8 GRPC_SHADOW_PEM_write_bio_PKCS8 +#define PEM_write_bio_PKCS8PrivateKey GRPC_SHADOW_PEM_write_bio_PKCS8PrivateKey +#define PEM_write_bio_PKCS8PrivateKey_nid GRPC_SHADOW_PEM_write_bio_PKCS8PrivateKey_nid +#define PEM_write_bio_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_PEM_write_bio_PKCS8_PRIV_KEY_INFO +#define d2i_PKCS8PrivateKey_bio GRPC_SHADOW_d2i_PKCS8PrivateKey_bio +#define d2i_PKCS8PrivateKey_fp GRPC_SHADOW_d2i_PKCS8PrivateKey_fp +#define i2d_PKCS8PrivateKey_bio GRPC_SHADOW_i2d_PKCS8PrivateKey_bio +#define i2d_PKCS8PrivateKey_fp GRPC_SHADOW_i2d_PKCS8PrivateKey_fp +#define i2d_PKCS8PrivateKey_nid_bio GRPC_SHADOW_i2d_PKCS8PrivateKey_nid_bio +#define i2d_PKCS8PrivateKey_nid_fp GRPC_SHADOW_i2d_PKCS8PrivateKey_nid_fp +#define PEM_read_DHparams GRPC_SHADOW_PEM_read_DHparams +#define PEM_read_PrivateKey GRPC_SHADOW_PEM_read_PrivateKey +#define PEM_read_bio_DHparams GRPC_SHADOW_PEM_read_bio_DHparams +#define PEM_read_bio_PrivateKey GRPC_SHADOW_PEM_read_bio_PrivateKey +#define PEM_write_PrivateKey GRPC_SHADOW_PEM_write_PrivateKey +#define PEM_write_bio_PrivateKey GRPC_SHADOW_PEM_write_bio_PrivateKey +#define PEM_read_X509 GRPC_SHADOW_PEM_read_X509 +#define PEM_read_bio_X509 GRPC_SHADOW_PEM_read_bio_X509 +#define PEM_write_X509 GRPC_SHADOW_PEM_write_X509 +#define PEM_write_bio_X509 GRPC_SHADOW_PEM_write_bio_X509 +#define PEM_read_X509_AUX GRPC_SHADOW_PEM_read_X509_AUX +#define PEM_read_bio_X509_AUX GRPC_SHADOW_PEM_read_bio_X509_AUX +#define PEM_write_X509_AUX GRPC_SHADOW_PEM_write_X509_AUX +#define PEM_write_bio_X509_AUX GRPC_SHADOW_PEM_write_bio_X509_AUX +#define ASN1_digest GRPC_SHADOW_ASN1_digest +#define ASN1_item_digest GRPC_SHADOW_ASN1_item_digest +#define ASN1_item_sign GRPC_SHADOW_ASN1_item_sign +#define ASN1_item_sign_ctx GRPC_SHADOW_ASN1_item_sign_ctx +#define ASN1_STRING_print_ex GRPC_SHADOW_ASN1_STRING_print_ex +#define ASN1_STRING_print_ex_fp GRPC_SHADOW_ASN1_STRING_print_ex_fp +#define ASN1_STRING_to_UTF8 GRPC_SHADOW_ASN1_STRING_to_UTF8 +#define X509_NAME_print_ex GRPC_SHADOW_X509_NAME_print_ex +#define X509_NAME_print_ex_fp GRPC_SHADOW_X509_NAME_print_ex_fp +#define ASN1_item_verify GRPC_SHADOW_ASN1_item_verify +#define x509_digest_sign_algorithm GRPC_SHADOW_x509_digest_sign_algorithm +#define x509_digest_verify_init GRPC_SHADOW_x509_digest_verify_init +#define ASN1_generate_nconf GRPC_SHADOW_ASN1_generate_nconf +#define ASN1_generate_v3 GRPC_SHADOW_ASN1_generate_v3 +#define X509_LOOKUP_hash_dir GRPC_SHADOW_X509_LOOKUP_hash_dir +#define X509_LOOKUP_file GRPC_SHADOW_X509_LOOKUP_file +#define X509_load_cert_crl_file GRPC_SHADOW_X509_load_cert_crl_file +#define X509_load_cert_file GRPC_SHADOW_X509_load_cert_file +#define X509_load_crl_file GRPC_SHADOW_X509_load_crl_file +#define i2d_PrivateKey GRPC_SHADOW_i2d_PrivateKey +#define RSA_PSS_PARAMS_free GRPC_SHADOW_RSA_PSS_PARAMS_free +#define RSA_PSS_PARAMS_it GRPC_SHADOW_RSA_PSS_PARAMS_it +#define RSA_PSS_PARAMS_new GRPC_SHADOW_RSA_PSS_PARAMS_new +#define d2i_RSA_PSS_PARAMS GRPC_SHADOW_d2i_RSA_PSS_PARAMS +#define i2d_RSA_PSS_PARAMS GRPC_SHADOW_i2d_RSA_PSS_PARAMS +#define x509_print_rsa_pss_params GRPC_SHADOW_x509_print_rsa_pss_params +#define x509_rsa_ctx_to_pss GRPC_SHADOW_x509_rsa_ctx_to_pss +#define x509_rsa_pss_to_ctx GRPC_SHADOW_x509_rsa_pss_to_ctx +#define X509_CRL_print GRPC_SHADOW_X509_CRL_print +#define X509_CRL_print_fp GRPC_SHADOW_X509_CRL_print_fp +#define X509_REQ_print GRPC_SHADOW_X509_REQ_print +#define X509_REQ_print_ex GRPC_SHADOW_X509_REQ_print_ex +#define X509_REQ_print_fp GRPC_SHADOW_X509_REQ_print_fp +#define ASN1_GENERALIZEDTIME_print GRPC_SHADOW_ASN1_GENERALIZEDTIME_print +#define ASN1_STRING_print GRPC_SHADOW_ASN1_STRING_print +#define ASN1_TIME_print GRPC_SHADOW_ASN1_TIME_print +#define ASN1_UTCTIME_print GRPC_SHADOW_ASN1_UTCTIME_print +#define X509_NAME_print GRPC_SHADOW_X509_NAME_print +#define X509_ocspid_print GRPC_SHADOW_X509_ocspid_print +#define X509_print GRPC_SHADOW_X509_print +#define X509_print_ex GRPC_SHADOW_X509_print_ex +#define X509_print_ex_fp GRPC_SHADOW_X509_print_ex_fp +#define X509_print_fp GRPC_SHADOW_X509_print_fp +#define X509_signature_print GRPC_SHADOW_X509_signature_print +#define X509_CERT_AUX_print GRPC_SHADOW_X509_CERT_AUX_print +#define PKCS8_pkey_get0 GRPC_SHADOW_PKCS8_pkey_get0 +#define PKCS8_pkey_set0 GRPC_SHADOW_PKCS8_pkey_set0 +#define X509_signature_dump GRPC_SHADOW_X509_signature_dump +#define X509_ATTRIBUTE_count GRPC_SHADOW_X509_ATTRIBUTE_count +#define X509_ATTRIBUTE_create_by_NID GRPC_SHADOW_X509_ATTRIBUTE_create_by_NID +#define X509_ATTRIBUTE_create_by_OBJ GRPC_SHADOW_X509_ATTRIBUTE_create_by_OBJ +#define X509_ATTRIBUTE_create_by_txt GRPC_SHADOW_X509_ATTRIBUTE_create_by_txt +#define X509_ATTRIBUTE_get0_data GRPC_SHADOW_X509_ATTRIBUTE_get0_data +#define X509_ATTRIBUTE_get0_object GRPC_SHADOW_X509_ATTRIBUTE_get0_object +#define X509_ATTRIBUTE_get0_type GRPC_SHADOW_X509_ATTRIBUTE_get0_type +#define X509_ATTRIBUTE_set1_data GRPC_SHADOW_X509_ATTRIBUTE_set1_data +#define X509_ATTRIBUTE_set1_object GRPC_SHADOW_X509_ATTRIBUTE_set1_object +#define X509at_add1_attr GRPC_SHADOW_X509at_add1_attr +#define X509at_add1_attr_by_NID GRPC_SHADOW_X509at_add1_attr_by_NID +#define X509at_add1_attr_by_OBJ GRPC_SHADOW_X509at_add1_attr_by_OBJ +#define X509at_add1_attr_by_txt GRPC_SHADOW_X509at_add1_attr_by_txt +#define X509at_delete_attr GRPC_SHADOW_X509at_delete_attr +#define X509at_get0_data_by_OBJ GRPC_SHADOW_X509at_get0_data_by_OBJ +#define X509at_get_attr GRPC_SHADOW_X509at_get_attr +#define X509at_get_attr_by_NID GRPC_SHADOW_X509at_get_attr_by_NID +#define X509at_get_attr_by_OBJ GRPC_SHADOW_X509at_get_attr_by_OBJ +#define X509at_get_attr_count GRPC_SHADOW_X509at_get_attr_count +#define X509_CRL_check_suiteb GRPC_SHADOW_X509_CRL_check_suiteb +#define X509_CRL_cmp GRPC_SHADOW_X509_CRL_cmp +#define X509_CRL_match GRPC_SHADOW_X509_CRL_match +#define X509_NAME_cmp GRPC_SHADOW_X509_NAME_cmp +#define X509_NAME_hash GRPC_SHADOW_X509_NAME_hash +#define X509_NAME_hash_old GRPC_SHADOW_X509_NAME_hash_old +#define X509_chain_check_suiteb GRPC_SHADOW_X509_chain_check_suiteb +#define X509_chain_up_ref GRPC_SHADOW_X509_chain_up_ref +#define X509_check_private_key GRPC_SHADOW_X509_check_private_key +#define X509_cmp GRPC_SHADOW_X509_cmp +#define X509_find_by_issuer_and_serial GRPC_SHADOW_X509_find_by_issuer_and_serial +#define X509_find_by_subject GRPC_SHADOW_X509_find_by_subject +#define X509_get0_pubkey_bitstr GRPC_SHADOW_X509_get0_pubkey_bitstr +#define X509_get_issuer_name GRPC_SHADOW_X509_get_issuer_name +#define X509_get_pubkey GRPC_SHADOW_X509_get_pubkey +#define X509_get_serialNumber GRPC_SHADOW_X509_get_serialNumber +#define X509_get_subject_name GRPC_SHADOW_X509_get_subject_name +#define X509_issuer_and_serial_cmp GRPC_SHADOW_X509_issuer_and_serial_cmp +#define X509_issuer_and_serial_hash GRPC_SHADOW_X509_issuer_and_serial_hash +#define X509_issuer_name_cmp GRPC_SHADOW_X509_issuer_name_cmp +#define X509_issuer_name_hash GRPC_SHADOW_X509_issuer_name_hash +#define X509_issuer_name_hash_old GRPC_SHADOW_X509_issuer_name_hash_old +#define X509_subject_name_cmp GRPC_SHADOW_X509_subject_name_cmp +#define X509_subject_name_hash GRPC_SHADOW_X509_subject_name_hash +#define X509_subject_name_hash_old GRPC_SHADOW_X509_subject_name_hash_old +#define X509_STORE_load_locations GRPC_SHADOW_X509_STORE_load_locations +#define X509_STORE_set_default_paths GRPC_SHADOW_X509_STORE_set_default_paths +#define X509_get_default_cert_area GRPC_SHADOW_X509_get_default_cert_area +#define X509_get_default_cert_dir GRPC_SHADOW_X509_get_default_cert_dir +#define X509_get_default_cert_dir_env GRPC_SHADOW_X509_get_default_cert_dir_env +#define X509_get_default_cert_file GRPC_SHADOW_X509_get_default_cert_file +#define X509_get_default_cert_file_env GRPC_SHADOW_X509_get_default_cert_file_env +#define X509_get_default_private_dir GRPC_SHADOW_X509_get_default_private_dir +#define X509_CRL_add1_ext_i2d GRPC_SHADOW_X509_CRL_add1_ext_i2d +#define X509_CRL_add_ext GRPC_SHADOW_X509_CRL_add_ext +#define X509_CRL_delete_ext GRPC_SHADOW_X509_CRL_delete_ext +#define X509_CRL_get_ext GRPC_SHADOW_X509_CRL_get_ext +#define X509_CRL_get_ext_by_NID GRPC_SHADOW_X509_CRL_get_ext_by_NID +#define X509_CRL_get_ext_by_OBJ GRPC_SHADOW_X509_CRL_get_ext_by_OBJ +#define X509_CRL_get_ext_by_critical GRPC_SHADOW_X509_CRL_get_ext_by_critical +#define X509_CRL_get_ext_count GRPC_SHADOW_X509_CRL_get_ext_count +#define X509_CRL_get_ext_d2i GRPC_SHADOW_X509_CRL_get_ext_d2i +#define X509_REVOKED_add1_ext_i2d GRPC_SHADOW_X509_REVOKED_add1_ext_i2d +#define X509_REVOKED_add_ext GRPC_SHADOW_X509_REVOKED_add_ext +#define X509_REVOKED_delete_ext GRPC_SHADOW_X509_REVOKED_delete_ext +#define X509_REVOKED_get_ext GRPC_SHADOW_X509_REVOKED_get_ext +#define X509_REVOKED_get_ext_by_NID GRPC_SHADOW_X509_REVOKED_get_ext_by_NID +#define X509_REVOKED_get_ext_by_OBJ GRPC_SHADOW_X509_REVOKED_get_ext_by_OBJ +#define X509_REVOKED_get_ext_by_critical GRPC_SHADOW_X509_REVOKED_get_ext_by_critical +#define X509_REVOKED_get_ext_count GRPC_SHADOW_X509_REVOKED_get_ext_count +#define X509_REVOKED_get_ext_d2i GRPC_SHADOW_X509_REVOKED_get_ext_d2i +#define X509_add1_ext_i2d GRPC_SHADOW_X509_add1_ext_i2d +#define X509_add_ext GRPC_SHADOW_X509_add_ext +#define X509_delete_ext GRPC_SHADOW_X509_delete_ext +#define X509_get_ext GRPC_SHADOW_X509_get_ext +#define X509_get_ext_by_NID GRPC_SHADOW_X509_get_ext_by_NID +#define X509_get_ext_by_OBJ GRPC_SHADOW_X509_get_ext_by_OBJ +#define X509_get_ext_by_critical GRPC_SHADOW_X509_get_ext_by_critical +#define X509_get_ext_count GRPC_SHADOW_X509_get_ext_count +#define X509_get_ext_d2i GRPC_SHADOW_X509_get_ext_d2i +#define X509_LOOKUP_by_alias GRPC_SHADOW_X509_LOOKUP_by_alias +#define X509_LOOKUP_by_fingerprint GRPC_SHADOW_X509_LOOKUP_by_fingerprint +#define X509_LOOKUP_by_issuer_serial GRPC_SHADOW_X509_LOOKUP_by_issuer_serial +#define X509_LOOKUP_by_subject GRPC_SHADOW_X509_LOOKUP_by_subject +#define X509_LOOKUP_ctrl GRPC_SHADOW_X509_LOOKUP_ctrl +#define X509_LOOKUP_free GRPC_SHADOW_X509_LOOKUP_free +#define X509_LOOKUP_init GRPC_SHADOW_X509_LOOKUP_init +#define X509_LOOKUP_new GRPC_SHADOW_X509_LOOKUP_new +#define X509_LOOKUP_shutdown GRPC_SHADOW_X509_LOOKUP_shutdown +#define X509_OBJECT_free_contents GRPC_SHADOW_X509_OBJECT_free_contents +#define X509_OBJECT_get0_X509 GRPC_SHADOW_X509_OBJECT_get0_X509 +#define X509_OBJECT_get_type GRPC_SHADOW_X509_OBJECT_get_type +#define X509_OBJECT_idx_by_subject GRPC_SHADOW_X509_OBJECT_idx_by_subject +#define X509_OBJECT_retrieve_by_subject GRPC_SHADOW_X509_OBJECT_retrieve_by_subject +#define X509_OBJECT_retrieve_match GRPC_SHADOW_X509_OBJECT_retrieve_match +#define X509_OBJECT_up_ref_count GRPC_SHADOW_X509_OBJECT_up_ref_count +#define X509_STORE_CTX_get0_store GRPC_SHADOW_X509_STORE_CTX_get0_store +#define X509_STORE_CTX_get1_issuer GRPC_SHADOW_X509_STORE_CTX_get1_issuer +#define X509_STORE_add_cert GRPC_SHADOW_X509_STORE_add_cert +#define X509_STORE_add_crl GRPC_SHADOW_X509_STORE_add_crl +#define X509_STORE_add_lookup GRPC_SHADOW_X509_STORE_add_lookup +#define X509_STORE_free GRPC_SHADOW_X509_STORE_free +#define X509_STORE_get0_objects GRPC_SHADOW_X509_STORE_get0_objects +#define X509_STORE_get0_param GRPC_SHADOW_X509_STORE_get0_param +#define X509_STORE_get1_certs GRPC_SHADOW_X509_STORE_get1_certs +#define X509_STORE_get1_crls GRPC_SHADOW_X509_STORE_get1_crls +#define X509_STORE_get_by_subject GRPC_SHADOW_X509_STORE_get_by_subject +#define X509_STORE_new GRPC_SHADOW_X509_STORE_new +#define X509_STORE_set0_additional_untrusted GRPC_SHADOW_X509_STORE_set0_additional_untrusted +#define X509_STORE_set1_param GRPC_SHADOW_X509_STORE_set1_param +#define X509_STORE_set_depth GRPC_SHADOW_X509_STORE_set_depth +#define X509_STORE_set_flags GRPC_SHADOW_X509_STORE_set_flags +#define X509_STORE_set_lookup_crls_cb GRPC_SHADOW_X509_STORE_set_lookup_crls_cb +#define X509_STORE_set_purpose GRPC_SHADOW_X509_STORE_set_purpose +#define X509_STORE_set_trust GRPC_SHADOW_X509_STORE_set_trust +#define X509_STORE_set_verify_cb GRPC_SHADOW_X509_STORE_set_verify_cb +#define X509_STORE_up_ref GRPC_SHADOW_X509_STORE_up_ref +#define X509_NAME_oneline GRPC_SHADOW_X509_NAME_oneline +#define X509_REQ_to_X509 GRPC_SHADOW_X509_REQ_to_X509 +#define X509_REQ_add1_attr GRPC_SHADOW_X509_REQ_add1_attr +#define X509_REQ_add1_attr_by_NID GRPC_SHADOW_X509_REQ_add1_attr_by_NID +#define X509_REQ_add1_attr_by_OBJ GRPC_SHADOW_X509_REQ_add1_attr_by_OBJ +#define X509_REQ_add1_attr_by_txt GRPC_SHADOW_X509_REQ_add1_attr_by_txt +#define X509_REQ_add_extensions GRPC_SHADOW_X509_REQ_add_extensions +#define X509_REQ_add_extensions_nid GRPC_SHADOW_X509_REQ_add_extensions_nid +#define X509_REQ_check_private_key GRPC_SHADOW_X509_REQ_check_private_key +#define X509_REQ_delete_attr GRPC_SHADOW_X509_REQ_delete_attr +#define X509_REQ_extension_nid GRPC_SHADOW_X509_REQ_extension_nid +#define X509_REQ_get_attr GRPC_SHADOW_X509_REQ_get_attr +#define X509_REQ_get_attr_by_NID GRPC_SHADOW_X509_REQ_get_attr_by_NID +#define X509_REQ_get_attr_by_OBJ GRPC_SHADOW_X509_REQ_get_attr_by_OBJ +#define X509_REQ_get_attr_count GRPC_SHADOW_X509_REQ_get_attr_count +#define X509_REQ_get_extension_nids GRPC_SHADOW_X509_REQ_get_extension_nids +#define X509_REQ_get_extensions GRPC_SHADOW_X509_REQ_get_extensions +#define X509_REQ_get_pubkey GRPC_SHADOW_X509_REQ_get_pubkey +#define X509_REQ_set_extension_nids GRPC_SHADOW_X509_REQ_set_extension_nids +#define X509_to_X509_REQ GRPC_SHADOW_X509_to_X509_REQ +#define X509_get0_extensions GRPC_SHADOW_X509_get0_extensions +#define X509_get0_notAfter GRPC_SHADOW_X509_get0_notAfter +#define X509_get0_notBefore GRPC_SHADOW_X509_get0_notBefore +#define X509_set_issuer_name GRPC_SHADOW_X509_set_issuer_name +#define X509_set_notAfter GRPC_SHADOW_X509_set_notAfter +#define X509_set_notBefore GRPC_SHADOW_X509_set_notBefore +#define X509_set_pubkey GRPC_SHADOW_X509_set_pubkey +#define X509_set_serialNumber GRPC_SHADOW_X509_set_serialNumber +#define X509_set_subject_name GRPC_SHADOW_X509_set_subject_name +#define X509_set_version GRPC_SHADOW_X509_set_version +#define X509_TRUST_add GRPC_SHADOW_X509_TRUST_add +#define X509_TRUST_cleanup GRPC_SHADOW_X509_TRUST_cleanup +#define X509_TRUST_get0 GRPC_SHADOW_X509_TRUST_get0 +#define X509_TRUST_get0_name GRPC_SHADOW_X509_TRUST_get0_name +#define X509_TRUST_get_by_id GRPC_SHADOW_X509_TRUST_get_by_id +#define X509_TRUST_get_count GRPC_SHADOW_X509_TRUST_get_count +#define X509_TRUST_get_flags GRPC_SHADOW_X509_TRUST_get_flags +#define X509_TRUST_get_trust GRPC_SHADOW_X509_TRUST_get_trust +#define X509_TRUST_set GRPC_SHADOW_X509_TRUST_set +#define X509_TRUST_set_default GRPC_SHADOW_X509_TRUST_set_default +#define X509_check_trust GRPC_SHADOW_X509_check_trust +#define X509_verify_cert_error_string GRPC_SHADOW_X509_verify_cert_error_string +#define X509_EXTENSION_create_by_NID GRPC_SHADOW_X509_EXTENSION_create_by_NID +#define X509_EXTENSION_create_by_OBJ GRPC_SHADOW_X509_EXTENSION_create_by_OBJ +#define X509_EXTENSION_get_critical GRPC_SHADOW_X509_EXTENSION_get_critical +#define X509_EXTENSION_get_data GRPC_SHADOW_X509_EXTENSION_get_data +#define X509_EXTENSION_get_object GRPC_SHADOW_X509_EXTENSION_get_object +#define X509_EXTENSION_set_critical GRPC_SHADOW_X509_EXTENSION_set_critical +#define X509_EXTENSION_set_data GRPC_SHADOW_X509_EXTENSION_set_data +#define X509_EXTENSION_set_object GRPC_SHADOW_X509_EXTENSION_set_object +#define X509v3_add_ext GRPC_SHADOW_X509v3_add_ext +#define X509v3_delete_ext GRPC_SHADOW_X509v3_delete_ext +#define X509v3_get_ext GRPC_SHADOW_X509v3_get_ext +#define X509v3_get_ext_by_NID GRPC_SHADOW_X509v3_get_ext_by_NID +#define X509v3_get_ext_by_OBJ GRPC_SHADOW_X509v3_get_ext_by_OBJ +#define X509v3_get_ext_by_critical GRPC_SHADOW_X509v3_get_ext_by_critical +#define X509v3_get_ext_count GRPC_SHADOW_X509v3_get_ext_count +#define X509_CRL_diff GRPC_SHADOW_X509_CRL_diff +#define X509_STORE_CTX_cleanup GRPC_SHADOW_X509_STORE_CTX_cleanup +#define X509_STORE_CTX_free GRPC_SHADOW_X509_STORE_CTX_free +#define X509_STORE_CTX_get0_current_crl GRPC_SHADOW_X509_STORE_CTX_get0_current_crl +#define X509_STORE_CTX_get0_current_issuer GRPC_SHADOW_X509_STORE_CTX_get0_current_issuer +#define X509_STORE_CTX_get0_param GRPC_SHADOW_X509_STORE_CTX_get0_param +#define X509_STORE_CTX_get0_parent_ctx GRPC_SHADOW_X509_STORE_CTX_get0_parent_ctx +#define X509_STORE_CTX_get0_policy_tree GRPC_SHADOW_X509_STORE_CTX_get0_policy_tree +#define X509_STORE_CTX_get0_untrusted GRPC_SHADOW_X509_STORE_CTX_get0_untrusted +#define X509_STORE_CTX_get1_chain GRPC_SHADOW_X509_STORE_CTX_get1_chain +#define X509_STORE_CTX_get_chain GRPC_SHADOW_X509_STORE_CTX_get_chain +#define X509_STORE_CTX_get_current_cert GRPC_SHADOW_X509_STORE_CTX_get_current_cert +#define X509_STORE_CTX_get_error GRPC_SHADOW_X509_STORE_CTX_get_error +#define X509_STORE_CTX_get_error_depth GRPC_SHADOW_X509_STORE_CTX_get_error_depth +#define X509_STORE_CTX_get_ex_data GRPC_SHADOW_X509_STORE_CTX_get_ex_data +#define X509_STORE_CTX_get_ex_new_index GRPC_SHADOW_X509_STORE_CTX_get_ex_new_index +#define X509_STORE_CTX_get_explicit_policy GRPC_SHADOW_X509_STORE_CTX_get_explicit_policy +#define X509_STORE_CTX_init GRPC_SHADOW_X509_STORE_CTX_init +#define X509_STORE_CTX_new GRPC_SHADOW_X509_STORE_CTX_new +#define X509_STORE_CTX_purpose_inherit GRPC_SHADOW_X509_STORE_CTX_purpose_inherit +#define X509_STORE_CTX_set0_crls GRPC_SHADOW_X509_STORE_CTX_set0_crls +#define X509_STORE_CTX_set0_param GRPC_SHADOW_X509_STORE_CTX_set0_param +#define X509_STORE_CTX_set_cert GRPC_SHADOW_X509_STORE_CTX_set_cert +#define X509_STORE_CTX_set_chain GRPC_SHADOW_X509_STORE_CTX_set_chain +#define X509_STORE_CTX_set_default GRPC_SHADOW_X509_STORE_CTX_set_default +#define X509_STORE_CTX_set_depth GRPC_SHADOW_X509_STORE_CTX_set_depth +#define X509_STORE_CTX_set_error GRPC_SHADOW_X509_STORE_CTX_set_error +#define X509_STORE_CTX_set_ex_data GRPC_SHADOW_X509_STORE_CTX_set_ex_data +#define X509_STORE_CTX_set_flags GRPC_SHADOW_X509_STORE_CTX_set_flags +#define X509_STORE_CTX_set_purpose GRPC_SHADOW_X509_STORE_CTX_set_purpose +#define X509_STORE_CTX_set_time GRPC_SHADOW_X509_STORE_CTX_set_time +#define X509_STORE_CTX_set_trust GRPC_SHADOW_X509_STORE_CTX_set_trust +#define X509_STORE_CTX_set_verify_cb GRPC_SHADOW_X509_STORE_CTX_set_verify_cb +#define X509_STORE_CTX_trusted_stack GRPC_SHADOW_X509_STORE_CTX_trusted_stack +#define X509_STORE_CTX_zero GRPC_SHADOW_X509_STORE_CTX_zero +#define X509_cmp_current_time GRPC_SHADOW_X509_cmp_current_time +#define X509_cmp_time GRPC_SHADOW_X509_cmp_time +#define X509_gmtime_adj GRPC_SHADOW_X509_gmtime_adj +#define X509_time_adj GRPC_SHADOW_X509_time_adj +#define X509_time_adj_ex GRPC_SHADOW_X509_time_adj_ex +#define X509_verify_cert GRPC_SHADOW_X509_verify_cert +#define X509_VERIFY_PARAM_add0_policy GRPC_SHADOW_X509_VERIFY_PARAM_add0_policy +#define X509_VERIFY_PARAM_add0_table GRPC_SHADOW_X509_VERIFY_PARAM_add0_table +#define X509_VERIFY_PARAM_add1_host GRPC_SHADOW_X509_VERIFY_PARAM_add1_host +#define X509_VERIFY_PARAM_clear_flags GRPC_SHADOW_X509_VERIFY_PARAM_clear_flags +#define X509_VERIFY_PARAM_free GRPC_SHADOW_X509_VERIFY_PARAM_free +#define X509_VERIFY_PARAM_get0 GRPC_SHADOW_X509_VERIFY_PARAM_get0 +#define X509_VERIFY_PARAM_get0_name GRPC_SHADOW_X509_VERIFY_PARAM_get0_name +#define X509_VERIFY_PARAM_get0_peername GRPC_SHADOW_X509_VERIFY_PARAM_get0_peername +#define X509_VERIFY_PARAM_get_count GRPC_SHADOW_X509_VERIFY_PARAM_get_count +#define X509_VERIFY_PARAM_get_depth GRPC_SHADOW_X509_VERIFY_PARAM_get_depth +#define X509_VERIFY_PARAM_get_flags GRPC_SHADOW_X509_VERIFY_PARAM_get_flags +#define X509_VERIFY_PARAM_inherit GRPC_SHADOW_X509_VERIFY_PARAM_inherit +#define X509_VERIFY_PARAM_lookup GRPC_SHADOW_X509_VERIFY_PARAM_lookup +#define X509_VERIFY_PARAM_new GRPC_SHADOW_X509_VERIFY_PARAM_new +#define X509_VERIFY_PARAM_set1 GRPC_SHADOW_X509_VERIFY_PARAM_set1 +#define X509_VERIFY_PARAM_set1_email GRPC_SHADOW_X509_VERIFY_PARAM_set1_email +#define X509_VERIFY_PARAM_set1_host GRPC_SHADOW_X509_VERIFY_PARAM_set1_host +#define X509_VERIFY_PARAM_set1_ip GRPC_SHADOW_X509_VERIFY_PARAM_set1_ip +#define X509_VERIFY_PARAM_set1_ip_asc GRPC_SHADOW_X509_VERIFY_PARAM_set1_ip_asc +#define X509_VERIFY_PARAM_set1_name GRPC_SHADOW_X509_VERIFY_PARAM_set1_name +#define X509_VERIFY_PARAM_set1_policies GRPC_SHADOW_X509_VERIFY_PARAM_set1_policies +#define X509_VERIFY_PARAM_set_depth GRPC_SHADOW_X509_VERIFY_PARAM_set_depth +#define X509_VERIFY_PARAM_set_flags GRPC_SHADOW_X509_VERIFY_PARAM_set_flags +#define X509_VERIFY_PARAM_set_hostflags GRPC_SHADOW_X509_VERIFY_PARAM_set_hostflags +#define X509_VERIFY_PARAM_set_purpose GRPC_SHADOW_X509_VERIFY_PARAM_set_purpose +#define X509_VERIFY_PARAM_set_time GRPC_SHADOW_X509_VERIFY_PARAM_set_time +#define X509_VERIFY_PARAM_set_trust GRPC_SHADOW_X509_VERIFY_PARAM_set_trust +#define X509_VERIFY_PARAM_table_cleanup GRPC_SHADOW_X509_VERIFY_PARAM_table_cleanup +#define X509_CRL_set_issuer_name GRPC_SHADOW_X509_CRL_set_issuer_name +#define X509_CRL_set_lastUpdate GRPC_SHADOW_X509_CRL_set_lastUpdate +#define X509_CRL_set_nextUpdate GRPC_SHADOW_X509_CRL_set_nextUpdate +#define X509_CRL_set_version GRPC_SHADOW_X509_CRL_set_version +#define X509_CRL_sort GRPC_SHADOW_X509_CRL_sort +#define X509_CRL_up_ref GRPC_SHADOW_X509_CRL_up_ref +#define X509_REVOKED_set_revocationDate GRPC_SHADOW_X509_REVOKED_set_revocationDate +#define X509_REVOKED_set_serialNumber GRPC_SHADOW_X509_REVOKED_set_serialNumber +#define X509_NAME_ENTRY_create_by_NID GRPC_SHADOW_X509_NAME_ENTRY_create_by_NID +#define X509_NAME_ENTRY_create_by_OBJ GRPC_SHADOW_X509_NAME_ENTRY_create_by_OBJ +#define X509_NAME_ENTRY_create_by_txt GRPC_SHADOW_X509_NAME_ENTRY_create_by_txt +#define X509_NAME_ENTRY_get_data GRPC_SHADOW_X509_NAME_ENTRY_get_data +#define X509_NAME_ENTRY_get_object GRPC_SHADOW_X509_NAME_ENTRY_get_object +#define X509_NAME_ENTRY_set_data GRPC_SHADOW_X509_NAME_ENTRY_set_data +#define X509_NAME_ENTRY_set_object GRPC_SHADOW_X509_NAME_ENTRY_set_object +#define X509_NAME_add_entry GRPC_SHADOW_X509_NAME_add_entry +#define X509_NAME_add_entry_by_NID GRPC_SHADOW_X509_NAME_add_entry_by_NID +#define X509_NAME_add_entry_by_OBJ GRPC_SHADOW_X509_NAME_add_entry_by_OBJ +#define X509_NAME_add_entry_by_txt GRPC_SHADOW_X509_NAME_add_entry_by_txt +#define X509_NAME_delete_entry GRPC_SHADOW_X509_NAME_delete_entry +#define X509_NAME_entry_count GRPC_SHADOW_X509_NAME_entry_count +#define X509_NAME_get_entry GRPC_SHADOW_X509_NAME_get_entry +#define X509_NAME_get_index_by_NID GRPC_SHADOW_X509_NAME_get_index_by_NID +#define X509_NAME_get_index_by_OBJ GRPC_SHADOW_X509_NAME_get_index_by_OBJ +#define X509_NAME_get_text_by_NID GRPC_SHADOW_X509_NAME_get_text_by_NID +#define X509_NAME_get_text_by_OBJ GRPC_SHADOW_X509_NAME_get_text_by_OBJ +#define X509_REQ_set_pubkey GRPC_SHADOW_X509_REQ_set_pubkey +#define X509_REQ_set_subject_name GRPC_SHADOW_X509_REQ_set_subject_name +#define X509_REQ_set_version GRPC_SHADOW_X509_REQ_set_version +#define NETSCAPE_SPKI_b64_decode GRPC_SHADOW_NETSCAPE_SPKI_b64_decode +#define NETSCAPE_SPKI_b64_encode GRPC_SHADOW_NETSCAPE_SPKI_b64_encode +#define NETSCAPE_SPKI_get_pubkey GRPC_SHADOW_NETSCAPE_SPKI_get_pubkey +#define NETSCAPE_SPKI_set_pubkey GRPC_SHADOW_NETSCAPE_SPKI_set_pubkey +#define X509_ALGORS_it GRPC_SHADOW_X509_ALGORS_it +#define X509_ALGOR_cmp GRPC_SHADOW_X509_ALGOR_cmp +#define X509_ALGOR_dup GRPC_SHADOW_X509_ALGOR_dup +#define X509_ALGOR_free GRPC_SHADOW_X509_ALGOR_free +#define X509_ALGOR_get0 GRPC_SHADOW_X509_ALGOR_get0 +#define X509_ALGOR_it GRPC_SHADOW_X509_ALGOR_it +#define X509_ALGOR_new GRPC_SHADOW_X509_ALGOR_new +#define X509_ALGOR_set0 GRPC_SHADOW_X509_ALGOR_set0 +#define X509_ALGOR_set_md GRPC_SHADOW_X509_ALGOR_set_md +#define d2i_X509_ALGOR GRPC_SHADOW_d2i_X509_ALGOR +#define d2i_X509_ALGORS GRPC_SHADOW_d2i_X509_ALGORS +#define i2d_X509_ALGOR GRPC_SHADOW_i2d_X509_ALGOR +#define i2d_X509_ALGORS GRPC_SHADOW_i2d_X509_ALGORS +#define NETSCAPE_SPKI_sign GRPC_SHADOW_NETSCAPE_SPKI_sign +#define NETSCAPE_SPKI_verify GRPC_SHADOW_NETSCAPE_SPKI_verify +#define X509_CRL_digest GRPC_SHADOW_X509_CRL_digest +#define X509_CRL_sign GRPC_SHADOW_X509_CRL_sign +#define X509_CRL_sign_ctx GRPC_SHADOW_X509_CRL_sign_ctx +#define X509_NAME_digest GRPC_SHADOW_X509_NAME_digest +#define X509_REQ_digest GRPC_SHADOW_X509_REQ_digest +#define X509_REQ_sign GRPC_SHADOW_X509_REQ_sign +#define X509_REQ_sign_ctx GRPC_SHADOW_X509_REQ_sign_ctx +#define X509_REQ_verify GRPC_SHADOW_X509_REQ_verify +#define X509_digest GRPC_SHADOW_X509_digest +#define X509_pubkey_digest GRPC_SHADOW_X509_pubkey_digest +#define X509_sign GRPC_SHADOW_X509_sign +#define X509_sign_ctx GRPC_SHADOW_X509_sign_ctx +#define X509_verify GRPC_SHADOW_X509_verify +#define d2i_DSAPrivateKey_bio GRPC_SHADOW_d2i_DSAPrivateKey_bio +#define d2i_DSAPrivateKey_fp GRPC_SHADOW_d2i_DSAPrivateKey_fp +#define d2i_DSA_PUBKEY_bio GRPC_SHADOW_d2i_DSA_PUBKEY_bio +#define d2i_DSA_PUBKEY_fp GRPC_SHADOW_d2i_DSA_PUBKEY_fp +#define d2i_ECPrivateKey_bio GRPC_SHADOW_d2i_ECPrivateKey_bio +#define d2i_ECPrivateKey_fp GRPC_SHADOW_d2i_ECPrivateKey_fp +#define d2i_EC_PUBKEY_bio GRPC_SHADOW_d2i_EC_PUBKEY_bio +#define d2i_EC_PUBKEY_fp GRPC_SHADOW_d2i_EC_PUBKEY_fp +#define d2i_PKCS8_PRIV_KEY_INFO_bio GRPC_SHADOW_d2i_PKCS8_PRIV_KEY_INFO_bio +#define d2i_PKCS8_PRIV_KEY_INFO_fp GRPC_SHADOW_d2i_PKCS8_PRIV_KEY_INFO_fp +#define d2i_PKCS8_bio GRPC_SHADOW_d2i_PKCS8_bio +#define d2i_PKCS8_fp GRPC_SHADOW_d2i_PKCS8_fp +#define d2i_PUBKEY_bio GRPC_SHADOW_d2i_PUBKEY_bio +#define d2i_PUBKEY_fp GRPC_SHADOW_d2i_PUBKEY_fp +#define d2i_PrivateKey_bio GRPC_SHADOW_d2i_PrivateKey_bio +#define d2i_PrivateKey_fp GRPC_SHADOW_d2i_PrivateKey_fp +#define d2i_RSAPrivateKey_bio GRPC_SHADOW_d2i_RSAPrivateKey_bio +#define d2i_RSAPrivateKey_fp GRPC_SHADOW_d2i_RSAPrivateKey_fp +#define d2i_RSAPublicKey_bio GRPC_SHADOW_d2i_RSAPublicKey_bio +#define d2i_RSAPublicKey_fp GRPC_SHADOW_d2i_RSAPublicKey_fp +#define d2i_RSA_PUBKEY_bio GRPC_SHADOW_d2i_RSA_PUBKEY_bio +#define d2i_RSA_PUBKEY_fp GRPC_SHADOW_d2i_RSA_PUBKEY_fp +#define d2i_X509_CRL_bio GRPC_SHADOW_d2i_X509_CRL_bio +#define d2i_X509_CRL_fp GRPC_SHADOW_d2i_X509_CRL_fp +#define d2i_X509_REQ_bio GRPC_SHADOW_d2i_X509_REQ_bio +#define d2i_X509_REQ_fp GRPC_SHADOW_d2i_X509_REQ_fp +#define d2i_X509_bio GRPC_SHADOW_d2i_X509_bio +#define d2i_X509_fp GRPC_SHADOW_d2i_X509_fp +#define i2d_DSAPrivateKey_bio GRPC_SHADOW_i2d_DSAPrivateKey_bio +#define i2d_DSAPrivateKey_fp GRPC_SHADOW_i2d_DSAPrivateKey_fp +#define i2d_DSA_PUBKEY_bio GRPC_SHADOW_i2d_DSA_PUBKEY_bio +#define i2d_DSA_PUBKEY_fp GRPC_SHADOW_i2d_DSA_PUBKEY_fp +#define i2d_ECPrivateKey_bio GRPC_SHADOW_i2d_ECPrivateKey_bio +#define i2d_ECPrivateKey_fp GRPC_SHADOW_i2d_ECPrivateKey_fp +#define i2d_EC_PUBKEY_bio GRPC_SHADOW_i2d_EC_PUBKEY_bio +#define i2d_EC_PUBKEY_fp GRPC_SHADOW_i2d_EC_PUBKEY_fp +#define i2d_PKCS8PrivateKeyInfo_bio GRPC_SHADOW_i2d_PKCS8PrivateKeyInfo_bio +#define i2d_PKCS8PrivateKeyInfo_fp GRPC_SHADOW_i2d_PKCS8PrivateKeyInfo_fp +#define i2d_PKCS8_PRIV_KEY_INFO_bio GRPC_SHADOW_i2d_PKCS8_PRIV_KEY_INFO_bio +#define i2d_PKCS8_PRIV_KEY_INFO_fp GRPC_SHADOW_i2d_PKCS8_PRIV_KEY_INFO_fp +#define i2d_PKCS8_bio GRPC_SHADOW_i2d_PKCS8_bio +#define i2d_PKCS8_fp GRPC_SHADOW_i2d_PKCS8_fp +#define i2d_PUBKEY_bio GRPC_SHADOW_i2d_PUBKEY_bio +#define i2d_PUBKEY_fp GRPC_SHADOW_i2d_PUBKEY_fp +#define i2d_PrivateKey_bio GRPC_SHADOW_i2d_PrivateKey_bio +#define i2d_PrivateKey_fp GRPC_SHADOW_i2d_PrivateKey_fp +#define i2d_RSAPrivateKey_bio GRPC_SHADOW_i2d_RSAPrivateKey_bio +#define i2d_RSAPrivateKey_fp GRPC_SHADOW_i2d_RSAPrivateKey_fp +#define i2d_RSAPublicKey_bio GRPC_SHADOW_i2d_RSAPublicKey_bio +#define i2d_RSAPublicKey_fp GRPC_SHADOW_i2d_RSAPublicKey_fp +#define i2d_RSA_PUBKEY_bio GRPC_SHADOW_i2d_RSA_PUBKEY_bio +#define i2d_RSA_PUBKEY_fp GRPC_SHADOW_i2d_RSA_PUBKEY_fp +#define i2d_X509_CRL_bio GRPC_SHADOW_i2d_X509_CRL_bio +#define i2d_X509_CRL_fp GRPC_SHADOW_i2d_X509_CRL_fp +#define i2d_X509_REQ_bio GRPC_SHADOW_i2d_X509_REQ_bio +#define i2d_X509_REQ_fp GRPC_SHADOW_i2d_X509_REQ_fp +#define i2d_X509_bio GRPC_SHADOW_i2d_X509_bio +#define i2d_X509_fp GRPC_SHADOW_i2d_X509_fp +#define X509_ATTRIBUTE_SET_it GRPC_SHADOW_X509_ATTRIBUTE_SET_it +#define X509_ATTRIBUTE_create GRPC_SHADOW_X509_ATTRIBUTE_create +#define X509_ATTRIBUTE_dup GRPC_SHADOW_X509_ATTRIBUTE_dup +#define X509_ATTRIBUTE_free GRPC_SHADOW_X509_ATTRIBUTE_free +#define X509_ATTRIBUTE_it GRPC_SHADOW_X509_ATTRIBUTE_it +#define X509_ATTRIBUTE_new GRPC_SHADOW_X509_ATTRIBUTE_new +#define d2i_X509_ATTRIBUTE GRPC_SHADOW_d2i_X509_ATTRIBUTE +#define i2d_X509_ATTRIBUTE GRPC_SHADOW_i2d_X509_ATTRIBUTE +#define X509_CRL_INFO_free GRPC_SHADOW_X509_CRL_INFO_free +#define X509_CRL_INFO_it GRPC_SHADOW_X509_CRL_INFO_it +#define X509_CRL_INFO_new GRPC_SHADOW_X509_CRL_INFO_new +#define X509_CRL_METHOD_free GRPC_SHADOW_X509_CRL_METHOD_free +#define X509_CRL_METHOD_new GRPC_SHADOW_X509_CRL_METHOD_new +#define X509_CRL_add0_revoked GRPC_SHADOW_X509_CRL_add0_revoked +#define X509_CRL_dup GRPC_SHADOW_X509_CRL_dup +#define X509_CRL_free GRPC_SHADOW_X509_CRL_free +#define X509_CRL_get0_by_cert GRPC_SHADOW_X509_CRL_get0_by_cert +#define X509_CRL_get0_by_serial GRPC_SHADOW_X509_CRL_get0_by_serial +#define X509_CRL_get_meth_data GRPC_SHADOW_X509_CRL_get_meth_data +#define X509_CRL_it GRPC_SHADOW_X509_CRL_it +#define X509_CRL_new GRPC_SHADOW_X509_CRL_new +#define X509_CRL_set_default_method GRPC_SHADOW_X509_CRL_set_default_method +#define X509_CRL_set_meth_data GRPC_SHADOW_X509_CRL_set_meth_data +#define X509_CRL_verify GRPC_SHADOW_X509_CRL_verify +#define X509_REVOKED_dup GRPC_SHADOW_X509_REVOKED_dup +#define X509_REVOKED_free GRPC_SHADOW_X509_REVOKED_free +#define X509_REVOKED_it GRPC_SHADOW_X509_REVOKED_it +#define X509_REVOKED_new GRPC_SHADOW_X509_REVOKED_new +#define d2i_X509_CRL GRPC_SHADOW_d2i_X509_CRL +#define d2i_X509_CRL_INFO GRPC_SHADOW_d2i_X509_CRL_INFO +#define d2i_X509_REVOKED GRPC_SHADOW_d2i_X509_REVOKED +#define i2d_X509_CRL GRPC_SHADOW_i2d_X509_CRL +#define i2d_X509_CRL_INFO GRPC_SHADOW_i2d_X509_CRL_INFO +#define i2d_X509_REVOKED GRPC_SHADOW_i2d_X509_REVOKED +#define X509_EXTENSIONS_it GRPC_SHADOW_X509_EXTENSIONS_it +#define X509_EXTENSION_dup GRPC_SHADOW_X509_EXTENSION_dup +#define X509_EXTENSION_free GRPC_SHADOW_X509_EXTENSION_free +#define X509_EXTENSION_it GRPC_SHADOW_X509_EXTENSION_it +#define X509_EXTENSION_new GRPC_SHADOW_X509_EXTENSION_new +#define d2i_X509_EXTENSION GRPC_SHADOW_d2i_X509_EXTENSION +#define d2i_X509_EXTENSIONS GRPC_SHADOW_d2i_X509_EXTENSIONS +#define i2d_X509_EXTENSION GRPC_SHADOW_i2d_X509_EXTENSION +#define i2d_X509_EXTENSIONS GRPC_SHADOW_i2d_X509_EXTENSIONS +#define X509_INFO_free GRPC_SHADOW_X509_INFO_free +#define X509_INFO_new GRPC_SHADOW_X509_INFO_new +#define X509_NAME_ENTRIES_it GRPC_SHADOW_X509_NAME_ENTRIES_it +#define X509_NAME_ENTRY_dup GRPC_SHADOW_X509_NAME_ENTRY_dup +#define X509_NAME_ENTRY_free GRPC_SHADOW_X509_NAME_ENTRY_free +#define X509_NAME_ENTRY_it GRPC_SHADOW_X509_NAME_ENTRY_it +#define X509_NAME_ENTRY_new GRPC_SHADOW_X509_NAME_ENTRY_new +#define X509_NAME_ENTRY_set GRPC_SHADOW_X509_NAME_ENTRY_set +#define X509_NAME_INTERNAL_it GRPC_SHADOW_X509_NAME_INTERNAL_it +#define X509_NAME_dup GRPC_SHADOW_X509_NAME_dup +#define X509_NAME_free GRPC_SHADOW_X509_NAME_free +#define X509_NAME_get0_der GRPC_SHADOW_X509_NAME_get0_der +#define X509_NAME_it GRPC_SHADOW_X509_NAME_it +#define X509_NAME_new GRPC_SHADOW_X509_NAME_new +#define X509_NAME_set GRPC_SHADOW_X509_NAME_set +#define d2i_X509_NAME GRPC_SHADOW_d2i_X509_NAME +#define d2i_X509_NAME_ENTRY GRPC_SHADOW_d2i_X509_NAME_ENTRY +#define i2d_X509_NAME GRPC_SHADOW_i2d_X509_NAME +#define i2d_X509_NAME_ENTRY GRPC_SHADOW_i2d_X509_NAME_ENTRY +#define X509_PKEY_free GRPC_SHADOW_X509_PKEY_free +#define X509_PKEY_new GRPC_SHADOW_X509_PKEY_new +#define X509_PUBKEY_free GRPC_SHADOW_X509_PUBKEY_free +#define X509_PUBKEY_get GRPC_SHADOW_X509_PUBKEY_get +#define X509_PUBKEY_get0_param GRPC_SHADOW_X509_PUBKEY_get0_param +#define X509_PUBKEY_it GRPC_SHADOW_X509_PUBKEY_it +#define X509_PUBKEY_new GRPC_SHADOW_X509_PUBKEY_new +#define X509_PUBKEY_set GRPC_SHADOW_X509_PUBKEY_set +#define X509_PUBKEY_set0_param GRPC_SHADOW_X509_PUBKEY_set0_param +#define d2i_DSA_PUBKEY GRPC_SHADOW_d2i_DSA_PUBKEY +#define d2i_EC_PUBKEY GRPC_SHADOW_d2i_EC_PUBKEY +#define d2i_PUBKEY GRPC_SHADOW_d2i_PUBKEY +#define d2i_RSA_PUBKEY GRPC_SHADOW_d2i_RSA_PUBKEY +#define d2i_X509_PUBKEY GRPC_SHADOW_d2i_X509_PUBKEY +#define i2d_DSA_PUBKEY GRPC_SHADOW_i2d_DSA_PUBKEY +#define i2d_EC_PUBKEY GRPC_SHADOW_i2d_EC_PUBKEY +#define i2d_PUBKEY GRPC_SHADOW_i2d_PUBKEY +#define i2d_RSA_PUBKEY GRPC_SHADOW_i2d_RSA_PUBKEY +#define i2d_X509_PUBKEY GRPC_SHADOW_i2d_X509_PUBKEY +#define X509_REQ_INFO_free GRPC_SHADOW_X509_REQ_INFO_free +#define X509_REQ_INFO_it GRPC_SHADOW_X509_REQ_INFO_it +#define X509_REQ_INFO_new GRPC_SHADOW_X509_REQ_INFO_new +#define X509_REQ_dup GRPC_SHADOW_X509_REQ_dup +#define X509_REQ_free GRPC_SHADOW_X509_REQ_free +#define X509_REQ_it GRPC_SHADOW_X509_REQ_it +#define X509_REQ_new GRPC_SHADOW_X509_REQ_new +#define d2i_X509_REQ GRPC_SHADOW_d2i_X509_REQ +#define d2i_X509_REQ_INFO GRPC_SHADOW_d2i_X509_REQ_INFO +#define i2d_X509_REQ GRPC_SHADOW_i2d_X509_REQ +#define i2d_X509_REQ_INFO GRPC_SHADOW_i2d_X509_REQ_INFO +#define X509_SIG_free GRPC_SHADOW_X509_SIG_free +#define X509_SIG_it GRPC_SHADOW_X509_SIG_it +#define X509_SIG_new GRPC_SHADOW_X509_SIG_new +#define d2i_X509_SIG GRPC_SHADOW_d2i_X509_SIG +#define i2d_X509_SIG GRPC_SHADOW_i2d_X509_SIG +#define NETSCAPE_SPKAC_free GRPC_SHADOW_NETSCAPE_SPKAC_free +#define NETSCAPE_SPKAC_it GRPC_SHADOW_NETSCAPE_SPKAC_it +#define NETSCAPE_SPKAC_new GRPC_SHADOW_NETSCAPE_SPKAC_new +#define NETSCAPE_SPKI_free GRPC_SHADOW_NETSCAPE_SPKI_free +#define NETSCAPE_SPKI_it GRPC_SHADOW_NETSCAPE_SPKI_it +#define NETSCAPE_SPKI_new GRPC_SHADOW_NETSCAPE_SPKI_new +#define d2i_NETSCAPE_SPKAC GRPC_SHADOW_d2i_NETSCAPE_SPKAC +#define d2i_NETSCAPE_SPKI GRPC_SHADOW_d2i_NETSCAPE_SPKI +#define i2d_NETSCAPE_SPKAC GRPC_SHADOW_i2d_NETSCAPE_SPKAC +#define i2d_NETSCAPE_SPKI GRPC_SHADOW_i2d_NETSCAPE_SPKI +#define X509_VAL_free GRPC_SHADOW_X509_VAL_free +#define X509_VAL_it GRPC_SHADOW_X509_VAL_it +#define X509_VAL_new GRPC_SHADOW_X509_VAL_new +#define d2i_X509_VAL GRPC_SHADOW_d2i_X509_VAL +#define i2d_X509_VAL GRPC_SHADOW_i2d_X509_VAL +#define X509_CINF_free GRPC_SHADOW_X509_CINF_free +#define X509_CINF_it GRPC_SHADOW_X509_CINF_it +#define X509_CINF_new GRPC_SHADOW_X509_CINF_new +#define X509_dup GRPC_SHADOW_X509_dup +#define X509_free GRPC_SHADOW_X509_free +#define X509_get0_signature GRPC_SHADOW_X509_get0_signature +#define X509_get_ex_data GRPC_SHADOW_X509_get_ex_data +#define X509_get_ex_new_index GRPC_SHADOW_X509_get_ex_new_index +#define X509_get_signature_nid GRPC_SHADOW_X509_get_signature_nid +#define X509_it GRPC_SHADOW_X509_it +#define X509_new GRPC_SHADOW_X509_new +#define X509_parse_from_buffer GRPC_SHADOW_X509_parse_from_buffer +#define X509_set_ex_data GRPC_SHADOW_X509_set_ex_data +#define X509_up_ref GRPC_SHADOW_X509_up_ref +#define d2i_X509 GRPC_SHADOW_d2i_X509 +#define d2i_X509_AUX GRPC_SHADOW_d2i_X509_AUX +#define d2i_X509_CINF GRPC_SHADOW_d2i_X509_CINF +#define i2d_X509 GRPC_SHADOW_i2d_X509 +#define i2d_X509_AUX GRPC_SHADOW_i2d_X509_AUX +#define i2d_X509_CINF GRPC_SHADOW_i2d_X509_CINF +#define X509_CERT_AUX_free GRPC_SHADOW_X509_CERT_AUX_free +#define X509_CERT_AUX_it GRPC_SHADOW_X509_CERT_AUX_it +#define X509_CERT_AUX_new GRPC_SHADOW_X509_CERT_AUX_new +#define X509_add1_reject_object GRPC_SHADOW_X509_add1_reject_object +#define X509_add1_trust_object GRPC_SHADOW_X509_add1_trust_object +#define X509_alias_get0 GRPC_SHADOW_X509_alias_get0 +#define X509_alias_set1 GRPC_SHADOW_X509_alias_set1 +#define X509_keyid_get0 GRPC_SHADOW_X509_keyid_get0 +#define X509_keyid_set1 GRPC_SHADOW_X509_keyid_set1 +#define X509_reject_clear GRPC_SHADOW_X509_reject_clear +#define X509_trust_clear GRPC_SHADOW_X509_trust_clear +#define d2i_X509_CERT_AUX GRPC_SHADOW_d2i_X509_CERT_AUX +#define i2d_X509_CERT_AUX GRPC_SHADOW_i2d_X509_CERT_AUX +#define policy_cache_find_data GRPC_SHADOW_policy_cache_find_data +#define policy_cache_free GRPC_SHADOW_policy_cache_free +#define policy_cache_set GRPC_SHADOW_policy_cache_set +#define policy_data_free GRPC_SHADOW_policy_data_free +#define policy_data_new GRPC_SHADOW_policy_data_new +#define X509_policy_level_get0_node GRPC_SHADOW_X509_policy_level_get0_node +#define X509_policy_level_node_count GRPC_SHADOW_X509_policy_level_node_count +#define X509_policy_node_get0_parent GRPC_SHADOW_X509_policy_node_get0_parent +#define X509_policy_node_get0_policy GRPC_SHADOW_X509_policy_node_get0_policy +#define X509_policy_node_get0_qualifiers GRPC_SHADOW_X509_policy_node_get0_qualifiers +#define X509_policy_tree_get0_level GRPC_SHADOW_X509_policy_tree_get0_level +#define X509_policy_tree_get0_policies GRPC_SHADOW_X509_policy_tree_get0_policies +#define X509_policy_tree_get0_user_policies GRPC_SHADOW_X509_policy_tree_get0_user_policies +#define X509_policy_tree_level_count GRPC_SHADOW_X509_policy_tree_level_count +#define policy_cache_set_mapping GRPC_SHADOW_policy_cache_set_mapping +#define level_add_node GRPC_SHADOW_level_add_node +#define level_find_node GRPC_SHADOW_level_find_node +#define policy_node_cmp_new GRPC_SHADOW_policy_node_cmp_new +#define policy_node_free GRPC_SHADOW_policy_node_free +#define policy_node_match GRPC_SHADOW_policy_node_match +#define tree_find_sk GRPC_SHADOW_tree_find_sk +#define X509_policy_check GRPC_SHADOW_X509_policy_check +#define X509_policy_tree_free GRPC_SHADOW_X509_policy_tree_free +#define v3_akey_id GRPC_SHADOW_v3_akey_id +#define AUTHORITY_KEYID_free GRPC_SHADOW_AUTHORITY_KEYID_free +#define AUTHORITY_KEYID_it GRPC_SHADOW_AUTHORITY_KEYID_it +#define AUTHORITY_KEYID_new GRPC_SHADOW_AUTHORITY_KEYID_new +#define d2i_AUTHORITY_KEYID GRPC_SHADOW_d2i_AUTHORITY_KEYID +#define i2d_AUTHORITY_KEYID GRPC_SHADOW_i2d_AUTHORITY_KEYID +#define GENERAL_NAME_print GRPC_SHADOW_GENERAL_NAME_print +#define a2i_GENERAL_NAME GRPC_SHADOW_a2i_GENERAL_NAME +#define i2v_GENERAL_NAME GRPC_SHADOW_i2v_GENERAL_NAME +#define i2v_GENERAL_NAMES GRPC_SHADOW_i2v_GENERAL_NAMES +#define v2i_GENERAL_NAME GRPC_SHADOW_v2i_GENERAL_NAME +#define v2i_GENERAL_NAMES GRPC_SHADOW_v2i_GENERAL_NAMES +#define v2i_GENERAL_NAME_ex GRPC_SHADOW_v2i_GENERAL_NAME_ex +#define v3_alt GRPC_SHADOW_v3_alt +#define BASIC_CONSTRAINTS_free GRPC_SHADOW_BASIC_CONSTRAINTS_free +#define BASIC_CONSTRAINTS_it GRPC_SHADOW_BASIC_CONSTRAINTS_it +#define BASIC_CONSTRAINTS_new GRPC_SHADOW_BASIC_CONSTRAINTS_new +#define d2i_BASIC_CONSTRAINTS GRPC_SHADOW_d2i_BASIC_CONSTRAINTS +#define i2d_BASIC_CONSTRAINTS GRPC_SHADOW_i2d_BASIC_CONSTRAINTS +#define v3_bcons GRPC_SHADOW_v3_bcons +#define i2v_ASN1_BIT_STRING GRPC_SHADOW_i2v_ASN1_BIT_STRING +#define v2i_ASN1_BIT_STRING GRPC_SHADOW_v2i_ASN1_BIT_STRING +#define v3_key_usage GRPC_SHADOW_v3_key_usage +#define v3_nscert GRPC_SHADOW_v3_nscert +#define X509V3_EXT_CRL_add_nconf GRPC_SHADOW_X509V3_EXT_CRL_add_nconf +#define X509V3_EXT_REQ_add_nconf GRPC_SHADOW_X509V3_EXT_REQ_add_nconf +#define X509V3_EXT_add_nconf GRPC_SHADOW_X509V3_EXT_add_nconf +#define X509V3_EXT_add_nconf_sk GRPC_SHADOW_X509V3_EXT_add_nconf_sk +#define X509V3_EXT_i2d GRPC_SHADOW_X509V3_EXT_i2d +#define X509V3_EXT_nconf GRPC_SHADOW_X509V3_EXT_nconf +#define X509V3_EXT_nconf_nid GRPC_SHADOW_X509V3_EXT_nconf_nid +#define X509V3_get_section GRPC_SHADOW_X509V3_get_section +#define X509V3_get_string GRPC_SHADOW_X509V3_get_string +#define X509V3_section_free GRPC_SHADOW_X509V3_section_free +#define X509V3_set_ctx GRPC_SHADOW_X509V3_set_ctx +#define X509V3_set_nconf GRPC_SHADOW_X509V3_set_nconf +#define X509V3_string_free GRPC_SHADOW_X509V3_string_free +#define CERTIFICATEPOLICIES_free GRPC_SHADOW_CERTIFICATEPOLICIES_free +#define CERTIFICATEPOLICIES_it GRPC_SHADOW_CERTIFICATEPOLICIES_it +#define CERTIFICATEPOLICIES_new GRPC_SHADOW_CERTIFICATEPOLICIES_new +#define NOTICEREF_free GRPC_SHADOW_NOTICEREF_free +#define NOTICEREF_it GRPC_SHADOW_NOTICEREF_it +#define NOTICEREF_new GRPC_SHADOW_NOTICEREF_new +#define POLICYINFO_free GRPC_SHADOW_POLICYINFO_free +#define POLICYINFO_it GRPC_SHADOW_POLICYINFO_it +#define POLICYINFO_new GRPC_SHADOW_POLICYINFO_new +#define POLICYQUALINFO_free GRPC_SHADOW_POLICYQUALINFO_free +#define POLICYQUALINFO_it GRPC_SHADOW_POLICYQUALINFO_it +#define POLICYQUALINFO_new GRPC_SHADOW_POLICYQUALINFO_new +#define USERNOTICE_free GRPC_SHADOW_USERNOTICE_free +#define USERNOTICE_it GRPC_SHADOW_USERNOTICE_it +#define USERNOTICE_new GRPC_SHADOW_USERNOTICE_new +#define X509_POLICY_NODE_print GRPC_SHADOW_X509_POLICY_NODE_print +#define d2i_CERTIFICATEPOLICIES GRPC_SHADOW_d2i_CERTIFICATEPOLICIES +#define d2i_NOTICEREF GRPC_SHADOW_d2i_NOTICEREF +#define d2i_POLICYINFO GRPC_SHADOW_d2i_POLICYINFO +#define d2i_POLICYQUALINFO GRPC_SHADOW_d2i_POLICYQUALINFO +#define d2i_USERNOTICE GRPC_SHADOW_d2i_USERNOTICE +#define i2d_CERTIFICATEPOLICIES GRPC_SHADOW_i2d_CERTIFICATEPOLICIES +#define i2d_NOTICEREF GRPC_SHADOW_i2d_NOTICEREF +#define i2d_POLICYINFO GRPC_SHADOW_i2d_POLICYINFO +#define i2d_POLICYQUALINFO GRPC_SHADOW_i2d_POLICYQUALINFO +#define i2d_USERNOTICE GRPC_SHADOW_i2d_USERNOTICE +#define v3_cpols GRPC_SHADOW_v3_cpols +#define CRL_DIST_POINTS_free GRPC_SHADOW_CRL_DIST_POINTS_free +#define CRL_DIST_POINTS_it GRPC_SHADOW_CRL_DIST_POINTS_it +#define CRL_DIST_POINTS_new GRPC_SHADOW_CRL_DIST_POINTS_new +#define DIST_POINT_NAME_free GRPC_SHADOW_DIST_POINT_NAME_free +#define DIST_POINT_NAME_it GRPC_SHADOW_DIST_POINT_NAME_it +#define DIST_POINT_NAME_new GRPC_SHADOW_DIST_POINT_NAME_new +#define DIST_POINT_free GRPC_SHADOW_DIST_POINT_free +#define DIST_POINT_it GRPC_SHADOW_DIST_POINT_it +#define DIST_POINT_new GRPC_SHADOW_DIST_POINT_new +#define DIST_POINT_set_dpname GRPC_SHADOW_DIST_POINT_set_dpname +#define ISSUING_DIST_POINT_free GRPC_SHADOW_ISSUING_DIST_POINT_free +#define ISSUING_DIST_POINT_it GRPC_SHADOW_ISSUING_DIST_POINT_it +#define ISSUING_DIST_POINT_new GRPC_SHADOW_ISSUING_DIST_POINT_new +#define d2i_CRL_DIST_POINTS GRPC_SHADOW_d2i_CRL_DIST_POINTS +#define d2i_DIST_POINT GRPC_SHADOW_d2i_DIST_POINT +#define d2i_DIST_POINT_NAME GRPC_SHADOW_d2i_DIST_POINT_NAME +#define d2i_ISSUING_DIST_POINT GRPC_SHADOW_d2i_ISSUING_DIST_POINT +#define i2d_CRL_DIST_POINTS GRPC_SHADOW_i2d_CRL_DIST_POINTS +#define i2d_DIST_POINT GRPC_SHADOW_i2d_DIST_POINT +#define i2d_DIST_POINT_NAME GRPC_SHADOW_i2d_DIST_POINT_NAME +#define i2d_ISSUING_DIST_POINT GRPC_SHADOW_i2d_ISSUING_DIST_POINT +#define v3_crld GRPC_SHADOW_v3_crld +#define v3_freshest_crl GRPC_SHADOW_v3_freshest_crl +#define v3_idp GRPC_SHADOW_v3_idp +#define i2s_ASN1_ENUMERATED_TABLE GRPC_SHADOW_i2s_ASN1_ENUMERATED_TABLE +#define v3_crl_reason GRPC_SHADOW_v3_crl_reason +#define EXTENDED_KEY_USAGE_free GRPC_SHADOW_EXTENDED_KEY_USAGE_free +#define EXTENDED_KEY_USAGE_it GRPC_SHADOW_EXTENDED_KEY_USAGE_it +#define EXTENDED_KEY_USAGE_new GRPC_SHADOW_EXTENDED_KEY_USAGE_new +#define d2i_EXTENDED_KEY_USAGE GRPC_SHADOW_d2i_EXTENDED_KEY_USAGE +#define i2d_EXTENDED_KEY_USAGE GRPC_SHADOW_i2d_EXTENDED_KEY_USAGE +#define v3_ext_ku GRPC_SHADOW_v3_ext_ku +#define v3_ocsp_accresp GRPC_SHADOW_v3_ocsp_accresp +#define EDIPARTYNAME_free GRPC_SHADOW_EDIPARTYNAME_free +#define EDIPARTYNAME_it GRPC_SHADOW_EDIPARTYNAME_it +#define EDIPARTYNAME_new GRPC_SHADOW_EDIPARTYNAME_new +#define GENERAL_NAMES_free GRPC_SHADOW_GENERAL_NAMES_free +#define GENERAL_NAMES_it GRPC_SHADOW_GENERAL_NAMES_it +#define GENERAL_NAMES_new GRPC_SHADOW_GENERAL_NAMES_new +#define GENERAL_NAME_cmp GRPC_SHADOW_GENERAL_NAME_cmp +#define GENERAL_NAME_dup GRPC_SHADOW_GENERAL_NAME_dup +#define GENERAL_NAME_free GRPC_SHADOW_GENERAL_NAME_free +#define GENERAL_NAME_get0_otherName GRPC_SHADOW_GENERAL_NAME_get0_otherName +#define GENERAL_NAME_get0_value GRPC_SHADOW_GENERAL_NAME_get0_value +#define GENERAL_NAME_it GRPC_SHADOW_GENERAL_NAME_it +#define GENERAL_NAME_new GRPC_SHADOW_GENERAL_NAME_new +#define GENERAL_NAME_set0_othername GRPC_SHADOW_GENERAL_NAME_set0_othername +#define GENERAL_NAME_set0_value GRPC_SHADOW_GENERAL_NAME_set0_value +#define OTHERNAME_cmp GRPC_SHADOW_OTHERNAME_cmp +#define OTHERNAME_free GRPC_SHADOW_OTHERNAME_free +#define OTHERNAME_it GRPC_SHADOW_OTHERNAME_it +#define OTHERNAME_new GRPC_SHADOW_OTHERNAME_new +#define d2i_EDIPARTYNAME GRPC_SHADOW_d2i_EDIPARTYNAME +#define d2i_GENERAL_NAME GRPC_SHADOW_d2i_GENERAL_NAME +#define d2i_GENERAL_NAMES GRPC_SHADOW_d2i_GENERAL_NAMES +#define d2i_OTHERNAME GRPC_SHADOW_d2i_OTHERNAME +#define i2d_EDIPARTYNAME GRPC_SHADOW_i2d_EDIPARTYNAME +#define i2d_GENERAL_NAME GRPC_SHADOW_i2d_GENERAL_NAME +#define i2d_GENERAL_NAMES GRPC_SHADOW_i2d_GENERAL_NAMES +#define i2d_OTHERNAME GRPC_SHADOW_i2d_OTHERNAME +#define v3_ns_ia5_list GRPC_SHADOW_v3_ns_ia5_list +#define ACCESS_DESCRIPTION_free GRPC_SHADOW_ACCESS_DESCRIPTION_free +#define ACCESS_DESCRIPTION_it GRPC_SHADOW_ACCESS_DESCRIPTION_it +#define ACCESS_DESCRIPTION_new GRPC_SHADOW_ACCESS_DESCRIPTION_new +#define AUTHORITY_INFO_ACCESS_free GRPC_SHADOW_AUTHORITY_INFO_ACCESS_free +#define AUTHORITY_INFO_ACCESS_it GRPC_SHADOW_AUTHORITY_INFO_ACCESS_it +#define AUTHORITY_INFO_ACCESS_new GRPC_SHADOW_AUTHORITY_INFO_ACCESS_new +#define d2i_ACCESS_DESCRIPTION GRPC_SHADOW_d2i_ACCESS_DESCRIPTION +#define d2i_AUTHORITY_INFO_ACCESS GRPC_SHADOW_d2i_AUTHORITY_INFO_ACCESS +#define i2a_ACCESS_DESCRIPTION GRPC_SHADOW_i2a_ACCESS_DESCRIPTION +#define i2d_ACCESS_DESCRIPTION GRPC_SHADOW_i2d_ACCESS_DESCRIPTION +#define i2d_AUTHORITY_INFO_ACCESS GRPC_SHADOW_i2d_AUTHORITY_INFO_ACCESS +#define v3_info GRPC_SHADOW_v3_info +#define v3_sinfo GRPC_SHADOW_v3_sinfo +#define v3_crl_num GRPC_SHADOW_v3_crl_num +#define v3_delta_crl GRPC_SHADOW_v3_delta_crl +#define v3_inhibit_anyp GRPC_SHADOW_v3_inhibit_anyp +#define X509V3_EXT_add GRPC_SHADOW_X509V3_EXT_add +#define X509V3_EXT_add_alias GRPC_SHADOW_X509V3_EXT_add_alias +#define X509V3_EXT_add_list GRPC_SHADOW_X509V3_EXT_add_list +#define X509V3_EXT_cleanup GRPC_SHADOW_X509V3_EXT_cleanup +#define X509V3_EXT_d2i GRPC_SHADOW_X509V3_EXT_d2i +#define X509V3_EXT_free GRPC_SHADOW_X509V3_EXT_free +#define X509V3_EXT_get GRPC_SHADOW_X509V3_EXT_get +#define X509V3_EXT_get_nid GRPC_SHADOW_X509V3_EXT_get_nid +#define X509V3_add1_i2d GRPC_SHADOW_X509V3_add1_i2d +#define X509V3_add_standard_extensions GRPC_SHADOW_X509V3_add_standard_extensions +#define X509V3_get_d2i GRPC_SHADOW_X509V3_get_d2i +#define GENERAL_SUBTREE_free GRPC_SHADOW_GENERAL_SUBTREE_free +#define GENERAL_SUBTREE_it GRPC_SHADOW_GENERAL_SUBTREE_it +#define GENERAL_SUBTREE_new GRPC_SHADOW_GENERAL_SUBTREE_new +#define NAME_CONSTRAINTS_check GRPC_SHADOW_NAME_CONSTRAINTS_check +#define NAME_CONSTRAINTS_free GRPC_SHADOW_NAME_CONSTRAINTS_free +#define NAME_CONSTRAINTS_it GRPC_SHADOW_NAME_CONSTRAINTS_it +#define NAME_CONSTRAINTS_new GRPC_SHADOW_NAME_CONSTRAINTS_new +#define v3_name_constraints GRPC_SHADOW_v3_name_constraints +#define v3_pci GRPC_SHADOW_v3_pci +#define PROXY_CERT_INFO_EXTENSION_free GRPC_SHADOW_PROXY_CERT_INFO_EXTENSION_free +#define PROXY_CERT_INFO_EXTENSION_it GRPC_SHADOW_PROXY_CERT_INFO_EXTENSION_it +#define PROXY_CERT_INFO_EXTENSION_new GRPC_SHADOW_PROXY_CERT_INFO_EXTENSION_new +#define PROXY_POLICY_free GRPC_SHADOW_PROXY_POLICY_free +#define PROXY_POLICY_it GRPC_SHADOW_PROXY_POLICY_it +#define PROXY_POLICY_new GRPC_SHADOW_PROXY_POLICY_new +#define d2i_PROXY_CERT_INFO_EXTENSION GRPC_SHADOW_d2i_PROXY_CERT_INFO_EXTENSION +#define d2i_PROXY_POLICY GRPC_SHADOW_d2i_PROXY_POLICY +#define i2d_PROXY_CERT_INFO_EXTENSION GRPC_SHADOW_i2d_PROXY_CERT_INFO_EXTENSION +#define i2d_PROXY_POLICY GRPC_SHADOW_i2d_PROXY_POLICY +#define POLICY_CONSTRAINTS_free GRPC_SHADOW_POLICY_CONSTRAINTS_free +#define POLICY_CONSTRAINTS_it GRPC_SHADOW_POLICY_CONSTRAINTS_it +#define POLICY_CONSTRAINTS_new GRPC_SHADOW_POLICY_CONSTRAINTS_new +#define v3_policy_constraints GRPC_SHADOW_v3_policy_constraints +#define PKEY_USAGE_PERIOD_free GRPC_SHADOW_PKEY_USAGE_PERIOD_free +#define PKEY_USAGE_PERIOD_it GRPC_SHADOW_PKEY_USAGE_PERIOD_it +#define PKEY_USAGE_PERIOD_new GRPC_SHADOW_PKEY_USAGE_PERIOD_new +#define d2i_PKEY_USAGE_PERIOD GRPC_SHADOW_d2i_PKEY_USAGE_PERIOD +#define i2d_PKEY_USAGE_PERIOD GRPC_SHADOW_i2d_PKEY_USAGE_PERIOD +#define v3_pkey_usage_period GRPC_SHADOW_v3_pkey_usage_period +#define POLICY_MAPPINGS_it GRPC_SHADOW_POLICY_MAPPINGS_it +#define POLICY_MAPPING_free GRPC_SHADOW_POLICY_MAPPING_free +#define POLICY_MAPPING_it GRPC_SHADOW_POLICY_MAPPING_it +#define POLICY_MAPPING_new GRPC_SHADOW_POLICY_MAPPING_new +#define v3_policy_mappings GRPC_SHADOW_v3_policy_mappings +#define X509V3_EXT_print GRPC_SHADOW_X509V3_EXT_print +#define X509V3_EXT_print_fp GRPC_SHADOW_X509V3_EXT_print_fp +#define X509V3_EXT_val_prn GRPC_SHADOW_X509V3_EXT_val_prn +#define X509V3_extensions_print GRPC_SHADOW_X509V3_extensions_print +#define X509_PURPOSE_add GRPC_SHADOW_X509_PURPOSE_add +#define X509_PURPOSE_cleanup GRPC_SHADOW_X509_PURPOSE_cleanup +#define X509_PURPOSE_get0 GRPC_SHADOW_X509_PURPOSE_get0 +#define X509_PURPOSE_get0_name GRPC_SHADOW_X509_PURPOSE_get0_name +#define X509_PURPOSE_get0_sname GRPC_SHADOW_X509_PURPOSE_get0_sname +#define X509_PURPOSE_get_by_id GRPC_SHADOW_X509_PURPOSE_get_by_id +#define X509_PURPOSE_get_by_sname GRPC_SHADOW_X509_PURPOSE_get_by_sname +#define X509_PURPOSE_get_count GRPC_SHADOW_X509_PURPOSE_get_count +#define X509_PURPOSE_get_id GRPC_SHADOW_X509_PURPOSE_get_id +#define X509_PURPOSE_get_trust GRPC_SHADOW_X509_PURPOSE_get_trust +#define X509_PURPOSE_set GRPC_SHADOW_X509_PURPOSE_set +#define X509_check_akid GRPC_SHADOW_X509_check_akid +#define X509_check_ca GRPC_SHADOW_X509_check_ca +#define X509_check_issued GRPC_SHADOW_X509_check_issued +#define X509_check_purpose GRPC_SHADOW_X509_check_purpose +#define X509_supported_extension GRPC_SHADOW_X509_supported_extension +#define i2s_ASN1_OCTET_STRING GRPC_SHADOW_i2s_ASN1_OCTET_STRING +#define s2i_ASN1_OCTET_STRING GRPC_SHADOW_s2i_ASN1_OCTET_STRING +#define v3_skey_id GRPC_SHADOW_v3_skey_id +#define SXNETID_free GRPC_SHADOW_SXNETID_free +#define SXNETID_it GRPC_SHADOW_SXNETID_it +#define SXNETID_new GRPC_SHADOW_SXNETID_new +#define SXNET_add_id_INTEGER GRPC_SHADOW_SXNET_add_id_INTEGER +#define SXNET_add_id_asc GRPC_SHADOW_SXNET_add_id_asc +#define SXNET_add_id_ulong GRPC_SHADOW_SXNET_add_id_ulong +#define SXNET_free GRPC_SHADOW_SXNET_free +#define SXNET_get_id_INTEGER GRPC_SHADOW_SXNET_get_id_INTEGER +#define SXNET_get_id_asc GRPC_SHADOW_SXNET_get_id_asc +#define SXNET_get_id_ulong GRPC_SHADOW_SXNET_get_id_ulong +#define SXNET_it GRPC_SHADOW_SXNET_it +#define SXNET_new GRPC_SHADOW_SXNET_new +#define d2i_SXNET GRPC_SHADOW_d2i_SXNET +#define d2i_SXNETID GRPC_SHADOW_d2i_SXNETID +#define i2d_SXNET GRPC_SHADOW_i2d_SXNET +#define i2d_SXNETID GRPC_SHADOW_i2d_SXNETID +#define v3_sxnet GRPC_SHADOW_v3_sxnet +#define X509V3_NAME_from_section GRPC_SHADOW_X509V3_NAME_from_section +#define X509V3_add_value GRPC_SHADOW_X509V3_add_value +#define X509V3_add_value_bool GRPC_SHADOW_X509V3_add_value_bool +#define X509V3_add_value_bool_nf GRPC_SHADOW_X509V3_add_value_bool_nf +#define X509V3_add_value_int GRPC_SHADOW_X509V3_add_value_int +#define X509V3_add_value_uchar GRPC_SHADOW_X509V3_add_value_uchar +#define X509V3_conf_free GRPC_SHADOW_X509V3_conf_free +#define X509V3_get_value_bool GRPC_SHADOW_X509V3_get_value_bool +#define X509V3_get_value_int GRPC_SHADOW_X509V3_get_value_int +#define X509V3_parse_list GRPC_SHADOW_X509V3_parse_list +#define X509_REQ_get1_email GRPC_SHADOW_X509_REQ_get1_email +#define X509_check_email GRPC_SHADOW_X509_check_email +#define X509_check_host GRPC_SHADOW_X509_check_host +#define X509_check_ip GRPC_SHADOW_X509_check_ip +#define X509_check_ip_asc GRPC_SHADOW_X509_check_ip_asc +#define X509_email_free GRPC_SHADOW_X509_email_free +#define X509_get1_email GRPC_SHADOW_X509_get1_email +#define X509_get1_ocsp GRPC_SHADOW_X509_get1_ocsp +#define a2i_IPADDRESS GRPC_SHADOW_a2i_IPADDRESS +#define a2i_IPADDRESS_NC GRPC_SHADOW_a2i_IPADDRESS_NC +#define a2i_ipadd GRPC_SHADOW_a2i_ipadd +#define hex_to_string GRPC_SHADOW_hex_to_string +#define i2s_ASN1_ENUMERATED GRPC_SHADOW_i2s_ASN1_ENUMERATED +#define i2s_ASN1_INTEGER GRPC_SHADOW_i2s_ASN1_INTEGER +#define name_cmp GRPC_SHADOW_name_cmp +#define s2i_ASN1_INTEGER GRPC_SHADOW_s2i_ASN1_INTEGER +#define string_to_hex GRPC_SHADOW_string_to_hex +#define PKCS7_get_raw_certificates GRPC_SHADOW_PKCS7_get_raw_certificates +#define pkcs7_bundle GRPC_SHADOW_pkcs7_bundle +#define pkcs7_parse_header GRPC_SHADOW_pkcs7_parse_header +#define PKCS7_bundle_CRLs GRPC_SHADOW_PKCS7_bundle_CRLs +#define PKCS7_bundle_certificates GRPC_SHADOW_PKCS7_bundle_certificates +#define PKCS7_get_CRLs GRPC_SHADOW_PKCS7_get_CRLs +#define PKCS7_get_PEM_CRLs GRPC_SHADOW_PKCS7_get_PEM_CRLs +#define PKCS7_get_PEM_certificates GRPC_SHADOW_PKCS7_get_PEM_certificates +#define PKCS7_get_certificates GRPC_SHADOW_PKCS7_get_certificates +#define PKCS8_marshal_encrypted_private_key GRPC_SHADOW_PKCS8_marshal_encrypted_private_key +#define PKCS8_parse_encrypted_private_key GRPC_SHADOW_PKCS8_parse_encrypted_private_key +#define pkcs12_key_gen GRPC_SHADOW_pkcs12_key_gen +#define pkcs8_pbe_decrypt GRPC_SHADOW_pkcs8_pbe_decrypt +#define EVP_PKCS82PKEY GRPC_SHADOW_EVP_PKCS82PKEY +#define EVP_PKEY2PKCS8 GRPC_SHADOW_EVP_PKEY2PKCS8 +#define PKCS12_PBE_add GRPC_SHADOW_PKCS12_PBE_add +#define PKCS12_free GRPC_SHADOW_PKCS12_free +#define PKCS12_get_key_and_certs GRPC_SHADOW_PKCS12_get_key_and_certs +#define PKCS12_parse GRPC_SHADOW_PKCS12_parse +#define PKCS12_verify_mac GRPC_SHADOW_PKCS12_verify_mac +#define PKCS8_PRIV_KEY_INFO_free GRPC_SHADOW_PKCS8_PRIV_KEY_INFO_free +#define PKCS8_PRIV_KEY_INFO_it GRPC_SHADOW_PKCS8_PRIV_KEY_INFO_it +#define PKCS8_PRIV_KEY_INFO_new GRPC_SHADOW_PKCS8_PRIV_KEY_INFO_new +#define PKCS8_decrypt GRPC_SHADOW_PKCS8_decrypt +#define PKCS8_encrypt GRPC_SHADOW_PKCS8_encrypt +#define d2i_PKCS12 GRPC_SHADOW_d2i_PKCS12 +#define d2i_PKCS12_bio GRPC_SHADOW_d2i_PKCS12_bio +#define d2i_PKCS12_fp GRPC_SHADOW_d2i_PKCS12_fp +#define d2i_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_d2i_PKCS8_PRIV_KEY_INFO +#define i2d_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_i2d_PKCS8_PRIV_KEY_INFO +#define PKCS5_pbe2_decrypt_init GRPC_SHADOW_PKCS5_pbe2_decrypt_init +#define PKCS5_pbe2_encrypt_init GRPC_SHADOW_PKCS5_pbe2_encrypt_init + +#endif /* GRPC_SHADOW_BORINGSSL_SYMBOLS */ + +#endif /* GRPC_CORE_TSI_GRPC_SHADOW_BORINGSSL_H */ diff --git a/src/core/tsi/ssl/session_cache/ssl_session.h b/src/core/tsi/ssl/session_cache/ssl_session.h index 115221ec06..e847267cb3 100644 --- a/src/core/tsi/ssl/session_cache/ssl_session.h +++ b/src/core/tsi/ssl/session_cache/ssl_session.h @@ -21,6 +21,8 @@ #include <grpc/support/port_platform.h> +#include "src/core/tsi/grpc_shadow_boringssl.h" + #include <grpc/slice.h> extern "C" { diff --git a/src/core/tsi/ssl/session_cache/ssl_session_cache.cc b/src/core/tsi/ssl/session_cache/ssl_session_cache.cc index fe4f83a13d..f9184bcc34 100644 --- a/src/core/tsi/ssl/session_cache/ssl_session_cache.cc +++ b/src/core/tsi/ssl/session_cache/ssl_session_cache.cc @@ -18,9 +18,10 @@ #include <grpc/support/port_platform.h> -#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h" - +#include "src/core/lib/gprpp/mutex_lock.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/tsi/ssl/session_cache/ssl_session.h" +#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h" #include <grpc/support/log.h> #include <grpc/support/string_util.h> @@ -53,7 +54,7 @@ class SslSessionLRUCache::Node { SetSession(std::move(session)); } - ~Node() { grpc_slice_unref(key_); } + ~Node() { grpc_slice_unref_internal(key_); } // Not copyable nor movable. Node(const Node&) = delete; @@ -97,7 +98,7 @@ SslSessionLRUCache::~SslSessionLRUCache() { } size_t SslSessionLRUCache::Size() { - grpc_core::mu_guard guard(&lock_); + grpc_core::MutexLock lock(&lock_); return use_order_list_size_; } @@ -117,7 +118,7 @@ SslSessionLRUCache::Node* SslSessionLRUCache::FindLocked( } void SslSessionLRUCache::Put(const char* key, SslSessionPtr session) { - grpc_core::mu_guard guard(&lock_); + grpc_core::MutexLock lock(&lock_); Node* node = FindLocked(grpc_slice_from_static_string(key)); if (node != nullptr) { node->SetSession(std::move(session)); @@ -140,7 +141,7 @@ void SslSessionLRUCache::Put(const char* key, SslSessionPtr session) { } SslSessionPtr SslSessionLRUCache::Get(const char* key) { - grpc_core::mu_guard guard(&lock_); + grpc_core::MutexLock lock(&lock_); // Key is only used for lookups. grpc_slice key_slice = grpc_slice_from_static_string(key); Node* node = FindLocked(key_slice); diff --git a/src/core/tsi/ssl/session_cache/ssl_session_cache.h b/src/core/tsi/ssl/session_cache/ssl_session_cache.h index a90cca1a2e..37fa2d124c 100644 --- a/src/core/tsi/ssl/session_cache/ssl_session_cache.h +++ b/src/core/tsi/ssl/session_cache/ssl_session_cache.h @@ -21,6 +21,8 @@ #include <grpc/support/port_platform.h> +#include "src/core/tsi/grpc_shadow_boringssl.h" + #include <grpc/slice.h> #include <grpc/support/sync.h> diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc index e66fc9ba03..d6a72ada0d 100644 --- a/src/core/tsi/ssl_transport_security.cc +++ b/src/core/tsi/ssl_transport_security.cc @@ -18,6 +18,8 @@ #include <grpc/support/port_platform.h> +#include "src/core/tsi/grpc_shadow_boringssl.h" + #include "src/core/tsi/ssl_transport_security.h" #include <limits.h> @@ -216,7 +218,7 @@ static void ssl_log_where_info(const SSL* ssl, int where, int flag, /* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */ static void ssl_info_callback(const SSL* ssl, int where, int ret) { if (ret == 0) { - gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n"); + gpr_log(GPR_ERROR, "ssl_info_callback: error occurred.\n"); return; } @@ -1049,9 +1051,9 @@ static tsi_result ssl_handshaker_result_extract_peer( } const char* session_reused = SSL_session_reused(impl->ssl) ? "true" : "false"; - result = tsi_construct_string_peer_property( + result = tsi_construct_string_peer_property_from_cstring( TSI_SSL_SESSION_REUSED_PEER_PROPERTY, session_reused, - strlen(session_reused) + 1, &peer->properties[peer->property_count]); + &peer->properties[peer->property_count]); if (result != TSI_OK) return result; peer->property_count++; diff --git a/src/core/tsi/ssl_types.h b/src/core/tsi/ssl_types.h index b15d02be39..0ce5e2ee6f 100644 --- a/src/core/tsi/ssl_types.h +++ b/src/core/tsi/ssl_types.h @@ -29,6 +29,8 @@ #include <grpc/support/port_platform.h> +#include "src/core/tsi/grpc_shadow_boringssl.h" + #include <openssl/ssl.h> #ifdef OPENSSL_IS_BORINGSSL diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index 39b891c2e1..2cab41b3f5 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -20,6 +20,7 @@ #include <chrono> #include <condition_variable> +#include <cstring> #include <memory> #include <mutex> @@ -42,21 +43,40 @@ #include <grpcpp/support/time.h> #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/gprpp/thd.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/surface/completion_queue.h" namespace grpc { static internal::GrpcLibraryInitializer g_gli_initializer; -Channel::Channel(const grpc::string& host, grpc_channel* channel) +Channel::Channel( + const grpc::string& host, grpc_channel* channel, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) : host_(host), c_channel_(channel) { + auto* vector = interceptor_creators.release(); + if (vector != nullptr) { + interceptor_creators_ = std::move(*vector); + } g_gli_initializer.summon(); } -Channel::~Channel() { grpc_channel_destroy(c_channel_); } +Channel::~Channel() { + grpc_channel_destroy(c_channel_); + if (callback_cq_ != nullptr) { + callback_cq_->Shutdown(); + } +} namespace { +inline grpc_slice SliceFromArray(const char* arr, size_t len) { + return g_core_codegen_interface->grpc_slice_from_copied_buffer(arr, len); +} + grpc::string GetChannelInfoField(grpc_channel* channel, grpc_channel_info* channel_info, char*** channel_info_field) { @@ -103,16 +123,17 @@ internal::Call Channel::CreateCall(const internal::RpcMethod& method, context->propagation_options_.c_bitmask(), cq->cq(), method.channel_tag(), context->raw_deadline(), nullptr); } else { - const char* host_str = nullptr; - if (!context->authority().empty()) { - host_str = context->authority_.c_str(); + const string* host_str = nullptr; + if (!context->authority_.empty()) { + host_str = &context->authority_; } else if (!host_.empty()) { - host_str = host_.c_str(); + host_str = &host_; } - grpc_slice method_slice = SliceFromCopiedString(method.name()); + grpc_slice method_slice = + SliceFromArray(method.name(), strlen(method.name())); grpc_slice host_slice; if (host_str != nullptr) { - host_slice = SliceFromCopiedString(host_str); + host_slice = SliceFromCopiedString(*host_str); } c_call = grpc_channel_create_call( c_channel_, context->propagate_from_call_, @@ -135,8 +156,8 @@ void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops, size_t nops = 0; grpc_op cops[MAX_OPS]; ops->FillOps(call->call(), cops, &nops); - GPR_ASSERT(GRPC_CALL_OK == - grpc_call_start_batch(call->call(), cops, nops, ops, nullptr)); + GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call->call(), cops, nops, + ops->cq_tag(), nullptr)); } void* Channel::RegisterMethod(const char* method) { @@ -185,4 +206,41 @@ bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed, return ok; } +namespace { +class ShutdownCallback : public grpc_experimental_completion_queue_functor { + public: + ShutdownCallback() { functor_run = &ShutdownCallback::Run; } + // TakeCQ takes ownership of the cq into the shutdown callback + // so that the shutdown callback will be responsible for destroying it + void TakeCQ(CompletionQueue* cq) { cq_ = cq; } + + // The Run function will get invoked by the completion queue library + // when the shutdown is actually complete + static void Run(grpc_experimental_completion_queue_functor* cb, int) { + auto* callback = static_cast<ShutdownCallback*>(cb); + delete callback->cq_; + grpc_core::Delete(callback); + } + + private: + CompletionQueue* cq_ = nullptr; +}; +} // namespace + +CompletionQueue* Channel::CallbackCQ() { + // TODO(vjpai): Consider using a single global CQ for the default CQ + // if there is no explicit per-channel CQ registered + std::lock_guard<std::mutex> l(mu_); + if (callback_cq_ == nullptr) { + auto* shutdown_callback = grpc_core::New<ShutdownCallback>(); + callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, + shutdown_callback}); + + // Transfer ownership of the new cq to its own shutdown callback + shutdown_callback->TakeCQ(callback_cq_); + } + return callback_cq_; +} + } // namespace grpc diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index 67a46ce0e1..efdff6c265 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -39,11 +39,43 @@ std::shared_ptr<Channel> CreateCustomChannel( const std::shared_ptr<ChannelCredentials>& creds, const ChannelArguments& args) { GrpcLibraryCodegen init_lib; // We need to call init in case of a bad creds. - return creds ? creds->CreateChannel(target, args) - : CreateChannelInternal( - "", grpc_lame_client_channel_create( - nullptr, GRPC_STATUS_INVALID_ARGUMENT, - "Invalid credentials.")); + return creds + ? creds->CreateChannel(target, args) + : CreateChannelInternal("", + grpc_lame_client_channel_create( + nullptr, GRPC_STATUS_INVALID_ARGUMENT, + "Invalid credentials."), + nullptr); } +namespace experimental { +/// Create a new \em custom \a Channel pointing to \a target with \a +/// interceptors being invoked per call. +/// +/// \warning For advanced use and testing ONLY. Override default channel +/// arguments only if necessary. +/// +/// \param target The URI of the endpoint to connect to. +/// \param creds Credentials to use for the created channel. If it does not +/// hold an object or is invalid, a lame channel (one on which all operations +/// fail) is returned. +/// \param args Options for channel creation. +std::shared_ptr<Channel> CreateCustomChannelWithInterceptors( + const grpc::string& target, + const std::shared_ptr<ChannelCredentials>& creds, + const ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) { + return creds + ? creds->CreateChannelWithInterceptors( + target, args, std::move(interceptor_creators)) + : CreateChannelInternal("", + grpc_lame_client_channel_create( + nullptr, GRPC_STATUS_INVALID_ARGUMENT, + "Invalid credentials."), + nullptr); +} +} // namespace experimental + } // namespace grpc diff --git a/src/cpp/client/create_channel_internal.cc b/src/cpp/client/create_channel_internal.cc index aa96edfcff..313d682aae 100644 --- a/src/cpp/client/create_channel_internal.cc +++ b/src/cpp/client/create_channel_internal.cc @@ -24,8 +24,12 @@ struct grpc_channel; namespace grpc { -std::shared_ptr<Channel> CreateChannelInternal(const grpc::string& host, - grpc_channel* c_channel) { - return std::shared_ptr<Channel>(new Channel(host, c_channel)); +std::shared_ptr<Channel> CreateChannelInternal( + const grpc::string& host, grpc_channel* c_channel, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) { + return std::shared_ptr<Channel>( + new Channel(host, c_channel, std::move(interceptor_creators))); } } // namespace grpc diff --git a/src/cpp/client/create_channel_internal.h b/src/cpp/client/create_channel_internal.h index 86e8167277..512fc22866 100644 --- a/src/cpp/client/create_channel_internal.h +++ b/src/cpp/client/create_channel_internal.h @@ -21,6 +21,7 @@ #include <memory> +#include <grpcpp/impl/codegen/client_interceptor.h> #include <grpcpp/support/config.h> struct grpc_channel; @@ -28,8 +29,11 @@ struct grpc_channel; namespace grpc { class Channel; -std::shared_ptr<Channel> CreateChannelInternal(const grpc::string& host, - grpc_channel* c_channel); +std::shared_ptr<Channel> CreateChannelInternal( + const grpc::string& host, grpc_channel* c_channel, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators); } // namespace grpc diff --git a/src/cpp/client/create_channel_posix.cc b/src/cpp/client/create_channel_posix.cc index f9285c9b28..8d775e7a87 100644 --- a/src/cpp/client/create_channel_posix.cc +++ b/src/cpp/client/create_channel_posix.cc @@ -33,7 +33,8 @@ std::shared_ptr<Channel> CreateInsecureChannelFromFd(const grpc::string& target, internal::GrpcLibrary init_lib; init_lib.init(); return CreateChannelInternal( - "", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr)); + "", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr), + nullptr); } std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd( @@ -42,10 +43,31 @@ std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd( init_lib.init(); grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); - return CreateChannelInternal("", grpc_insecure_channel_create_from_fd( - target.c_str(), fd, &channel_args)); + return CreateChannelInternal( + "", + grpc_insecure_channel_create_from_fd(target.c_str(), fd, &channel_args), + nullptr); +} + +namespace experimental { + +std::shared_ptr<Channel> CreateCustomInsecureChannelWithInterceptorsFromFd( + const grpc::string& target, int fd, const ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) { + internal::GrpcLibrary init_lib; + init_lib.init(); + grpc_channel_args channel_args; + args.SetChannelArgs(&channel_args); + return CreateChannelInternal( + "", + grpc_insecure_channel_create_from_fd(target.c_str(), fd, &channel_args), + std::move(interceptor_creators)); } +} // namespace experimental + #endif // GPR_SUPPORT_CHANNELS_FROM_FD } // namespace grpc diff --git a/src/cpp/client/cronet_credentials.cc b/src/cpp/client/cronet_credentials.cc index 5c65ad05ea..09a76b428c 100644 --- a/src/cpp/client/cronet_credentials.cc +++ b/src/cpp/client/cronet_credentials.cc @@ -31,16 +31,25 @@ class CronetChannelCredentialsImpl final : public ChannelCredentials { std::shared_ptr<grpc::Channel> CreateChannel( const string& target, const grpc::ChannelArguments& args) override { - grpc_channel_args channel_args; - args.SetChannelArgs(&channel_args); - return CreateChannelInternal( - "", grpc_cronet_secure_channel_create(engine_, target.c_str(), - &channel_args, nullptr)); + return CreateChannelWithInterceptors(target, args, nullptr); } SecureChannelCredentials* AsSecureCredentials() override { return nullptr; } private: + std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors( + const string& target, const grpc::ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) override { + grpc_channel_args channel_args; + args.SetChannelArgs(&channel_args); + return CreateChannelInternal( + "", + grpc_cronet_secure_channel_create(engine_, target.c_str(), + &channel_args, nullptr), + std::move(interceptor_creators)); + } void* engine_; }; diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc index 67ef46bebe..87902b26f0 100644 --- a/src/cpp/client/generic_stub.cc +++ b/src/cpp/client/generic_stub.cc @@ -16,9 +16,11 @@ * */ -#include <grpcpp/generic/generic_stub.h> +#include <functional> +#include <grpcpp/generic/generic_stub.h> #include <grpcpp/impl/rpc_method.h> +#include <grpcpp/support/client_callback.h> namespace grpc { @@ -60,4 +62,14 @@ std::unique_ptr<GenericClientAsyncResponseReader> GenericStub::PrepareUnaryCall( context, request, false)); } +void GenericStub::experimental_type::UnaryCall( + ClientContext* context, const grpc::string& method, + const ByteBuffer* request, ByteBuffer* response, + std::function<void(Status)> on_completion) { + internal::CallbackUnaryCall( + stub_->channel_.get(), + internal::RpcMethod(method.c_str(), internal::RpcMethod::NORMAL_RPC), + context, request, response, std::move(on_completion)); +} + } // namespace grpc diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc index 04dc5c0bcc..b816e0c59a 100644 --- a/src/cpp/client/insecure_credentials.cc +++ b/src/cpp/client/insecure_credentials.cc @@ -32,11 +32,20 @@ class InsecureChannelCredentialsImpl final : public ChannelCredentials { public: std::shared_ptr<grpc::Channel> CreateChannel( const string& target, const grpc::ChannelArguments& args) override { + return CreateChannelWithInterceptors(target, args, nullptr); + } + + std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors( + const string& target, const grpc::ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) override { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); return CreateChannelInternal( "", - grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr)); + grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr), + std::move(interceptor_creators)); } SecureChannelCredentials* AsSecureCredentials() override { return nullptr; } diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index e48fbeb86d..d1cd78e755 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -36,12 +36,22 @@ SecureChannelCredentials::SecureChannelCredentials( std::shared_ptr<grpc::Channel> SecureChannelCredentials::CreateChannel( const string& target, const grpc::ChannelArguments& args) { + return CreateChannelWithInterceptors(target, args, nullptr); +} + +std::shared_ptr<grpc::Channel> +SecureChannelCredentials::CreateChannelWithInterceptors( + const string& target, const grpc::ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); return CreateChannelInternal( args.GetSslTargetNameOverride(), grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args, - nullptr)); + nullptr), + std::move(interceptor_creators)); } SecureCallCredentials::SecureCallCredentials(grpc_call_credentials* c_creds) diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h index 85cb54227c..bfb6e17ee9 100644 --- a/src/cpp/client/secure_credentials.h +++ b/src/cpp/client/secure_credentials.h @@ -36,9 +36,15 @@ class SecureChannelCredentials final : public ChannelCredentials { std::shared_ptr<grpc::Channel> CreateChannel( const string& target, const grpc::ChannelArguments& args) override; + SecureChannelCredentials* AsSecureCredentials() override { return this; } private: + std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors( + const string& target, const grpc::ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) override; grpc_channel_credentials* const c_creds_; }; diff --git a/src/cpp/common/alarm.cc b/src/cpp/common/alarm.cc index 15a373d8a5..5819a4210b 100644 --- a/src/cpp/common/alarm.cc +++ b/src/cpp/common/alarm.cc @@ -39,17 +39,6 @@ class AlarmImpl : public CompletionQueueTag { AlarmImpl() : cq_(nullptr), tag_(nullptr) { gpr_ref_init(&refs_, 1); grpc_timer_init_unset(&timer_); - GRPC_CLOSURE_INIT(&on_alarm_, - [](void* arg, grpc_error* error) { - // queue the op on the completion queue - AlarmImpl* alarm = static_cast<AlarmImpl*>(arg); - alarm->Ref(); - grpc_cq_end_op( - alarm->cq_, alarm, error, - [](void* arg, grpc_cq_completion* completion) {}, - arg, &alarm->completion_); - }, - this, grpc_schedule_on_exec_ctx); } ~AlarmImpl() { grpc_core::ExecCtx exec_ctx; @@ -68,6 +57,32 @@ class AlarmImpl : public CompletionQueueTag { cq_ = cq->cq(); tag_ = tag; GPR_ASSERT(grpc_cq_begin_op(cq_, this)); + GRPC_CLOSURE_INIT(&on_alarm_, + [](void* arg, grpc_error* error) { + // queue the op on the completion queue + AlarmImpl* alarm = static_cast<AlarmImpl*>(arg); + alarm->Ref(); + grpc_cq_end_op( + alarm->cq_, alarm, error, + [](void* arg, grpc_cq_completion* completion) {}, + arg, &alarm->completion_); + }, + this, grpc_schedule_on_exec_ctx); + grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline), + &on_alarm_); + } + void Set(gpr_timespec deadline, std::function<void(bool)> f) { + grpc_core::ExecCtx exec_ctx; + // Don't use any CQ at all. Instead just use the timer to fire the function + callback_ = std::move(f); + Ref(); + GRPC_CLOSURE_INIT(&on_alarm_, + [](void* arg, grpc_error* error) { + AlarmImpl* alarm = static_cast<AlarmImpl*>(arg); + alarm->callback_(error == GRPC_ERROR_NONE); + alarm->Unref(); + }, + this, grpc_schedule_on_exec_ctx); grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline), &on_alarm_); } @@ -95,6 +110,7 @@ class AlarmImpl : public CompletionQueueTag { // completion queue where events about this alarm will be posted grpc_completion_queue* cq_; void* tag_; + std::function<void(bool)> callback_; }; } // namespace internal @@ -113,6 +129,15 @@ void Alarm::SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag) { static_cast<internal::AlarmImpl*>(alarm_)->Set(cq, deadline, tag); } +void Alarm::SetInternal(gpr_timespec deadline, std::function<void(bool)> f) { + // Note that we know that alarm_ is actually an internal::AlarmImpl + // but we declared it as the base pointer to avoid a forward declaration + // or exposing core data structures in the C++ public headers. + // Thus it is safe to use a static_cast to the subclass here, and the + // C++ style guide allows us to do so in this case + static_cast<internal::AlarmImpl*>(alarm_)->Set(deadline, std::move(f)); +} + Alarm::~Alarm() { if (alarm_ != nullptr) { static_cast<internal::AlarmImpl*>(alarm_)->Destroy(); diff --git a/src/cpp/common/channel_filter.cc b/src/cpp/common/channel_filter.cc index 0634b0416f..422e7bb65e 100644 --- a/src/cpp/common/channel_filter.cc +++ b/src/cpp/common/channel_filter.cc @@ -78,13 +78,8 @@ bool MaybeAddFilter(grpc_channel_stack_builder* builder, void* arg) { grpc_channel_stack_builder_get_channel_arguments(builder); if (!filter.include_filter(*args)) return true; } - if (filter.prepend) { - return grpc_channel_stack_builder_prepend_filter(builder, &filter.filter, - nullptr, nullptr); - } else { - return grpc_channel_stack_builder_append_filter(builder, &filter.filter, - nullptr, nullptr); - } + return grpc_channel_stack_builder_prepend_filter(builder, &filter.filter, + nullptr, nullptr); } } // namespace diff --git a/src/cpp/common/channel_filter.h b/src/cpp/common/channel_filter.h index 359c72737c..5e569c97e6 100644 --- a/src/cpp/common/channel_filter.h +++ b/src/cpp/common/channel_filter.h @@ -36,8 +36,7 @@ /// \c ChannelData. Then register the filter using something like this: /// \code{.cpp} /// RegisterChannelFilter<MyChannelDataSubclass, MyCallDataSubclass>( -/// "name-of-filter", GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_LOW, -/// true, nullptr); +/// "name-of-filter", GRPC_SERVER_CHANNEL, INT_MAX, nullptr); /// \endcode namespace grpc { @@ -352,7 +351,6 @@ class ChannelFilter final { struct FilterRecord { grpc_channel_stack_type stack_type; int priority; - bool prepend; std::function<bool(const grpc_channel_args&)> include_filter; grpc_channel_filter filter; }; @@ -365,14 +363,12 @@ void ChannelFilterPluginShutdown(); /// Registers a new filter. /// Must be called by only one thread at a time. -/// The \a prepend argument decides whether to prepend or append the filter. /// The \a include_filter argument specifies a function that will be called /// to determine at run-time whether or not to add the filter. If the /// value is nullptr, the filter will be added unconditionally. template <typename ChannelDataType, typename CallDataType> void RegisterChannelFilter( const char* name, grpc_channel_stack_type stack_type, int priority, - bool prepend, std::function<bool(const grpc_channel_args&)> include_filter) { // If we haven't been called before, initialize channel_filters and // call grpc_register_plugin(). @@ -387,7 +383,6 @@ void RegisterChannelFilter( internal::FilterRecord filter_record = { stack_type, priority, - prepend, include_filter, {FilterType::StartTransportStreamOpBatch, FilterType::StartTransportOp, FilterType::call_data_size, FilterType::InitCallElement, diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index b8fca9a6ee..8abd45efb7 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -22,5 +22,5 @@ #include <grpcpp/grpcpp.h> namespace grpc { -grpc::string Version() { return "1.15.0-dev"; } +grpc::string Version() { return "1.17.0-dev"; } } // namespace grpc diff --git a/src/cpp/ext/filters/census/grpc_plugin.cc b/src/cpp/ext/filters/census/grpc_plugin.cc index f79e0e0e96..f978ed3bf5 100644 --- a/src/cpp/ext/filters/census/grpc_plugin.cc +++ b/src/cpp/ext/filters/census/grpc_plugin.cc @@ -32,12 +32,10 @@ namespace grpc { void RegisterOpenCensusPlugin() { RegisterChannelFilter<CensusChannelData, CensusClientCallData>( - "opencensus_client", GRPC_CLIENT_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH, true /* prepend */, + "opencensus_client", GRPC_CLIENT_CHANNEL, INT_MAX /* priority */, nullptr /* condition function */); RegisterChannelFilter<CensusChannelData, CensusServerCallData>( - "opencensus_server", GRPC_SERVER_CHANNEL, - GRPC_CHANNEL_INIT_PRIORITY_VERY_HIGH, true /* prepend */, + "opencensus_server", GRPC_SERVER_CHANNEL, INT_MAX /* priority */, nullptr /* condition function */); // Access measures to ensure they are initialized. Otherwise, creating a view diff --git a/src/cpp/ext/filters/census/grpc_plugin.h b/src/cpp/ext/filters/census/grpc_plugin.h index 7ff2e7a8b8..9e319cb994 100644 --- a/src/cpp/ext/filters/census/grpc_plugin.h +++ b/src/cpp/ext/filters/census/grpc_plugin.h @@ -24,15 +24,11 @@ #include "absl/strings/string_view.h" #include "include/grpcpp/opencensus.h" #include "opencensus/stats/stats.h" -#include "opencensus/trace/span.h" namespace grpc { class ServerContext; -// Returns the tracing Span for the current RPC. -::opencensus::trace::Span GetSpanFromServerContext(ServerContext* context); - // The tag keys set when recording RPC stats. ::opencensus::stats::TagKey ClientMethodTagKey(); ::opencensus::stats::TagKey ClientStatusTagKey(); diff --git a/src/cpp/ext/filters/census/server_filter.cc b/src/cpp/ext/filters/census/server_filter.cc index c7c62eefe5..b5f3d5a13a 100644 --- a/src/cpp/ext/filters/census/server_filter.cc +++ b/src/cpp/ext/filters/census/server_filter.cc @@ -93,7 +93,7 @@ void CensusServerCallData::OnDoneRecvInitialMetadataCb(void* user_data, FilterInitialMetadata(initial_metadata, &sml); calld->path_ = grpc_slice_ref_internal(sml.path); calld->method_ = GetMethod(&calld->path_); - calld->qualified_method_ = StrCat("Recv.", calld->method_); + calld->qualified_method_ = absl::StrCat("Recv.", calld->method_); const char* tracing_str = GRPC_SLICE_IS_EMPTY(sml.tracing_slice) ? "" diff --git a/src/cpp/server/channelz/channelz_service.cc b/src/cpp/server/channelz/channelz_service.cc index 77c175e5b8..79ed9102e5 100644 --- a/src/cpp/server/channelz/channelz_service.cc +++ b/src/cpp/server/channelz/channelz_service.cc @@ -32,6 +32,42 @@ Status ChannelzService::GetTopChannels( ServerContext* unused, const channelz::v1::GetTopChannelsRequest* request, channelz::v1::GetTopChannelsResponse* response) { char* json_str = grpc_channelz_get_top_channels(request->start_channel_id()); + if (json_str == nullptr) { + return Status(INTERNAL, "grpc_channelz_get_top_channels returned null"); + } + google::protobuf::util::Status s = + google::protobuf::util::JsonStringToMessage(json_str, response); + gpr_free(json_str); + if (s != google::protobuf::util::Status::OK) { + return Status(INTERNAL, s.ToString()); + } + return Status::OK; +} + +Status ChannelzService::GetServers( + ServerContext* unused, const channelz::v1::GetServersRequest* request, + channelz::v1::GetServersResponse* response) { + char* json_str = grpc_channelz_get_servers(request->start_server_id()); + if (json_str == nullptr) { + return Status(INTERNAL, "grpc_channelz_get_servers returned null"); + } + google::protobuf::util::Status s = + google::protobuf::util::JsonStringToMessage(json_str, response); + gpr_free(json_str); + if (s != google::protobuf::util::Status::OK) { + return Status(INTERNAL, s.ToString()); + } + return Status::OK; +} + +Status ChannelzService::GetServerSockets( + ServerContext* unused, const channelz::v1::GetServerSocketsRequest* request, + channelz::v1::GetServerSocketsResponse* response) { + char* json_str = grpc_channelz_get_server_sockets(request->server_id(), + request->start_socket_id()); + if (json_str == nullptr) { + return Status(INTERNAL, "grpc_channelz_get_server_sockets returned null"); + } google::protobuf::util::Status s = google::protobuf::util::JsonStringToMessage(json_str, response); gpr_free(json_str); @@ -45,6 +81,41 @@ Status ChannelzService::GetChannel( ServerContext* unused, const channelz::v1::GetChannelRequest* request, channelz::v1::GetChannelResponse* response) { char* json_str = grpc_channelz_get_channel(request->channel_id()); + if (json_str == nullptr) { + return Status(NOT_FOUND, "No object found for that ChannelId"); + } + google::protobuf::util::Status s = + google::protobuf::util::JsonStringToMessage(json_str, response); + gpr_free(json_str); + if (s != google::protobuf::util::Status::OK) { + return Status(INTERNAL, s.ToString()); + } + return Status::OK; +} + +Status ChannelzService::GetSubchannel( + ServerContext* unused, const channelz::v1::GetSubchannelRequest* request, + channelz::v1::GetSubchannelResponse* response) { + char* json_str = grpc_channelz_get_subchannel(request->subchannel_id()); + if (json_str == nullptr) { + return Status(NOT_FOUND, "No object found for that SubchannelId"); + } + google::protobuf::util::Status s = + google::protobuf::util::JsonStringToMessage(json_str, response); + gpr_free(json_str); + if (s != google::protobuf::util::Status::OK) { + return Status(INTERNAL, s.ToString()); + } + return Status::OK; +} + +Status ChannelzService::GetSocket(ServerContext* unused, + const channelz::v1::GetSocketRequest* request, + channelz::v1::GetSocketResponse* response) { + char* json_str = grpc_channelz_get_socket(request->socket_id()); + if (json_str == nullptr) { + return Status(NOT_FOUND, "No object found for that SocketId"); + } google::protobuf::util::Status s = google::protobuf::util::JsonStringToMessage(json_str, response); gpr_free(json_str); diff --git a/src/cpp/server/channelz/channelz_service.h b/src/cpp/server/channelz/channelz_service.h index f619ea49e0..590b5d492e 100644 --- a/src/cpp/server/channelz/channelz_service.h +++ b/src/cpp/server/channelz/channelz_service.h @@ -32,10 +32,27 @@ class ChannelzService final : public channelz::v1::Channelz::Service { Status GetTopChannels( ServerContext* unused, const channelz::v1::GetTopChannelsRequest* request, channelz::v1::GetTopChannelsResponse* response) override; + // implementation of GetServers rpc + Status GetServers(ServerContext* unused, + const channelz::v1::GetServersRequest* request, + channelz::v1::GetServersResponse* response) override; + // implementation of GetServerSockets rpc + Status GetServerSockets( + ServerContext* unused, + const channelz::v1::GetServerSocketsRequest* request, + channelz::v1::GetServerSocketsResponse* response) override; // implementation of GetChannel rpc Status GetChannel(ServerContext* unused, const channelz::v1::GetChannelRequest* request, channelz::v1::GetChannelResponse* response) override; + // implementation of GetSubchannel rpc + Status GetSubchannel(ServerContext* unused, + const channelz::v1::GetSubchannelRequest* request, + channelz::v1::GetSubchannelResponse* response) override; + // implementation of GetSocket rpc + Status GetSocket(ServerContext* unused, + const channelz::v1::GetSocketRequest* request, + channelz::v1::GetSocketResponse* response) override; }; } // namespace grpc diff --git a/src/cpp/server/health/default_health_check_service.cc b/src/cpp/server/health/default_health_check_service.cc index bfda67d086..0c03fdf17a 100644 --- a/src/cpp/server/health/default_health_check_service.cc +++ b/src/cpp/server/health/default_health_check_service.cc @@ -30,29 +30,159 @@ #include "src/cpp/server/health/health.pb.h" namespace grpc { + +// +// DefaultHealthCheckService +// + +DefaultHealthCheckService::DefaultHealthCheckService() { + services_map_[""].SetServingStatus(SERVING); +} + +void DefaultHealthCheckService::SetServingStatus( + const grpc::string& service_name, bool serving) { + std::unique_lock<std::mutex> lock(mu_); + services_map_[service_name].SetServingStatus(serving ? SERVING : NOT_SERVING); +} + +void DefaultHealthCheckService::SetServingStatus(bool serving) { + const ServingStatus status = serving ? SERVING : NOT_SERVING; + std::unique_lock<std::mutex> lock(mu_); + for (auto& p : services_map_) { + ServiceData& service_data = p.second; + service_data.SetServingStatus(status); + } +} + +DefaultHealthCheckService::ServingStatus +DefaultHealthCheckService::GetServingStatus( + const grpc::string& service_name) const { + std::lock_guard<std::mutex> lock(mu_); + auto it = services_map_.find(service_name); + if (it == services_map_.end()) { + return NOT_FOUND; + } + const ServiceData& service_data = it->second; + return service_data.GetServingStatus(); +} + +void DefaultHealthCheckService::RegisterCallHandler( + const grpc::string& service_name, + std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) { + std::unique_lock<std::mutex> lock(mu_); + ServiceData& service_data = services_map_[service_name]; + service_data.AddCallHandler(handler /* copies ref */); + HealthCheckServiceImpl::CallHandler* h = handler.get(); + h->SendHealth(std::move(handler), service_data.GetServingStatus()); +} + +void DefaultHealthCheckService::UnregisterCallHandler( + const grpc::string& service_name, + std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) { + std::unique_lock<std::mutex> lock(mu_); + auto it = services_map_.find(service_name); + if (it == services_map_.end()) return; + ServiceData& service_data = it->second; + service_data.RemoveCallHandler(std::move(handler)); + if (service_data.Unused()) { + services_map_.erase(it); + } +} + +DefaultHealthCheckService::HealthCheckServiceImpl* +DefaultHealthCheckService::GetHealthCheckService( + std::unique_ptr<ServerCompletionQueue> cq) { + GPR_ASSERT(impl_ == nullptr); + impl_.reset(new HealthCheckServiceImpl(this, std::move(cq))); + return impl_.get(); +} + +// +// DefaultHealthCheckService::ServiceData +// + +void DefaultHealthCheckService::ServiceData::SetServingStatus( + ServingStatus status) { + status_ = status; + for (auto& call_handler : call_handlers_) { + call_handler->SendHealth(call_handler /* copies ref */, status); + } +} + +void DefaultHealthCheckService::ServiceData::AddCallHandler( + std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) { + call_handlers_.insert(std::move(handler)); +} + +void DefaultHealthCheckService::ServiceData::RemoveCallHandler( + std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) { + call_handlers_.erase(handler); +} + +// +// DefaultHealthCheckService::HealthCheckServiceImpl +// + namespace { const char kHealthCheckMethodName[] = "/grpc.health.v1.Health/Check"; +const char kHealthWatchMethodName[] = "/grpc.health.v1.Health/Watch"; } // namespace DefaultHealthCheckService::HealthCheckServiceImpl::HealthCheckServiceImpl( - DefaultHealthCheckService* service) - : service_(service), method_(nullptr) { - internal::MethodHandler* handler = - new internal::RpcMethodHandler<HealthCheckServiceImpl, ByteBuffer, - ByteBuffer>( - std::mem_fn(&HealthCheckServiceImpl::Check), this); - method_ = new internal::RpcServiceMethod( - kHealthCheckMethodName, internal::RpcMethod::NORMAL_RPC, handler); - AddMethod(method_); -} - -Status DefaultHealthCheckService::HealthCheckServiceImpl::Check( - ServerContext* context, const ByteBuffer* request, ByteBuffer* response) { - // Decode request. - std::vector<Slice> slices; - if (!request->Dump(&slices).ok()) { - return Status(StatusCode::INVALID_ARGUMENT, ""); + DefaultHealthCheckService* database, + std::unique_ptr<ServerCompletionQueue> cq) + : database_(database), cq_(std::move(cq)) { + // Add Check() method. + AddMethod(new internal::RpcServiceMethod( + kHealthCheckMethodName, internal::RpcMethod::NORMAL_RPC, nullptr)); + // Add Watch() method. + AddMethod(new internal::RpcServiceMethod( + kHealthWatchMethodName, internal::RpcMethod::SERVER_STREAMING, nullptr)); + // Create serving thread. + thread_ = std::unique_ptr<::grpc_core::Thread>( + new ::grpc_core::Thread("grpc_health_check_service", Serve, this)); +} + +DefaultHealthCheckService::HealthCheckServiceImpl::~HealthCheckServiceImpl() { + // We will reach here after the server starts shutting down. + shutdown_ = true; + { + std::unique_lock<std::mutex> lock(cq_shutdown_mu_); + cq_->Shutdown(); } + thread_->Join(); +} + +void DefaultHealthCheckService::HealthCheckServiceImpl::StartServingThread() { + // Request the calls we're interested in. + // We do this before starting the serving thread, so that we know it's + // done before server startup is complete. + CheckCallHandler::CreateAndStart(cq_.get(), database_, this); + WatchCallHandler::CreateAndStart(cq_.get(), database_, this); + // Start serving thread. + thread_->Start(); +} + +void DefaultHealthCheckService::HealthCheckServiceImpl::Serve(void* arg) { + HealthCheckServiceImpl* service = + reinterpret_cast<HealthCheckServiceImpl*>(arg); + void* tag; + bool ok; + while (true) { + if (!service->cq_->Next(&tag, &ok)) { + // The completion queue is shutting down. + GPR_ASSERT(service->shutdown_); + break; + } + auto* next_step = static_cast<CallableTag*>(tag); + next_step->Run(ok); + } +} + +bool DefaultHealthCheckService::HealthCheckServiceImpl::DecodeRequest( + const ByteBuffer& request, grpc::string* service_name) { + std::vector<Slice> slices; + if (!request.Dump(&slices).ok()) return false; uint8_t* request_bytes = nullptr; bool request_bytes_owned = false; size_t request_size = 0; @@ -64,14 +194,13 @@ Status DefaultHealthCheckService::HealthCheckServiceImpl::Check( request_size = slices[0].size(); } else { request_bytes_owned = true; - request_bytes = static_cast<uint8_t*>(gpr_malloc(request->Length())); + request_bytes = static_cast<uint8_t*>(gpr_malloc(request.Length())); uint8_t* copy_to = request_bytes; for (size_t i = 0; i < slices.size(); i++) { memcpy(copy_to, slices[i].begin(), slices[i].size()); copy_to += slices[i].size(); } } - if (request_bytes != nullptr) { pb_istream_t istream = pb_istream_from_buffer(request_bytes, request_size); bool decode_status = pb_decode( @@ -79,26 +208,22 @@ Status DefaultHealthCheckService::HealthCheckServiceImpl::Check( if (request_bytes_owned) { gpr_free(request_bytes); } - if (!decode_status) { - return Status(StatusCode::INVALID_ARGUMENT, ""); - } - } - - // Check status from the associated default health checking service. - DefaultHealthCheckService::ServingStatus serving_status = - service_->GetServingStatus( - request_struct.has_service ? request_struct.service : ""); - if (serving_status == DefaultHealthCheckService::NOT_FOUND) { - return Status(StatusCode::NOT_FOUND, ""); + if (!decode_status) return false; } + *service_name = request_struct.has_service ? request_struct.service : ""; + return true; +} - // Encode response +bool DefaultHealthCheckService::HealthCheckServiceImpl::EncodeResponse( + ServingStatus status, ByteBuffer* response) { grpc_health_v1_HealthCheckResponse response_struct; response_struct.has_status = true; response_struct.status = - serving_status == DefaultHealthCheckService::SERVING - ? grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING - : grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING; + status == NOT_FOUND + ? grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN + : status == SERVING + ? grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING + : grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING; pb_ostream_t ostream; memset(&ostream, 0, sizeof(ostream)); pb_encode(&ostream, grpc_health_v1_HealthCheckResponse_fields, @@ -108,48 +233,250 @@ Status DefaultHealthCheckService::HealthCheckServiceImpl::Check( GRPC_SLICE_LENGTH(response_slice)); bool encode_status = pb_encode( &ostream, grpc_health_v1_HealthCheckResponse_fields, &response_struct); - if (!encode_status) { - return Status(StatusCode::INTERNAL, "Failed to encode response."); - } + if (!encode_status) return false; Slice encoded_response(response_slice, Slice::STEAL_REF); ByteBuffer response_buffer(&encoded_response, 1); response->Swap(&response_buffer); - return Status::OK; + return true; } -DefaultHealthCheckService::DefaultHealthCheckService() { - services_map_.emplace("", true); +// +// DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler +// + +void DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler:: + CreateAndStart(ServerCompletionQueue* cq, + DefaultHealthCheckService* database, + HealthCheckServiceImpl* service) { + std::shared_ptr<CallHandler> self = + std::make_shared<CheckCallHandler>(cq, database, service); + CheckCallHandler* handler = static_cast<CheckCallHandler*>(self.get()); + { + std::unique_lock<std::mutex> lock(service->cq_shutdown_mu_); + if (service->shutdown_) return; + // Request a Check() call. + handler->next_ = + CallableTag(std::bind(&CheckCallHandler::OnCallReceived, handler, + std::placeholders::_1, std::placeholders::_2), + std::move(self)); + service->RequestAsyncUnary(0, &handler->ctx_, &handler->request_, + &handler->writer_, cq, cq, &handler->next_); + } } -void DefaultHealthCheckService::SetServingStatus( - const grpc::string& service_name, bool serving) { - std::lock_guard<std::mutex> lock(mu_); - services_map_[service_name] = serving; +DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler:: + CheckCallHandler(ServerCompletionQueue* cq, + DefaultHealthCheckService* database, + HealthCheckServiceImpl* service) + : cq_(cq), database_(database), service_(service), writer_(&ctx_) {} + +void DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler:: + OnCallReceived(std::shared_ptr<CallHandler> self, bool ok) { + if (!ok) { + // The value of ok being false means that the server is shutting down. + return; + } + // Spawn a new handler instance to serve the next new client. Every handler + // instance will deallocate itself when it's done. + CreateAndStart(cq_, database_, service_); + // Process request. + gpr_log(GPR_DEBUG, "[HCS %p] Health check started for handler %p", service_, + this); + grpc::string service_name; + grpc::Status status = Status::OK; + ByteBuffer response; + if (!service_->DecodeRequest(request_, &service_name)) { + status = Status(StatusCode::INVALID_ARGUMENT, "could not parse request"); + } else { + ServingStatus serving_status = database_->GetServingStatus(service_name); + if (serving_status == NOT_FOUND) { + status = Status(StatusCode::NOT_FOUND, "service name unknown"); + } else if (!service_->EncodeResponse(serving_status, &response)) { + status = Status(StatusCode::INTERNAL, "could not encode response"); + } + } + // Send response. + { + std::unique_lock<std::mutex> lock(service_->cq_shutdown_mu_); + if (!service_->shutdown_) { + next_ = + CallableTag(std::bind(&CheckCallHandler::OnFinishDone, this, + std::placeholders::_1, std::placeholders::_2), + std::move(self)); + if (status.ok()) { + writer_.Finish(response, status, &next_); + } else { + writer_.FinishWithError(status, &next_); + } + } + } } -void DefaultHealthCheckService::SetServingStatus(bool serving) { - std::lock_guard<std::mutex> lock(mu_); - for (auto iter = services_map_.begin(); iter != services_map_.end(); ++iter) { - iter->second = serving; +void DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler:: + OnFinishDone(std::shared_ptr<CallHandler> self, bool ok) { + if (ok) { + gpr_log(GPR_DEBUG, "[HCS %p] Health check call finished for handler %p", + service_, this); } } -DefaultHealthCheckService::ServingStatus -DefaultHealthCheckService::GetServingStatus( - const grpc::string& service_name) const { - std::lock_guard<std::mutex> lock(mu_); - const auto& iter = services_map_.find(service_name); - if (iter == services_map_.end()) { - return NOT_FOUND; +// +// DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler +// + +void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + CreateAndStart(ServerCompletionQueue* cq, + DefaultHealthCheckService* database, + HealthCheckServiceImpl* service) { + std::shared_ptr<CallHandler> self = + std::make_shared<WatchCallHandler>(cq, database, service); + WatchCallHandler* handler = static_cast<WatchCallHandler*>(self.get()); + { + std::unique_lock<std::mutex> lock(service->cq_shutdown_mu_); + if (service->shutdown_) return; + // Request AsyncNotifyWhenDone(). + handler->on_done_notified_ = + CallableTag(std::bind(&WatchCallHandler::OnDoneNotified, handler, + std::placeholders::_1, std::placeholders::_2), + self /* copies ref */); + handler->ctx_.AsyncNotifyWhenDone(&handler->on_done_notified_); + // Request a Watch() call. + handler->next_ = + CallableTag(std::bind(&WatchCallHandler::OnCallReceived, handler, + std::placeholders::_1, std::placeholders::_2), + std::move(self)); + service->RequestAsyncServerStreaming(1, &handler->ctx_, &handler->request_, + &handler->stream_, cq, cq, + &handler->next_); } - return iter->second ? SERVING : NOT_SERVING; } -DefaultHealthCheckService::HealthCheckServiceImpl* -DefaultHealthCheckService::GetHealthCheckService() { - GPR_ASSERT(impl_ == nullptr); - impl_.reset(new HealthCheckServiceImpl(this)); - return impl_.get(); +DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + WatchCallHandler(ServerCompletionQueue* cq, + DefaultHealthCheckService* database, + HealthCheckServiceImpl* service) + : cq_(cq), database_(database), service_(service), stream_(&ctx_) {} + +void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + OnCallReceived(std::shared_ptr<CallHandler> self, bool ok) { + if (!ok) { + // Server shutting down. + // + // AsyncNotifyWhenDone() needs to be called before the call starts, but the + // tag will not pop out if the call never starts ( + // https://github.com/grpc/grpc/issues/10136). So we need to manually + // release the ownership of the handler in this case. + GPR_ASSERT(on_done_notified_.ReleaseHandler() != nullptr); + return; + } + // Spawn a new handler instance to serve the next new client. Every handler + // instance will deallocate itself when it's done. + CreateAndStart(cq_, database_, service_); + // Parse request. + if (!service_->DecodeRequest(request_, &service_name_)) { + SendFinish(std::move(self), + Status(StatusCode::INVALID_ARGUMENT, "could not parse request")); + return; + } + // Register the call for updates to the service. + gpr_log(GPR_DEBUG, + "[HCS %p] Health watch started for service \"%s\" (handler: %p)", + service_, service_name_.c_str(), this); + database_->RegisterCallHandler(service_name_, std::move(self)); +} + +void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + SendHealth(std::shared_ptr<CallHandler> self, ServingStatus status) { + std::unique_lock<std::mutex> lock(send_mu_); + // If there's already a send in flight, cache the new status, and + // we'll start a new send for it when the one in flight completes. + if (send_in_flight_) { + pending_status_ = status; + return; + } + // Start a send. + SendHealthLocked(std::move(self), status); +} + +void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + SendHealthLocked(std::shared_ptr<CallHandler> self, ServingStatus status) { + send_in_flight_ = true; + // Construct response. + ByteBuffer response; + bool success = service_->EncodeResponse(status, &response); + // Grab shutdown lock and send response. + std::unique_lock<std::mutex> cq_lock(service_->cq_shutdown_mu_); + if (service_->shutdown_) { + SendFinishLocked(std::move(self), Status::CANCELLED); + return; + } + if (!success) { + SendFinishLocked(std::move(self), + Status(StatusCode::INTERNAL, "could not encode response")); + return; + } + next_ = CallableTag(std::bind(&WatchCallHandler::OnSendHealthDone, this, + std::placeholders::_1, std::placeholders::_2), + std::move(self)); + stream_.Write(response, &next_); +} + +void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + OnSendHealthDone(std::shared_ptr<CallHandler> self, bool ok) { + if (!ok) { + SendFinish(std::move(self), Status::CANCELLED); + return; + } + std::unique_lock<std::mutex> lock(send_mu_); + send_in_flight_ = false; + // If we got a new status since we started the last send, start a + // new send for it. + if (pending_status_ != NOT_FOUND) { + auto status = pending_status_; + pending_status_ = NOT_FOUND; + SendHealthLocked(std::move(self), status); + } +} + +void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + SendFinish(std::shared_ptr<CallHandler> self, const Status& status) { + if (finish_called_) return; + std::unique_lock<std::mutex> cq_lock(service_->cq_shutdown_mu_); + if (!service_->shutdown_) return; + SendFinishLocked(std::move(self), status); +} + +void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + SendFinishLocked(std::shared_ptr<CallHandler> self, const Status& status) { + on_finish_done_ = + CallableTag(std::bind(&WatchCallHandler::OnFinishDone, this, + std::placeholders::_1, std::placeholders::_2), + std::move(self)); + stream_.Finish(status, &on_finish_done_); + finish_called_ = true; +} + +void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + OnFinishDone(std::shared_ptr<CallHandler> self, bool ok) { + if (ok) { + gpr_log(GPR_DEBUG, + "[HCS %p] Health watch call finished (service_name: \"%s\", " + "handler: %p).", + service_, service_name_.c_str(), this); + } +} + +// TODO(roth): This method currently assumes that there will be only one +// thread polling the cq and invoking the corresponding callbacks. If +// that changes, we will need to add synchronization here. +void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler:: + OnDoneNotified(std::shared_ptr<CallHandler> self, bool ok) { + GPR_ASSERT(ok); + gpr_log(GPR_DEBUG, + "[HCS %p] Healt watch call is notified done (handler: %p, " + "is_cancelled: %d).", + service_, this, static_cast<int>(ctx_.IsCancelled())); + SendFinish(std::move(self), Status::CANCELLED); } } // namespace grpc diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h index a1ce5aa64e..3bab76b6b0 100644 --- a/src/cpp/server/health/default_health_check_service.h +++ b/src/cpp/server/health/default_health_check_service.h @@ -19,42 +19,260 @@ #ifndef GRPC_INTERNAL_CPP_SERVER_DEFAULT_HEALTH_CHECK_SERVICE_H #define GRPC_INTERNAL_CPP_SERVER_DEFAULT_HEALTH_CHECK_SERVICE_H +#include <atomic> #include <mutex> +#include <set> +#include <grpc/support/log.h> +#include <grpcpp/grpcpp.h> #include <grpcpp/health_check_service_interface.h> +#include <grpcpp/impl/codegen/async_generic_service.h> +#include <grpcpp/impl/codegen/async_unary_call.h> #include <grpcpp/impl/codegen/service_type.h> #include <grpcpp/support/byte_buffer.h> +#include "src/core/lib/gprpp/thd.h" + namespace grpc { // Default implementation of HealthCheckServiceInterface. Server will create and // own it. class DefaultHealthCheckService final : public HealthCheckServiceInterface { public: + enum ServingStatus { NOT_FOUND, SERVING, NOT_SERVING }; + // The service impl to register with the server. class HealthCheckServiceImpl : public Service { public: - explicit HealthCheckServiceImpl(DefaultHealthCheckService* service); + // Base class for call handlers. + class CallHandler { + public: + virtual ~CallHandler() = default; + virtual void SendHealth(std::shared_ptr<CallHandler> self, + ServingStatus status) = 0; + }; - Status Check(ServerContext* context, const ByteBuffer* request, - ByteBuffer* response); + HealthCheckServiceImpl(DefaultHealthCheckService* database, + std::unique_ptr<ServerCompletionQueue> cq); + + ~HealthCheckServiceImpl(); + + void StartServingThread(); private: - const DefaultHealthCheckService* const service_; - internal::RpcServiceMethod* method_; + // A tag that can be called with a bool argument. It's tailored for + // CallHandler's use. Before being used, it should be constructed with a + // method of CallHandler and a shared pointer to the handler. The + // shared pointer will be moved to the invoked function and the function + // can only be invoked once. That makes ref counting of the handler easier, + // because the shared pointer is not bound to the function and can be gone + // once the invoked function returns (if not used any more). + class CallableTag { + public: + using HandlerFunction = + std::function<void(std::shared_ptr<CallHandler>, bool)>; + + CallableTag() {} + + CallableTag(HandlerFunction func, std::shared_ptr<CallHandler> handler) + : handler_function_(std::move(func)), handler_(std::move(handler)) { + GPR_ASSERT(handler_function_ != nullptr); + GPR_ASSERT(handler_ != nullptr); + } + + // Runs the tag. This should be called only once. The handler is no + // longer owned by this tag after this method is invoked. + void Run(bool ok) { + GPR_ASSERT(handler_function_ != nullptr); + GPR_ASSERT(handler_ != nullptr); + handler_function_(std::move(handler_), ok); + } + + // Releases and returns the shared pointer to the handler. + std::shared_ptr<CallHandler> ReleaseHandler() { + return std::move(handler_); + } + + private: + HandlerFunction handler_function_ = nullptr; + std::shared_ptr<CallHandler> handler_; + }; + + // Call handler for Check method. + // Each handler takes care of one call. It contains per-call data and it + // will access the members of the parent class (i.e., + // DefaultHealthCheckService) for per-service health data. + class CheckCallHandler : public CallHandler { + public: + // Instantiates a CheckCallHandler and requests the next health check + // call. The handler object will manage its own lifetime, so no action is + // needed from the caller any more regarding that object. + static void CreateAndStart(ServerCompletionQueue* cq, + DefaultHealthCheckService* database, + HealthCheckServiceImpl* service); + + // This ctor is public because we want to use std::make_shared<> in + // CreateAndStart(). This ctor shouldn't be used elsewhere. + CheckCallHandler(ServerCompletionQueue* cq, + DefaultHealthCheckService* database, + HealthCheckServiceImpl* service); + + // Not used for Check. + void SendHealth(std::shared_ptr<CallHandler> self, + ServingStatus status) override {} + + private: + // Called when we receive a call. + // Spawns a new handler so that we can keep servicing future calls. + void OnCallReceived(std::shared_ptr<CallHandler> self, bool ok); + + // Called when Finish() is done. + void OnFinishDone(std::shared_ptr<CallHandler> self, bool ok); + + // The members passed down from HealthCheckServiceImpl. + ServerCompletionQueue* cq_; + DefaultHealthCheckService* database_; + HealthCheckServiceImpl* service_; + + ByteBuffer request_; + GenericServerAsyncResponseWriter writer_; + ServerContext ctx_; + + CallableTag next_; + }; + + // Call handler for Watch method. + // Each handler takes care of one call. It contains per-call data and it + // will access the members of the parent class (i.e., + // DefaultHealthCheckService) for per-service health data. + class WatchCallHandler : public CallHandler { + public: + // Instantiates a WatchCallHandler and requests the next health check + // call. The handler object will manage its own lifetime, so no action is + // needed from the caller any more regarding that object. + static void CreateAndStart(ServerCompletionQueue* cq, + DefaultHealthCheckService* database, + HealthCheckServiceImpl* service); + + // This ctor is public because we want to use std::make_shared<> in + // CreateAndStart(). This ctor shouldn't be used elsewhere. + WatchCallHandler(ServerCompletionQueue* cq, + DefaultHealthCheckService* database, + HealthCheckServiceImpl* service); + + void SendHealth(std::shared_ptr<CallHandler> self, + ServingStatus status) override; + + private: + // Called when we receive a call. + // Spawns a new handler so that we can keep servicing future calls. + void OnCallReceived(std::shared_ptr<CallHandler> self, bool ok); + + // Requires holding send_mu_. + void SendHealthLocked(std::shared_ptr<CallHandler> self, + ServingStatus status); + + // When sending a health result finishes. + void OnSendHealthDone(std::shared_ptr<CallHandler> self, bool ok); + + void SendFinish(std::shared_ptr<CallHandler> self, const Status& status); + + // Requires holding service_->cq_shutdown_mu_. + void SendFinishLocked(std::shared_ptr<CallHandler> self, + const Status& status); + + // Called when Finish() is done. + void OnFinishDone(std::shared_ptr<CallHandler> self, bool ok); + + // Called when AsyncNotifyWhenDone() notifies us. + void OnDoneNotified(std::shared_ptr<CallHandler> self, bool ok); + + // The members passed down from HealthCheckServiceImpl. + ServerCompletionQueue* cq_; + DefaultHealthCheckService* database_; + HealthCheckServiceImpl* service_; + + ByteBuffer request_; + grpc::string service_name_; + GenericServerAsyncWriter stream_; + ServerContext ctx_; + + std::mutex send_mu_; + bool send_in_flight_ = false; // Guarded by mu_. + ServingStatus pending_status_ = NOT_FOUND; // Guarded by mu_. + + bool finish_called_ = false; + CallableTag next_; + CallableTag on_done_notified_; + CallableTag on_finish_done_; + }; + + // Handles the incoming requests and drives the completion queue in a loop. + static void Serve(void* arg); + + // Returns true on success. + static bool DecodeRequest(const ByteBuffer& request, + grpc::string* service_name); + static bool EncodeResponse(ServingStatus status, ByteBuffer* response); + + // Needed to appease Windows compilers, which don't seem to allow + // nested classes to access protected members in the parent's + // superclass. + using Service::RequestAsyncServerStreaming; + using Service::RequestAsyncUnary; + + DefaultHealthCheckService* database_; + std::unique_ptr<ServerCompletionQueue> cq_; + + // To synchronize the operations related to shutdown state of cq_, so that + // we don't enqueue new tags into cq_ after it is already shut down. + std::mutex cq_shutdown_mu_; + std::atomic_bool shutdown_{false}; + std::unique_ptr<::grpc_core::Thread> thread_; }; DefaultHealthCheckService(); + void SetServingStatus(const grpc::string& service_name, bool serving) override; void SetServingStatus(bool serving) override; - enum ServingStatus { NOT_FOUND, SERVING, NOT_SERVING }; + ServingStatus GetServingStatus(const grpc::string& service_name) const; - HealthCheckServiceImpl* GetHealthCheckService(); + + HealthCheckServiceImpl* GetHealthCheckService( + std::unique_ptr<ServerCompletionQueue> cq); private: + // Stores the current serving status of a service and any call + // handlers registered for updates when the service's status changes. + class ServiceData { + public: + void SetServingStatus(ServingStatus status); + ServingStatus GetServingStatus() const { return status_; } + void AddCallHandler( + std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler); + void RemoveCallHandler( + std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler); + bool Unused() const { + return call_handlers_.empty() && status_ == NOT_FOUND; + } + + private: + ServingStatus status_ = NOT_FOUND; + std::set<std::shared_ptr<HealthCheckServiceImpl::CallHandler>> + call_handlers_; + }; + + void RegisterCallHandler( + const grpc::string& service_name, + std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler); + + void UnregisterCallHandler( + const grpc::string& service_name, + std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler); + mutable std::mutex mu_; - std::map<grpc::string, bool> services_map_; + std::map<grpc::string, ServiceData> services_map_; // Guarded by mu_. std::unique_ptr<HealthCheckServiceImpl> impl_; }; diff --git a/src/cpp/server/health/health.pb.c b/src/cpp/server/health/health.pb.c index 09bd98a3d9..5c214c7160 100644 --- a/src/cpp/server/health/health.pb.c +++ b/src/cpp/server/health/health.pb.c @@ -2,7 +2,6 @@ /* Generated by nanopb-0.3.7-dev */ #include "src/cpp/server/health/health.pb.h" - /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. diff --git a/src/cpp/server/health/health.pb.h b/src/cpp/server/health/health.pb.h index 29e1f3bacb..9d54ccd618 100644 --- a/src/cpp/server/health/health.pb.h +++ b/src/cpp/server/health/health.pb.h @@ -17,11 +17,12 @@ extern "C" { typedef enum _grpc_health_v1_HealthCheckResponse_ServingStatus { grpc_health_v1_HealthCheckResponse_ServingStatus_UNKNOWN = 0, grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING = 1, - grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING = 2 + grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING = 2, + grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN = 3 } grpc_health_v1_HealthCheckResponse_ServingStatus; #define _grpc_health_v1_HealthCheckResponse_ServingStatus_MIN grpc_health_v1_HealthCheckResponse_ServingStatus_UNKNOWN -#define _grpc_health_v1_HealthCheckResponse_ServingStatus_MAX grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING -#define _grpc_health_v1_HealthCheckResponse_ServingStatus_ARRAYSIZE ((grpc_health_v1_HealthCheckResponse_ServingStatus)(grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING+1)) +#define _grpc_health_v1_HealthCheckResponse_ServingStatus_MAX grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN +#define _grpc_health_v1_HealthCheckResponse_ServingStatus_ARRAYSIZE ((grpc_health_v1_HealthCheckResponse_ServingStatus)(grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN+1)) /* Struct definitions */ typedef struct _grpc_health_v1_HealthCheckRequest { diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc index 46872c85a1..373a925059 100644 --- a/src/cpp/server/server_cc.cc +++ b/src/cpp/server/server_cc.cc @@ -380,7 +380,6 @@ class Server::SyncRequestThreadManager : public ThreadManager { int cq_timeout_msec_; std::vector<std::unique_ptr<SyncRequest>> sync_requests_; std::unique_ptr<internal::RpcServiceMethod> unknown_method_; - std::unique_ptr<internal::RpcServiceMethod> health_check_; std::shared_ptr<Server::GlobalCallbacks> global_callbacks_; }; @@ -473,7 +472,21 @@ std::shared_ptr<Channel> Server::InProcessChannel( const ChannelArguments& args) { grpc_channel_args channel_args = args.c_channel_args(); return CreateChannelInternal( - "inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr)); + "inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr), + nullptr); +} + +std::shared_ptr<Channel> +Server::experimental_type::InProcessChannelWithInterceptors( + const ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) { + grpc_channel_args channel_args = args.c_channel_args(); + return CreateChannelInternal( + "inproc", + grpc_inproc_channel_create(server_->server_, &channel_args, nullptr), + std::move(interceptor_creators)); } static grpc_server_register_method_payload_handling PayloadHandlingForMethod( @@ -559,16 +572,24 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) { // Only create default health check service when user did not provide an // explicit one. + ServerCompletionQueue* health_check_cq = nullptr; + DefaultHealthCheckService::HealthCheckServiceImpl* + default_health_check_service_impl = nullptr; if (health_check_service_ == nullptr && !health_check_service_disabled_ && DefaultHealthCheckServiceEnabled()) { - if (sync_server_cqs_ == nullptr || sync_server_cqs_->empty()) { - gpr_log(GPR_INFO, - "Default health check service disabled at async-only server."); - } else { - auto* default_hc_service = new DefaultHealthCheckService; - health_check_service_.reset(default_hc_service); - RegisterService(nullptr, default_hc_service->GetHealthCheckService()); - } + auto* default_hc_service = new DefaultHealthCheckService; + health_check_service_.reset(default_hc_service); + // We create a non-polling CQ to avoid impacting application + // performance. This ensures that we don't introduce thread hops + // for application requests that wind up on this CQ, which is polled + // in its own thread. + health_check_cq = new ServerCompletionQueue(GRPC_CQ_NON_POLLING); + grpc_server_register_completion_queue(server_, health_check_cq->cq(), + nullptr); + default_health_check_service_impl = + default_hc_service->GetHealthCheckService( + std::unique_ptr<ServerCompletionQueue>(health_check_cq)); + RegisterService(nullptr, default_health_check_service_impl); } grpc_server_start(server_); @@ -583,18 +604,25 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) { new UnimplementedAsyncRequest(this, cqs[i]); } } + if (health_check_cq != nullptr) { + new UnimplementedAsyncRequest(this, health_check_cq); + } } // If this server has any support for synchronous methods (has any sync // server CQs), make sure that we have a ResourceExhausted handler // to deal with the case of thread exhaustion - if (!sync_server_cqs_->empty()) { + if (sync_server_cqs_ != nullptr && !sync_server_cqs_->empty()) { resource_exhausted_handler_.reset(new internal::ResourceExhaustedHandler); } for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) { (*it)->Start(); } + + if (default_health_check_service_impl != nullptr) { + default_health_check_service_impl->StartServingThread(); + } } void Server::ShutdownInternal(gpr_timespec deadline) { @@ -657,6 +685,7 @@ void Server::PerformOpsOnCall(internal::CallOpSetInterface* ops, size_t nops = 0; grpc_op cops[MAX_OPS]; ops->FillOps(call->call(), cops, &nops); + // TODO(vjpai): Use ops->cq_tag once this case supports callbacks auto result = grpc_call_start_batch(call->call(), cops, nops, ops, nullptr); if (result != GRPC_CALL_OK) { gpr_log(GPR_ERROR, "Fatal: grpc_call_start_batch returned %d", result); @@ -686,9 +715,6 @@ ServerInterface::BaseAsyncRequest::~BaseAsyncRequest() { bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, bool* status) { - if (*status) { - context_->client_metadata_.FillMap(); - } context_->set_call(call_); context_->cq_ = call_cq_; internal::Call call(call_, server_, call_cq_, diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index 6f5bde0d9f..b7254b6bb9 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -61,6 +61,9 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface { tag_ = tag; } + /// TODO(vjpai): Allow override of cq_tag if appropriate for callback API + void* cq_tag() override { return this; } + void Unref(); private: @@ -134,7 +137,6 @@ ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata_array* arr) compression_level_set_(false), has_pending_ops_(false) { std::swap(*client_metadata_.arr(), *arr); - client_metadata_.FillMap(); } ServerContext::~ServerContext() { diff --git a/src/csharp/.editorconfig b/src/csharp/.editorconfig index fabce7f5ba..c9a2c48a7d 100644 --- a/src/csharp/.editorconfig +++ b/src/csharp/.editorconfig @@ -6,3 +6,26 @@ indent_style = space indent_size = 4 insert_final_newline = true tab_width = 4 + +; https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference +[*.cs] +dotnet_sort_system_directives_first = true +csharp_new_line_before_open_brace = accessors, anonymous_methods, control_blocks, events, indexers, local_functions, methods, properties, types +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true diff --git a/src/csharp/Grpc.Core.Tests/ChannelConnectivityTest.cs b/src/csharp/Grpc.Core.Tests/ChannelConnectivityTest.cs index a43040f01a..0834ddadda 100644 --- a/src/csharp/Grpc.Core.Tests/ChannelConnectivityTest.cs +++ b/src/csharp/Grpc.Core.Tests/ChannelConnectivityTest.cs @@ -57,19 +57,23 @@ namespace Grpc.Core.Tests [Test] public async Task Channel_WaitForStateChangedAsync() { - helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => - { - return Task.FromResult(request); - }); - Assert.ThrowsAsync(typeof(TaskCanceledException), - async () => await channel.WaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(10))); + async () => await channel.WaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(0))); var stateChangedTask = channel.WaitForStateChangedAsync(channel.State); + await channel.ConnectAsync(DateTime.UtcNow.AddMilliseconds(5000)); + await stateChangedTask; + Assert.AreEqual(ChannelState.Ready, channel.State); + } - await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"); + [Test] + public async Task Channel_TryWaitForStateChangedAsync() + { + Assert.IsFalse(await channel.TryWaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(0))); - await stateChangedTask; + var stateChangedTask = channel.TryWaitForStateChangedAsync(channel.State); + await channel.ConnectAsync(DateTime.UtcNow.AddMilliseconds(5000)); + Assert.IsTrue(await stateChangedTask); Assert.AreEqual(ChannelState.Ready, channel.State); } diff --git a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs index 62cc904a61..843d88bfb6 100644 --- a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs +++ b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs @@ -17,13 +17,7 @@ #endregion using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using Grpc.Core; using Grpc.Core.Internal; -using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests @@ -44,9 +38,38 @@ namespace Grpc.Core.Tests Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(null, new FakeCallCredentials())); Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(new FakeChannelCredentials(true), null)); - + // forbid composing non-composable Assert.Throws(typeof(ArgumentException), () => ChannelCredentials.Create(new FakeChannelCredentials(false), new FakeCallCredentials())); } + + [Test] + public void ChannelCredentials_NativeCredentialsAreReused() + { + // always returning the same native object is critical for subchannel sharing to work with secure channels + var creds = new SslCredentials(); + var nativeCreds1 = creds.GetNativeCredentials(); + var nativeCreds2 = creds.GetNativeCredentials(); + Assert.AreSame(nativeCreds1, nativeCreds2); + } + + [Test] + public void ChannelCredentials_CreateExceptionIsCached() + { + var creds = new ChannelCredentialsWithCreateNativeThrows(); + var ex1 = Assert.Throws(typeof(Exception), () => creds.GetNativeCredentials()); + var ex2 = Assert.Throws(typeof(Exception), () => creds.GetNativeCredentials()); + Assert.AreSame(ex1, ex2); + } + + internal class ChannelCredentialsWithCreateNativeThrows : ChannelCredentials + { + internal override bool IsComposable => false; + + internal override ChannelCredentialsSafeHandle CreateNativeCredentials() + { + throw new Exception("Creation of native credentials has failed on purpose."); + } + } } } diff --git a/src/csharp/Grpc.Core.Tests/ContextualMarshallerTest.cs b/src/csharp/Grpc.Core.Tests/ContextualMarshallerTest.cs new file mode 100644 index 0000000000..c3aee726f2 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/ContextualMarshallerTest.cs @@ -0,0 +1,119 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class ContextualMarshallerTest + { + const string Host = "127.0.0.1"; + + MockServiceHelper helper; + Server server; + Channel channel; + + [SetUp] + public void Init() + { + var contextualMarshaller = new Marshaller<string>( + (str, serializationContext) => + { + if (str == "UNSERIALIZABLE_VALUE") + { + // Google.Protobuf throws exception inherited from IOException + throw new IOException("Error serializing the message."); + } + if (str == "SERIALIZE_TO_NULL") + { + return; + } + var bytes = System.Text.Encoding.UTF8.GetBytes(str); + serializationContext.Complete(bytes); + }, + (deserializationContext) => + { + var buffer = deserializationContext.PayloadAsNewBuffer(); + Assert.AreEqual(buffer.Length, deserializationContext.PayloadLength); + var s = System.Text.Encoding.UTF8.GetString(buffer); + if (s == "UNPARSEABLE_VALUE") + { + // Google.Protobuf throws exception inherited from IOException + throw new IOException("Error parsing the message."); + } + return s; + }); + helper = new MockServiceHelper(Host, contextualMarshaller); + server = helper.GetServer(); + server.Start(); + channel = helper.GetChannel(); + } + + [TearDown] + public void Cleanup() + { + channel.ShutdownAsync().Wait(); + server.ShutdownAsync().Wait(); + } + + [Test] + public void UnaryCall() + { + helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => + { + return Task.FromResult(request); + }); + Assert.AreEqual("ABC", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC")); + } + + [Test] + public void ResponseParsingError_UnaryResponse() + { + helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => + { + return Task.FromResult("UNPARSEABLE_VALUE"); + }); + + var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "REQUEST")); + Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); + } + + [Test] + public void RequestSerializationError_BlockingUnary() + { + Assert.Throws<IOException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE")); + } + + [Test] + public void SerializationResultIsNull_BlockingUnary() + { + Assert.Throws<NullReferenceException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "SERIALIZE_TO_NULL")); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs index 7d658576e5..f23c9e9757 100644 --- a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs +++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs @@ -16,15 +16,7 @@ #endregion -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using Grpc.Core; using Grpc.Core.Internal; -using Grpc.Core.Utils; -using NUnit.Framework; namespace Grpc.Core.Tests { @@ -42,7 +34,7 @@ namespace Grpc.Core.Tests get { return composable; } } - internal override ChannelCredentialsSafeHandle ToNativeCredentials() + internal override ChannelCredentialsSafeHandle CreateNativeCredentials() { return null; } diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs index 9aab54d2d0..775849d89b 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs @@ -107,6 +107,42 @@ namespace Grpc.Core.Internal.Tests } [Test] + public void AsyncUnary_RequestSerializationExceptionDoesntLeakResources() + { + string nullRequest = null; // will throw when serializing + Assert.Throws(typeof(ArgumentNullException), () => asyncCall.UnaryCallAsync(nullRequest)); + Assert.AreEqual(0, channel.GetCallReferenceCount()); + Assert.IsTrue(fakeCall.IsDisposed); + } + + [Test] + public void AsyncUnary_StartCallFailureDoesntLeakResources() + { + fakeCall.MakeStartCallFail(); + Assert.Throws(typeof(InvalidOperationException), () => asyncCall.UnaryCallAsync("request1")); + Assert.AreEqual(0, channel.GetCallReferenceCount()); + Assert.IsTrue(fakeCall.IsDisposed); + } + + [Test] + public void SyncUnary_RequestSerializationExceptionDoesntLeakResources() + { + string nullRequest = null; // will throw when serializing + Assert.Throws(typeof(ArgumentNullException), () => asyncCall.UnaryCall(nullRequest)); + Assert.AreEqual(0, channel.GetCallReferenceCount()); + Assert.IsTrue(fakeCall.IsDisposed); + } + + [Test] + public void SyncUnary_StartCallFailureDoesntLeakResources() + { + fakeCall.MakeStartCallFail(); + Assert.Throws(typeof(InvalidOperationException), () => asyncCall.UnaryCall("request1")); + Assert.AreEqual(0, channel.GetCallReferenceCount()); + Assert.IsTrue(fakeCall.IsDisposed); + } + + [Test] public void ClientStreaming_StreamingReadNotAllowed() { asyncCall.ClientStreamingCallAsync(); @@ -328,6 +364,15 @@ namespace Grpc.Core.Internal.Tests } [Test] + public void ClientStreaming_StartCallFailureDoesntLeakResources() + { + fakeCall.MakeStartCallFail(); + Assert.Throws(typeof(InvalidOperationException), () => asyncCall.ClientStreamingCallAsync()); + Assert.AreEqual(0, channel.GetCallReferenceCount()); + Assert.IsTrue(fakeCall.IsDisposed); + } + + [Test] public void ServerStreaming_StreamingSendNotAllowed() { asyncCall.StartServerStreamingCall("request1"); @@ -402,6 +447,27 @@ namespace Grpc.Core.Internal.Tests } [Test] + public void ServerStreaming_RequestSerializationExceptionDoesntLeakResources() + { + string nullRequest = null; // will throw when serializing + Assert.Throws(typeof(ArgumentNullException), () => asyncCall.StartServerStreamingCall(nullRequest)); + Assert.AreEqual(0, channel.GetCallReferenceCount()); + Assert.IsTrue(fakeCall.IsDisposed); + + var responseStream = new ClientResponseStream<string, string>(asyncCall); + var readTask = responseStream.MoveNext(); + } + + [Test] + public void ServerStreaming_StartCallFailureDoesntLeakResources() + { + fakeCall.MakeStartCallFail(); + Assert.Throws(typeof(InvalidOperationException), () => asyncCall.StartServerStreamingCall("request1")); + Assert.AreEqual(0, channel.GetCallReferenceCount()); + Assert.IsTrue(fakeCall.IsDisposed); + } + + [Test] public void DuplexStreaming_NoRequestNoResponse_Success() { asyncCall.StartDuplexStreamingCall(); @@ -558,6 +624,15 @@ namespace Grpc.Core.Internal.Tests AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled); } + [Test] + public void DuplexStreaming_StartCallFailureDoesntLeakResources() + { + fakeCall.MakeStartCallFail(); + Assert.Throws(typeof(InvalidOperationException), () => asyncCall.StartDuplexStreamingCall()); + Assert.AreEqual(0, channel.GetCallReferenceCount()); + Assert.IsTrue(fakeCall.IsDisposed); + } + ClientSideStatus CreateClientSideStatus(StatusCode statusCode) { return new ClientSideStatus(new Status(statusCode, ""), new Metadata()); diff --git a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs index 581ac3384b..ef67918dab 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs @@ -31,6 +31,7 @@ namespace Grpc.Core.Internal.Tests /// </summary> internal class FakeNativeCall : INativeCall { + private bool shouldStartCallFail; public IUnaryResponseClientCallback UnaryResponseClientCallback { get; @@ -102,26 +103,31 @@ namespace Grpc.Core.Internal.Tests public void StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags) { + StartCallMaybeFail(); UnaryResponseClientCallback = callback; } public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags) { + StartCallMaybeFail(); throw new NotImplementedException(); } public void StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags) { + StartCallMaybeFail(); UnaryResponseClientCallback = callback; } public void StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags) { + StartCallMaybeFail(); ReceivedStatusOnClientCallback = callback; } public void StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags) { + StartCallMaybeFail(); ReceivedStatusOnClientCallback = callback; } @@ -165,5 +171,22 @@ namespace Grpc.Core.Internal.Tests { IsDisposed = true; } + + /// <summary> + /// Emulate CallSafeHandle.CheckOk() failure for all future attempts + /// to start a call. + /// </summary> + public void MakeStartCallFail() + { + shouldStartCallFail = true; + } + + private void StartCallMaybeFail() + { + if (shouldStartCallFail) + { + throw new InvalidOperationException("Start call has failed."); + } + } } } diff --git a/src/csharp/Grpc.Core.Tests/MarshallerTest.cs b/src/csharp/Grpc.Core.Tests/MarshallerTest.cs new file mode 100644 index 0000000000..97f64a0575 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/MarshallerTest.cs @@ -0,0 +1,105 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class MarshallerTest + { + [Test] + public void ContextualSerializerEmulation() + { + Func<string, byte[]> simpleSerializer = System.Text.Encoding.UTF8.GetBytes; + Func<byte[], string> simpleDeserializer = System.Text.Encoding.UTF8.GetString; + var marshaller = new Marshaller<string>(simpleSerializer, + simpleDeserializer); + + Assert.AreSame(simpleSerializer, marshaller.Serializer); + Assert.AreSame(simpleDeserializer, marshaller.Deserializer); + + // test that emulated contextual serializer and deserializer work + string origMsg = "abc"; + var serializationContext = new FakeSerializationContext(); + marshaller.ContextualSerializer(origMsg, serializationContext); + + var deserializationContext = new FakeDeserializationContext(serializationContext.Payload); + Assert.AreEqual(origMsg, marshaller.ContextualDeserializer(deserializationContext)); + } + + [Test] + public void SimpleSerializerEmulation() + { + Action<string, SerializationContext> contextualSerializer = (str, context) => + { + var bytes = System.Text.Encoding.UTF8.GetBytes(str); + context.Complete(bytes); + }; + Func<DeserializationContext, string> contextualDeserializer = (context) => + { + return System.Text.Encoding.UTF8.GetString(context.PayloadAsNewBuffer()); + }; + var marshaller = new Marshaller<string>(contextualSerializer, contextualDeserializer); + + Assert.AreSame(contextualSerializer, marshaller.ContextualSerializer); + Assert.AreSame(contextualDeserializer, marshaller.ContextualDeserializer); + + // test that emulated serializer and deserializer work + var origMsg = "abc"; + var serialized = marshaller.Serializer(origMsg); + Assert.AreEqual(origMsg, marshaller.Deserializer(serialized)); + } + + class FakeSerializationContext : SerializationContext + { + public byte[] Payload; + public override void Complete(byte[] payload) + { + this.Payload = payload; + } + } + + class FakeDeserializationContext : DeserializationContext + { + public byte[] payload; + + public FakeDeserializationContext(byte[] payload) + { + this.payload = payload; + } + + public override int PayloadLength => payload.Length; + + public override byte[] PayloadAsNewBuffer() + { + return payload; + } + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/MetadataTest.cs b/src/csharp/Grpc.Core.Tests/MetadataTest.cs index 8916731757..d85d7572a6 100644 --- a/src/csharp/Grpc.Core.Tests/MetadataTest.cs +++ b/src/csharp/Grpc.Core.Tests/MetadataTest.cs @@ -66,11 +66,30 @@ namespace Grpc.Core.Tests new Metadata.Entry("0123456789abc", "XYZ"); new Metadata.Entry("-abc", "XYZ"); new Metadata.Entry("a_bc_", "XYZ"); + new Metadata.Entry("abc.xyz", "XYZ"); + new Metadata.Entry("abc.xyz-bin", new byte[] {1, 2, 3}); Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc[", "xyz")); Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc/", "xyz")); } [Test] + public void KeysAreNormalized_UppercaseKey() + { + var uppercaseKey = "ABC"; + var entry = new Metadata.Entry(uppercaseKey, "XYZ"); + Assert.AreEqual("abc", entry.Key); + } + + [Test] + public void KeysAreNormalized_LowercaseKey() + { + var lowercaseKey = "abc"; + var entry = new Metadata.Entry(lowercaseKey, "XYZ"); + // no allocation if key already lowercase + Assert.AreSame(lowercaseKey, entry.Key); + } + + [Test] public void Entry_ConstructionPreconditions() { Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry(null, "xyz")); diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs index eaad409ec0..0904453b6e 100644 --- a/src/csharp/Grpc.Core.Tests/SanityTest.cs +++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs @@ -102,6 +102,7 @@ namespace Grpc.Core.Tests "Grpc.HealthCheck.Tests", "Grpc.IntegrationTesting", "Grpc.Reflection.Tests", + "Grpc.Tools.Tests", }; foreach (var assemblyName in otherAssemblies) { diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index e9930b6fbc..7ce929dfa3 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -72,9 +72,9 @@ namespace Grpc.Core this.environment = GrpcEnvironment.AddRef(); this.completionQueue = this.environment.PickCompletionQueue(); - using (var nativeCredentials = credentials.ToNativeCredentials()) using (var nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options.Values)) { + var nativeCredentials = credentials.GetNativeCredentials(); if (nativeCredentials != null) { this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, target, nativeChannelArgs); @@ -136,7 +136,7 @@ namespace Grpc.Core /// </summary> public async Task WaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null) { - var result = await WaitForStateChangedInternalAsync(lastObservedState, deadline).ConfigureAwait(false); + var result = await TryWaitForStateChangedAsync(lastObservedState, deadline).ConfigureAwait(false); if (!result) { throw new TaskCanceledException("Reached deadline."); @@ -147,7 +147,7 @@ namespace Grpc.Core /// Returned tasks completes once channel state has become different from /// given lastObservedState (<c>true</c> is returned) or if the wait has timed out (<c>false</c> is returned). /// </summary> - internal Task<bool> WaitForStateChangedInternalAsync(ChannelState lastObservedState, DateTime? deadline = null) + public Task<bool> TryWaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null) { GrpcPreconditions.CheckArgument(lastObservedState != ChannelState.Shutdown, "Shutdown is a terminal state. No further state changes can occur."); @@ -297,6 +297,12 @@ namespace Grpc.Core activeCallCounter.Decrement(); } + // for testing only + internal long GetCallReferenceCount() + { + return activeCallCounter.Count; + } + private ChannelState GetConnectivityState(bool tryToConnect) { try diff --git a/src/csharp/Grpc.Core/ChannelCredentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs index ba482897d7..3ce32f31b7 100644 --- a/src/csharp/Grpc.Core/ChannelCredentials.cs +++ b/src/csharp/Grpc.Core/ChannelCredentials.cs @@ -31,6 +31,19 @@ namespace Grpc.Core public abstract class ChannelCredentials { static readonly ChannelCredentials InsecureInstance = new InsecureCredentialsImpl(); + readonly Lazy<ChannelCredentialsSafeHandle> cachedNativeCredentials; + + /// <summary> + /// Creates a new instance of channel credentials + /// </summary> + public ChannelCredentials() + { + // Native credentials object need to be kept alive once initialized for subchannel sharing to work correctly + // with secure connections. See https://github.com/grpc/grpc/issues/15207. + // We rely on finalizer to clean up the native portion of ChannelCredentialsSafeHandle after the ChannelCredentials + // instance becomes unused. + this.cachedNativeCredentials = new Lazy<ChannelCredentialsSafeHandle>(() => CreateNativeCredentials()); + } /// <summary> /// Returns instance of credentials that provides no security and @@ -57,11 +70,22 @@ namespace Grpc.Core } /// <summary> - /// Creates native object for the credentials. May return null if insecure channel - /// should be created. + /// Gets native object for the credentials, creating one if it already doesn't exist. May return null if insecure channel + /// should be created. Caller must not call <c>Dispose()</c> on the returned native credentials as their lifetime + /// is managed by this class (and instances of native credentials are cached). + /// </summary> + /// <returns>The native credentials.</returns> + internal ChannelCredentialsSafeHandle GetNativeCredentials() + { + return cachedNativeCredentials.Value; + } + + /// <summary> + /// Creates a new native object for the credentials. May return null if insecure channel + /// should be created. For internal use only, use <see cref="GetNativeCredentials"/> instead. /// </summary> /// <returns>The native credentials.</returns> - internal abstract ChannelCredentialsSafeHandle ToNativeCredentials(); + internal abstract ChannelCredentialsSafeHandle CreateNativeCredentials(); /// <summary> /// Returns <c>true</c> if this credential type allows being composed by <c>CompositeCredentials</c>. @@ -73,7 +97,7 @@ namespace Grpc.Core private sealed class InsecureCredentialsImpl : ChannelCredentials { - internal override ChannelCredentialsSafeHandle ToNativeCredentials() + internal override ChannelCredentialsSafeHandle CreateNativeCredentials() { return null; } @@ -145,7 +169,7 @@ namespace Grpc.Core get { return true; } } - internal override ChannelCredentialsSafeHandle ToNativeCredentials() + internal override ChannelCredentialsSafeHandle CreateNativeCredentials() { return ChannelCredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair); } @@ -173,12 +197,11 @@ namespace Grpc.Core GrpcPreconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition."); } - internal override ChannelCredentialsSafeHandle ToNativeCredentials() + internal override ChannelCredentialsSafeHandle CreateNativeCredentials() { - using (var channelCreds = channelCredentials.ToNativeCredentials()) using (var callCreds = callCredentials.ToNativeCredentials()) { - var nativeComposite = ChannelCredentialsSafeHandle.CreateComposite(channelCreds, callCreds); + var nativeComposite = ChannelCredentialsSafeHandle.CreateComposite(channelCredentials.GetNativeCredentials(), callCreds); if (nativeComposite.IsInvalid) { throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials."); 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/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs index fac34071be..05edce7467 100644 --- a/src/csharp/Grpc.Core/ClientBase.cs +++ b/src/csharp/Grpc.Core/ClientBase.cs @@ -151,12 +151,12 @@ namespace Grpc.Core { private class ClientBaseConfigurationInterceptor : Interceptor { - readonly Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor; + readonly Func<IMethod, string, CallOptions, ClientBaseConfigurationInfo> interceptor; /// <summary> /// Creates a new instance of ClientBaseConfigurationInterceptor given the specified header and host interceptor function. /// </summary> - public ClientBaseConfigurationInterceptor(Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor) + public ClientBaseConfigurationInterceptor(Func<IMethod, string, CallOptions, ClientBaseConfigurationInfo> interceptor) { this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor)); } @@ -166,7 +166,7 @@ namespace Grpc.Core where TResponse : class { var newHostAndCallOptions = interceptor(context.Method, context.Host, context.Options); - return new ClientInterceptorContext<TRequest, TResponse>(context.Method, newHostAndCallOptions.Item1, newHostAndCallOptions.Item2); + return new ClientInterceptorContext<TRequest, TResponse>(context.Method, newHostAndCallOptions.Host, newHostAndCallOptions.CallOptions); } public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation) @@ -195,6 +195,18 @@ namespace Grpc.Core } } + internal struct ClientBaseConfigurationInfo + { + internal readonly string Host; + internal readonly CallOptions CallOptions; + + internal ClientBaseConfigurationInfo(string host, CallOptions callOptions) + { + Host = host; + CallOptions = callOptions; + } + } + readonly CallInvoker undecoratedCallInvoker; readonly string host; @@ -206,7 +218,7 @@ namespace Grpc.Core internal CallInvoker CreateDecoratedCallInvoker() { - return undecoratedCallInvoker.Intercept(new ClientBaseConfigurationInterceptor((method, host, options) => Tuple.Create(this.host, options))); + return undecoratedCallInvoker.Intercept(new ClientBaseConfigurationInterceptor((method, host, options) => new ClientBaseConfigurationInfo(this.host, options))); } internal ClientBaseConfiguration WithHost(string host) diff --git a/src/csharp/Grpc.Core/DeserializationContext.cs b/src/csharp/Grpc.Core/DeserializationContext.cs new file mode 100644 index 0000000000..5b6372ef85 --- /dev/null +++ b/src/csharp/Grpc.Core/DeserializationContext.cs @@ -0,0 +1,46 @@ +#region Copyright notice and license + +// 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. + +#endregion + +namespace Grpc.Core +{ + /// <summary> + /// Provides access to the payload being deserialized when deserializing messages. + /// </summary> + public abstract class DeserializationContext + { + /// <summary> + /// Get the total length of the payload in bytes. + /// </summary> + public abstract int PayloadLength { get; } + + /// <summary> + /// Gets the entire payload as a newly allocated byte array. + /// Once the byte array is returned, the byte array becomes owned by the caller and won't be ever accessed or reused by gRPC again. + /// NOTE: Obtaining the buffer as a newly allocated byte array is the simplest way of accessing the payload, + /// but it can have important consequences in high-performance scenarios. + /// In particular, using this method usually requires copying of the entire buffer one extra time. + /// Also, allocating a new buffer each time can put excessive pressure on GC, especially if + /// the payload is more than 86700 bytes large (which means the newly allocated buffer will be placed in LOH, + /// and LOH object can only be garbage collected via a full ("stop the world") GC run). + /// NOTE: Deserializers are expected not to call this method more than once per received message + /// (as there is no practical reason for doing so) and <c>DeserializationContext</c> implementations are free to assume so. + /// </summary> + /// <returns>byte array containing the entire payload.</returns> + public abstract byte[] PayloadAsNewBuffer(); + } +} diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 9946d1a6cf..4cdf0ee6a7 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -17,6 +17,7 @@ #endregion using System; +using System.Threading; using System.Threading.Tasks; using Grpc.Core.Logging; using Grpc.Core.Profiling; @@ -34,6 +35,8 @@ namespace Grpc.Core.Internal readonly CallInvocationDetails<TRequest, TResponse> details; readonly INativeCall injectedNativeCall; // for testing + bool registeredWithChannel; + // Dispose of to de-register cancellation token registration IDisposable cancellationTokenRegistration; @@ -77,43 +80,59 @@ namespace Grpc.Core.Internal using (profiler.NewScope("AsyncCall.UnaryCall")) using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.CreateSync()) { - byte[] payload = UnsafeSerialize(msg); + bool callStartedOk = false; + try + { + unaryResponseTcs = new TaskCompletionSource<TResponse>(); - unaryResponseTcs = new TaskCompletionSource<TResponse>(); + lock (myLock) + { + GrpcPreconditions.CheckState(!started); + started = true; + Initialize(cq); - lock (myLock) - { - GrpcPreconditions.CheckState(!started); - started = true; - Initialize(cq); + halfcloseRequested = true; + readingDone = true; + } - halfcloseRequested = true; - readingDone = true; - } + byte[] payload = UnsafeSerialize(msg); - using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) - { - var ctx = details.Channel.Environment.BatchContextPool.Lease(); - try + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { - call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); - var ev = cq.Pluck(ctx.Handle); - bool success = (ev.success != 0); + var ctx = details.Channel.Environment.BatchContextPool.Lease(); try { - using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch")) + call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); + callStartedOk = true; + + var ev = cq.Pluck(ctx.Handle); + bool success = (ev.success != 0); + try { - HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata()); + using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch")) + { + HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata()); + } + } + catch (Exception e) + { + Logger.Error(e, "Exception occurred while invoking completion delegate."); } } - catch (Exception e) + finally { - Logger.Error(e, "Exception occured while invoking completion delegate."); + ctx.Recycle(); } } - finally + } + finally + { + if (!callStartedOk) { - ctx.Recycle(); + lock (myLock) + { + OnFailedToStartCallLocked(); + } } } @@ -130,22 +149,35 @@ namespace Grpc.Core.Internal { lock (myLock) { - GrpcPreconditions.CheckState(!started); - started = true; + bool callStartedOk = false; + try + { + GrpcPreconditions.CheckState(!started); + started = true; - Initialize(details.Channel.CompletionQueue); + Initialize(details.Channel.CompletionQueue); - halfcloseRequested = true; - readingDone = true; + halfcloseRequested = true; + readingDone = true; - byte[] payload = UnsafeSerialize(msg); + byte[] payload = UnsafeSerialize(msg); - unaryResponseTcs = new TaskCompletionSource<TResponse>(); - using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) + unaryResponseTcs = new TaskCompletionSource<TResponse>(); + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) + { + call.StartUnary(UnaryResponseClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); + callStartedOk = true; + } + + return unaryResponseTcs.Task; + } + finally { - call.StartUnary(UnaryResponseClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); + if (!callStartedOk) + { + OnFailedToStartCallLocked(); + } } - return unaryResponseTcs.Task; } } @@ -157,20 +189,32 @@ namespace Grpc.Core.Internal { lock (myLock) { - GrpcPreconditions.CheckState(!started); - started = true; + bool callStartedOk = false; + try + { + GrpcPreconditions.CheckState(!started); + started = true; - Initialize(details.Channel.CompletionQueue); + Initialize(details.Channel.CompletionQueue); - readingDone = true; + readingDone = true; + + unaryResponseTcs = new TaskCompletionSource<TResponse>(); + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) + { + call.StartClientStreaming(UnaryResponseClientCallback, metadataArray, details.Options.Flags); + callStartedOk = true; + } - unaryResponseTcs = new TaskCompletionSource<TResponse>(); - using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) + return unaryResponseTcs.Task; + } + finally { - call.StartClientStreaming(UnaryResponseClientCallback, metadataArray, details.Options.Flags); + if (!callStartedOk) + { + OnFailedToStartCallLocked(); + } } - - return unaryResponseTcs.Task; } } @@ -181,21 +225,33 @@ namespace Grpc.Core.Internal { lock (myLock) { - GrpcPreconditions.CheckState(!started); - started = true; + bool callStartedOk = false; + try + { + GrpcPreconditions.CheckState(!started); + started = true; - Initialize(details.Channel.CompletionQueue); + Initialize(details.Channel.CompletionQueue); - halfcloseRequested = true; + halfcloseRequested = true; - byte[] payload = UnsafeSerialize(msg); + byte[] payload = UnsafeSerialize(msg); - streamingResponseCallFinishedTcs = new TaskCompletionSource<object>(); - using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) + streamingResponseCallFinishedTcs = new TaskCompletionSource<object>(); + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) + { + call.StartServerStreaming(ReceivedStatusOnClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); + callStartedOk = true; + } + call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback); + } + finally { - call.StartServerStreaming(ReceivedStatusOnClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags); + if (!callStartedOk) + { + OnFailedToStartCallLocked(); + } } - call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback); } } @@ -207,17 +263,29 @@ namespace Grpc.Core.Internal { lock (myLock) { - GrpcPreconditions.CheckState(!started); - started = true; + bool callStartedOk = false; + try + { + GrpcPreconditions.CheckState(!started); + started = true; - Initialize(details.Channel.CompletionQueue); + Initialize(details.Channel.CompletionQueue); - streamingResponseCallFinishedTcs = new TaskCompletionSource<object>(); - using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) + streamingResponseCallFinishedTcs = new TaskCompletionSource<object>(); + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) + { + call.StartDuplexStreaming(ReceivedStatusOnClientCallback, metadataArray, details.Options.Flags); + callStartedOk = true; + } + call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback); + } + finally { - call.StartDuplexStreaming(ReceivedStatusOnClientCallback, metadataArray, details.Options.Flags); + if (!callStartedOk) + { + OnFailedToStartCallLocked(); + } } - call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback); } } @@ -325,9 +393,22 @@ namespace Grpc.Core.Internal } } - protected override void OnAfterReleaseResources() + protected override void OnAfterReleaseResourcesLocked() { - details.Channel.RemoveCallReference(this); + if (registeredWithChannel) + { + details.Channel.RemoveCallReference(this); + registeredWithChannel = false; + } + } + + protected override void OnAfterReleaseResourcesUnlocked() + { + // If cancellation callback is in progress, this can block + // so we need to do this outside of call's lock to prevent + // deadlock. + // See https://github.com/grpc/grpc/issues/14777 + // See https://github.com/dotnet/corefx/issues/14903 cancellationTokenRegistration?.Dispose(); } @@ -385,10 +466,27 @@ namespace Grpc.Core.Internal var call = CreateNativeCall(cq); details.Channel.AddCallReference(this); + registeredWithChannel = true; InitializeInternal(call); + RegisterCancellationCallback(); } + private void OnFailedToStartCallLocked() + { + ReleaseResources(); + + // We need to execute the hook that disposes the cancellation token + // registration, but it cannot be done from under a lock. + // To make things simple, we just schedule the unregistering + // on a threadpool. + // - Once the native call is disposed, the Cancel() calls are ignored anyway + // - We don't care about the overhead as OnFailedToStartCallLocked() only happens + // when something goes very bad when initializing a call and that should + // never happen when gRPC is used correctly. + ThreadPool.QueueUserWorkItem((state) => OnAfterReleaseResourcesUnlocked()); + } + private INativeCall CreateNativeCall(CompletionQueueSafeHandle cq) { if (injectedNativeCall != null) @@ -448,6 +546,7 @@ namespace Grpc.Core.Internal TResponse msg = default(TResponse); var deserializeException = TryDeserialize(receivedMessage, out msg); + bool releasedResources; lock (myLock) { finished = true; @@ -464,7 +563,12 @@ namespace Grpc.Core.Internal streamingWriteTcs = null; } - ReleaseResourcesIfPossible(); + releasedResources = ReleaseResourcesIfPossible(); + } + + if (releasedResources) + { + OnAfterReleaseResourcesUnlocked(); } responseHeadersTcs.SetResult(responseHeaders); @@ -494,6 +598,7 @@ namespace Grpc.Core.Internal TaskCompletionSource<object> delayedStreamingWriteTcs = null; + bool releasedResources; lock (myLock) { finished = true; @@ -504,7 +609,12 @@ namespace Grpc.Core.Internal streamingWriteTcs = null; } - ReleaseResourcesIfPossible(); + releasedResources = ReleaseResourcesIfPossible(); + } + + if (releasedResources) + { + OnAfterReleaseResourcesUnlocked(); } if (delayedStreamingWriteTcs != null) diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 3273c26b88..a93dc34620 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -189,17 +189,21 @@ namespace Grpc.Core.Internal /// </summary> protected abstract Exception GetRpcExceptionClientOnly(); - private void ReleaseResources() + protected void ReleaseResources() { if (call != null) { call.Dispose(); } disposed = true; - OnAfterReleaseResources(); + OnAfterReleaseResourcesLocked(); } - protected virtual void OnAfterReleaseResources() + protected virtual void OnAfterReleaseResourcesLocked() + { + } + + protected virtual void OnAfterReleaseResourcesUnlocked() { } @@ -235,6 +239,7 @@ namespace Grpc.Core.Internal { bool delayCompletion = false; TaskCompletionSource<object> origTcs = null; + bool releasedResources; lock (myLock) { if (!success && !finished && IsClient) { @@ -252,7 +257,12 @@ namespace Grpc.Core.Internal streamingWriteTcs = null; } - ReleaseResourcesIfPossible(); + releasedResources = ReleaseResourcesIfPossible(); + } + + if (releasedResources) + { + OnAfterReleaseResourcesUnlocked(); } if (!success) @@ -282,9 +292,15 @@ namespace Grpc.Core.Internal /// </summary> protected void HandleSendStatusFromServerFinished(bool success) { + bool releasedResources; lock (myLock) { - ReleaseResourcesIfPossible(); + releasedResources = ReleaseResourcesIfPossible(); + } + + if (releasedResources) + { + OnAfterReleaseResourcesUnlocked(); } if (!success) @@ -310,6 +326,7 @@ namespace Grpc.Core.Internal var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null; TaskCompletionSource<TRead> origTcs = null; + bool releasedResources; lock (myLock) { origTcs = streamingReadTcs; @@ -332,7 +349,12 @@ namespace Grpc.Core.Internal streamingReadTcs = null; } - ReleaseResourcesIfPossible(); + releasedResources = ReleaseResourcesIfPossible(); + } + + if (releasedResources) + { + OnAfterReleaseResourcesUnlocked(); } if (deserializeException != null && !IsClient) diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index 11acb27533..0ceca4abb8 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -184,7 +184,7 @@ namespace Grpc.Core.Internal throw new InvalidOperationException("Call be only called for client calls"); } - protected override void OnAfterReleaseResources() + protected override void OnAfterReleaseResourcesLocked() { server.RemoveCallReference(this); } @@ -206,6 +206,7 @@ namespace Grpc.Core.Internal { // NOTE: because this event is a result of batch containing GRPC_OP_RECV_CLOSE_ON_SERVER, // success will be always set to true. + bool releasedResources; lock (myLock) { finished = true; @@ -217,7 +218,12 @@ namespace Grpc.Core.Internal streamingReadTcs = new TaskCompletionSource<TRequest>(); streamingReadTcs.SetResult(default(TRequest)); } - ReleaseResourcesIfPossible(); + releasedResources = ReleaseResourcesIfPossible(); + } + + if (releasedResources) + { + OnAfterReleaseResourcesUnlocked(); } if (cancelled) diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs index 53a859d18f..085e7faf59 100644 --- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs @@ -144,7 +144,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Logger.Error(e, "Exception occured while invoking batch completion delegate."); + Logger.Error(e, "Exception occurred while invoking batch completion delegate."); } finally { diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs index 8ddda9be5c..622cfde9e7 100644 --- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs +++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs @@ -189,7 +189,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Logger.Error(e, "Exception occured while extracting event from completion registry."); + Logger.Error(e, "Exception occurred while extracting event from completion registry."); } } } @@ -233,7 +233,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Logger.Error(e, "Exception occured while invoking completion delegate"); + Logger.Error(e, "Exception occurred while invoking completion delegate"); } finally { diff --git a/src/csharp/Grpc.Core/Internal/MarshalUtils.cs b/src/csharp/Grpc.Core/Internal/MarshalUtils.cs index 3f9605bfdd..09ded1a036 100644 --- a/src/csharp/Grpc.Core/Internal/MarshalUtils.cs +++ b/src/csharp/Grpc.Core/Internal/MarshalUtils.cs @@ -35,6 +35,13 @@ namespace Grpc.Core.Internal /// </summary> public static string PtrToStringUTF8(IntPtr ptr, int len) { + if (len == 0) + { + return ""; + } + + // TODO(jtattermusch): once Span dependency is added, + // use Span-based API to decode the string without copying the buffer. var bytes = new byte[len]; Marshal.Copy(ptr, bytes, 0, len); return EncodingUTF8.GetString(bytes); diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs index 4d695e8850..faeb51e6f7 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs @@ -68,8 +68,8 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionStatusMsg); - Logger.Error(e, GetMetadataExceptionLogMsg); + // eat the exception, we must not throw when inside callback from native code. + Logger.Error(e, "Exception occurred while invoking native metadata interceptor handler."); } } @@ -87,7 +87,8 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionStatusMsg); + string detail = GetMetadataExceptionStatusMsg + " " + e.ToString(); + Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, detail); Logger.Error(e, GetMetadataExceptionLogMsg); } } 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/RequestCallContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs index ebc2d6d8d6..24fde75e5a 100644 --- a/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs @@ -112,7 +112,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Logger.Error(e, "Exception occured while invoking request call completion delegate."); + Logger.Error(e, "Exception occurred while invoking request call completion delegate."); } finally { 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/Internal/UnmanagedLibrary.cs b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs index 7185d68efe..1786fc2e3f 100644 --- a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs +++ b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs @@ -51,11 +51,12 @@ namespace Grpc.Core.Internal Logger.Debug("Attempting to load native library \"{0}\"", this.libraryPath); - this.handle = PlatformSpecificLoadLibrary(this.libraryPath); + this.handle = PlatformSpecificLoadLibrary(this.libraryPath, out string loadLibraryErrorDetail); if (this.handle == IntPtr.Zero) { - throw new IOException(string.Format("Error loading native library \"{0}\"", this.libraryPath)); + throw new IOException(string.Format("Error loading native library \"{0}\". {1}", + this.libraryPath, loadLibraryErrorDetail)); } } @@ -129,31 +130,44 @@ namespace Grpc.Core.Internal /// <summary> /// Loads library in a platform specific way. /// </summary> - private static IntPtr PlatformSpecificLoadLibrary(string libraryPath) + private static IntPtr PlatformSpecificLoadLibrary(string libraryPath, out string errorMsg) { if (PlatformApis.IsWindows) { + // TODO(jtattermusch): populate the error on Windows + errorMsg = null; return Windows.LoadLibrary(libraryPath); } if (PlatformApis.IsLinux) { if (PlatformApis.IsMono) { - return Mono.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + return LoadLibraryPosix(Mono.dlopen, Mono.dlerror, libraryPath, out errorMsg); } if (PlatformApis.IsNetCore) { - return CoreCLR.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + return LoadLibraryPosix(CoreCLR.dlopen, CoreCLR.dlerror, libraryPath, out errorMsg); } - return Linux.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + return LoadLibraryPosix(Linux.dlopen, Linux.dlerror, libraryPath, out errorMsg); } if (PlatformApis.IsMacOSX) { - return MacOSX.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + return LoadLibraryPosix(MacOSX.dlopen, MacOSX.dlerror, libraryPath, out errorMsg); } throw new InvalidOperationException("Unsupported platform."); } + private static IntPtr LoadLibraryPosix(Func<string, int, IntPtr> dlopenFunc, Func<IntPtr> dlerrorFunc, string libraryPath, out string errorMsg) + { + errorMsg = null; + IntPtr ret = dlopenFunc(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + if (ret == IntPtr.Zero) + { + errorMsg = Marshal.PtrToStringAnsi(dlerrorFunc()); + } + return ret; + } + private static string FirstValidLibraryPath(string[] libraryPathAlternatives) { GrpcPreconditions.CheckArgument(libraryPathAlternatives.Length > 0, "libraryPathAlternatives cannot be empty."); @@ -184,6 +198,9 @@ namespace Grpc.Core.Internal internal static extern IntPtr dlopen(string filename, int flags); [DllImport("libdl.so")] + internal static extern IntPtr dlerror(); + + [DllImport("libdl.so")] internal static extern IntPtr dlsym(IntPtr handle, string symbol); } @@ -193,6 +210,9 @@ namespace Grpc.Core.Internal internal static extern IntPtr dlopen(string filename, int flags); [DllImport("libSystem.dylib")] + internal static extern IntPtr dlerror(); + + [DllImport("libSystem.dylib")] internal static extern IntPtr dlsym(IntPtr handle, string symbol); } @@ -209,6 +229,9 @@ namespace Grpc.Core.Internal internal static extern IntPtr dlopen(string filename, int flags); [DllImport("__Internal")] + internal static extern IntPtr dlerror(); + + [DllImport("__Internal")] internal static extern IntPtr dlsym(IntPtr handle, string symbol); } @@ -223,6 +246,9 @@ namespace Grpc.Core.Internal internal static extern IntPtr dlopen(string filename, int flags); [DllImport("libcoreclr.so")] + internal static extern IntPtr dlerror(); + + [DllImport("libcoreclr.so")] internal static extern IntPtr dlsym(IntPtr handle, string symbol); } } diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs index 1d758ca935..0af9aa586b 100644 --- a/src/csharp/Grpc.Core/Marshaller.cs +++ b/src/csharp/Grpc.Core/Marshaller.cs @@ -29,36 +29,129 @@ namespace Grpc.Core readonly Func<T, byte[]> serializer; readonly Func<byte[], T> deserializer; + readonly Action<T, SerializationContext> contextualSerializer; + readonly Func<DeserializationContext, T> contextualDeserializer; + /// <summary> - /// Initializes a new marshaller. + /// Initializes a new marshaller from simple serialize/deserialize functions. /// </summary> /// <param name="serializer">Function that will be used to serialize messages.</param> /// <param name="deserializer">Function that will be used to deserialize messages.</param> public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer) { - this.serializer = GrpcPreconditions.CheckNotNull(serializer, "serializer"); - this.deserializer = GrpcPreconditions.CheckNotNull(deserializer, "deserializer"); + this.serializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer)); + this.deserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer)); + this.contextualSerializer = EmulateContextualSerializer; + this.contextualDeserializer = EmulateContextualDeserializer; } /// <summary> - /// Gets the serializer function. + /// Initializes a new marshaller from serialize/deserialize fuctions that can access serialization and deserialization + /// context. Compared to the simple serializer/deserializer functions, using the contextual version provides more + /// flexibility and can lead to increased efficiency (and better performance). + /// Note: This constructor is part of an experimental API that can change or be removed without any prior notice. /// </summary> - public Func<T, byte[]> Serializer + /// <param name="serializer">Function that will be used to serialize messages.</param> + /// <param name="deserializer">Function that will be used to deserialize messages.</param> + public Marshaller(Action<T, SerializationContext> serializer, Func<DeserializationContext, T> deserializer) { - get - { - return this.serializer; - } + this.contextualSerializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer)); + this.contextualDeserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer)); + // TODO(jtattermusch): once gRPC C# library switches to using contextual (de)serializer, + // emulating the simple (de)serializer will become unnecessary. + this.serializer = EmulateSimpleSerializer; + this.deserializer = EmulateSimpleDeserializer; } /// <summary> + /// Gets the serializer function. + /// </summary> + public Func<T, byte[]> Serializer => this.serializer; + + /// <summary> /// Gets the deserializer function. /// </summary> - public Func<byte[], T> Deserializer + public Func<byte[], T> Deserializer => this.deserializer; + + /// <summary> + /// Gets the serializer function. + /// Note: experimental API that can change or be removed without any prior notice. + /// </summary> + public Action<T, SerializationContext> ContextualSerializer => this.contextualSerializer; + + /// <summary> + /// Gets the serializer function. + /// Note: experimental API that can change or be removed without any prior notice. + /// </summary> + public Func<DeserializationContext, T> ContextualDeserializer => this.contextualDeserializer; + + // for backward compatibility, emulate the simple serializer using the contextual one + private byte[] EmulateSimpleSerializer(T msg) { - get + // TODO(jtattermusch): avoid the allocation by passing a thread-local instance + // This code will become unnecessary once gRPC C# library switches to using contextual (de)serializer. + var context = new EmulatedSerializationContext(); + this.contextualSerializer(msg, context); + return context.GetPayload(); + } + + // for backward compatibility, emulate the simple deserializer using the contextual one + private T EmulateSimpleDeserializer(byte[] payload) + { + // TODO(jtattermusch): avoid the allocation by passing a thread-local instance + // This code will become unnecessary once gRPC C# library switches to using contextual (de)serializer. + var context = new EmulatedDeserializationContext(payload); + return this.contextualDeserializer(context); + } + + // for backward compatibility, emulate the contextual serializer using the simple one + private void EmulateContextualSerializer(T message, SerializationContext context) + { + var payload = this.serializer(message); + context.Complete(payload); + } + + // for backward compatibility, emulate the contextual deserializer using the simple one + private T EmulateContextualDeserializer(DeserializationContext context) + { + return this.deserializer(context.PayloadAsNewBuffer()); + } + + internal class EmulatedSerializationContext : SerializationContext + { + bool isComplete; + byte[] payload; + + public override void Complete(byte[] payload) + { + GrpcPreconditions.CheckState(!isComplete); + this.isComplete = true; + this.payload = payload; + } + + internal byte[] GetPayload() + { + return this.payload; + } + } + + internal class EmulatedDeserializationContext : DeserializationContext + { + readonly byte[] payload; + bool alreadyCalledPayloadAsNewBuffer; + + public EmulatedDeserializationContext(byte[] payload) + { + this.payload = GrpcPreconditions.CheckNotNull(payload); + } + + public override int PayloadLength => payload.Length; + + public override byte[] PayloadAsNewBuffer() { - return this.deserializer; + GrpcPreconditions.CheckState(!alreadyCalledPayloadAsNewBuffer); + alreadyCalledPayloadAsNewBuffer = true; + return payload; } } } @@ -77,6 +170,15 @@ namespace Grpc.Core } /// <summary> + /// Creates a marshaller from specified contextual serializer and deserializer. + /// Note: This method is part of an experimental API that can change or be removed without any prior notice. + /// </summary> + public static Marshaller<T> Create<T>(Action<T, SerializationContext> serializer, Func<DeserializationContext, T> deserializer) + { + return new Marshaller<T>(serializer, deserializer); + } + + /// <summary> /// Returns a marshaller for <c>string</c> type. This is useful for testing. /// </summary> public static Marshaller<string> StringMarshaller diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs index 0e4456278c..bc263c3469 100644 --- a/src/csharp/Grpc.Core/Metadata.cs +++ b/src/csharp/Grpc.Core/Metadata.cs @@ -135,7 +135,7 @@ namespace Grpc.Core } /// <summary> - /// <see cref="T:IList`1"/> + /// Adds a new ASCII-valued metadata entry. See <c>Metadata.Entry</c> constructor for params. /// </summary> public void Add(string key, string value) { @@ -143,7 +143,7 @@ namespace Grpc.Core } /// <summary> - /// <see cref="T:IList`1"/> + /// Adds a new binary-valued metadata entry. See <c>Metadata.Entry</c> constructor for params. /// </summary> public void Add(string key, byte[] valueBytes) { @@ -225,8 +225,6 @@ namespace Grpc.Core /// </summary> public class Entry { - private static readonly Regex ValidKeyRegex = new Regex("^[a-z0-9_-]+$"); - readonly string key; readonly string value; readonly byte[] valueBytes; @@ -241,7 +239,7 @@ namespace Grpc.Core /// <summary> /// Initializes a new instance of the <see cref="Grpc.Core.Metadata.Entry"/> struct with a binary value. /// </summary> - /// <param name="key">Metadata key, needs to have suffix indicating a binary valued metadata entry.</param> + /// <param name="key">Metadata key. Gets converted to lowercase. Needs to have suffix indicating a binary valued metadata entry. Can only contain lowercase alphanumeric characters, underscores, hyphens and dots.</param> /// <param name="valueBytes">Value bytes.</param> public Entry(string key, byte[] valueBytes) { @@ -255,9 +253,9 @@ namespace Grpc.Core } /// <summary> - /// Initializes a new instance of the <see cref="Grpc.Core.Metadata.Entry"/> struct holding an ASCII value. + /// Initializes a new instance of the <see cref="Grpc.Core.Metadata.Entry"/> struct with an ASCII value. /// </summary> - /// <param name="key">Metadata key, must not use suffix indicating a binary valued metadata entry.</param> + /// <param name="key">Metadata key. Gets converted to lowercase. Must not use suffix indicating a binary valued metadata entry. Can only contain lowercase alphanumeric characters, underscores, hyphens and dots.</param> /// <param name="value">Value string. Only ASCII characters are allowed.</param> public Entry(string key, string value) { @@ -358,10 +356,42 @@ namespace Grpc.Core private static string NormalizeKey(string key) { - var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLowerInvariant(); - GrpcPreconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized), - "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens."); - return normalized; + GrpcPreconditions.CheckNotNull(key, "key"); + + GrpcPreconditions.CheckArgument(IsValidKey(key, out bool isLowercase), + "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores, hyphens and dots."); + if (isLowercase) + { + // save allocation of a new string if already lowercase + return key; + } + + return key.ToLowerInvariant(); + } + + private static bool IsValidKey(string input, out bool isLowercase) + { + isLowercase = true; + for (int i = 0; i < input.Length; i++) + { + char c = input[i]; + if ('a' <= c && c <= 'z' || + '0' <= c && c <= '9' || + c == '.' || + c == '_' || + c == '-' ) + continue; + + if ('A' <= c && c <= 'Z') + { + isLowercase = false; + continue; + } + + return false; + } + + return true; } /// <summary> 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/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs index 94429d74ce..ff89897565 100644 --- a/src/csharp/Grpc.Core/RpcException.cs +++ b/src/csharp/Grpc.Core/RpcException.cs @@ -33,10 +33,8 @@ namespace Grpc.Core /// Creates a new <c>RpcException</c> associated with given status. /// </summary> /// <param name="status">Resulting status of a call.</param> - public RpcException(Status status) : base(status.ToString()) + public RpcException(Status status) : this(status, Metadata.Empty, status.ToString()) { - this.status = status; - this.trailers = Metadata.Empty; } /// <summary> @@ -44,10 +42,8 @@ namespace Grpc.Core /// </summary> /// <param name="status">Resulting status of a call.</param> /// <param name="message">The exception message.</param> - public RpcException(Status status, string message) : base(message) + public RpcException(Status status, string message) : this(status, Metadata.Empty, message) { - this.status = status; - this.trailers = Metadata.Empty; } /// <summary> @@ -55,7 +51,17 @@ namespace Grpc.Core /// </summary> /// <param name="status">Resulting status of a call.</param> /// <param name="trailers">Response trailing metadata.</param> - public RpcException(Status status, Metadata trailers) : base(status.ToString()) + public RpcException(Status status, Metadata trailers) : this(status, trailers, status.ToString()) + { + } + + /// <summary> + /// Creates a new <c>RpcException</c> associated with given status, message and trailing response metadata. + /// </summary> + /// <param name="status">Resulting status of a call.</param> + /// <param name="trailers">Response trailing metadata.</param> + /// <param name="message">The exception message.</param> + public RpcException(Status status, Metadata trailers, string message) : base(message) { this.status = status; this.trailers = GrpcPreconditions.CheckNotNull(trailers); diff --git a/src/csharp/Grpc.Core/SerializationContext.cs b/src/csharp/Grpc.Core/SerializationContext.cs new file mode 100644 index 0000000000..cf4d1595da --- /dev/null +++ b/src/csharp/Grpc.Core/SerializationContext.cs @@ -0,0 +1,34 @@ +#region Copyright notice and license + +// 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. + +#endregion + +namespace Grpc.Core +{ + /// <summary> + /// Provides storage for payload when serializing a message. + /// </summary> + public abstract class SerializationContext + { + /// <summary> + /// Use the byte array as serialized form of current message and mark serialization process as complete. + /// Complete() can only be called once. By calling this method the caller gives up the ownership of the + /// payload which must not be accessed afterwards. + /// </summary> + /// <param name="payload">the serialized form of current message</param> + public abstract void Complete(byte[] payload); + } +} 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.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 45bd8ebd85..ed0d884365 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ <!-- This file is generated --> <Project> <PropertyGroup> - <GrpcCsharpVersion>1.15.0-dev</GrpcCsharpVersion> + <GrpcCsharpVersion>1.17.0-dev</GrpcCsharpVersion> <GoogleProtobufVersion>3.6.1</GoogleProtobufVersion> </PropertyGroup> </Project> diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 295e0f2577..14714c8c4a 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -33,11 +33,11 @@ namespace Grpc.Core /// <summary> /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies /// </summary> - public const string CurrentAssemblyFileVersion = "1.15.0.0"; + public const string CurrentAssemblyFileVersion = "1.17.0.0"; /// <summary> /// Current version of gRPC C# /// </summary> - public const string CurrentVersion = "1.15.0-dev"; + public const string CurrentVersion = "1.17.0-dev"; } } diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index ad7033b782..8daf3fa98b 100755 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -18,7 +18,7 @@ <ItemGroup> <PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" /> - <PackageReference Include="CommandLineParser" Version="2.1.1-beta" /> + <PackageReference Include="CommandLineParser" Version="2.3.0" /> <PackageReference Include="NUnit" Version="3.10.1" /> <PackageReference Include="NUnitLite" Version="3.10.1" /> </ItemGroup> diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs index c83ccd2612..40447854f4 100644 --- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs @@ -153,9 +153,10 @@ namespace Grpc.IntegrationTesting [Test] public void MetadataCredentials_InterceptorThrows() { + var authInterceptorExceptionMessage = "Auth interceptor throws"; var callCredentials = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { - throw new Exception("Auth interceptor throws"); + throw new Exception(authInterceptorExceptionMessage); })); var channelCredentials = ChannelCredentials.Create(TestCredentials.CreateSslCredentials(), callCredentials); channel = new Channel(Host, server.Ports.Single().BoundPort, channelCredentials, options); @@ -163,6 +164,7 @@ namespace Grpc.IntegrationTesting var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { })); Assert.AreEqual(StatusCode.Unavailable, ex.Status.StatusCode); + StringAssert.Contains(authInterceptorExceptionMessage, ex.Status.Detail); } private class FakeTestService : TestService.TestServiceBase 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/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj index 8a629f9748..d39d46cf1b 100644 --- a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj +++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj @@ -16,7 +16,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="CommandLineParser" Version="2.1.1-beta" /> + <PackageReference Include="CommandLineParser" Version="2.3.0" /> </ItemGroup> <ItemGroup Condition=" '$(TargetFramework)' == 'net45' "> diff --git a/src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs new file mode 100644 index 0000000000..e4c9b2fa84 --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs @@ -0,0 +1,85 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using NUnit.Framework; + +namespace Grpc.Tools.Tests +{ + public class CSharpGeneratorTest : GeneratorTest + { + GeneratorServices _generator; + + [SetUp] + public new void SetUp() + { + _generator = GeneratorServices.GetForLanguage("CSharp", _log); + } + + [TestCase("foo.proto", "Foo.cs", "FooGrpc.cs")] + [TestCase("sub/foo.proto", "Foo.cs", "FooGrpc.cs")] + [TestCase("one_two.proto", "OneTwo.cs", "OneTwoGrpc.cs")] + [TestCase("__one_two!.proto", "OneTwo!.cs", "OneTwo!Grpc.cs")] + [TestCase("one(two).proto", "One(two).cs", "One(two)Grpc.cs")] + [TestCase("one_(two).proto", "One(two).cs", "One(two)Grpc.cs")] + [TestCase("one two.proto", "One two.cs", "One twoGrpc.cs")] + [TestCase("one_ two.proto", "One two.cs", "One twoGrpc.cs")] + [TestCase("one .proto", "One .cs", "One Grpc.cs")] + public void NameMangling(string proto, string expectCs, string expectGrpcCs) + { + var poss = _generator.GetPossibleOutputs(Utils.MakeItem(proto, "grpcservices", "both")); + Assert.AreEqual(2, poss.Length); + Assert.Contains(expectCs, poss); + Assert.Contains(expectGrpcCs, poss); + } + + [Test] + public void NoGrpcOneOutput() + { + var poss = _generator.GetPossibleOutputs(Utils.MakeItem("foo.proto")); + Assert.AreEqual(1, poss.Length); + } + + [TestCase("none")] + [TestCase("")] + public void GrpcNoneOneOutput(string grpc) + { + var item = Utils.MakeItem("foo.proto", "grpcservices", grpc); + var poss = _generator.GetPossibleOutputs(item); + Assert.AreEqual(1, poss.Length); + } + + [TestCase("client")] + [TestCase("server")] + [TestCase("both")] + public void GrpcEnabledTwoOutputs(string grpc) + { + var item = Utils.MakeItem("foo.proto", "grpcservices", grpc); + var poss = _generator.GetPossibleOutputs(item); + Assert.AreEqual(2, poss.Length); + } + + [Test] + public void OutputDirMetadataRecognized() + { + var item = Utils.MakeItem("foo.proto", "OutputDir", "out"); + var poss = _generator.GetPossibleOutputs(item); + Assert.AreEqual(1, poss.Length); + Assert.That(poss[0], Is.EqualTo("out/Foo.cs") | Is.EqualTo("out\\Foo.cs")); + } + }; +} diff --git a/src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs new file mode 100644 index 0000000000..bd0405a03a --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs @@ -0,0 +1,88 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.IO; +using NUnit.Framework; + +namespace Grpc.Tools.Tests +{ + public class CppGeneratorTest : GeneratorTest + { + GeneratorServices _generator; + + [SetUp] + public new void SetUp() + { + _generator = GeneratorServices.GetForLanguage("Cpp", _log); + } + + [TestCase("foo.proto", "", "foo")] + [TestCase("foo.proto", ".", "foo")] + [TestCase("foo.proto", "./", "foo")] + [TestCase("sub/foo.proto", "", "sub/foo")] + [TestCase("root/sub/foo.proto", "root", "sub/foo")] + [TestCase("root/sub/foo.proto", "root", "sub/foo")] + [TestCase("/root/sub/foo.proto", "/root", "sub/foo")] + public void RelativeDirectoryCompute(string proto, string root, string expectStem) + { + if (Path.DirectorySeparatorChar == '\\') + expectStem = expectStem.Replace('/', '\\'); + var poss = _generator.GetPossibleOutputs(Utils.MakeItem(proto, "ProtoRoot", root)); + Assert.AreEqual(2, poss.Length); + Assert.Contains(expectStem + ".pb.cc", poss); + Assert.Contains(expectStem + ".pb.h", poss); + } + + [Test] + public void NoGrpcTwoOutputs() + { + var poss = _generator.GetPossibleOutputs(Utils.MakeItem("foo.proto")); + Assert.AreEqual(2, poss.Length); + } + + [TestCase("false")] + [TestCase("")] + public void GrpcDisabledTwoOutput(string grpc) + { + var item = Utils.MakeItem("foo.proto", "grpcservices", grpc); + var poss = _generator.GetPossibleOutputs(item); + Assert.AreEqual(2, poss.Length); + } + + [TestCase("true")] + public void GrpcEnabledFourOutputs(string grpc) + { + var item = Utils.MakeItem("foo.proto", "grpcservices", grpc); + var poss = _generator.GetPossibleOutputs(item); + Assert.AreEqual(4, poss.Length); + Assert.Contains("foo.pb.cc", poss); + Assert.Contains("foo.pb.h", poss); + Assert.Contains("foo_grpc.pb.cc", poss); + Assert.Contains("foo_grpc.pb.h", poss); + } + + [Test] + public void OutputDirMetadataRecognized() + { + var item = Utils.MakeItem("foo.proto", "OutputDir", "out"); + var poss = _generator.GetPossibleOutputs(item); + Assert.AreEqual(2, poss.Length); + Assert.That(Path.GetDirectoryName(poss[0]), Is.EqualTo("out")); + } + }; +} diff --git a/src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs b/src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs new file mode 100644 index 0000000000..e89a8f4b5d --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs @@ -0,0 +1,146 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.IO; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using NUnit.Framework; + +namespace Grpc.Tools.Tests +{ + public class DepFileUtilTest + { + + [Test] + public void HashString64Hex_IsSane() + { + string hashFoo1 = DepFileUtil.HashString64Hex("foo"); + string hashEmpty = DepFileUtil.HashString64Hex(""); + string hashFoo2 = DepFileUtil.HashString64Hex("foo"); + + StringAssert.IsMatch("^[a-f0-9]{16}$", hashFoo1); + Assert.AreEqual(hashFoo1, hashFoo2); + Assert.AreNotEqual(hashFoo1, hashEmpty); + } + + [Test] + public void GetDepFilenameForProto_IsSane() + { + StringAssert.IsMatch(@"^out[\\/][a-f0-9]{16}_foo.protodep$", + DepFileUtil.GetDepFilenameForProto("out", "foo.proto")); + StringAssert.IsMatch(@"^[a-f0-9]{16}_foo.protodep$", + DepFileUtil.GetDepFilenameForProto("", "foo.proto")); + } + + [Test] + public void GetDepFilenameForProto_HashesDir() + { + string PickHash(string fname) => + DepFileUtil.GetDepFilenameForProto("", fname).Substring(0, 16); + + string same1 = PickHash("dir1/dir2/foo.proto"); + string same2 = PickHash("dir1/dir2/proto.foo"); + string same3 = PickHash("dir1/dir2/proto"); + string same4 = PickHash("dir1/dir2/.proto"); + string unsame1 = PickHash("dir2/foo.proto"); + string unsame2 = PickHash("/dir2/foo.proto"); + + Assert.AreEqual(same1, same2); + Assert.AreEqual(same1, same3); + Assert.AreEqual(same1, same4); + Assert.AreNotEqual(same1, unsame1); + Assert.AreNotEqual(unsame1, unsame2); + } + + ////////////////////////////////////////////////////////////////////////// + // Full file reading tests + + // Generated by protoc on Windows. Slashes vary. + const string depFile1 = + @"C:\projects\foo\src\./foo.grpc.pb.cc \ +C:\projects\foo\src\./foo.grpc.pb.h \ +C:\projects\foo\src\./foo.pb.cc \ + C:\projects\foo\src\./foo.pb.h: C:/usr/include/google/protobuf/wrappers.proto\ + C:/usr/include/google/protobuf/any.proto\ +C:/usr/include/google/protobuf/source_context.proto\ + C:/usr/include/google/protobuf/type.proto\ + foo.proto"; + + // This has a nasty output directory with a space. + const string depFile2 = + @"obj\Release x64\net45\/Foo.cs \ +obj\Release x64\net45\/FooGrpc.cs: C:/usr/include/google/protobuf/wrappers.proto\ + C:/projects/foo/src//foo.proto"; + + [Test] + public void ReadDependencyInput_FullFile1() + { + string[] deps = ReadDependencyInputFromFileData(depFile1, "foo.proto"); + + Assert.NotNull(deps); + Assert.That(deps, Has.Length.InRange(4, 5)); // foo.proto may or may not be listed. + Assert.That(deps, Has.One.EndsWith("wrappers.proto")); + Assert.That(deps, Has.One.EndsWith("type.proto")); + Assert.That(deps, Has.None.StartWith(" ")); + } + + [Test] + public void ReadDependencyInput_FullFile2() + { + string[] deps = ReadDependencyInputFromFileData(depFile2, "C:/projects/foo/src/foo.proto"); + + Assert.NotNull(deps); + Assert.That(deps, Has.Length.InRange(1, 2)); + Assert.That(deps, Has.One.EndsWith("wrappers.proto")); + Assert.That(deps, Has.None.StartWith(" ")); + } + + [Test] + public void ReadDependencyInput_FullFileUnparsable() + { + string[] deps = ReadDependencyInputFromFileData("a:/foo.proto", "/foo.proto"); + Assert.NotNull(deps); + Assert.Zero(deps.Length); + } + + // NB in our tests files are put into the temp directory but all have + // different names. Avoid adding files with the same directory path and + // name, or add reasonable handling for it if required. Tests are run in + // parallel and will collide otherwise. + private string[] ReadDependencyInputFromFileData(string fileData, string protoName) + { + string tempPath = Path.GetTempPath(); + string tempfile = DepFileUtil.GetDepFilenameForProto(tempPath, protoName); + try + { + File.WriteAllText(tempfile, fileData); + var mockEng = new Moq.Mock<IBuildEngine>(); + var log = new TaskLoggingHelper(mockEng.Object, "x"); + return DepFileUtil.ReadDependencyInputs(tempPath, protoName, log); + } + finally + { + try + { + File.Delete(tempfile); + } + catch { } + } + } + }; +} diff --git a/src/csharp/Grpc.Tools.Tests/GeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/GeneratorTest.cs new file mode 100644 index 0000000000..8a8fc81aba --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/GeneratorTest.cs @@ -0,0 +1,55 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Moq; +using NUnit.Framework; + +namespace Grpc.Tools.Tests +{ + public class GeneratorTest + { + protected Mock<IBuildEngine> _mockEngine; + protected TaskLoggingHelper _log; + + [SetUp] + public void SetUp() + { + _mockEngine = new Mock<IBuildEngine>(); + _log = new TaskLoggingHelper(_mockEngine.Object, "dummy"); + } + + [TestCase("csharp")] + [TestCase("CSharp")] + [TestCase("cpp")] + public void ValidLanguages(string lang) + { + Assert.IsNotNull(GeneratorServices.GetForLanguage(lang, _log)); + _mockEngine.Verify(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()), Times.Never); + } + + [TestCase("")] + [TestCase("COBOL")] + public void InvalidLanguages(string lang) + { + Assert.IsNull(GeneratorServices.GetForLanguage(lang, _log)); + _mockEngine.Verify(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()), Times.Once); + } + }; +} diff --git a/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj b/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj new file mode 100644 index 0000000000..a2d4874eec --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj @@ -0,0 +1,78 @@ +<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + + <Import Project="..\Grpc.Core\Version.csproj.include" /> + + <PropertyGroup> + <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks> + <OutputType>Exe</OutputType> + </PropertyGroup> + + <Import Project="..\Grpc.Core\SourceLink.csproj.include" /> + + <!-- This is copied verbatim from Grpc.Core/Common.csproj.include. Other settings + in that file conflict with the intent of this build, as it cannot be signed, + and may not compile Grpc.Core/Version.cs, as that file references constants + in Grpc.Core.dll. + TODO(kkm): Refactor imports. --> + <PropertyGroup Condition=" '$(OS)' != 'Windows_NT' and '$(MSBuildRuntimeType)' == 'Core' "> + <!-- Use Mono reference assemblies in SDK build: https://github.com/dotnet/sdk/issues/335 --> + <FrameworkPathOverride Condition="Exists('/usr/lib/mono/4.5-api')">/usr/lib/mono/4.5-api</FrameworkPathOverride> + <FrameworkPathOverride Condition="Exists('/usr/local/lib/mono/4.5-api')">/usr/local/lib/mono/4.5-api</FrameworkPathOverride> + <FrameworkPathOverride Condition="Exists('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api</FrameworkPathOverride> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\Grpc.Tools\Grpc.Tools.csproj" /> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="Moq" Version="4.8.3" /> + <PackageReference Include="NUnit; NUnitLite" Version="3.10.1" /> + <PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" /> + </ItemGroup> + + <PropertyGroup Condition=" '$(TargetFramework)' != 'net45' "> + <DefineConstants>$(DefineConstants);NETCORE</DefineConstants> + </PropertyGroup> + + <ItemGroup Condition=" '$(TargetFramework)' == 'net45' "> + <Reference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.v4.0" /> + </ItemGroup> + + <ItemGroup Condition=" '$(TargetFramework)' != 'net45' "> + <PackageReference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.Core" Version="15.6.*" /> + </ItemGroup> + + <!-- Groups below is a hack to allow the test to run under Mono Framework build. + ========================================================================== --> + + <!-- Mono unfortunately comes with broken Microsoft.Build.* assemblies installed in + the GAC, but fortunately searches for runtime assemblies in a different order + than Windows CLR host: the GAC assemblies have the lowest search priority, (see + https://www.mono-project.com/docs/advanced/assemblies-and-the-gac/), not the + highest as is in Windows (documented at + https://docs.microsoft.com/dotnet/framework/deployment/how-the-runtime-locates-assemblies). + To run the tests under Mono, we need correct assemblies in the same directory as + the test executable. Correct versions are in the MSBuild directory under Mono. --> + <ItemGroup Condition=" '$(TargetFramework)' == 'net45' and '$(OS)' != 'Windows_NT' "> + <None Include="$(_MSBuildAssemblyPath)/Microsoft.Build.Framework.dll; + $(_MSBuildAssemblyPath)/Microsoft.Build.Utilities.v4.0.dll; + $(_MSBuildAssemblyPath)/Microsoft.Build.Utilities.Core.dll" + CopyToOutputDirectory="Always" Visible="false" /> + </ItemGroup> + <PropertyGroup Condition=" '$(TargetFramework)' == 'net45' and '$(OS)' != 'Windows_NT' "> + <!-- The None items are included into assembly candidate resolution by default, and + we do not want that, as they are not valid as reference assemblies (the version of + Microsoft.Build.Utilities.v4.0 is a pure facade for Microsoft.Build.Utilities.Core, + and does not define any types at all). Exclude them from assembly resolution. See + https://github.com/Microsoft/msbuild/blob/50639058f/documentation/wiki/ResolveAssemblyReference.md --> + <AssemblySearchPaths>{HintPathFromItem};{TargetFrameworkDirectory};{RawFileName}</AssemblySearchPaths> + <!-- Mono knows better where its MSBuild is. --> + <_MSBuildAssemblyPath Condition=" '$(MSBuildRuntimeType)' != 'Core' " + >$(MSBuildToolsPath)</_MSBuildAssemblyPath> + <!-- Under dotnet, make the best guess we can. --> + <_MSBuildAssemblyPath Condition=" '$(MSBuildRuntimeType)' == 'Core' " + >$(FrameworkPathOverride)/../msbuild/$(MSBuildToolsVersion)/bin</_MSBuildAssemblyPath> + </PropertyGroup> + +</Project> diff --git a/src/csharp/Grpc.Tools.Tests/NUnitMain.cs b/src/csharp/Grpc.Tools.Tests/NUnitMain.cs new file mode 100644 index 0000000000..418c33820e --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/NUnitMain.cs @@ -0,0 +1,33 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.Reflection; +using NUnitLite; + +namespace Grpc.Tools.Tests +{ + static class NUnitMain + { + public static int Main(string[] args) => +#if NETCOREAPP1_0 || NETCOREAPP1_1 + new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args); +#else + new AutoRun().Execute(args); +#endif + }; +} diff --git a/src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs new file mode 100644 index 0000000000..ea763f4e40 --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs @@ -0,0 +1,76 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.Reflection; // UWYU: Object.GetType() extension. +using Microsoft.Build.Framework; +using Moq; +using NUnit.Framework; + +namespace Grpc.Tools.Tests +{ + public class ProtoCompileBasicTest + { + // Mock task class that stops right before invoking protoc. + public class ProtoCompileTestable : ProtoCompile + { + public string LastPathToTool { get; private set; } + public string[] LastResponseFile { get; private set; } + + protected override int ExecuteTool(string pathToTool, + string response, + string commandLine) + { + // We should never be using command line commands. + Assert.That(commandLine, Is.Null | Is.Empty); + + // Must receive a path to tool + Assert.That(pathToTool, Is.Not.Null & Is.Not.Empty); + Assert.That(response, Is.Not.Null & Does.EndWith("\n")); + + LastPathToTool = pathToTool; + LastResponseFile = response.Remove(response.Length - 1).Split('\n'); + + // Do not run the tool, but pretend it ran successfully. + return 0; + } + }; + + protected Mock<IBuildEngine> _mockEngine; + protected ProtoCompileTestable _task; + + [SetUp] + public void SetUp() + { + _mockEngine = new Mock<IBuildEngine>(); + _task = new ProtoCompileTestable { + BuildEngine = _mockEngine.Object + }; + } + + [TestCase("ProtoBuf")] + [TestCase("Generator")] + [TestCase("OutputDir")] + [Description("We trust MSBuild to initialize these properties.")] + public void RequiredAttributePresentOnProperty(string prop) + { + var pinfo = _task.GetType()?.GetProperty(prop); + Assert.NotNull(pinfo); + Assert.That(pinfo, Has.Attribute<RequiredAttribute>()); + } + }; +} diff --git a/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs new file mode 100644 index 0000000000..cac7146634 --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs @@ -0,0 +1,179 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.IO; +using Microsoft.Build.Framework; +using Moq; +using NUnit.Framework; + +namespace Grpc.Tools.Tests +{ + public class ProtoCompileCommandLineGeneratorTest : ProtoCompileBasicTest + { + [SetUp] + public new void SetUp() + { + _task.Generator = "csharp"; + _task.OutputDir = "outdir"; + _task.ProtoBuf = Utils.MakeSimpleItems("a.proto"); + } + + void ExecuteExpectSuccess() + { + _mockEngine + .Setup(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>())) + .Callback((BuildErrorEventArgs e) => + Assert.Fail($"Error logged by build engine:\n{e.Message}")); + bool result = _task.Execute(); + Assert.IsTrue(result); + } + + [Test] + public void MinimalCompile() + { + ExecuteExpectSuccess(); + Assert.That(_task.LastPathToTool, Does.Match(@"protoc(.exe)?$")); + Assert.That(_task.LastResponseFile, Is.EqualTo(new[] { + "--csharp_out=outdir", "a.proto" })); + } + + [Test] + public void CompileTwoFiles() + { + _task.ProtoBuf = Utils.MakeSimpleItems("a.proto", "foo/b.proto"); + ExecuteExpectSuccess(); + Assert.That(_task.LastResponseFile, Is.EqualTo(new[] { + "--csharp_out=outdir", "a.proto", "foo/b.proto" })); + } + + [Test] + public void CompileWithProtoPaths() + { + _task.ProtoPath = new[] { "/path1", "/path2" }; + ExecuteExpectSuccess(); + Assert.That(_task.LastResponseFile, Is.EqualTo(new[] { + "--csharp_out=outdir", "--proto_path=/path1", + "--proto_path=/path2", "a.proto" })); + } + + [TestCase("Cpp")] + [TestCase("CSharp")] + [TestCase("Java")] + [TestCase("Javanano")] + [TestCase("Js")] + [TestCase("Objc")] + [TestCase("Php")] + [TestCase("Python")] + [TestCase("Ruby")] + public void CompileWithOptions(string gen) + { + _task.Generator = gen; + _task.OutputOptions = new[] { "foo", "bar" }; + ExecuteExpectSuccess(); + gen = gen.ToLowerInvariant(); + Assert.That(_task.LastResponseFile, Is.EqualTo(new[] { + $"--{gen}_out=outdir", $"--{gen}_opt=foo,bar", "a.proto" })); + } + + [Test] + public void OutputDependencyFile() + { + _task.DependencyOut = "foo/my.protodep"; + // Task fails trying to read the non-generated file; we ignore that. + _task.Execute(); + Assert.That(_task.LastResponseFile, + Does.Contain("--dependency_out=foo/my.protodep")); + } + + [Test] + public void OutputDependencyWithProtoDepDir() + { + _task.ProtoDepDir = "foo"; + // Task fails trying to read the non-generated file; we ignore that. + _task.Execute(); + Assert.That(_task.LastResponseFile, + Has.One.Match(@"^--dependency_out=foo[/\\].+_a.protodep$")); + } + + [Test] + public void GenerateGrpc() + { + _task.GrpcPluginExe = "/foo/grpcgen"; + ExecuteExpectSuccess(); + Assert.That(_task.LastResponseFile, Is.SupersetOf(new[] { + "--csharp_out=outdir", "--grpc_out=outdir", + "--plugin=protoc-gen-grpc=/foo/grpcgen" })); + } + + [Test] + public void GenerateGrpcWithOutDir() + { + _task.GrpcPluginExe = "/foo/grpcgen"; + _task.GrpcOutputDir = "gen-out"; + ExecuteExpectSuccess(); + Assert.That(_task.LastResponseFile, Is.SupersetOf(new[] { + "--csharp_out=outdir", "--grpc_out=gen-out" })); + } + + [Test] + public void GenerateGrpcWithOptions() + { + _task.GrpcPluginExe = "/foo/grpcgen"; + _task.GrpcOutputOptions = new[] { "baz", "quux" }; + ExecuteExpectSuccess(); + Assert.That(_task.LastResponseFile, + Does.Contain("--grpc_opt=baz,quux")); + } + + [Test] + public void DirectoryArgumentsSlashTrimmed() + { + _task.GrpcPluginExe = "/foo/grpcgen"; + _task.GrpcOutputDir = "gen-out/"; + _task.OutputDir = "outdir/"; + _task.ProtoPath = new[] { "/path1/", "/path2/" }; + ExecuteExpectSuccess(); + Assert.That(_task.LastResponseFile, Is.SupersetOf(new[] { + "--proto_path=/path1", "--proto_path=/path2", + "--csharp_out=outdir", "--grpc_out=gen-out" })); + } + + [TestCase(".", ".")] + [TestCase("/", "/")] + [TestCase("//", "/")] + [TestCase("/foo/", "/foo")] + [TestCase("/foo", "/foo")] + [TestCase("foo/", "foo")] + [TestCase("foo//", "foo")] + [TestCase("foo/\\", "foo")] + [TestCase("foo\\/", "foo")] + [TestCase("C:\\foo", "C:\\foo")] + [TestCase("C:", "C:")] + [TestCase("C:\\", "C:\\")] + [TestCase("C:\\\\", "C:\\")] + public void DirectorySlashTrimmingCases(string given, string expect) + { + if (Path.DirectorySeparatorChar == '/') + expect = expect.Replace('\\', '/'); + _task.OutputDir = given; + ExecuteExpectSuccess(); + Assert.That(_task.LastResponseFile, + Does.Contain("--csharp_out=" + expect)); + } + }; +} diff --git a/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs new file mode 100644 index 0000000000..1773dcb875 --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs @@ -0,0 +1,51 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using Microsoft.Build.Framework; +using Moq; +using NUnit.Framework; + +namespace Grpc.Tools.Tests +{ + public class ProtoCompileCommandLinePrinterTest : ProtoCompileBasicTest + { + [SetUp] + public new void SetUp() + { + _task.Generator = "csharp"; + _task.OutputDir = "outdir"; + _task.ProtoBuf = Utils.MakeSimpleItems("a.proto"); + + _mockEngine + .Setup(me => me.LogMessageEvent(It.IsAny<BuildMessageEventArgs>())) + .Callback((BuildMessageEventArgs e) => + Assert.Fail($"Error logged by build engine:\n{e.Message}")) + .Verifiable("Command line was not output by the task."); + } + + void ExecuteExpectSuccess() + { + _mockEngine + .Setup(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>())) + .Callback((BuildErrorEventArgs e) => + Assert.Fail($"Error logged by build engine:\n{e.Message}")); + bool result = _task.Execute(); + Assert.IsTrue(result); + } + }; +} diff --git a/src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs new file mode 100644 index 0000000000..54723b74fc --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs @@ -0,0 +1,139 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.Runtime.InteropServices; // For NETCORE tests. +using Microsoft.Build.Framework; +using Moq; +using NUnit.Framework; + +namespace Grpc.Tools.Tests +{ + public class ProtoToolsPlatformTaskTest + { + ProtoToolsPlatform _task; + int _cpuMatched, _osMatched; + + [OneTimeSetUp] + public void SetUp() + { + var mockEng = new Mock<IBuildEngine>(); + _task = new ProtoToolsPlatform() { BuildEngine = mockEng.Object }; + _task.Execute(); + } + + [OneTimeTearDown] + public void TearDown() + { + Assert.AreEqual(1, _cpuMatched, "CPU type detection failed"); + Assert.AreEqual(1, _osMatched, "OS detection failed"); + } + +#if NETCORE + // PlatformAttribute not yet available in NUnit, coming soon: + // https://github.com/nunit/nunit/pull/3003. + // Use same test case names as under the full framework. + [Test] + public void CpuIsX86() + { + if (RuntimeInformation.OSArchitecture == Architecture.X86) + { + _cpuMatched++; + Assert.AreEqual("x86", _task.Cpu); + } + } + + [Test] + public void CpuIsX64() + { + if (RuntimeInformation.OSArchitecture == Architecture.X64) + { + _cpuMatched++; + Assert.AreEqual("x64", _task.Cpu); + } + } + + [Test] + public void OsIsWindows() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + _osMatched++; + Assert.AreEqual("windows", _task.Os); + } + } + + [Test] + public void OsIsLinux() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + _osMatched++; + Assert.AreEqual("linux", _task.Os); + } + } + + [Test] + public void OsIsMacOsX() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + _osMatched++; + Assert.AreEqual("macosx", _task.Os); + } + } + +#else // !NETCORE, i.e. full framework. + + [Test, Platform("32-Bit")] + public void CpuIsX86() + { + _cpuMatched++; + Assert.AreEqual("x86", _task.Cpu); + } + + [Test, Platform("64-Bit")] + public void CpuIsX64() + { + _cpuMatched++; + Assert.AreEqual("x64", _task.Cpu); + } + + [Test, Platform("Win")] + public void OsIsWindows() + { + _osMatched++; + Assert.AreEqual("windows", _task.Os); + } + + [Test, Platform("Linux")] + public void OsIsLinux() + { + _osMatched++; + Assert.AreEqual("linux", _task.Os); + } + + [Test, Platform("MacOSX")] + public void OsIsMacOsX() + { + _osMatched++; + Assert.AreEqual("macosx", _task.Os); + } + +#endif // NETCORE + }; +} diff --git a/src/csharp/Grpc.Tools.Tests/Utils.cs b/src/csharp/Grpc.Tools.Tests/Utils.cs new file mode 100644 index 0000000000..6e0f1cffd5 --- /dev/null +++ b/src/csharp/Grpc.Tools.Tests/Utils.cs @@ -0,0 +1,46 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Grpc.Tools.Tests +{ + static class Utils + { + // Build an item with a name from args[0] and metadata key-value pairs + // from the rest of args, interleaved. + // This does not do any checking, and expects an odd number of args. + public static ITaskItem MakeItem(params string[] args) + { + var item = new TaskItem(args[0]); + for (int i = 1; i < args.Length; i += 2) + { + item.SetMetadata(args[i], args[i + 1]); + } + return item; + } + + // Return an array of items from given itemspecs. + public static ITaskItem[] MakeSimpleItems(params string[] specs) + { + return specs.Select(s => new TaskItem(s)).ToArray(); + } + }; +} diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec deleted file mode 100644 index 0cae5572fd..0000000000 --- a/src/csharp/Grpc.Tools.nuspec +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<package> - <metadata> - <id>Grpc.Tools</id> - <title>gRPC C# Tools</title> - <summary>Tools for C# implementation of gRPC - an RPC library and framework</summary> - <description>Precompiled protobuf compiler and gRPC protobuf compiler plugin for generating gRPC client/server C# code. Binaries are available for Windows, Linux and MacOS.</description> - <version>$version$</version> - <authors>Google Inc.</authors> - <owners>grpc-packages</owners> - <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl> - <projectUrl>https://github.com/grpc/grpc</projectUrl> - <requireLicenseAcceptance>false</requireLicenseAcceptance> - <releaseNotes>Release $version$</releaseNotes> - <copyright>Copyright 2015, Google Inc.</copyright> - <tags>gRPC RPC Protocol HTTP/2</tags> - </metadata> - <files> - <!-- forward slashes in src path enable building on Linux --> - <file src="protoc_plugins/protoc_windows_x86/protoc.exe" target="tools/windows_x86/protoc.exe" /> - <file src="protoc_plugins/protoc_windows_x86/grpc_csharp_plugin.exe" target="tools/windows_x86/grpc_csharp_plugin.exe" /> - <file src="protoc_plugins/protoc_windows_x64/protoc.exe" target="tools/windows_x64/protoc.exe" /> - <file src="protoc_plugins/protoc_windows_x64/grpc_csharp_plugin.exe" target="tools/windows_x64/grpc_csharp_plugin.exe" /> - <file src="protoc_plugins/protoc_linux_x86/protoc" target="tools/linux_x86/protoc" /> - <file src="protoc_plugins/protoc_linux_x86/grpc_csharp_plugin" target="tools/linux_x86/grpc_csharp_plugin" /> - <file src="protoc_plugins/protoc_linux_x64/protoc" target="tools/linux_x64/protoc" /> - <file src="protoc_plugins/protoc_linux_x64/grpc_csharp_plugin" target="tools/linux_x64/grpc_csharp_plugin" /> - <file src="protoc_plugins/protoc_macos_x86/protoc" target="tools/macosx_x86/protoc" /> - <file src="protoc_plugins/protoc_macos_x86/grpc_csharp_plugin" target="tools/macosx_x86/grpc_csharp_plugin" /> - <file src="protoc_plugins/protoc_macos_x64/protoc" target="tools/macosx_x64/protoc" /> - <file src="protoc_plugins/protoc_macos_x64/grpc_csharp_plugin" target="tools/macosx_x64/grpc_csharp_plugin" /> - </files> -</package> diff --git a/src/csharp/Grpc.Tools/Common.cs b/src/csharp/Grpc.Tools/Common.cs new file mode 100644 index 0000000000..e6acdd6393 --- /dev/null +++ b/src/csharp/Grpc.Tools/Common.cs @@ -0,0 +1,114 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +[assembly: InternalsVisibleTo("Grpc.Tools.Tests")] + +namespace Grpc.Tools +{ + // Metadata names (MSBuild item attributes) that we refer to often. + static class Metadata + { + // On output dependency lists. + public static string Source = "Source"; + // On ProtoBuf items. + public static string ProtoRoot = "ProtoRoot"; + public static string OutputDir = "OutputDir"; + public static string GrpcServices = "GrpcServices"; + public static string GrpcOutputDir = "GrpcOutputDir"; + }; + + // A few flags used to control the behavior under various platforms. + internal static class Platform + { + public enum OsKind { Unknown, Windows, Linux, MacOsX }; + public static readonly OsKind Os; + + public enum CpuKind { Unknown, X86, X64 }; + public static readonly CpuKind Cpu; + + // This is not necessarily true, but good enough. BCL lacks a per-FS + // API to determine file case sensitivity. + public static bool IsFsCaseInsensitive => Os == OsKind.Windows; + public static bool IsWindows => Os == OsKind.Windows; + + static Platform() + { +#if NETCORE + Os = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OsKind.Windows + : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? OsKind.Linux + : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OsKind.MacOsX + : OsKind.Unknown; + + switch (RuntimeInformation.OSArchitecture) + { + case Architecture.X86: Cpu = CpuKind.X86; break; + case Architecture.X64: Cpu = CpuKind.X64; break; + // We do not have build tools for other architectures. + default: Cpu = CpuKind.Unknown; break; + } +#else + // Running under either Mono or full MS framework. + Os = OsKind.Windows; + if (Type.GetType("Mono.Runtime", throwOnError: false) != null) + { + // Congratulations. We are running under Mono. + var plat = Environment.OSVersion.Platform; + if (plat == PlatformID.MacOSX) + { + Os = OsKind.MacOsX; + } + else if (plat == PlatformID.Unix || (int)plat == 128) + { + // This is how Mono detects OSX internally. + Os = File.Exists("/usr/lib/libc.dylib") ? OsKind.MacOsX : OsKind.Linux; + } + } + + // Hope we are not building on ARM under Xamarin! + Cpu = Environment.Is64BitOperatingSystem ? CpuKind.X64 : CpuKind.X86; +#endif + } + }; + + // Exception handling helpers. + static class Exceptions + { + // Returns true iff the exception indicates an error from an I/O call. See + // https://github.com/Microsoft/msbuild/blob/v15.4.8.50001/src/Shared/ExceptionHandling.cs#L101 + static public bool IsIoRelated(Exception ex) => + ex is IOException || + (ex is ArgumentException && !(ex is ArgumentNullException)) || + ex is SecurityException || + ex is UnauthorizedAccessException || + ex is NotSupportedException; + }; + + // String helpers. + static class Strings + { + // Compare string to argument using OrdinalIgnoreCase comparison. + public static bool EqualNoCase(this string a, string b) => + string.Equals(a, b, StringComparison.OrdinalIgnoreCase); + } +} diff --git a/src/csharp/Grpc.Tools/DepFileUtil.cs b/src/csharp/Grpc.Tools/DepFileUtil.cs new file mode 100644 index 0000000000..440d3d535c --- /dev/null +++ b/src/csharp/Grpc.Tools/DepFileUtil.cs @@ -0,0 +1,273 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Grpc.Tools +{ + internal static class DepFileUtil + { + /* + Sample dependency files. Notable features we have to deal with: + * Slash doubling, must normalize them. + * Spaces in file names. Cannot just "unwrap" the line on backslash at eof; + rather, treat every line as containing one file name except for one with + the ':' separator, as containing exactly two. + * Deal with ':' also being drive letter separator (second example). + + obj\Release\net45\/Foo.cs \ + obj\Release\net45\/FooGrpc.cs: C:/foo/include/google/protobuf/wrappers.proto\ + C:/projects/foo/src//foo.proto + + C:\projects\foo\src\./foo.grpc.pb.cc \ + C:\projects\foo\src\./foo.grpc.pb.h \ + C:\projects\foo\src\./foo.pb.cc \ + C:\projects\foo\src\./foo.pb.h: C:/foo/include/google/protobuf/wrappers.proto\ + C:/foo/include/google/protobuf/any.proto\ + C:/foo/include/google/protobuf/source_context.proto\ + C:/foo/include/google/protobuf/type.proto\ + foo.proto + */ + + /// <summary> + /// Read file names from the dependency file to the right of ':' + /// </summary> + /// <param name="protoDepDir">Relative path to the dependency cache, e. g. "out"</param> + /// <param name="proto">Relative path to the proto item, e. g. "foo/file.proto"</param> + /// <param name="log">A <see cref="TaskLoggingHelper"/> for logging</param> + /// <returns> + /// Array of the proto file <b>input</b> dependencies as written by protoc, or empty + /// array if the dependency file does not exist or cannot be parsed. + /// </returns> + public static string[] ReadDependencyInputs(string protoDepDir, string proto, + TaskLoggingHelper log) + { + string depFilename = GetDepFilenameForProto(protoDepDir, proto); + string[] lines = ReadDepFileLines(depFilename, false, log); + if (lines.Length == 0) + { + return lines; + } + + var result = new List<string>(); + bool skip = true; + foreach (string line in lines) + { + // Start at the only line separating dependency outputs from inputs. + int ix = skip ? FindLineSeparator(line) : -1; + skip = skip && ix < 0; + if (skip) { continue; } + string file = ExtractFilenameFromLine(line, ix + 1, line.Length); + if (file == "") + { + log.LogMessage(MessageImportance.Low, + $"Skipping unparsable dependency file {depFilename}.\nLine with error: '{line}'"); + return new string[0]; + } + + // Do not bend over backwards trying not to include a proto into its + // own list of dependencies. Since a file is not older than self, + // it is safe to add; this is purely a memory optimization. + if (file != proto) + { + result.Add(file); + } + } + return result.ToArray(); + } + + /// <summary> + /// Read file names from the dependency file to the left of ':' + /// </summary> + /// <param name="depFilename">Path to dependency file written by protoc</param> + /// <param name="log">A <see cref="TaskLoggingHelper"/> for logging</param> + /// <returns> + /// Array of the protoc-generated outputs from the given dependency file + /// written by protoc, or empty array if the file does not exist or cannot + /// be parsed. + /// </returns> + /// <remarks> + /// Since this is called after a protoc invocation, an unparsable or missing + /// file causes an error-level message to be logged. + /// </remarks> + public static string[] ReadDependencyOutputs(string depFilename, + TaskLoggingHelper log) + { + string[] lines = ReadDepFileLines(depFilename, true, log); + if (lines.Length == 0) + { + return lines; + } + + var result = new List<string>(); + foreach (string line in lines) + { + int ix = FindLineSeparator(line); + string file = ExtractFilenameFromLine(line, 0, ix >= 0 ? ix : line.Length); + if (file == "") + { + log.LogError("Unable to parse generated dependency file {0}.\n" + + "Line with error: '{1}'", depFilename, line); + return new string[0]; + } + result.Add(file); + + // If this is the line with the separator, do not read further. + if (ix >= 0) { break; } + } + return result.ToArray(); + } + + /// <summary> + /// Construct relative dependency file name from directory hash and file name + /// </summary> + /// <param name="protoDepDir">Relative path to the dependency cache, e. g. "out"</param> + /// <param name="proto">Relative path to the proto item, e. g. "foo/file.proto"</param> + /// <returns> + /// Full relative path to the dependency file, e. g. + /// "out/deadbeef12345678_file.protodep" + /// </returns> + /// <remarks> + /// Since a project may contain proto files with the same filename but in different + /// directories, a unique filename for the dependency file is constructed based on the + /// proto file name both name and directory. The directory path can be arbitrary, + /// for example, it can be outside of the project, or an absolute path including + /// a drive letter, or a UNC network path. A name constructed from such a path by, + /// for example, replacing disallowed name characters with an underscore, may well + /// be over filesystem's allowed path length, since it will be located under the + /// project and solution directories, which are also some level deep from the root. + /// Instead of creating long and unwieldy names for these proto sources, we cache + /// the full path of the name without the filename, and append the filename to it, + /// as in e. g. "foo/file.proto" will yield the name "deadbeef12345678_file", where + /// "deadbeef12345678" is a presumed hash value of the string "foo/". This allows + /// the file names be short, unique (up to a hash collision), and still allowing + /// the user to guess their provenance. + /// </remarks> + public static string GetDepFilenameForProto(string protoDepDir, string proto) + { + string dirname = Path.GetDirectoryName(proto); + if (Platform.IsFsCaseInsensitive) + { + dirname = dirname.ToLowerInvariant(); + } + string dirhash = HashString64Hex(dirname); + string filename = Path.GetFileNameWithoutExtension(proto); + return Path.Combine(protoDepDir, $"{dirhash}_{filename}.protodep"); + } + + // Get a 64-bit hash for a directory string. We treat it as if it were + // unique, since there are not so many distinct proto paths in a project. + // We take the first 64 bit of the string SHA1. + // Internal for tests access only. + internal static string HashString64Hex(string str) + { + using (var sha1 = System.Security.Cryptography.SHA1.Create()) + { + byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(str)); + var hashstr = new StringBuilder(16); + for (int i = 0; i < 8; i++) + { + hashstr.Append(hash[i].ToString("x2")); + } + return hashstr.ToString(); + } + } + + // Extract filename between 'beg' (inclusive) and 'end' (exclusive) from + // line 'line', skipping over trailing and leading whitespace, and, when + // 'end' is immediately past end of line 'line', also final '\' (used + // as a line continuation token in the dep file). + // Returns an empty string if the filename cannot be extracted. + static string ExtractFilenameFromLine(string line, int beg, int end) + { + while (beg < end && char.IsWhiteSpace(line[beg])) beg++; + if (beg < end && end == line.Length && line[end - 1] == '\\') end--; + while (beg < end && char.IsWhiteSpace(line[end - 1])) end--; + if (beg == end) return ""; + + string filename = line.Substring(beg, end - beg); + try + { + // Normalize file name. + return Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename)); + } + catch (Exception ex) when (Exceptions.IsIoRelated(ex)) + { + return ""; + } + } + + // Finds the index of the ':' separating dependency clauses in the line, + // not taking Windows drive spec into account. Returns the index of the + // separating ':', or -1 if no separator found. + static int FindLineSeparator(string line) + { + // Mind this case where the first ':' is not separator: + // C:\foo\bar\.pb.h: C:/protobuf/wrappers.proto\ + int ix = line.IndexOf(':'); + if (ix <= 0 || ix == line.Length - 1 + || (line[ix + 1] != '/' && line[ix + 1] != '\\') + || !char.IsLetter(line[ix - 1])) + { + return ix; // Not a windows drive: no letter before ':', or no '\' after. + } + for (int j = ix - 1; --j >= 0;) + { + if (!char.IsWhiteSpace(line[j])) + { + return ix; // Not space or BOL only before "X:/". + } + } + return line.IndexOf(':', ix + 1); + } + + // Read entire dependency file. The 'required' parameter controls error + // logging behavior in case the file not found. We require this file when + // compiling, but reading it is optional when computing dependencies. + static string[] ReadDepFileLines(string filename, bool required, + TaskLoggingHelper log) + { + try + { + var result = File.ReadAllLines(filename); + if (!required) + { + log.LogMessage(MessageImportance.Low, $"Using dependency file {filename}"); + } + return result; + } + catch (Exception ex) when (Exceptions.IsIoRelated(ex)) + { + if (required) + { + log.LogError($"Unable to load {filename}: {ex.GetType().Name}: {ex.Message}"); + } + else + { + log.LogMessage(MessageImportance.Low, $"Skipping {filename}: {ex.Message}"); + } + return new string[0]; + } + } + }; +} diff --git a/src/csharp/Grpc.Tools/GeneratorServices.cs b/src/csharp/Grpc.Tools/GeneratorServices.cs new file mode 100644 index 0000000000..536ec43c83 --- /dev/null +++ b/src/csharp/Grpc.Tools/GeneratorServices.cs @@ -0,0 +1,194 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System; +using System.IO; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Grpc.Tools +{ + // Abstract class for language-specific analysis behavior, such + // as guessing the generated files the same way protoc does. + internal abstract class GeneratorServices + { + protected readonly TaskLoggingHelper Log; + protected GeneratorServices(TaskLoggingHelper log) { Log = log; } + + // Obtain a service for the given language (csharp, cpp). + public static GeneratorServices GetForLanguage(string lang, TaskLoggingHelper log) + { + if (lang.EqualNoCase("csharp")) { return new CSharpGeneratorServices(log); } + if (lang.EqualNoCase("cpp")) { return new CppGeneratorServices(log); } + + log.LogError("Invalid value '{0}' for task property 'Generator'. " + + "Supported generator languages: CSharp, Cpp.", lang); + return null; + } + + // Guess whether item's metadata suggests gRPC stub generation. + // When "gRPCServices" is not defined, assume gRPC is not used. + // When defined, C# uses "none" to skip gRPC, C++ uses "false", so + // recognize both. Since the value is tightly coupled to the scripts, + // we do not try to validate the value; scripts take care of that. + // It is safe to assume that gRPC is requested for any other value. + protected bool GrpcOutputPossible(ITaskItem proto) + { + string gsm = proto.GetMetadata(Metadata.GrpcServices); + return !gsm.EqualNoCase("") && !gsm.EqualNoCase("none") + && !gsm.EqualNoCase("false"); + } + + public abstract string[] GetPossibleOutputs(ITaskItem proto); + }; + + // C# generator services. + internal class CSharpGeneratorServices : GeneratorServices + { + public CSharpGeneratorServices(TaskLoggingHelper log) : base(log) { } + + public override string[] GetPossibleOutputs(ITaskItem protoItem) + { + bool doGrpc = GrpcOutputPossible(protoItem); + string filename = LowerUnderscoreToUpperCamel( + Path.GetFileNameWithoutExtension(protoItem.ItemSpec)); + + var outputs = new string[doGrpc ? 2 : 1]; + string outdir = protoItem.GetMetadata(Metadata.OutputDir); + string fileStem = Path.Combine(outdir, filename); + outputs[0] = fileStem + ".cs"; + if (doGrpc) + { + // Override outdir if kGrpcOutputDir present, default to proto output. + outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir); + if (outdir != "") + { + fileStem = Path.Combine(outdir, filename); + } + outputs[1] = fileStem + "Grpc.cs"; + } + return outputs; + } + + string LowerUnderscoreToUpperCamel(string str) + { + // See src/compiler/generator_helpers.h:118 + var result = new StringBuilder(str.Length, str.Length); + bool cap = true; + foreach (char c in str) + { + if (c == '_') + { + cap = true; + } + else if (cap) + { + result.Append(char.ToUpperInvariant(c)); + cap = false; + } + else + { + result.Append(c); + } + } + return result.ToString(); + } + }; + + // C++ generator services. + internal class CppGeneratorServices : GeneratorServices + { + public CppGeneratorServices(TaskLoggingHelper log) : base(log) { } + + public override string[] GetPossibleOutputs(ITaskItem protoItem) + { + bool doGrpc = GrpcOutputPossible(protoItem); + string root = protoItem.GetMetadata(Metadata.ProtoRoot); + string proto = protoItem.ItemSpec; + string filename = Path.GetFileNameWithoutExtension(proto); + // E. g., ("foo/", "foo/bar/x.proto") => "bar" + string relative = GetRelativeDir(root, proto); + + var outputs = new string[doGrpc ? 4 : 2]; + string outdir = protoItem.GetMetadata(Metadata.OutputDir); + string fileStem = Path.Combine(outdir, relative, filename); + outputs[0] = fileStem + ".pb.cc"; + outputs[1] = fileStem + ".pb.h"; + if (doGrpc) + { + // Override outdir if kGrpcOutputDir present, default to proto output. + outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir); + if (outdir != "") + { + fileStem = Path.Combine(outdir, relative, filename); + } + outputs[2] = fileStem + "_grpc.pb.cc"; + outputs[3] = fileStem + "_grpc.pb.h"; + } + return outputs; + } + + // Calculate part of proto path relative to root. Protoc is very picky + // about them matching exactly, so can be we. Expect root be exact prefix + // to proto, minus some slash normalization. + string GetRelativeDir(string root, string proto) + { + string protoDir = Path.GetDirectoryName(proto); + string rootDir = EndWithSlash(Path.GetDirectoryName(EndWithSlash(root))); + if (rootDir == s_dotSlash) + { + // Special case, otherwise we can return "./" instead of "" below! + return protoDir; + } + if (Platform.IsFsCaseInsensitive) + { + protoDir = protoDir.ToLowerInvariant(); + rootDir = rootDir.ToLowerInvariant(); + } + protoDir = EndWithSlash(protoDir); + if (!protoDir.StartsWith(rootDir)) + { + Log.LogWarning("ProtoBuf item '{0}' has the ProtoRoot metadata '{1}' " + + "which is not prefix to its path. Cannot compute relative path.", + proto, root); + return ""; + } + return protoDir.Substring(rootDir.Length); + } + + // './' or '.\', normalized per system. + static string s_dotSlash = "." + Path.DirectorySeparatorChar; + + static string EndWithSlash(string str) + { + if (str == "") + { + return s_dotSlash; + } + else if (str[str.Length - 1] != '\\' && str[str.Length - 1] != '/') + { + return str + Path.DirectorySeparatorChar; + } + else + { + return str; + } + } + }; +} diff --git a/src/csharp/Grpc.Tools/Grpc.Tools.csproj b/src/csharp/Grpc.Tools/Grpc.Tools.csproj new file mode 100644 index 0000000000..61fa75a4ec --- /dev/null +++ b/src/csharp/Grpc.Tools/Grpc.Tools.csproj @@ -0,0 +1,101 @@ +<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + + <Import Project="..\Grpc.Core\Version.csproj.include" /> + + <PropertyGroup> + <AssemblyName>Protobuf.MSBuild</AssemblyName> + <Version>$(GrpcCsharpVersion)</Version> + <!-- If changing targets, change also paths in Google.Protobuf.Tools.targets. --> + <TargetFrameworks>net45;netstandard1.3</TargetFrameworks> + </PropertyGroup> + + <!-- This is copied verbatim from Grpc.Core/Common.csproj.include. Other settings + in that file conflict with the intent of this build, as it cannot be signed, + and may not compile Grpc.Core/Version.cs, as that file references constants + in Grpc.Core.dll. + TODO(kkm): Refactor imports. --> + <PropertyGroup Condition=" '$(OS)' != 'Windows_NT' and '$(MSBuildRuntimeType)' == 'Core' "> + <!-- Use Mono reference assemblies in SDK build: https://github.com/dotnet/sdk/issues/335 --> + <FrameworkPathOverride Condition="Exists('/usr/lib/mono/4.5-api')">/usr/lib/mono/4.5-api</FrameworkPathOverride> + <FrameworkPathOverride Condition="Exists('/usr/local/lib/mono/4.5-api')">/usr/local/lib/mono/4.5-api</FrameworkPathOverride> + <FrameworkPathOverride Condition="Exists('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api</FrameworkPathOverride> + </PropertyGroup> + + <PropertyGroup Label="Asset root folders. TODO(kkm): Change with package separation."> + <!-- TODO(kkm): Rework whole section when splitting packages. --> + <!-- GRPC: ../../third_party/protobuf/src/google/protobuf/ --> + <!-- GPB: ../src/google/protobuf/ --> + <Assets_ProtoInclude>../../../third_party/protobuf/src/google/protobuf/</Assets_ProtoInclude> + + <!-- GPB: ../protoc/ --> + <!-- GRPC: ../protoc_plugins/protoc_ --> + <Assets_ProtoCompiler>../protoc_plugins/protoc_</Assets_ProtoCompiler> + + <!-- GRPC: ../protoc_plugins/ --> + <Assets_GrpcPlugins>../protoc_plugins/</Assets_GrpcPlugins> + </PropertyGroup> + + <PropertyGroup Condition=" '$(TargetFramework)' != 'net45' "> + <DefineConstants>$(DefineConstants);NETCORE</DefineConstants> + </PropertyGroup> + + <PropertyGroup Label="NuGet package definition" Condition=" '$(Configuration)' == 'Release' "> + <!-- TODO(kkm): Change to "build\" after splitting. --> + <BuildOutputTargetFolder>build\_protobuf\</BuildOutputTargetFolder> + <DevelopmentDependency>true</DevelopmentDependency> + <NoPackageAnalysis>true</NoPackageAnalysis> + <PackageId>Grpc.Tools</PackageId> + <Description>gRPC and Protocol Buffer compiler for managed C# and native C++ projects. + +Add this package to a project that contains .proto files to be compiled to code. +It contains the compilers, include files and project system integration for gRPC +and Protocol buffer service description files necessary to build them on Windows, +Linux and MacOS. Managed runtime is supplied separately in the Grpc.Core package.</Description> + <Copyright>Copyright 2018 gRPC authors</Copyright> + <Authors>gRPC authors</Authors> + <PackageLicenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</PackageLicenseUrl> + <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl> + <PackageTags>gRPC RPC protocol HTTP/2</PackageTags> + </PropertyGroup> + + <ItemGroup Label="NuGet package assets"> + <None Pack="true" PackagePath="build\" Include="build\**\*.xml; build\**\*.props; build\**\*.targets;" /> + + <!-- Protobuf assets (for Google.Protobuf.Tools) --> + <_ProtoAssetName Include="any;api;descriptor;duration;empty;field_mask; + source_context;struct;timestamp;type;wrappers" /> + <_Asset PackagePath="build/native/include/google/protobuf/" Include="@(_ProtoAssetName->'$(Assets_ProtoInclude)%(Identity).proto')" /> + + <!-- TODO(kkm): GPB builds assets into "macosx", GRPC into "macos". --> + <!-- TODO(kkm): Do not place non-tools under tools/, use build/native/bin/. --> + <!-- TODO(kkm): Do not package windows x64 builds (#13098). --> + <_Asset PackagePath="tools/windows_x86/protoc.exe" Include="$(Assets_ProtoCompiler)windows_x86/protoc.exe" /> + <_Asset PackagePath="tools/windows_x64/protoc.exe" Include="$(Assets_ProtoCompiler)windows_x64/protoc.exe" /> + <_Asset PackagePath="tools/linux_x86/protoc" Include="$(Assets_ProtoCompiler)linux_x86/protoc" /> + <_Asset PackagePath="tools/linux_x64/protoc" Include="$(Assets_ProtoCompiler)linux_x64/protoc" /> + <_Asset PackagePath="tools/macosx_x86/protoc" Include="$(Assets_ProtoCompiler)macos_x86/protoc" /> <!-- GPB: macosx--> + <_Asset PackagePath="tools/macosx_x64/protoc" Include="$(Assets_ProtoCompiler)macos_x64/protoc" /> <!-- GPB: macosx--> + + <!-- gRPC assets (for Grpc.Tools) --> + <_Asset PackagePath="tools/windows_x86/grpc_csharp_plugin.exe" Include="$(Assets_GrpcPlugins)protoc_windows_x86/grpc_csharp_plugin.exe" /> + <_Asset PackagePath="tools/windows_x64/grpc_csharp_plugin.exe" Include="$(Assets_GrpcPlugins)protoc_windows_x64/grpc_csharp_plugin.exe" /> + <_Asset PackagePath="tools/linux_x86/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_linux_x86/grpc_csharp_plugin" /> + <_Asset PackagePath="tools/linux_x64/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_linux_x64/grpc_csharp_plugin" /> + <_Asset PackagePath="tools/macosx_x86/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_macos_x86/grpc_csharp_plugin" /> + <_Asset PackagePath="tools/macosx_x64/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_macos_x64/grpc_csharp_plugin" /> + + <None Include="@(_Asset)" Pack="true" Visible="false" /> + </ItemGroup> + + <ItemGroup Condition=" '$(TargetFramework)' == 'net45' "> + <Reference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.v4.0" Pack="false" /> + </ItemGroup> + + <ItemGroup Condition=" '$(TargetFramework)' != 'net45' "> + <PackageReference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.Core" Version="15.6.*" /> + <!-- Set PrivateAssets="All" on all items, even those implicitly added, + so that they do not become dependencies of this package. --> + <PackageReference Update="@(PackageReference)" PrivateAssets="All" /> + </ItemGroup> + +</Project> diff --git a/src/csharp/Grpc.Tools/ProtoCompile.cs b/src/csharp/Grpc.Tools/ProtoCompile.cs new file mode 100644 index 0000000000..93608e1ac0 --- /dev/null +++ b/src/csharp/Grpc.Tools/ProtoCompile.cs @@ -0,0 +1,441 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Grpc.Tools +{ + /// <summary> + /// Run Google proto compiler (protoc). + /// + /// After a successful run, the task reads the dependency file if specified + /// to be saved by the compiler, and returns its output files. + /// + /// This task (unlike PrepareProtoCompile) does not attempt to guess anything + /// about language-specific behavior of protoc, and therefore can be used for + /// any language outputs. + /// </summary> + public class ProtoCompile : ToolTask + { + /* + + Usage: /home/kkm/work/protobuf/src/.libs/lt-protoc [OPTION] PROTO_FILES + Parse PROTO_FILES and generate output based on the options given: + -IPATH, --proto_path=PATH Specify the directory in which to search for + imports. May be specified multiple times; + directories will be searched in order. If not + given, the current working directory is used. + --version Show version info and exit. + -h, --help Show this text and exit. + --encode=MESSAGE_TYPE Read a text-format message of the given type + from standard input and write it in binary + to standard output. The message type must + be defined in PROTO_FILES or their imports. + --decode=MESSAGE_TYPE Read a binary message of the given type from + standard input and write it in text format + to standard output. The message type must + be defined in PROTO_FILES or their imports. + --decode_raw Read an arbitrary protocol message from + standard input and write the raw tag/value + pairs in text format to standard output. No + PROTO_FILES should be given when using this + flag. + --descriptor_set_in=FILES Specifies a delimited list of FILES + each containing a FileDescriptorSet (a + protocol buffer defined in descriptor.proto). + The FileDescriptor for each of the PROTO_FILES + provided will be loaded from these + FileDescriptorSets. If a FileDescriptor + appears multiple times, the first occurrence + will be used. + -oFILE, Writes a FileDescriptorSet (a protocol buffer, + --descriptor_set_out=FILE defined in descriptor.proto) containing all of + the input files to FILE. + --include_imports When using --descriptor_set_out, also include + all dependencies of the input files in the + set, so that the set is self-contained. + --include_source_info When using --descriptor_set_out, do not strip + SourceCodeInfo from the FileDescriptorProto. + This results in vastly larger descriptors that + include information about the original + location of each decl in the source file as + well as surrounding comments. + --dependency_out=FILE Write a dependency output file in the format + expected by make. This writes the transitive + set of input file paths to FILE + --error_format=FORMAT Set the format in which to print errors. + FORMAT may be 'gcc' (the default) or 'msvs' + (Microsoft Visual Studio format). + --print_free_field_numbers Print the free field numbers of the messages + defined in the given proto files. Groups share + the same field number space with the parent + message. Extension ranges are counted as + occupied fields numbers. + + --plugin=EXECUTABLE Specifies a plugin executable to use. + Normally, protoc searches the PATH for + plugins, but you may specify additional + executables not in the path using this flag. + Additionally, EXECUTABLE may be of the form + NAME=PATH, in which case the given plugin name + is mapped to the given executable even if + the executable's own name differs. + --cpp_out=OUT_DIR Generate C++ header and source. + --csharp_out=OUT_DIR Generate C# source file. + --java_out=OUT_DIR Generate Java source file. + --javanano_out=OUT_DIR Generate Java Nano source file. + --js_out=OUT_DIR Generate JavaScript source. + --objc_out=OUT_DIR Generate Objective C header and source. + --php_out=OUT_DIR Generate PHP source file. + --python_out=OUT_DIR Generate Python source file. + --ruby_out=OUT_DIR Generate Ruby source file. + @<filename> Read options and filenames from file. If a + relative file path is specified, the file + will be searched in the working directory. + The --proto_path option will not affect how + this argument file is searched. Content of + the file will be expanded in the position of + @<filename> as in the argument list. Note + that shell expansion is not applied to the + content of the file (i.e., you cannot use + quotes, wildcards, escapes, commands, etc.). + Each line corresponds to a single argument, + even if it contains spaces. + */ + static string[] s_supportedGenerators = new[] { "cpp", "csharp", "java", + "javanano", "js", "objc", + "php", "python", "ruby" }; + + /// <summary> + /// Code generator. + /// </summary> + [Required] + public string Generator { get; set; } + + /// <summary> + /// Protobuf files to compile. + /// </summary> + [Required] + public ITaskItem[] ProtoBuf { get; set; } + + /// <summary> + /// Directory where protoc dependency files are cached. If provided, dependency + /// output filename is autogenerated from source directory hash and file name. + /// Mutually exclusive with DependencyOut. + /// Switch: --dependency_out (with autogenerated file name). + /// </summary> + public string ProtoDepDir { get; set; } + + /// <summary> + /// Dependency file full name. Mutually exclusive with ProtoDepDir. + /// Autogenerated file name is available in this property after execution. + /// Switch: --dependency_out. + /// </summary> + [Output] + public string DependencyOut { get; set; } + + /// <summary> + /// The directories to search for imports. Directories will be searched + /// in order. If not given, the current working directory is used. + /// Switch: --proto_path. + /// </summary> + public string[] ProtoPath { get; set; } + + /// <summary> + /// Generated code directory. The generator property determines the language. + /// Switch: --GEN-out= (for different generators GEN). + /// </summary> + [Required] + public string OutputDir { get; set; } + + /// <summary> + /// Codegen options. See also OptionsFromMetadata. + /// Switch: --GEN_out= (for different generators GEN). + /// </summary> + public string[] OutputOptions { get; set; } + + /// <summary> + /// Full path to the gRPC plugin executable. If specified, gRPC generation + /// is enabled for the files. + /// Switch: --plugin=protoc-gen-grpc= + /// </summary> + public string GrpcPluginExe { get; set; } + + /// <summary> + /// Generated gRPC directory. The generator property determines the + /// language. If gRPC is enabled but this is not given, OutputDir is used. + /// Switch: --grpc_out= + /// </summary> + public string GrpcOutputDir { get; set; } + + /// <summary> + /// gRPC Codegen options. See also OptionsFromMetadata. + /// --grpc_opt=opt1,opt2=val (comma-separated). + /// </summary> + public string[] GrpcOutputOptions { get; set; } + + /// <summary> + /// List of files written in addition to generated outputs. Includes a + /// single item for the dependency file if written. + /// </summary> + [Output] + public ITaskItem[] AdditionalFileWrites { get; private set; } + + /// <summary> + /// List of language files generated by protoc. Empty unless DependencyOut + /// or ProtoDepDir is set, since the file writes are extracted from protoc + /// dependency output file. + /// </summary> + [Output] + public ITaskItem[] GeneratedFiles { get; private set; } + + // Hide this property from MSBuild, we should never use a shell script. + private new bool UseCommandProcessor { get; set; } + + protected override string ToolName => Platform.IsWindows ? "protoc.exe" : "protoc"; + + // Since we never try to really locate protoc.exe somehow, just try ToolExe + // as the full tool location. It will be either just protoc[.exe] from + // ToolName above if not set by the user, or a user-supplied full path. The + // base class will then resolve the former using system PATH. + protected override string GenerateFullPathToTool() => ToolExe; + + // Log protoc errors with the High priority (bold white in MsBuild, + // printed with -v:n, and shown in the Output windows in VS). + protected override MessageImportance StandardErrorLoggingImportance => MessageImportance.High; + + // Called by base class to validate arguments and make them consistent. + protected override bool ValidateParameters() + { + // Part of proto command line switches, must be lowercased. + Generator = Generator.ToLowerInvariant(); + if (!System.Array.Exists(s_supportedGenerators, g => g == Generator)) + { + Log.LogError("Invalid value for Generator='{0}'. Supported generators: {1}", + Generator, string.Join(", ", s_supportedGenerators)); + } + + if (ProtoDepDir != null && DependencyOut != null) + { + Log.LogError("Properties ProtoDepDir and DependencyOut may not be both specified"); + } + + if (ProtoBuf.Length > 1 && (ProtoDepDir != null || DependencyOut != null)) + { + Log.LogError("Proto compiler currently allows only one input when " + + "--dependency_out is specified (via ProtoDepDir or DependencyOut). " + + "Tracking issue: https://github.com/google/protobuf/pull/3959"); + } + + // Use ProtoDepDir to autogenerate DependencyOut + if (ProtoDepDir != null) + { + DependencyOut = DepFileUtil.GetDepFilenameForProto(ProtoDepDir, ProtoBuf[0].ItemSpec); + } + + if (GrpcPluginExe == null) + { + GrpcOutputOptions = null; + GrpcOutputDir = null; + } + else if (GrpcOutputDir == null) + { + // Use OutputDir for gRPC output if not specified otherwise by user. + GrpcOutputDir = OutputDir; + } + + return !Log.HasLoggedErrors && base.ValidateParameters(); + } + + // Protoc chokes on BOM, naturally. I would! + static readonly Encoding s_utf8WithoutBom = new UTF8Encoding(false); + protected override Encoding ResponseFileEncoding => s_utf8WithoutBom; + + // Protoc takes one argument per line from the response file, and does not + // require any quoting whatsoever. Otherwise, this is similar to the + // standard CommandLineBuilder + class ProtocResponseFileBuilder + { + StringBuilder _data = new StringBuilder(1000); + public override string ToString() => _data.ToString(); + + // If 'value' is not empty, append '--name=value\n'. + public void AddSwitchMaybe(string name, string value) + { + if (!string.IsNullOrEmpty(value)) + { + _data.Append("--").Append(name).Append("=") + .Append(value).Append('\n'); + } + } + + // Add switch with the 'values' separated by commas, for options. + public void AddSwitchMaybe(string name, string[] values) + { + if (values?.Length > 0) + { + _data.Append("--").Append(name).Append("=") + .Append(string.Join(",", values)).Append('\n'); + } + } + + // Add a positional argument to the file data. + public void AddArg(string arg) + { + _data.Append(arg).Append('\n'); + } + }; + + // Called by the base ToolTask to get response file contents. + protected override string GenerateResponseFileCommands() + { + var cmd = new ProtocResponseFileBuilder(); + cmd.AddSwitchMaybe(Generator + "_out", TrimEndSlash(OutputDir)); + cmd.AddSwitchMaybe(Generator + "_opt", OutputOptions); + cmd.AddSwitchMaybe("plugin=protoc-gen-grpc", GrpcPluginExe); + cmd.AddSwitchMaybe("grpc_out", TrimEndSlash(GrpcOutputDir)); + cmd.AddSwitchMaybe("grpc_opt", GrpcOutputOptions); + if (ProtoPath != null) + { + foreach (string path in ProtoPath) + cmd.AddSwitchMaybe("proto_path", TrimEndSlash(path)); + } + cmd.AddSwitchMaybe("dependency_out", DependencyOut); + foreach (var proto in ProtoBuf) + { + cmd.AddArg(proto.ItemSpec); + } + return cmd.ToString(); + } + + // Protoc cannot digest trailing slashes in directory names, + // curiously under Linux, but not in Windows. + static string TrimEndSlash(string dir) + { + if (dir == null || dir.Length <= 1) + { + return dir; + } + string trim = dir.TrimEnd('/', '\\'); + // Do not trim the root slash, drive letter possible. + if (trim.Length == 0) + { + // Slashes all the way down. + return dir.Substring(0, 1); + } + if (trim.Length == 2 && dir.Length > 2 && trim[1] == ':') + { + // We have a drive letter and root, e. g. 'C:\' + return dir.Substring(0, 3); + } + return trim; + } + + // Called by the base class to log tool's command line. + // + // Protoc command file is peculiar, with one argument per line, separated + // by newlines. Unwrap it for log readability into a single line, and also + // quote arguments, lest it look weird and so it may be copied and pasted + // into shell. Since this is for logging only, correct enough is correct. + protected override void LogToolCommand(string cmd) + { + var printer = new StringBuilder(1024); + + // Print 'str' slice into 'printer', wrapping in quotes if contains some + // interesting characters in file names, or if empty string. The list of + // characters requiring quoting is not by any means exhaustive; we are + // just striving to be nice, not guaranteeing to be nice. + var quotable = new[] { ' ', '!', '$', '&', '\'', '^' }; + void PrintQuoting(string str, int start, int count) + { + bool wrap = count == 0 || str.IndexOfAny(quotable, start, count) >= 0; + if (wrap) printer.Append('"'); + printer.Append(str, start, count); + if (wrap) printer.Append('"'); + } + + for (int ib = 0, ie; (ie = cmd.IndexOf('\n', ib)) >= 0; ib = ie + 1) + { + // First line only contains both the program name and the first switch. + // We can rely on at least the '--out_dir' switch being always present. + if (ib == 0) + { + int iep = cmd.IndexOf(" --"); + if (iep > 0) + { + PrintQuoting(cmd, 0, iep); + ib = iep + 1; + } + } + printer.Append(' '); + if (cmd[ib] == '-') + { + // Print switch unquoted, including '=' if any. + int iarg = cmd.IndexOf('=', ib, ie - ib); + if (iarg < 0) + { + // Bare switch without a '='. + printer.Append(cmd, ib, ie - ib); + continue; + } + printer.Append(cmd, ib, iarg + 1 - ib); + ib = iarg + 1; + } + // A positional argument or switch value. + PrintQuoting(cmd, ib, ie - ib); + } + + base.LogToolCommand(printer.ToString()); + } + + // Main task entry point. + public override bool Execute() + { + base.UseCommandProcessor = false; + + bool ok = base.Execute(); + if (!ok) + { + return false; + } + + // Read dependency output file from the compiler to retrieve the + // definitive list of created files. Report the dependency file + // itself as having been written to. + if (DependencyOut != null) + { + string[] outputs = DepFileUtil.ReadDependencyOutputs(DependencyOut, Log); + if (HasLoggedErrors) + { + return false; + } + + GeneratedFiles = new ITaskItem[outputs.Length]; + for (int i = 0; i < outputs.Length; i++) + { + GeneratedFiles[i] = new TaskItem(outputs[i]); + } + AdditionalFileWrites = new ITaskItem[] { new TaskItem(DependencyOut) }; + } + + return true; + } + }; +} diff --git a/src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs b/src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs new file mode 100644 index 0000000000..915be3421e --- /dev/null +++ b/src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs @@ -0,0 +1,86 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.Collections.Generic; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Grpc.Tools +{ + public class ProtoCompilerOutputs : Task + { + /// <summary> + /// Code generator. Currently supported are "csharp", "cpp". + /// </summary> + [Required] + public string Generator { get; set; } + + /// <summary> + /// All Proto files in the project. The task computes possible outputs + /// from these proto files, and returns them in the PossibleOutputs list. + /// Not all of these might be actually produced by protoc; this is dealt + /// with later in the ProtoCompile task which returns the list of + /// files actually produced by the compiler. + /// </summary> + [Required] + public ITaskItem[] ProtoBuf { get; set; } + + /// <summary> + /// Output items per each potential output. We do not look at existing + /// cached dependency even if they exist, since file may be refactored, + /// affecting whether or not gRPC code file is generated from a given proto. + /// Instead, all potentially possible generated sources are collected. + /// It is a wise idea to generate empty files later for those potentials + /// that are not actually created by protoc, so the dependency checks + /// result in a minimal recompilation. The Protoc task can output the + /// list of files it actually produces, given right combination of its + /// properties. + /// Output items will have the Source metadata set on them: + /// <ItemName Include="MyProto.cs" Source="my_proto.proto" /> + /// </summary> + [Output] + public ITaskItem[] PossibleOutputs { get; private set; } + + public override bool Execute() + { + var generator = GeneratorServices.GetForLanguage(Generator, Log); + if (generator == null) + { + // Error already logged, just return. + return false; + } + + // Get language-specific possible output. The generator expects certain + // metadata be set on the proto item. + var possible = new List<ITaskItem>(); + foreach (var proto in ProtoBuf) + { + var outputs = generator.GetPossibleOutputs(proto); + foreach (string output in outputs) + { + var ti = new TaskItem(output); + ti.SetMetadata(Metadata.Source, proto.ItemSpec); + possible.Add(ti); + } + } + PossibleOutputs = possible.ToArray(); + + return !Log.HasLoggedErrors; + } + }; +} diff --git a/src/csharp/Grpc.Tools/ProtoReadDependencies.cs b/src/csharp/Grpc.Tools/ProtoReadDependencies.cs new file mode 100644 index 0000000000..963837e8b7 --- /dev/null +++ b/src/csharp/Grpc.Tools/ProtoReadDependencies.cs @@ -0,0 +1,78 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using System.Collections.Generic; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Grpc.Tools +{ + public class ProtoReadDependencies : Task + { + /// <summary> + /// The collection is used to collect possible additional dependencies + /// of proto files cached under ProtoDepDir. + /// </summary> + [Required] + public ITaskItem[] ProtoBuf { get; set; } + + /// <summary> + /// Directory where protoc dependency files are cached. + /// </summary> + [Required] + public string ProtoDepDir { get; set; } + + /// <summary> + /// Additional items that a proto file depends on. This list may include + /// extra dependencies; we do our best to include as few extra positives + /// as reasonable to avoid missing any. The collection item is the + /// dependency, and its Source metadatum is the dependent proto file, like + /// <ItemName Include="/usr/include/proto/wrapper.proto" + /// Source="my_proto.proto" /> + /// </summary> + [Output] + public ITaskItem[] Dependencies { get; private set; } + + public override bool Execute() + { + // Read dependency files, where available. There might be none, + // just use a best effort. + if (ProtoDepDir != null) + { + var dependencies = new List<ITaskItem>(); + foreach (var proto in ProtoBuf) + { + string[] deps = DepFileUtil.ReadDependencyInputs(ProtoDepDir, proto.ItemSpec, Log); + foreach (string dep in deps) + { + var ti = new TaskItem(dep); + ti.SetMetadata(Metadata.Source, proto.ItemSpec); + dependencies.Add(ti); + } + } + Dependencies = dependencies.ToArray(); + } + else + { + Dependencies = new ITaskItem[0]; + } + + return !Log.HasLoggedErrors; + } + }; +} diff --git a/src/csharp/Grpc.Tools/ProtoToolsPlatform.cs b/src/csharp/Grpc.Tools/ProtoToolsPlatform.cs new file mode 100644 index 0000000000..aed8a66339 --- /dev/null +++ b/src/csharp/Grpc.Tools/ProtoToolsPlatform.cs @@ -0,0 +1,63 @@ +#region Copyright notice and license + +// Copyright 2018 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. + +#endregion + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Grpc.Tools +{ + /// <summary> + /// A helper task to resolve actual OS type and bitness. + /// </summary> + public class ProtoToolsPlatform : Task + { + /// <summary> + /// Return one of 'linux', 'macosx' or 'windows'. + /// If the OS is unknown, the property is not set. + /// </summary> + [Output] + public string Os { get; set; } + + /// <summary> + /// Return one of 'x64' or 'x86'. + /// If the CPU is unknown, the property is not set. + /// </summary> + [Output] + public string Cpu { get; set; } + + + public override bool Execute() + { + switch (Platform.Os) + { + case Platform.OsKind.Linux: Os = "linux"; break; + case Platform.OsKind.MacOsX: Os = "macosx"; break; + case Platform.OsKind.Windows: Os = "windows"; break; + default: Os = ""; break; + } + + switch (Platform.Cpu) + { + case Platform.CpuKind.X86: Cpu = "x86"; break; + case Platform.CpuKind.X64: Cpu = "x64"; break; + default: Cpu = ""; break; + } + return true; + } + }; +} diff --git a/src/csharp/Grpc.Tools/build/Grpc.Tools.props b/src/csharp/Grpc.Tools/build/Grpc.Tools.props new file mode 100644 index 0000000000..dbcd8bf494 --- /dev/null +++ b/src/csharp/Grpc.Tools/build/Grpc.Tools.props @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> + </PropertyGroup> + + <!-- Name of this file must match package ID. --> + <!-- Packages will be split later. --> + <Import Project="_grpc/_Grpc.Tools.props"/> + <Import Project="_protobuf/Google.Protobuf.Tools.props"/> +</Project> diff --git a/src/csharp/Grpc.Tools/build/Grpc.Tools.targets b/src/csharp/Grpc.Tools/build/Grpc.Tools.targets new file mode 100644 index 0000000000..c0a5b1e2c5 --- /dev/null +++ b/src/csharp/Grpc.Tools/build/Grpc.Tools.targets @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> + </PropertyGroup> + + <!-- Name of this file must match package ID. --> + <!-- Packages will be split later. --> + <Import Project="_grpc/_Grpc.Tools.targets"/> + <Import Project="_protobuf/Google.Protobuf.Tools.targets"/> +</Project> diff --git a/src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml b/src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml new file mode 100644 index 0000000000..54468eb5ef --- /dev/null +++ b/src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml @@ -0,0 +1,30 @@ +<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties"> + <Rule Name="ProtoBuf" + DisplayName="File Properties" + PageTemplate="generic" + Description="File Properties" + OverrideMode="Extend"> + <Rule.DataSource> + <DataSource Persistence="ProjectFile" Label="Configuration" ItemType="ProtoBuf" + HasConfigurationCondition="false" SourceOfDefaultValue="AfterContext" /> + </Rule.DataSource> + + <Rule.Categories> + <Category Name="gRPC" DisplayName="gRPC" /> + </Rule.Categories> + + <EnumProperty Name="GrpcServices" DisplayName="gRPC Stub Classes" + Category="gRPC" Default="Both" + Description="Generate gRPC server and client stub classes."> + <EnumValue Name="Both" DisplayName="Client and Server" IsDefault="true" /> + <EnumValue Name="Client" DisplayName="Client only" /> + <EnumValue Name="Server" DisplayName="Server only" /> + <EnumValue Name="None" DisplayName="Do not generate" /> + <EnumProperty.DataSource> + <DataSource ItemType="ProtoBuf" SourceOfDefaultValue="AfterContext" + PersistenceStyle="Attribute" /> + </EnumProperty.DataSource> + </EnumProperty> + + </Rule> +</ProjectSchemaDefinitions> diff --git a/src/csharp/Grpc.Tools/build/_grpc/README b/src/csharp/Grpc.Tools/build/_grpc/README new file mode 100644 index 0000000000..4a7204b9ff --- /dev/null +++ b/src/csharp/Grpc.Tools/build/_grpc/README @@ -0,0 +1,3 @@ +TODO(kkm): These file will go into Grpc.Tools/build after package split. + Remove leading underscores from file names; they are hiding the + files from some NuGet versions which pull them into project. diff --git a/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props new file mode 100644 index 0000000000..8ce07c48ab --- /dev/null +++ b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props @@ -0,0 +1,6 @@ +<?xml version="1.0"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> + </PropertyGroup> +</Project> diff --git a/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets new file mode 100644 index 0000000000..5f76c03ce5 --- /dev/null +++ b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> + <gRPC_PluginFileName Condition=" '$(gRPC_PluginFileName)' == '' and '$(Language)' == 'C#' ">grpc_csharp_plugin</gRPC_PluginFileName> + </PropertyGroup> + + <ItemGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' "> + <!-- Extend property pages with gRPC properties. --> + <PropertyPageSchema Include="$(MSBuildThisFileDirectory)Grpc.CSharp.xml"> + <Context>File;BrowseObject</Context> + </PropertyPageSchema> + </ItemGroup> + + <ItemDefinitionGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' "> + <ProtoBuf> + <GrpcServices Condition=" '%(ProtoBuf.GrpcServices)' == '' ">Both</GrpcServices> + </ProtoBuf> + </ItemDefinitionGroup> + + <!-- This target is invoked in a C# project, or can be called in a customized project. --> + <Target Name="gRPC_ResolvePluginFullPath" AfterTargets="Protobuf_ResolvePlatform"> + <PropertyGroup> + <!-- TODO(kkm): Do not use Protobuf_PackagedToolsPath, roll gRPC's own. --> + <!-- TODO(kkm): Do not package windows x64 builds (#13098). --> + <gRPC_PluginFullPath Condition=" '$(gRPC_PluginFullPath)' == '' and '$(Protobuf_ToolsOs)' == 'windows' " + >$(Protobuf_PackagedToolsPath)\$(Protobuf_ToolsOs)_x86\$(gRPC_PluginFileName).exe</gRPC_PluginFullPath> + <gRPC_PluginFullPath Condition=" '$(gRPC_PluginFullPath)' == '' " + >$(Protobuf_PackagedToolsPath)/$(Protobuf_ToolsOs)_$(Protobuf_ToolsCpu)/$(gRPC_PluginFileName)</gRPC_PluginFullPath> + </PropertyGroup> + </Target> + + <Target Name="_gRPC_PrepareCompileOptions" AfterTargets="Protobuf_PrepareCompileOptions"> + <ItemGroup Condition=" '$(Language)' == 'C#' "> + <Protobuf_Compile Condition=" %(Protobuf_Compile.GrpcServices) != 'None' "> + <GrpcPluginExe Condition=" '%(Protobuf_Compile.GrpcPluginExe)' == '' ">$(gRPC_PluginFullPath)</GrpcPluginExe> + <GrpcOutputDir Condition=" '%(Protobuf_Compile.GrpcOutputDir)' == '' " >%(Protobuf_Compile.OutputDir)</GrpcOutputDir> + <_GrpcOutputOptions Condition=" '%(Protobuf_Compile.Access)' == 'Internal' ">%(Protobuf_Compile._GrpcOutputOptions);internal_access</_GrpcOutputOptions> + </Protobuf_Compile> + <Protobuf_Compile Condition=" '%(Protobuf_Compile.GrpcServices)' == 'Client' "> + <_GrpcOutputOptions>%(Protobuf_Compile._GrpcOutputOptions);no_server</_GrpcOutputOptions> + </Protobuf_Compile> + <Protobuf_Compile Condition=" '%(Protobuf_Compile.GrpcServices)' == 'Server' "> + <_GrpcOutputOptions>%(Protobuf_Compile._GrpcOutputOptions);no_client</_GrpcOutputOptions> + </Protobuf_Compile> + </ItemGroup> + </Target> +</Project> diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props new file mode 100644 index 0000000000..9f2d8bb4b5 --- /dev/null +++ b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props @@ -0,0 +1,24 @@ +<?xml version="1.0"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> + + <!-- Revision number of this package conventions (as if "API" version). --> + <Protobuf_ToolingRevision>1</Protobuf_ToolingRevision> + + <!-- TODO(kkm): Remove one "../" when separating packages. --> + <!-- TODO(kkm): Do not place non-tools under tools/, use build/native/bin/. --> + <Protobuf_PackagedToolsPath>$( [System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../../tools) )</Protobuf_PackagedToolsPath> + <Protobuf_StandardImportsPath>$( [System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../native/include) )</Protobuf_StandardImportsPath> + </PropertyGroup> + + <!-- NET SDK projects only: include proto files by default. Other project + types are not setting or using $(EnableDefaultItems). + Note that MSBuild evaluates all ItemGroups and their conditions in the + final pass over the build script, so properties like EnableDefaultProtoBufItems + here can be changed later in the project. --> + <ItemGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' "> + <ProtoBuf Include="**/*.proto" + Condition=" '$(EnableDefaultItems)' == 'true' and '$(EnableDefaultProtoBufItems)' == 'true' " /> + </ItemGroup> +</Project> diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets new file mode 100644 index 0000000000..1d233d23a8 --- /dev/null +++ b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets @@ -0,0 +1,384 @@ +<?xml version="1.0"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> + <!-- We allow a non-C# generator be set by the user, but skip adding outputs to Compile in this case. --> + <Protobuf_Generator Condition=" '$(Protobuf_Generator)' == '' and '$(Language)' == 'C#' ">CSharp</Protobuf_Generator> + <!-- Configuration is passing the smoke test. --> + <Protobuf_ProjectSupported Condition=" '$(Protobuf_Generator)' != '' ">true</Protobuf_ProjectSupported> + <_Protobuf_MsBuildAssembly Condition=" '$(MSBuildRuntimeType)' == 'Core' ">netstandard1.3\Protobuf.MSBuild.dll</_Protobuf_MsBuildAssembly> + <_Protobuf_MsBuildAssembly Condition=" '$(MSBuildRuntimeType)' != 'Core' ">net45\Protobuf.MSBuild.dll</_Protobuf_MsBuildAssembly> + </PropertyGroup> + + <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoToolsPlatform" /> + <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoCompilerOutputs" /> + <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoReadDependencies" /> + <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoCompile" /> + + <PropertyGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' "> + <Protobuf_IntermediatePath Condition=" '$(Protobuf_IntermediatePath)' == '' ">$(IntermediateOutputPath)</Protobuf_IntermediatePath> + <Protobuf_OutputPath Condition=" '$(Protobuf_OutputPath)' == '' ">$(Protobuf_IntermediatePath)</Protobuf_OutputPath> + <Protobuf_DepFilesPath Condition=" '$(Protobuf_DepFilesPath)' == '' ">$(Protobuf_IntermediatePath)</Protobuf_DepFilesPath> + </PropertyGroup> + + <ItemDefinitionGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' "> + <ProtoBuf> + <Access Condition="'%(ProtoBuf.Access)' == '' ">Public</Access> + <ProtoCompile Condition="'%(ProtoBuf.ProtoCompile)' == '' ">True</ProtoCompile> + <ProtoRoot Condition="'%(ProtoBuf.ProtoRoot)' == '' " /> + <CompileOutputs Condition="'%(ProtoBuf.CompileOutputs)' == ''">True</CompileOutputs> + <OutputDir Condition="'%(ProtoBuf.OutputDir)' == '' ">$(Protobuf_OutputPath)</OutputDir> + </ProtoBuf> + </ItemDefinitionGroup> + + <ItemGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' "> + <PropertyPageSchema Include="$(MSBuildThisFileDirectory)Protobuf.CSharp.xml"> + <Context>File;BrowseObject</Context> + </PropertyPageSchema> + <AvailableItemName Include="ProtoBuf" /> + </ItemGroup> + + <PropertyGroup> + <!-- NET SDK: by default, do not include proto files in the directory. + Current Microsoft's recommendation is against globbing: + https://docs.microsoft.com/en-us/dotnet/core/tools/csproj#recommendation --> + <EnableDefaultProtoBufItems Condition=" '$(EnableDefaultProtoBufItems)' == '' ">false</EnableDefaultProtoBufItems> + </PropertyGroup> + + <!-- Check configuration sanity before build. --> + <Target Name="_Protobuf_SanityCheck" BeforeTargets="PrepareForBuild"> + <Error + Condition=" '$(Protobuf_ProjectSupported)' != 'true' " + Text="Google.Protobuf.Tools proto compilation is only supported by default in a C# project (extension .csproj)" /> + </Target> + + <!--================================================================================ + Tool path resolution + =================================================================================--> + + <!-- Extension point for plugin packages: use Protobuf_ToolsOs and Protobuf_ToolsCpu + to resolve executable. Either or both may be blank, however, if resolution + fails; do check them before using. --> + <Target Name="Protobuf_ResolvePlatform"> + <ProtoToolsPlatform> + <Output TaskParameter="Os" PropertyName="_Protobuf_ToolsOs"/> + <Output TaskParameter="Cpu" PropertyName="_Protobuf_ToolsCpu"/> + </ProtoToolsPlatform> + + <PropertyGroup> + <!-- First try environment variable. --> + <Protobuf_ToolsOs>$(PROTOBUF_TOOLS_OS)</Protobuf_ToolsOs> + <Protobuf_ToolsCpu>$(PROTOBUF_TOOLS_CPU)</Protobuf_ToolsCpu> + <Protobuf_ProtocFullPath>$(PROTOBUF_PROTOC)</Protobuf_ProtocFullPath> + + <!-- Next try OS and CPU resolved by ProtoToolsPlatform. --> + <Protobuf_ToolsOs Condition=" '$(Protobuf_ToolsOs)' == '' ">$(_Protobuf_ToolsOs)</Protobuf_ToolsOs> + <Protobuf_ToolsCpu Condition=" '$(Protobuf_ToolsCpu)' == '' ">$(_Protobuf_ToolsCpu)</Protobuf_ToolsCpu> + <!-- TODO(kkm): Do not package windows x64 builds (#13098). --> + <Protobuf_ProtocFullPath Condition=" '$(Protobuf_ProtocFullPath)' == '' and '$(Protobuf_ToolsOs)' == 'windows' " + >$(Protobuf_PackagedToolsPath)\$(Protobuf_ToolsOs)_x86\protoc.exe</Protobuf_ProtocFullPath> + <Protobuf_ProtocFullPath Condition=" '$(Protobuf_ProtocFullPath)' == '' " + >$(Protobuf_PackagedToolsPath)/$(Protobuf_ToolsOs)_$(Protobuf_ToolsCpu)/protoc</Protobuf_ProtocFullPath> + </PropertyGroup> + + <Error Condition=" '$(DesignTimeBuild)' != 'true' and '$(PROTOBUF_PROTOC)' == '' + and ( '$(Protobuf_ToolsOs)' == '' or '$(Protobuf_ToolsCpu)' == '' ) " + Text="Google.Protobuf.Tools cannot determine host OS and CPU. Use environment variables PROTOBUF_TOOLS_OS={linux|macosx|windows} and PROTOBUF_TOOLS_CPU={x86|x64} to try the closest match to your system. You may also set PROTOBUF_PROTOC to specify full path to the host-provided compiler (v3.5+ is required)." /> + </Target> + + <!--================================================================================ + Proto compilation + =================================================================================--> + + <!-- Extension points. --> + <Target Name="Protobuf_BeforeCompile" /> + <Target Name="Protobuf_AfterCompile" /> + + <!-- Main compile sequence. Certain steps are gated by the value $(DesignTimeBuild), + so the sequence is good for either design time or build time. --> + <Target Name="Protobuf_Compile" + Condition=" '@(ProtoBuf)' != '' " + DependsOnTargets=" Protobuf_BeforeCompile; + Protobuf_ResolvePlatform; + _Protobuf_SelectFiles; + Protobuf_PrepareCompile; + _Protobuf_AugmentLanguageCompile; + _Protobuf_CoreCompile; + Protobuf_ReconcileOutputs; + Protobuf_AfterCompile" /> + + <!-- Do proto compilation by default in a C# project. In other types, the user invoke + Protobuf_Compile directly where required. --> + <!-- TODO(kkm): Do shared compile in outer multitarget project? --> + <Target Name="_Protobuf_Compile_BeforeCsCompile" + BeforeTargets="BeforeCompile" + DependsOnTargets="Protobuf_Compile" + Condition=" '$(Language)' == 'C#' " /> + + <Target Name="_Protobuf_SelectFiles"> + <!-- Guess .proto root for the files. Whenever the root is set for a file explicitly, + leave it as is. Otherwise, for files under the project directory, set the root + to "." for the project's directory, as it is the current when compiling; for the + files outside of project directory, use each .proto file's directory as the root. --> + <FindUnderPath Path="$(MSBuildProjectDirectory)" + Files="@(ProtoBuf->WithMetadataValue('ProtoRoot',''))"> + <Output TaskParameter="InPath" ItemName="_Protobuf_NoRootInProject"/> + <Output TaskParameter="OutOfPath" ItemName="_Protobuf_NoRootElsewhere"/> + </FindUnderPath> + <ItemGroup> + <!-- Files with explicit metadata. --> + <Protobuf_Compile Include="@(ProtoBuf->HasMetadata('ProtoRoot'))" /> + <!-- In-project files will have ProtoRoot='.'. --> + <Protobuf_Compile Include="@(_Protobuf_NoRootInProject)"> + <ProtoRoot>.</ProtoRoot> + </Protobuf_Compile> + <!-- Out-of-project files will have respective ProtoRoot='%(RelativeDir)'. --> + <Protobuf_Compile Include="@(_Protobuf_NoRootElsewhere)"> + <ProtoRoot>%(RelativeDir)</ProtoRoot> + </Protobuf_Compile> + <!-- Remove files not for compile. --> + <Protobuf_Compile Remove="@(Protobuf_Compile)" Condition=" !%(ProtoCompile) " /> + <!-- Ensure invariant Source=%(Identity). --> + <Protobuf_Compile> + <Source>%(Identity)</Source> + </Protobuf_Compile> + </ItemGroup> + </Target> + + <!-- Extension point for non-C# project. Protobuf_Generator should be supported + by the ProtoCompile task, but we skip inferring expected outputs. All proto + files will be always recompiled with a warning, unless you add expectations + to the Protobuf_ExpectedOutputs collection. + + All inferred ExpectedOutputs will be added to code compile (C#) in a C# project + by default. This is controlled per-proto by the CompileOutputs metadata. --> + <Target Name="Protobuf_PrepareCompile" Condition=" '@(Protobuf_Compile)' != '' "> + <!-- Predict expected names. --> + <ProtoCompilerOutputs Condition=" '$(Language)' == 'C#' " + ProtoBuf="@(Protobuf_Compile)" + Generator="$(Protobuf_Generator)"> + <Output TaskParameter="PossibleOutputs" ItemName="Protobuf_ExpectedOutputs" /> + </ProtoCompilerOutputs> + <!-- Read any dependency files from previous compiles. --> + <ProtoReadDependencies Condition=" '$(Protobuf_DepFilesPath)' != '' and '$(DesignTimeBuild)' != 'true' " + ProtoBuf="@(Protobuf_Compile)" + ProtoDepDir="$(Protobuf_DepFilesPath)" > + <Output TaskParameter="Dependencies" ItemName="Protobuf_Dependencies" /> + </ProtoReadDependencies> + </Target> + + <!-- Add all expected outputs, and only these, to language compile. --> + <Target Name="_Protobuf_AugmentLanguageCompile" + DependsOnTargets="_Protobuf_EnforceInvariants" + Condition=" '$(Language)' == 'C#' "> + <ItemGroup> + <_Protobuf_CodeCompile Include="@(Protobuf_ExpectedOutputs->Distinct())" + Condition=" '%(Source)' != '' and '@(Protobuf_Compile->WithMetadataValue('CompileOutputs', 'true'))' != '' " /> + <Compile Include="@(_Protobuf_CodeCompile)" /> + </ItemGroup> + </Target> + + <!-- These invariants must be kept for compile up-to-date check to work. --> + <Target Name="_Protobuf_EnforceInvariants"> + <!-- Enforce Source=Identity on proto files. The 'Source' metadata is used as a common + key to match dependencies/expected outputs in the lists for up-to-date checks. --> + <ItemGroup> + <Protobuf_Compile> + <Source>%(Identity)</Source> + </Protobuf_Compile> + </ItemGroup> + + <!-- Remove possible output and dependency declarations that have no Source set, or those + not matching any proto marked for compilation. --> + <ItemGroup> + <Protobuf_ExpectedOutputs Remove="@(Protobuf_ExpectedOutputs)" Condition=" '%(Protobuf_ExpectedOutputs.Source)' == '' " /> + <Protobuf_ExpectedOutputs Remove="@(Protobuf_ExpectedOutputs)" Condition=" '%(Source)' != '' and '@(Protobuf_Compile)' == '' " /> + <Protobuf_Dependencies Remove="@(Protobuf_Dependencies)" Condition=" '%(Protobuf_Dependencies.Source)' == '' " /> + <Protobuf_Dependencies Remove="@(Protobuf_Dependencies)" Condition=" '%(Source)' != '' and '@(Protobuf_Compile)' == '' " /> + </ItemGroup> + </Target> + + <!-- Gather files with and without known outputs, separately. --> + <Target Name="_Protobuf_GatherStaleFiles" + Condition=" '@(Protobuf_Compile)' != '' " + DependsOnTargets="_Protobuf_EnforceInvariants; _Protobuf_GatherStaleSimple; _Protobuf_GatherStaleBatched"> + <ItemGroup> + <!-- Drop outputs from MSBuild inference (they won't have the '_Exec' metadata). --> + <_Protobuf_OutOfDateProto Remove="@(_Protobuf_OutOfDateProto->WithMetadataValue('_Exec',''))" /> + </ItemGroup> + </Target> + + <Target Name="_Protobuf_GatherStaleSimple"> + <!-- Simple selection: always compile files that have no declared outputs (but warn below). --> + <ItemGroup> + <_Protobuf_OutOfDateProto Include="@(Protobuf_Compile)" + Condition = " '%(Source)' != '' and '@(Protobuf_ExpectedOutputs)' == '' "> + <_Exec>true</_Exec> + </_Protobuf_OutOfDateProto> + </ItemGroup> + + <!-- You are seeing this warning because there was no Protobuf_ExpectedOutputs items with + their Source attribute pointing to the proto files listed in the warning. Such files + will be recompiled on every build, as there is nothing to run up-to-date check against. + Set Protobuf_NoOrphanWarning to 'true' to suppress if this is what you want. --> + <Warning Condition=" '@(_Protobuf_OutOfDateProto)' != '' and '$(Protobuf_NoOrphanWarning)' != 'true' " + Text="The following files have no known outputs, and will be always recompiled as if out-of-date: @(_Protobuf_Orphans->' %(Identity)', '')" /> + </Target> + + <Target Name="_Protobuf_GatherStaleBatched" + Inputs="@(Protobuf_Compile);%(Source);@(Protobuf_Dependencies);$(MSBuildAllProjects)" + Outputs="@(Protobuf_ExpectedOutputs)" > + <!-- The '_Exec' metadatum is set to distinguish really executed items from those MSBuild so + "helpfully" infers in a bucketed task. For the same reason, cannot use the intrinsic + ItemGroup task here. --> + <CreateItem Include="@(Protobuf_Compile)" AdditionalMetadata="_Exec=true"> + <Output TaskParameter="Include" ItemName="_Protobuf_OutOfDateProto"/> + </CreateItem> + </Target> + + <!-- Extension point: Plugins massage metadata into recognized metadata + values passed to the ProtoCompile task. --> + <Target Name="Protobuf_PrepareCompileOptions" Condition=" '@(Protobuf_Compile)' != '' "> + <ItemGroup> + <Protobuf_Compile> + <_OutputOptions Condition=" '%(Protobuf_Compile.Access)' == 'Internal' ">%(Protobuf_Compile._OutputOptions);internal_access</_OutputOptions> + </Protobuf_Compile> + </ItemGroup> + </Target> + + <Target Name="_Protobuf_CoreCompile" + Condition=" '$(DesignTimeBuild)' != 'true' " + DependsOnTargets="Protobuf_PrepareCompileOptions;_Protobuf_GatherStaleFiles"> + <!-- Ensure output directories. --> + <MakeDir Directories="%(_Protobuf_OutOfDateProto.OutputDir)" /> + <MakeDir Directories="%(_Protobuf_OutOfDateProto.GrpcOutputDir)" /> + <MakeDir Directories="$(Protobuf_DepFilesPath)" /> + + <!-- Force output to the current directory if the user has set it to empty. --> + <ItemGroup> + <_Protobuf_OutOfDateProto> + <OutputDir Condition=" '%(OutputDir)' == '' ">.</OutputDir> + </_Protobuf_OutOfDateProto> + </ItemGroup> + + <ProtoCompile Condition=" '@(_Protobuf_OutOfDateProto)' != '' " + ToolExe="$(Protobuf_ProtocFullPath)" + Generator="$(Protobuf_Generator)" + ProtoBuf="%(_Protobuf_OutOfDateProto.Source)" + ProtoPath="%(_Protobuf_OutOfDateProto.AdditionalImportDirs);$(Protobuf_StandardImportsPath);%(_Protobuf_OutOfDateProto.ProtoRoot)" + ProtoDepDir="$(Protobuf_DepFilesPath)" + OutputDir="%(_Protobuf_OutOfDateProto.OutputDir)" + OutputOptions="%(_Protobuf_OutOfDateProto._OutputOptions)" + GrpcPluginExe="%(_Protobuf_OutOfDateProto.GrpcPluginExe)" + GrpcOutputDir="%(_Protobuf_OutOfDateProto.GrpcOutputDir)" + GrpcOutputOptions="%(_Protobuf_OutOfDateProto._GrpcOutputOptions)" + > + <Output TaskParameter="GeneratedFiles" ItemName="_Protobuf_GeneratedFiles"/> + </ProtoCompile> + + <!-- Compute files expected but not in fact produced by protoc. --> + <ItemGroup Condition=" '@(_Protobuf_OutOfDateProto)' != '' "> + <Protobuf_ExpectedNotGenerated Include="@(Protobuf_ExpectedOutputs)" + Condition=" '%(Source)' != '' and '@(_Protobuf_OutOfDateProto)' != '' " /> + <Protobuf_ExpectedNotGenerated Remove="@(_Protobuf_GeneratedFiles)" /> + </ItemGroup> + </Target> + + <!-- Extension point. Plugins and/or unsupported projects may take special care of the + Protobuf_ExpectedNotGenerated list in BeforeTargets. We just silently create the + missing outputs so that out-of-date checks work (we do not add them to language + compile though). You can empty this collection in your Before targets to do nothing. + The target is not executed if the proto compiler is not executed. --> + <Target Name="Protobuf_ReconcileOutputs" + Condition=" '$(DesignTimeBuild)' != 'true' "> + <!-- Warn about unexpected/missing files outside object file directory only. + This should have happened because build was incorrectly customized. --> + <FindUnderPath Path="$(BaseIntermediateOutputPath)" Files="@(Protobuf_ExpectedNotGenerated)"> + <Output TaskParameter="InPath" ItemName="_Protobuf_ExpectedNotGeneratedInTemp"/> + <Output TaskParameter="OutOfPath" ItemName="_Protobuf_ExpectedNotGeneratedElsewhere"/> + </FindUnderPath> + + <!-- Prevent unnecessary recompilation by silently creating empty files. This probably + has happened because a proto file with an rpc service was processed by the gRPC + plugin, and the user did not set GrpcOutput to None. When we treat outputs as + transient, we can do it permissively. --> + <Touch Files="@(_Protobuf_ExpectedNotGeneratedInTemp)" AlwaysCreate="true" /> + + <!-- Also create empty files outside of the intermediate directory, if the user wants so. --> + <Touch Files="@(_Protobuf_ExpectedNotGeneratedElsewhere)" AlwaysCreate="true" + Condition=" '$(Protobuf_TouchMissingExpected)' == 'true' "/> + + <!-- You are seeing this warning because there were some Protobuf_ExpectedOutputs items + (outside of the transient directory under obj/) not in fact produced by protoc. --> + <Warning Condition=" '@(_Protobuf_ExpectedNotGeneratedElsewhere)' != '' and $(Protobuf_NoWarnMissingExpected) != 'true' " + Text="Some expected protoc outputs were not generated. @(_Protobuf_ExpectedNotGeneratedElsewhere->' %(Identity)', '')" /> + </Target> + + <!--================================================================================ + Proto cleanup + =================================================================================--> + + <!-- We fully support cleanup only in a C# project. If extending the build for other + generators/plugins, then mostly roll your own. --> + + <!-- Extension points. --> + <Target Name="Protobuf_BeforeClean" /> + <Target Name="Protobuf_AfterClean" /> + + <!-- Main cleanup sequence. --> + <Target Name="Protobuf_Clean" + Condition=" '@(ProtoBuf)' != '' " + DependsOnTargets=" Protobuf_BeforeClean; + Protobuf_PrepareClean; + _Protobuf_CoreClean; + Protobuf_AfterClean" /> + + <!-- Do proto cleanup by default in a C# project. In other types, the user should + invoke Protobuf_Clean directly if required. --> + <Target Name="_Protobuf_Clean_AfterCsClean" + AfterTargets="CoreClean" + DependsOnTargets="Protobuf_Clean" + Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' " /> + + <!-- Extension point for non-C# project. ProtoCompilerOutputs is not invoked for + non-C# projects, since inferring protoc outputs is required, so this is a + no-op in other project types. In your extension target populate the + Protobuf_ExpectedOutputs with all possible output. An option is to include + all existing outputs using Include with a wildcard, if you know where to look. + + Note this is like Protobuf_PrepareCompile, but uses @(Protobuf) regardless + of the Compile metadata, to remove all possible outputs. Plugins should err + on the side of overextending the Protobuf_ExpectedOutputs here. + + All ExpectedOutputs will be removed. --> + <Target Name="Protobuf_PrepareClean" Condition=" '@(Protobuf)' != '' "> + <!-- Predict expected names. --> + <ProtoCompilerOutputs Condition=" '$(Language)' == 'C#' " + ProtoBuf="@(Protobuf)" + Generator="$(Protobuf_Generator)"> + <Output TaskParameter="PossibleOutputs" ItemName="Protobuf_ExpectedOutputs" /> + </ProtoCompilerOutputs> + </Target> + + <Target Name="_Protobuf_CoreClean"> + <ItemGroup> + <_Protobuf_Protodep Include="$(Protobuf_DepFilesPath)*.protodep" /> + </ItemGroup> + <Delete Files="@(Protobuf_ExpectedOutputs);@(_Protobuf_Protodep)" TreatErrorsAsWarnings="true" /> + </Target> + + <!--================================================================================ + Design-time support + =================================================================================--> + + <!-- Add all .proto files to the SourceFilesProjectOutputGroupOutput, so that: + * Visual Studio triggers a build when any of them changed; + * The Pack target includes .proto files into the source package. --> + <Target Name="_Protobuf_SourceFilesProjectOutputGroup" + BeforeTargets="SourceFilesProjectOutputGroup" + Condition=" '@(ProtoBuf)' != '' " > + <ItemGroup> + <SourceFilesProjectOutputGroupOutput Include="@(ProtoBuf->'%(FullPath)')" /> + </ItemGroup> + </Target> +</Project> diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml b/src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml new file mode 100644 index 0000000000..2c41fbcbd0 --- /dev/null +++ b/src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml @@ -0,0 +1,99 @@ +<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties"> + <FileExtension Name=".proto" + ContentType="ProtoFile" /> + + <ContentType Name="ProtoFile" + DisplayName="Protocol buffer definitions file" + ItemType="ProtoBuf" /> + + <ItemType Name="ProtoBuf" + DisplayName="Protobuf compiler" /> + + <Rule Name="ProtoBuf" + DisplayName="File Properties" + PageTemplate="generic" + Description="File Properties" + OverrideMode="Extend"> + <Rule.DataSource> + <DataSource Persistence="ProjectFile" Label="Configuration" ItemType="ProtoBuf" + HasConfigurationCondition="false" SourceOfDefaultValue="AfterContext" /> + </Rule.DataSource> + + <Rule.Categories> + <Category Name="Advanced" DisplayName="Advanced" /> + <Category Name="Protobuf" DisplayName="Protobuf" /> + <Category Name="Misc" DisplayName="Misc" /> + </Rule.Categories> + + <DynamicEnumProperty Name="{}{ItemType}" DisplayName="Build Action" Category="Advanced" + Description="How the file relates to the build and deployment processes." + EnumProvider="ItemTypes" /> + + <StringProperty Name="Identity" Visible="false" ReadOnly="true"> + <StringProperty.DataSource> + <DataSource Persistence="Intrinsic" ItemType="ProtoBuf" + PersistedName="Identity" SourceOfDefaultValue="AfterContext" /> + </StringProperty.DataSource> + </StringProperty> + + <StringProperty Name="FullPath" + DisplayName="Full Path" + ReadOnly="true" + Category="Misc" + Description="Location of the file."> + <StringProperty.DataSource> + <DataSource Persistence="Intrinsic" ItemType="ProtoBuf" + PersistedName="FullPath" SourceOfDefaultValue="AfterContext" /> + </StringProperty.DataSource> + </StringProperty> + + <StringProperty Name="FileNameAndExtension" + DisplayName="File Name" + ReadOnly="true" + Category="Misc" + Description="Name of the file or folder."> + <StringProperty.DataSource> + <DataSource Persistence="Intrinsic" ItemType="ProtoBuf" + PersistedName="FileNameAndExtension" SourceOfDefaultValue="AfterContext" /> + </StringProperty.DataSource> + </StringProperty> + + <BoolProperty Name="Visible" Visible="false" Default="true" /> + + <StringProperty Name="DependentUpon" Visible="false"> + <StringProperty.Metadata> + <NameValuePair Name="DoNotCopyAcrossProjects" Value="true" /> + </StringProperty.Metadata> + </StringProperty> + + <StringProperty Name="Link" Visible="false"> + <StringProperty.DataSource> + <DataSource SourceOfDefaultValue="AfterContext" /> + </StringProperty.DataSource> + <StringProperty.Metadata> + <NameValuePair Name="DoNotCopyAcrossProjects" Value="true" /> + </StringProperty.Metadata> + </StringProperty> + + <EnumProperty Name="Access" DisplayName="Class Access" + Category="Protobuf" + Description="Public or internal access modifier on generated classes."> + <EnumValue Name="Public" DisplayName="Public" IsDefault="true" /> + <EnumValue Name="Internal" DisplayName="Internal" /> + <EnumProperty.DataSource> + <DataSource ItemType="ProtoBuf" SourceOfDefaultValue="AfterContext" + PersistenceStyle="Attribute" /> + </EnumProperty.DataSource> + </EnumProperty> + + <BoolProperty Name="ProtoCompile" DisplayName="Compile Protobuf" + Category="Protobuf" Default="true" + Description="Specifies if this file is compiled or only imported by other files."> + <BoolProperty.DataSource> + <DataSource ItemType="ProtoBuf" SourceOfDefaultValue="AfterContext" + PersistenceStyle="Attribute" /> + </BoolProperty.DataSource> + </BoolProperty> + + </Rule> +</ProjectSchemaDefinitions> diff --git a/src/csharp/Grpc.Tools/build/_protobuf/README b/src/csharp/Grpc.Tools/build/_protobuf/README new file mode 100644 index 0000000000..e6e358a218 --- /dev/null +++ b/src/csharp/Grpc.Tools/build/_protobuf/README @@ -0,0 +1 @@ +TODO(kkm): These file will go into Google.Protobuf.Tools/build after package split. diff --git a/src/csharp/Grpc.Tools/build/native/Grpc.Tools.props b/src/csharp/Grpc.Tools/build/native/Grpc.Tools.props new file mode 100644 index 0000000000..f83c4d135a --- /dev/null +++ b/src/csharp/Grpc.Tools/build/native/Grpc.Tools.props @@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> + + <!-- Revision number of this package conventions (as if "API" version). --> + <Protobuf_ToolingRevision>1</Protobuf_ToolingRevision> + + <!-- For a Visual Studio C++ native project we currently only resolve tools and import paths. --> + <!-- TODO(kkm): Do not place non-tools under tools/, use build/native/bin/. --> + <!-- TODO(kkm): Do not package windows x64 builds (#13098). --> + <Protobuf_ProtocFullPath>$(MSBuildThisFileDirectory)..\..\tools\windows_x86\protoc.exe</Protobuf_ProtocFullPath> + <Protobuf_StandardImportsPath>$(MSBuildThisFileDirectory)include\</Protobuf_StandardImportsPath> + <gRPC_PluginFileName>grpc_cpp_plugin</gRPC_PluginFileName> + <gRPC_PluginFullPath>$(MSBuildThisFileDirectory)..\..\tools\windows_x86\grpc_cpp_plugin.exe</gRPC_PluginFullPath> + </PropertyGroup> +</Project> diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln index d9a7b8d556..6c1b2e9998 100644 --- a/src/csharp/Grpc.sln +++ b/src/csharp/Grpc.sln @@ -39,6 +39,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Reflection.Tests", "Gr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Microbenchmarks", "Grpc.Microbenchmarks\Grpc.Microbenchmarks.csproj", "{84C17746-4727-4290-8E8B-A380793DAE1E}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Tools", "Grpc.Tools\Grpc.Tools.csproj", "{8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Tools.Tests", "Grpc.Tools.Tests\Grpc.Tools.Tests.csproj", "{AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -117,6 +121,14 @@ Global {84C17746-4727-4290-8E8B-A380793DAE1E}.Debug|Any CPU.Build.0 = Debug|Any CPU {84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.ActiveCfg = Release|Any CPU {84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.Build.0 = Release|Any CPU + {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Release|Any CPU.Build.0 = Release|Any CPU + {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 8f38f0aa20..27688360e9 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.15.0-dev +set VERSION=1.17.0-dev @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe @@ -39,10 +39,10 @@ xcopy /Y /I nativelibs\csharp_ext_windows_x64\grpc_csharp_ext.dll ..\..\cmake\bu %DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error %DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error %DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.Tools --output ..\..\..\artifacts || goto :error %NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error %NUGET% pack Grpc.Core.NativeDebug.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts -%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts @rem copy resulting nuget packages to artifacts directory xcopy /Y /I *.nupkg ..\..\artifacts\ || goto :error diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat index 9c53114b84..dd74de0491 100644 --- a/src/csharp/build_unitypackage.bat +++ b/src/csharp/build_unitypackage.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.15.0-dev +set VERSION=1.17.0-dev @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe 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/experimental/README.md b/src/csharp/experimental/README.md index bd53cbcd35..64515075ce 100644 --- a/src/csharp/experimental/README.md +++ b/src/csharp/experimental/README.md @@ -22,10 +22,14 @@ gRPC C# now has experimental support for Unity. Please try using gRPC with Unity and provide feedback! How to test gRPC in a Unity project + 1. Create a Unity project that targets .NET 4.x (Edit -> Project Settings -> Editor -> Scripting Runtime Version). gRPC uses APIs that are only available in .NET4.5+ so this is a requirement. + 2. Download the latest development build of `grpc_unity_package.VERSION.zip` from [daily builds](https://packages.grpc.io/) + 3. Extract the `.zip` file in the `Assets` directory in your Unity project + 4. Unity IDE will pick up all the bundled files and add them to project automatically. You should be able to use gRPC and Protobuf in your scripts from now on. 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/src/csharp/tests.json b/src/csharp/tests.json index c2f243fe0a..760776f9e7 100644 --- a/src/csharp/tests.json +++ b/src/csharp/tests.json @@ -23,8 +23,10 @@ "Grpc.Core.Tests.ClientServerTest", "Grpc.Core.Tests.CompressionTest", "Grpc.Core.Tests.ContextPropagationTest", + "Grpc.Core.Tests.ContextualMarshallerTest", "Grpc.Core.Tests.GrpcEnvironmentTest", "Grpc.Core.Tests.HalfcloseTest", + "Grpc.Core.Tests.MarshallerTest", "Grpc.Core.Tests.MarshallingErrorsTest", "Grpc.Core.Tests.MetadataTest", "Grpc.Core.Tests.PerformanceTest", @@ -62,5 +64,15 @@ "Grpc.Reflection.Tests": [ "Grpc.Reflection.Tests.ReflectionClientServerTest", "Grpc.Reflection.Tests.SymbolRegistryTest" + ], + "Grpc.Tools.Tests": [ + "Grpc.Tools.Tests.CppGeneratorTest", + "Grpc.Tools.Tests.CSharpGeneratorTest", + "Grpc.Tools.Tests.DepFileUtilTest", + "Grpc.Tools.Tests.GeneratorTest", + "Grpc.Tools.Tests.ProtoCompileBasicTest", + "Grpc.Tools.Tests.ProtoCompileCommandLineGeneratorTest", + "Grpc.Tools.Tests.ProtoCompileCommandLinePrinterTest", + "Grpc.Tools.Tests.ProtoToolsPlatformTaskTest" ] } diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 5e9a9a4513..a95a120d21 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.15.0-dev' + v = '1.17.0-dev' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/BoringSSL-GRPC.podspec b/src/objective-c/BoringSSL-GRPC.podspec new file mode 100644 index 0000000000..04e4d5768f --- /dev/null +++ b/src/objective-c/BoringSSL-GRPC.podspec @@ -0,0 +1,4528 @@ + +# This file has been automatically generated from a template file. +# Please make modifications to +# `templates/src/objective-c/BoringSSL-GRPC.podspec.template` instead. This +# file can be regenerated from the template by running +# `tools/buildgen/generate_projects.sh`. + +# BoringSSL CocoaPods podspec + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Pod::Spec.new do |s| + s.name = 'BoringSSL-GRPC' + version = '0.0.2' + s.version = version + s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google\'s needs.' + # Adapted from the homepage: + s.description = <<-DESC + BoringSSL is a fork of OpenSSL that is designed to meet Google's needs. + + Although BoringSSL is an open source project, it is not intended for general use, as OpenSSL is. + We don't recommend that third parties depend upon it. Doing so is likely to be frustrating + because there are no guarantees of API stability. Only the latest version of this pod is + supported, and every new version is a new major version. + + We update Google libraries and programs that use BoringSSL as needed when deciding to make API + changes. This allows us to mostly avoid compromises in the name of compatibility. It works for + us, but it may not work for you. + + As a Cocoapods pod, it has the advantage over OpenSSL's pods that the library doesn't need to + be precompiled. This eliminates the 10 - 20 minutes of wait the first time a user does "pod + install", lets it be used as a dynamic framework (pending solution of Cocoapods' issue #4605), + and works with bitcode automatically. It's also thought to be smaller than OpenSSL (which takes + 1MB - 2MB per ARM architecture), but we don't have specific numbers yet. + + BoringSSL arose because Google used OpenSSL for many years in various ways and, over time, built + up a large number of patches that were maintained while tracking upstream OpenSSL. As Google's + product portfolio became more complex, more copies of OpenSSL sprung up and the effort involved + in maintaining all these patches in multiple places was growing steadily. + + Currently BoringSSL is the SSL library in Chrome/Chromium, Android (but it's not part of the + NDK) and a number of other apps/programs. + DESC + s.homepage = 'https://github.com/google/boringssl' + s.license = { :type => 'Mixed', :file => 'LICENSE' } + # "The name and email addresses of the library maintainers, not the Podspec maintainer." + s.authors = 'Adam Langley', 'David Benjamin', 'Matt Braithwaite' + + s.source = { + :git => 'https://github.com/google/boringssl.git', + :commit => "b29b21a81b32ec273f118f589f46d56ad3332420", + } + + s.ios.deployment_target = '5.0' + s.osx.deployment_target = '10.7' + + name = 'openssl_grpc' + + # When creating a dynamic framework, name it openssl.framework instead of BoringSSL.framework. + # This lets users write their includes like `#include <openssl/ssl.h>` as opposed to `#include + # <BoringSSL/ssl.h>`. + s.module_name = name + + # When creating a dynamic framework, copy the headers under `include/openssl/` into the root of + # the `Headers/` directory of the framework (i.e., not under `Headers/include/openssl`). + # + # TODO(jcanizales): Debug why this doesn't work on macOS. + s.header_mappings_dir = 'include/openssl' + + # The above has an undesired effect when creating a static library: It forces users to write + # includes like `#include <BoringSSL/ssl.h>`. `s.header_dir` adds a path prefix to that, and + # because Cocoapods lets omit the pod name when including headers of static libraries, the + # following lets users write `#include <openssl/ssl.h>`. + s.header_dir = name + + # The module map and umbrella header created automatically by Cocoapods don't work for C libraries + # like this one. The following file, and a correct umbrella header, are created on the fly by the + # `prepare_command` of this pod. + s.module_map = 'include/openssl/BoringSSL.modulemap' + + # We don't need to inhibit all warnings; only -Wno-shorten-64-to-32. But Cocoapods' linter doesn't + # want that for some reason. + s.compiler_flags = '-DOPENSSL_NO_ASM', '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w' + s.requires_arc = false + + # Like many other C libraries, BoringSSL has its public headers under `include/<libname>/` and its + # sources and private headers in other directories outside `include/`. Cocoapods' linter doesn't + # allow any header to be listed outside the `header_mappings_dir` (even though doing so works in + # practice). Because we need our `header_mappings_dir` to be `include/openssl/` for the reason + # mentioned above, we work around the linter limitation by dividing the pod into two subspecs, one + # for public headers and the other for implementation. Each gets its own `header_mappings_dir`, + # making the linter happy. + s.subspec 'Interface' do |ss| + ss.header_mappings_dir = 'include/openssl' + ss.source_files = 'include/openssl/*.h' + end + s.subspec 'Implementation' do |ss| + ss.header_mappings_dir = '.' + ss.source_files = 'ssl/*.{h,cc}', + 'ssl/**/*.{h,cc}', + '*.{h,c}', + 'crypto/*.{h,c}', + 'crypto/**/*.{h,c}', + 'third_party/fiat/*.{h,c}' + ss.private_header_files = 'ssl/*.h', + 'ssl/**/*.h', + '*.h', + 'crypto/*.h', + 'crypto/**/*.h' + # bcm.c includes other source files, creating duplicated symbols. Since it is not used, we + # explicitly exclude it from the pod. + # TODO (mxyan): Work with BoringSSL team to remove this hack. + ss.exclude_files = 'crypto/fipsmodule/bcm.c', + '**/*_test.*', + '**/test_*.*', + '**/test/*.*' + + ss.dependency "#{s.name}/Interface", version + end + + s.prepare_command = <<-END_OF_COMMAND + # Add a module map and an umbrella header + cat > include/openssl/umbrella.h <<EOF + #include "ssl.h" + #include "crypto.h" + #include "aes.h" + /* The following macros are defined by base.h. The latter is the first file included by the + other headers. */ + #if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) + # include "arm_arch.h" + #endif + #include "asn1.h" + #include "asn1_mac.h" + #include "asn1t.h" + #include "blowfish.h" + #include "cast.h" + #include "chacha.h" + #include "cmac.h" + #include "conf.h" + #include "cpu.h" + #include "curve25519.h" + #include "des.h" + #include "dtls1.h" + #include "hkdf.h" + #include "md4.h" + #include "md5.h" + #include "obj_mac.h" + #include "objects.h" + #include "opensslv.h" + #include "ossl_typ.h" + #include "pkcs12.h" + #include "pkcs7.h" + #include "pkcs8.h" + #include "poly1305.h" + #include "rand.h" + #include "rc4.h" + #include "ripemd.h" + #include "safestack.h" + #include "srtp.h" + #include "x509.h" + #include "x509v3.h" + EOF + cat > include/openssl/BoringSSL.modulemap <<EOF + framework module openssl { + umbrella header "umbrella.h" + textual header "arm_arch.h" + export * + module * { export * } + } + EOF + + # This is a bit ridiculous, but requiring people to install Go in order to build is slightly + # more ridiculous IMO. + # TODO(jcanizales): Translate err_data_generate.go into a Bash or Ruby script. + cat > err_data.c <<EOF + /* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + + /* This file was generated by err_data_generate.go. */ + + #include <openssl/base.h> + #include <openssl/err.h> + #include <openssl/type_check.h> + + + OPENSSL_COMPILE_ASSERT(ERR_LIB_NONE == 1, library_values_changed_1); + OPENSSL_COMPILE_ASSERT(ERR_LIB_SYS == 2, library_values_changed_2); + OPENSSL_COMPILE_ASSERT(ERR_LIB_BN == 3, library_values_changed_3); + OPENSSL_COMPILE_ASSERT(ERR_LIB_RSA == 4, library_values_changed_4); + OPENSSL_COMPILE_ASSERT(ERR_LIB_DH == 5, library_values_changed_5); + OPENSSL_COMPILE_ASSERT(ERR_LIB_EVP == 6, library_values_changed_6); + OPENSSL_COMPILE_ASSERT(ERR_LIB_BUF == 7, library_values_changed_7); + OPENSSL_COMPILE_ASSERT(ERR_LIB_OBJ == 8, library_values_changed_8); + OPENSSL_COMPILE_ASSERT(ERR_LIB_PEM == 9, library_values_changed_9); + OPENSSL_COMPILE_ASSERT(ERR_LIB_DSA == 10, library_values_changed_10); + OPENSSL_COMPILE_ASSERT(ERR_LIB_X509 == 11, library_values_changed_11); + OPENSSL_COMPILE_ASSERT(ERR_LIB_ASN1 == 12, library_values_changed_12); + OPENSSL_COMPILE_ASSERT(ERR_LIB_CONF == 13, library_values_changed_13); + OPENSSL_COMPILE_ASSERT(ERR_LIB_CRYPTO == 14, library_values_changed_14); + OPENSSL_COMPILE_ASSERT(ERR_LIB_EC == 15, library_values_changed_15); + OPENSSL_COMPILE_ASSERT(ERR_LIB_SSL == 16, library_values_changed_16); + OPENSSL_COMPILE_ASSERT(ERR_LIB_BIO == 17, library_values_changed_17); + OPENSSL_COMPILE_ASSERT(ERR_LIB_PKCS7 == 18, library_values_changed_18); + OPENSSL_COMPILE_ASSERT(ERR_LIB_PKCS8 == 19, library_values_changed_19); + OPENSSL_COMPILE_ASSERT(ERR_LIB_X509V3 == 20, library_values_changed_20); + OPENSSL_COMPILE_ASSERT(ERR_LIB_RAND == 21, library_values_changed_21); + OPENSSL_COMPILE_ASSERT(ERR_LIB_ENGINE == 22, library_values_changed_22); + OPENSSL_COMPILE_ASSERT(ERR_LIB_OCSP == 23, library_values_changed_23); + OPENSSL_COMPILE_ASSERT(ERR_LIB_UI == 24, library_values_changed_24); + OPENSSL_COMPILE_ASSERT(ERR_LIB_COMP == 25, library_values_changed_25); + OPENSSL_COMPILE_ASSERT(ERR_LIB_ECDSA == 26, library_values_changed_26); + OPENSSL_COMPILE_ASSERT(ERR_LIB_ECDH == 27, library_values_changed_27); + OPENSSL_COMPILE_ASSERT(ERR_LIB_HMAC == 28, library_values_changed_28); + OPENSSL_COMPILE_ASSERT(ERR_LIB_DIGEST == 29, library_values_changed_29); + OPENSSL_COMPILE_ASSERT(ERR_LIB_CIPHER == 30, library_values_changed_30); + OPENSSL_COMPILE_ASSERT(ERR_LIB_HKDF == 31, library_values_changed_31); + OPENSSL_COMPILE_ASSERT(ERR_LIB_USER == 32, library_values_changed_32); + OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == 33, library_values_changed_num); + + const uint32_t kOpenSSLReasonValues[] = { + 0xc320838, + 0xc328852, + 0xc330861, + 0xc338871, + 0xc340880, + 0xc348899, + 0xc3508a5, + 0xc3588c2, + 0xc3608e2, + 0xc3688f0, + 0xc370900, + 0xc37890d, + 0xc38091d, + 0xc388928, + 0xc39093e, + 0xc39894d, + 0xc3a0961, + 0xc3a8845, + 0xc3b00ea, + 0xc3b88d4, + 0x10320845, + 0x10329513, + 0x1033151f, + 0x10339538, + 0x1034154b, + 0x10348eed, + 0x10350c5e, + 0x1035955e, + 0x10361573, + 0x10369586, + 0x103715a5, + 0x103795be, + 0x103815d3, + 0x103895f1, + 0x10391600, + 0x1039961c, + 0x103a1637, + 0x103a9646, + 0x103b1662, + 0x103b967d, + 0x103c1694, + 0x103c80ea, + 0x103d16a5, + 0x103d96b9, + 0x103e16d8, + 0x103e96e7, + 0x103f16fe, + 0x103f9711, + 0x10400c22, + 0x10409724, + 0x10411742, + 0x10419755, + 0x1042176f, + 0x1042977f, + 0x10431793, + 0x104397a9, + 0x104417c1, + 0x104497d6, + 0x104517ea, + 0x104597fc, + 0x104605fb, + 0x1046894d, + 0x10471811, + 0x10479828, + 0x1048183d, + 0x1048984b, + 0x10490e4f, + 0x14320c05, + 0x14328c13, + 0x14330c22, + 0x14338c34, + 0x143400ac, + 0x143480ea, + 0x18320083, + 0x18328f43, + 0x183300ac, + 0x18338f59, + 0x18340f6d, + 0x183480ea, + 0x18350f82, + 0x18358f9a, + 0x18360faf, + 0x18368fc3, + 0x18370fe7, + 0x18378ffd, + 0x18381011, + 0x18389021, + 0x18390a73, + 0x18399031, + 0x183a1059, + 0x183a907f, + 0x183b0c6a, + 0x183b90b4, + 0x183c10c6, + 0x183c90d1, + 0x183d10e1, + 0x183d90f2, + 0x183e1103, + 0x183e9115, + 0x183f113e, + 0x183f9157, + 0x1840116f, + 0x184086d3, + 0x184110a2, + 0x1841906d, + 0x1842108c, + 0x18429046, + 0x20321196, + 0x243211a2, + 0x24328993, + 0x243311b4, + 0x243391c1, + 0x243411ce, + 0x243491e0, + 0x243511ef, + 0x2435920c, + 0x24361219, + 0x24369227, + 0x24371235, + 0x24379243, + 0x2438124c, + 0x24389259, + 0x2439126c, + 0x28320c52, + 0x28328c6a, + 0x28330c22, + 0x28338c7d, + 0x28340c5e, + 0x283480ac, + 0x283500ea, + 0x2c322c30, + 0x2c329283, + 0x2c332c3e, + 0x2c33ac50, + 0x2c342c64, + 0x2c34ac76, + 0x2c352c91, + 0x2c35aca3, + 0x2c362cb6, + 0x2c36832d, + 0x2c372cc3, + 0x2c37acd5, + 0x2c382cfa, + 0x2c38ad11, + 0x2c392d1f, + 0x2c39ad2f, + 0x2c3a2d41, + 0x2c3aad55, + 0x2c3b2d66, + 0x2c3bad85, + 0x2c3c1295, + 0x2c3c92ab, + 0x2c3d2d99, + 0x2c3d92c4, + 0x2c3e2db6, + 0x2c3eadc4, + 0x2c3f2ddc, + 0x2c3fadf4, + 0x2c402e01, + 0x2c409196, + 0x2c412e12, + 0x2c41ae25, + 0x2c42116f, + 0x2c42ae36, + 0x2c430720, + 0x2c43ad77, + 0x2c442ce8, + 0x30320000, + 0x30328015, + 0x3033001f, + 0x30338038, + 0x3034004a, + 0x30348064, + 0x3035006b, + 0x30358083, + 0x30360094, + 0x303680ac, + 0x303700b9, + 0x303780c8, + 0x303800ea, + 0x303880f7, + 0x3039010a, + 0x30398125, + 0x303a013a, + 0x303a814e, + 0x303b0162, + 0x303b8173, + 0x303c018c, + 0x303c81a9, + 0x303d01b7, + 0x303d81cb, + 0x303e01db, + 0x303e81f4, + 0x303f0204, + 0x303f8217, + 0x30400226, + 0x30408232, + 0x30410247, + 0x30418257, + 0x3042026e, + 0x3042827b, + 0x3043028e, + 0x3043829d, + 0x304402b2, + 0x304482d3, + 0x304502e6, + 0x304582f9, + 0x30460312, + 0x3046832d, + 0x3047034a, + 0x30478363, + 0x30480371, + 0x30488382, + 0x30490391, + 0x304983a9, + 0x304a03bb, + 0x304a83cf, + 0x304b03ee, + 0x304b8401, + 0x304c040c, + 0x304c841d, + 0x304d0429, + 0x304d843f, + 0x304e044d, + 0x304e8463, + 0x304f0475, + 0x304f8487, + 0x3050049a, + 0x305084ad, + 0x305104be, + 0x305184ce, + 0x305204e6, + 0x305284fb, + 0x30530513, + 0x30538527, + 0x3054053f, + 0x30548558, + 0x30550571, + 0x3055858e, + 0x30560599, + 0x305685b1, + 0x305705c1, + 0x305785d2, + 0x305805e5, + 0x305885fb, + 0x30590604, + 0x30598619, + 0x305a062c, + 0x305a863b, + 0x305b065b, + 0x305b866a, + 0x305c068b, + 0x305c86a7, + 0x305d06b3, + 0x305d86d3, + 0x305e06ef, + 0x305e8700, + 0x305f0716, + 0x305f8720, + 0x34320b63, + 0x34328b77, + 0x34330b94, + 0x34338ba7, + 0x34340bb6, + 0x34348bef, + 0x34350bd3, + 0x3c320083, + 0x3c328ca7, + 0x3c330cc0, + 0x3c338cdb, + 0x3c340cf8, + 0x3c348d22, + 0x3c350d3d, + 0x3c358d63, + 0x3c360d7c, + 0x3c368d94, + 0x3c370da5, + 0x3c378db3, + 0x3c380dc0, + 0x3c388dd4, + 0x3c390c6a, + 0x3c398de8, + 0x3c3a0dfc, + 0x3c3a890d, + 0x3c3b0e0c, + 0x3c3b8e27, + 0x3c3c0e39, + 0x3c3c8e6c, + 0x3c3d0e76, + 0x3c3d8e8a, + 0x3c3e0e98, + 0x3c3e8ebd, + 0x3c3f0c93, + 0x3c3f8ea6, + 0x3c4000ac, + 0x3c4080ea, + 0x3c410d13, + 0x3c418d52, + 0x3c420e4f, + 0x403218a4, + 0x403298ba, + 0x403318e8, + 0x403398f2, + 0x40341909, + 0x40349927, + 0x40351937, + 0x40359949, + 0x40361956, + 0x40369962, + 0x40371977, + 0x40379989, + 0x40381994, + 0x403899a6, + 0x40390eed, + 0x403999b6, + 0x403a19c9, + 0x403a99ea, + 0x403b19fb, + 0x403b9a0b, + 0x403c0064, + 0x403c8083, + 0x403d1a8f, + 0x403d9aa5, + 0x403e1ab4, + 0x403e9aec, + 0x403f1b06, + 0x403f9b14, + 0x40401b29, + 0x40409b3d, + 0x40411b5a, + 0x40419b75, + 0x40421b8e, + 0x40429ba1, + 0x40431bb5, + 0x40439bcd, + 0x40441be4, + 0x404480ac, + 0x40451bf9, + 0x40459c0b, + 0x40461c2f, + 0x40469c4f, + 0x40471c5d, + 0x40479c84, + 0x40481cc1, + 0x40489cda, + 0x40491cf1, + 0x40499d0b, + 0x404a1d22, + 0x404a9d40, + 0x404b1d58, + 0x404b9d6f, + 0x404c1d85, + 0x404c9d97, + 0x404d1db8, + 0x404d9dda, + 0x404e1dee, + 0x404e9dfb, + 0x404f1e28, + 0x404f9e51, + 0x40501e8c, + 0x40509ea0, + 0x40511ebb, + 0x40521ecb, + 0x40529eef, + 0x40531f07, + 0x40539f1a, + 0x40541f2f, + 0x40549f52, + 0x40551f60, + 0x40559f7d, + 0x40561f8a, + 0x40569fa3, + 0x40571fbb, + 0x40579fce, + 0x40581fe3, + 0x4058a00a, + 0x40592039, + 0x4059a066, + 0x405a207a, + 0x405aa08a, + 0x405b20a2, + 0x405ba0b3, + 0x405c20c6, + 0x405ca105, + 0x405d2112, + 0x405da129, + 0x405e2167, + 0x405e8ab1, + 0x405f2188, + 0x405fa195, + 0x406021a3, + 0x4060a1c5, + 0x40612209, + 0x4061a241, + 0x40622258, + 0x4062a269, + 0x4063227a, + 0x4063a28f, + 0x406422a6, + 0x4064a2d2, + 0x406522ed, + 0x4065a304, + 0x4066231c, + 0x4066a346, + 0x40672371, + 0x4067a392, + 0x406823b9, + 0x4068a3da, + 0x4069240c, + 0x4069a43a, + 0x406a245b, + 0x406aa47b, + 0x406b2603, + 0x406ba626, + 0x406c263c, + 0x406ca8b7, + 0x406d28e6, + 0x406da90e, + 0x406e293c, + 0x406ea989, + 0x406f29a8, + 0x406fa9e0, + 0x407029f3, + 0x4070aa10, + 0x40710800, + 0x4071aa22, + 0x40722a35, + 0x4072aa4e, + 0x40732a66, + 0x40739482, + 0x40742a7a, + 0x4074aa94, + 0x40752aa5, + 0x4075aab9, + 0x40762ac7, + 0x40769259, + 0x40772aec, + 0x4077ab0e, + 0x40782b29, + 0x4078ab62, + 0x40792b79, + 0x4079ab8f, + 0x407a2b9b, + 0x407aabae, + 0x407b2bc3, + 0x407babd5, + 0x407c2c06, + 0x407cac0f, + 0x407d23f5, + 0x407d9e61, + 0x407e2b3e, + 0x407ea01a, + 0x407f1c71, + 0x407f9a31, + 0x40801e38, + 0x40809c99, + 0x40811edd, + 0x40819e12, + 0x40822927, + 0x40829a17, + 0x40831ff5, + 0x4083a2b7, + 0x40841cad, + 0x4084a052, + 0x408520d7, + 0x4085a1ed, + 0x40862149, + 0x40869e7b, + 0x4087296d, + 0x4087a21e, + 0x40881a78, + 0x4088a3a5, + 0x40891ac7, + 0x40899a54, + 0x408a265c, + 0x408a9862, + 0x408b2bea, + 0x408ba9bd, + 0x408c20e7, + 0x408c987e, + 0x41f4252e, + 0x41f925c0, + 0x41fe24b3, + 0x41fea6a8, + 0x41ff2799, + 0x42032547, + 0x42082569, + 0x4208a5a5, + 0x42092497, + 0x4209a5df, + 0x420a24ee, + 0x420aa4ce, + 0x420b250e, + 0x420ba587, + 0x420c27b5, + 0x420ca675, + 0x420d268f, + 0x420da6c6, + 0x421226e0, + 0x4217277c, + 0x4217a722, + 0x421c2744, + 0x421f26ff, + 0x422127cc, + 0x4226275f, + 0x422b289b, + 0x422ba849, + 0x422c2883, + 0x422ca808, + 0x422d27e7, + 0x422da868, + 0x422e282e, + 0x422ea954, + 0x4432072b, + 0x4432873a, + 0x44330746, + 0x44338754, + 0x44340767, + 0x44348778, + 0x4435077f, + 0x44358789, + 0x4436079c, + 0x443687b2, + 0x443707c4, + 0x443787d1, + 0x443807e0, + 0x443887e8, + 0x44390800, + 0x4439880e, + 0x443a0821, + 0x48321283, + 0x48329295, + 0x483312ab, + 0x483392c4, + 0x4c3212e9, + 0x4c3292f9, + 0x4c33130c, + 0x4c33932c, + 0x4c3400ac, + 0x4c3480ea, + 0x4c351338, + 0x4c359346, + 0x4c361362, + 0x4c369375, + 0x4c371384, + 0x4c379392, + 0x4c3813a7, + 0x4c3893b3, + 0x4c3913d3, + 0x4c3993fd, + 0x4c3a1416, + 0x4c3a942f, + 0x4c3b05fb, + 0x4c3b9448, + 0x4c3c145a, + 0x4c3c9469, + 0x4c3d1482, + 0x4c3d8c45, + 0x4c3e14db, + 0x4c3e9491, + 0x4c3f14fd, + 0x4c3f9259, + 0x4c4014a7, + 0x4c4092d5, + 0x4c4114cb, + 0x50322e48, + 0x5032ae57, + 0x50332e62, + 0x5033ae72, + 0x50342e8b, + 0x5034aea5, + 0x50352eb3, + 0x5035aec9, + 0x50362edb, + 0x5036aef1, + 0x50372f0a, + 0x5037af1d, + 0x50382f35, + 0x5038af46, + 0x50392f5b, + 0x5039af6f, + 0x503a2f8f, + 0x503aafa5, + 0x503b2fbd, + 0x503bafcf, + 0x503c2feb, + 0x503cb002, + 0x503d301b, + 0x503db031, + 0x503e303e, + 0x503eb054, + 0x503f3066, + 0x503f8382, + 0x50403079, + 0x5040b089, + 0x504130a3, + 0x5041b0b2, + 0x504230cc, + 0x5042b0e9, + 0x504330f9, + 0x5043b109, + 0x50443118, + 0x5044843f, + 0x5045312c, + 0x5045b14a, + 0x5046315d, + 0x5046b173, + 0x50473185, + 0x5047b19a, + 0x504831c0, + 0x5048b1ce, + 0x504931e1, + 0x5049b1f6, + 0x504a320c, + 0x504ab21c, + 0x504b323c, + 0x504bb24f, + 0x504c3272, + 0x504cb2a0, + 0x504d32b2, + 0x504db2cf, + 0x504e32ea, + 0x504eb306, + 0x504f3318, + 0x504fb32f, + 0x5050333e, + 0x505086ef, + 0x50513351, + 0x58320f2b, + 0x68320eed, + 0x68328c6a, + 0x68330c7d, + 0x68338efb, + 0x68340f0b, + 0x683480ea, + 0x6c320ec9, + 0x6c328c34, + 0x6c330ed4, + 0x74320a19, + 0x743280ac, + 0x74330c45, + 0x7832097e, + 0x78328993, + 0x7833099f, + 0x78338083, + 0x783409ae, + 0x783489c3, + 0x783509e2, + 0x78358a04, + 0x78360a19, + 0x78368a2f, + 0x78370a3f, + 0x78378a60, + 0x78380a73, + 0x78388a85, + 0x78390a92, + 0x78398ab1, + 0x783a0ac6, + 0x783a8ad4, + 0x783b0ade, + 0x783b8af2, + 0x783c0b09, + 0x783c8b1e, + 0x783d0b35, + 0x783d8b4a, + 0x783e0aa0, + 0x783e8a52, + 0x7c321185, + }; + + const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]); + + const char kOpenSSLReasonStringData[] = + "ASN1_LENGTH_MISMATCH\\0" + "AUX_ERROR\\0" + "BAD_GET_ASN1_OBJECT_CALL\\0" + "BAD_OBJECT_HEADER\\0" + "BMPSTRING_IS_WRONG_LENGTH\\0" + "BN_LIB\\0" + "BOOLEAN_IS_WRONG_LENGTH\\0" + "BUFFER_TOO_SMALL\\0" + "CONTEXT_NOT_INITIALISED\\0" + "DECODE_ERROR\\0" + "DEPTH_EXCEEDED\\0" + "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED\\0" + "ENCODE_ERROR\\0" + "ERROR_GETTING_TIME\\0" + "EXPECTING_AN_ASN1_SEQUENCE\\0" + "EXPECTING_AN_INTEGER\\0" + "EXPECTING_AN_OBJECT\\0" + "EXPECTING_A_BOOLEAN\\0" + "EXPECTING_A_TIME\\0" + "EXPLICIT_LENGTH_MISMATCH\\0" + "EXPLICIT_TAG_NOT_CONSTRUCTED\\0" + "FIELD_MISSING\\0" + "FIRST_NUM_TOO_LARGE\\0" + "HEADER_TOO_LONG\\0" + "ILLEGAL_BITSTRING_FORMAT\\0" + "ILLEGAL_BOOLEAN\\0" + "ILLEGAL_CHARACTERS\\0" + "ILLEGAL_FORMAT\\0" + "ILLEGAL_HEX\\0" + "ILLEGAL_IMPLICIT_TAG\\0" + "ILLEGAL_INTEGER\\0" + "ILLEGAL_NESTED_TAGGING\\0" + "ILLEGAL_NULL\\0" + "ILLEGAL_NULL_VALUE\\0" + "ILLEGAL_OBJECT\\0" + "ILLEGAL_OPTIONAL_ANY\\0" + "ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE\\0" + "ILLEGAL_TAGGED_ANY\\0" + "ILLEGAL_TIME_VALUE\\0" + "INTEGER_NOT_ASCII_FORMAT\\0" + "INTEGER_TOO_LARGE_FOR_LONG\\0" + "INVALID_BIT_STRING_BITS_LEFT\\0" + "INVALID_BMPSTRING_LENGTH\\0" + "INVALID_DIGIT\\0" + "INVALID_MODIFIER\\0" + "INVALID_NUMBER\\0" + "INVALID_OBJECT_ENCODING\\0" + "INVALID_SEPARATOR\\0" + "INVALID_TIME_FORMAT\\0" + "INVALID_UNIVERSALSTRING_LENGTH\\0" + "INVALID_UTF8STRING\\0" + "LIST_ERROR\\0" + "MISSING_ASN1_EOS\\0" + "MISSING_EOC\\0" + "MISSING_SECOND_NUMBER\\0" + "MISSING_VALUE\\0" + "MSTRING_NOT_UNIVERSAL\\0" + "MSTRING_WRONG_TAG\\0" + "NESTED_ASN1_ERROR\\0" + "NESTED_ASN1_STRING\\0" + "NON_HEX_CHARACTERS\\0" + "NOT_ASCII_FORMAT\\0" + "NOT_ENOUGH_DATA\\0" + "NO_MATCHING_CHOICE_TYPE\\0" + "NULL_IS_WRONG_LENGTH\\0" + "OBJECT_NOT_ASCII_FORMAT\\0" + "ODD_NUMBER_OF_CHARS\\0" + "SECOND_NUMBER_TOO_LARGE\\0" + "SEQUENCE_LENGTH_MISMATCH\\0" + "SEQUENCE_NOT_CONSTRUCTED\\0" + "SEQUENCE_OR_SET_NEEDS_CONFIG\\0" + "SHORT_LINE\\0" + "STREAMING_NOT_SUPPORTED\\0" + "STRING_TOO_LONG\\0" + "STRING_TOO_SHORT\\0" + "TAG_VALUE_TOO_HIGH\\0" + "TIME_NOT_ASCII_FORMAT\\0" + "TOO_LONG\\0" + "TYPE_NOT_CONSTRUCTED\\0" + "TYPE_NOT_PRIMITIVE\\0" + "UNEXPECTED_EOC\\0" + "UNIVERSALSTRING_IS_WRONG_LENGTH\\0" + "UNKNOWN_FORMAT\\0" + "UNKNOWN_MESSAGE_DIGEST_ALGORITHM\\0" + "UNKNOWN_SIGNATURE_ALGORITHM\\0" + "UNKNOWN_TAG\\0" + "UNSUPPORTED_ANY_DEFINED_BY_TYPE\\0" + "UNSUPPORTED_PUBLIC_KEY_TYPE\\0" + "UNSUPPORTED_TYPE\\0" + "WRONG_PUBLIC_KEY_TYPE\\0" + "WRONG_TAG\\0" + "WRONG_TYPE\\0" + "BAD_FOPEN_MODE\\0" + "BROKEN_PIPE\\0" + "CONNECT_ERROR\\0" + "ERROR_SETTING_NBIO\\0" + "INVALID_ARGUMENT\\0" + "IN_USE\\0" + "KEEPALIVE\\0" + "NBIO_CONNECT_ERROR\\0" + "NO_HOSTNAME_SPECIFIED\\0" + "NO_PORT_SPECIFIED\\0" + "NO_SUCH_FILE\\0" + "NULL_PARAMETER\\0" + "SYS_LIB\\0" + "UNABLE_TO_CREATE_SOCKET\\0" + "UNINITIALIZED\\0" + "UNSUPPORTED_METHOD\\0" + "WRITE_TO_READ_ONLY_BIO\\0" + "ARG2_LT_ARG3\\0" + "BAD_ENCODING\\0" + "BAD_RECIPROCAL\\0" + "BIGNUM_TOO_LONG\\0" + "BITS_TOO_SMALL\\0" + "CALLED_WITH_EVEN_MODULUS\\0" + "DIV_BY_ZERO\\0" + "EXPAND_ON_STATIC_BIGNUM_DATA\\0" + "INPUT_NOT_REDUCED\\0" + "INVALID_INPUT\\0" + "INVALID_RANGE\\0" + "NEGATIVE_NUMBER\\0" + "NOT_A_SQUARE\\0" + "NOT_INITIALIZED\\0" + "NO_INVERSE\\0" + "PRIVATE_KEY_TOO_LARGE\\0" + "P_IS_NOT_PRIME\\0" + "TOO_MANY_ITERATIONS\\0" + "TOO_MANY_TEMPORARY_VARIABLES\\0" + "AES_KEY_SETUP_FAILED\\0" + "BAD_DECRYPT\\0" + "BAD_KEY_LENGTH\\0" + "CTRL_NOT_IMPLEMENTED\\0" + "CTRL_OPERATION_NOT_IMPLEMENTED\\0" + "DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH\\0" + "INITIALIZATION_ERROR\\0" + "INPUT_NOT_INITIALIZED\\0" + "INVALID_AD_SIZE\\0" + "INVALID_KEY_LENGTH\\0" + "INVALID_NONCE\\0" + "INVALID_NONCE_SIZE\\0" + "INVALID_OPERATION\\0" + "IV_TOO_LARGE\\0" + "NO_CIPHER_SET\\0" + "NO_DIRECTION_SET\\0" + "OUTPUT_ALIASES_INPUT\\0" + "TAG_TOO_LARGE\\0" + "TOO_LARGE\\0" + "UNSUPPORTED_AD_SIZE\\0" + "UNSUPPORTED_INPUT_SIZE\\0" + "UNSUPPORTED_KEY_SIZE\\0" + "UNSUPPORTED_NONCE_SIZE\\0" + "UNSUPPORTED_TAG_SIZE\\0" + "WRONG_FINAL_BLOCK_LENGTH\\0" + "LIST_CANNOT_BE_NULL\\0" + "MISSING_CLOSE_SQUARE_BRACKET\\0" + "MISSING_EQUAL_SIGN\\0" + "NO_CLOSE_BRACE\\0" + "UNABLE_TO_CREATE_NEW_SECTION\\0" + "VARIABLE_EXPANSION_TOO_LONG\\0" + "VARIABLE_HAS_NO_VALUE\\0" + "BAD_GENERATOR\\0" + "INVALID_PUBKEY\\0" + "MODULUS_TOO_LARGE\\0" + "NO_PRIVATE_VALUE\\0" + "UNKNOWN_HASH\\0" + "BAD_Q_VALUE\\0" + "BAD_VERSION\\0" + "MISSING_PARAMETERS\\0" + "NEED_NEW_SETUP_VALUES\\0" + "BIGNUM_OUT_OF_RANGE\\0" + "COORDINATES_OUT_OF_RANGE\\0" + "D2I_ECPKPARAMETERS_FAILURE\\0" + "EC_GROUP_NEW_BY_NAME_FAILURE\\0" + "GROUP2PKPARAMETERS_FAILURE\\0" + "GROUP_MISMATCH\\0" + "I2D_ECPKPARAMETERS_FAILURE\\0" + "INCOMPATIBLE_OBJECTS\\0" + "INVALID_COFACTOR\\0" + "INVALID_COMPRESSED_POINT\\0" + "INVALID_COMPRESSION_BIT\\0" + "INVALID_ENCODING\\0" + "INVALID_FIELD\\0" + "INVALID_FORM\\0" + "INVALID_GROUP_ORDER\\0" + "INVALID_PRIVATE_KEY\\0" + "MISSING_PRIVATE_KEY\\0" + "NON_NAMED_CURVE\\0" + "PKPARAMETERS2GROUP_FAILURE\\0" + "POINT_AT_INFINITY\\0" + "POINT_IS_NOT_ON_CURVE\\0" + "PUBLIC_KEY_VALIDATION_FAILED\\0" + "SLOT_FULL\\0" + "UNDEFINED_GENERATOR\\0" + "UNKNOWN_GROUP\\0" + "UNKNOWN_ORDER\\0" + "WRONG_CURVE_PARAMETERS\\0" + "WRONG_ORDER\\0" + "KDF_FAILED\\0" + "POINT_ARITHMETIC_FAILURE\\0" + "BAD_SIGNATURE\\0" + "NOT_IMPLEMENTED\\0" + "RANDOM_NUMBER_GENERATION_FAILED\\0" + "OPERATION_NOT_SUPPORTED\\0" + "COMMAND_NOT_SUPPORTED\\0" + "DIFFERENT_KEY_TYPES\\0" + "DIFFERENT_PARAMETERS\\0" + "EXPECTING_AN_EC_KEY_KEY\\0" + "EXPECTING_AN_RSA_KEY\\0" + "EXPECTING_A_DSA_KEY\\0" + "ILLEGAL_OR_UNSUPPORTED_PADDING_MODE\\0" + "INVALID_DIGEST_LENGTH\\0" + "INVALID_DIGEST_TYPE\\0" + "INVALID_KEYBITS\\0" + "INVALID_MGF1_MD\\0" + "INVALID_PADDING_MODE\\0" + "INVALID_PARAMETERS\\0" + "INVALID_PSS_SALTLEN\\0" + "INVALID_SIGNATURE\\0" + "KEYS_NOT_SET\\0" + "MEMORY_LIMIT_EXCEEDED\\0" + "NOT_A_PRIVATE_KEY\\0" + "NO_DEFAULT_DIGEST\\0" + "NO_KEY_SET\\0" + "NO_MDC2_SUPPORT\\0" + "NO_NID_FOR_CURVE\\0" + "NO_OPERATION_SET\\0" + "NO_PARAMETERS_SET\\0" + "OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE\\0" + "OPERATON_NOT_INITIALIZED\\0" + "UNKNOWN_PUBLIC_KEY_TYPE\\0" + "UNSUPPORTED_ALGORITHM\\0" + "OUTPUT_TOO_LARGE\\0" + "UNKNOWN_NID\\0" + "BAD_BASE64_DECODE\\0" + "BAD_END_LINE\\0" + "BAD_IV_CHARS\\0" + "BAD_PASSWORD_READ\\0" + "CIPHER_IS_NULL\\0" + "ERROR_CONVERTING_PRIVATE_KEY\\0" + "NOT_DEK_INFO\\0" + "NOT_ENCRYPTED\\0" + "NOT_PROC_TYPE\\0" + "NO_START_LINE\\0" + "READ_KEY\\0" + "SHORT_HEADER\\0" + "UNSUPPORTED_CIPHER\\0" + "UNSUPPORTED_ENCRYPTION\\0" + "BAD_PKCS7_VERSION\\0" + "NOT_PKCS7_SIGNED_DATA\\0" + "NO_CERTIFICATES_INCLUDED\\0" + "NO_CRLS_INCLUDED\\0" + "BAD_ITERATION_COUNT\\0" + "BAD_PKCS12_DATA\\0" + "BAD_PKCS12_VERSION\\0" + "CIPHER_HAS_NO_OBJECT_IDENTIFIER\\0" + "CRYPT_ERROR\\0" + "ENCRYPT_ERROR\\0" + "ERROR_SETTING_CIPHER_PARAMS\\0" + "INCORRECT_PASSWORD\\0" + "KEYGEN_FAILURE\\0" + "KEY_GEN_ERROR\\0" + "METHOD_NOT_SUPPORTED\\0" + "MISSING_MAC\\0" + "MULTIPLE_PRIVATE_KEYS_IN_PKCS12\\0" + "PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED\\0" + "PKCS12_TOO_DEEPLY_NESTED\\0" + "PRIVATE_KEY_DECODE_ERROR\\0" + "PRIVATE_KEY_ENCODE_ERROR\\0" + "UNKNOWN_ALGORITHM\\0" + "UNKNOWN_CIPHER\\0" + "UNKNOWN_CIPHER_ALGORITHM\\0" + "UNKNOWN_DIGEST\\0" + "UNSUPPORTED_KEYLENGTH\\0" + "UNSUPPORTED_KEY_DERIVATION_FUNCTION\\0" + "UNSUPPORTED_PRF\\0" + "UNSUPPORTED_PRIVATE_KEY_ALGORITHM\\0" + "UNSUPPORTED_SALT_TYPE\\0" + "BAD_E_VALUE\\0" + "BAD_FIXED_HEADER_DECRYPT\\0" + "BAD_PAD_BYTE_COUNT\\0" + "BAD_RSA_PARAMETERS\\0" + "BLOCK_TYPE_IS_NOT_01\\0" + "BN_NOT_INITIALIZED\\0" + "CANNOT_RECOVER_MULTI_PRIME_KEY\\0" + "CRT_PARAMS_ALREADY_GIVEN\\0" + "CRT_VALUES_INCORRECT\\0" + "DATA_LEN_NOT_EQUAL_TO_MOD_LEN\\0" + "DATA_TOO_LARGE\\0" + "DATA_TOO_LARGE_FOR_KEY_SIZE\\0" + "DATA_TOO_LARGE_FOR_MODULUS\\0" + "DATA_TOO_SMALL\\0" + "DATA_TOO_SMALL_FOR_KEY_SIZE\\0" + "DIGEST_TOO_BIG_FOR_RSA_KEY\\0" + "D_E_NOT_CONGRUENT_TO_1\\0" + "EMPTY_PUBLIC_KEY\\0" + "FIRST_OCTET_INVALID\\0" + "INCONSISTENT_SET_OF_CRT_VALUES\\0" + "INTERNAL_ERROR\\0" + "INVALID_MESSAGE_LENGTH\\0" + "KEY_SIZE_TOO_SMALL\\0" + "LAST_OCTET_INVALID\\0" + "MUST_HAVE_AT_LEAST_TWO_PRIMES\\0" + "NO_PUBLIC_EXPONENT\\0" + "NULL_BEFORE_BLOCK_MISSING\\0" + "N_NOT_EQUAL_P_Q\\0" + "OAEP_DECODING_ERROR\\0" + "ONLY_ONE_OF_P_Q_GIVEN\\0" + "OUTPUT_BUFFER_TOO_SMALL\\0" + "PADDING_CHECK_FAILED\\0" + "PKCS_DECODING_ERROR\\0" + "SLEN_CHECK_FAILED\\0" + "SLEN_RECOVERY_FAILED\\0" + "UNKNOWN_ALGORITHM_TYPE\\0" + "UNKNOWN_PADDING_TYPE\\0" + "VALUE_MISSING\\0" + "WRONG_SIGNATURE_LENGTH\\0" + "ALPN_MISMATCH_ON_EARLY_DATA\\0" + "APPLICATION_DATA_INSTEAD_OF_HANDSHAKE\\0" + "APP_DATA_IN_HANDSHAKE\\0" + "ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT\\0" + "BAD_ALERT\\0" + "BAD_CHANGE_CIPHER_SPEC\\0" + "BAD_DATA_RETURNED_BY_CALLBACK\\0" + "BAD_DH_P_LENGTH\\0" + "BAD_DIGEST_LENGTH\\0" + "BAD_ECC_CERT\\0" + "BAD_ECPOINT\\0" + "BAD_HANDSHAKE_RECORD\\0" + "BAD_HELLO_REQUEST\\0" + "BAD_LENGTH\\0" + "BAD_PACKET_LENGTH\\0" + "BAD_RSA_ENCRYPT\\0" + "BAD_SRTP_MKI_VALUE\\0" + "BAD_SRTP_PROTECTION_PROFILE_LIST\\0" + "BAD_SSL_FILETYPE\\0" + "BAD_WRITE_RETRY\\0" + "BIO_NOT_SET\\0" + "BLOCK_CIPHER_PAD_IS_WRONG\\0" + "BUFFERED_MESSAGES_ON_CIPHER_CHANGE\\0" + "CANNOT_HAVE_BOTH_PRIVKEY_AND_METHOD\\0" + "CANNOT_PARSE_LEAF_CERT\\0" + "CA_DN_LENGTH_MISMATCH\\0" + "CA_DN_TOO_LONG\\0" + "CCS_RECEIVED_EARLY\\0" + "CERTIFICATE_AND_PRIVATE_KEY_MISMATCH\\0" + "CERTIFICATE_VERIFY_FAILED\\0" + "CERT_CB_ERROR\\0" + "CERT_LENGTH_MISMATCH\\0" + "CHANNEL_ID_NOT_P256\\0" + "CHANNEL_ID_SIGNATURE_INVALID\\0" + "CIPHER_OR_HASH_UNAVAILABLE\\0" + "CLIENTHELLO_PARSE_FAILED\\0" + "CLIENTHELLO_TLSEXT\\0" + "CONNECTION_REJECTED\\0" + "CONNECTION_TYPE_NOT_SET\\0" + "CUSTOM_EXTENSION_ERROR\\0" + "DATA_LENGTH_TOO_LONG\\0" + "DECRYPTION_FAILED\\0" + "DECRYPTION_FAILED_OR_BAD_RECORD_MAC\\0" + "DH_PUBLIC_VALUE_LENGTH_IS_WRONG\\0" + "DH_P_TOO_LONG\\0" + "DIGEST_CHECK_FAILED\\0" + "DOWNGRADE_DETECTED\\0" + "DTLS_MESSAGE_TOO_BIG\\0" + "DUPLICATE_EXTENSION\\0" + "DUPLICATE_KEY_SHARE\\0" + "ECC_CERT_NOT_FOR_SIGNING\\0" + "EMS_STATE_INCONSISTENT\\0" + "ENCRYPTED_LENGTH_TOO_LONG\\0" + "ERROR_ADDING_EXTENSION\\0" + "ERROR_IN_RECEIVED_CIPHER_LIST\\0" + "ERROR_PARSING_EXTENSION\\0" + "EXCESSIVE_MESSAGE_SIZE\\0" + "EXTRA_DATA_IN_MESSAGE\\0" + "FRAGMENT_MISMATCH\\0" + "GOT_NEXT_PROTO_WITHOUT_EXTENSION\\0" + "HANDSHAKE_FAILURE_ON_CLIENT_HELLO\\0" + "HTTPS_PROXY_REQUEST\\0" + "HTTP_REQUEST\\0" + "INAPPROPRIATE_FALLBACK\\0" + "INVALID_ALPN_PROTOCOL\\0" + "INVALID_COMMAND\\0" + "INVALID_COMPRESSION_LIST\\0" + "INVALID_MESSAGE\\0" + "INVALID_OUTER_RECORD_TYPE\\0" + "INVALID_SCT_LIST\\0" + "INVALID_SSL_SESSION\\0" + "INVALID_TICKET_KEYS_LENGTH\\0" + "LENGTH_MISMATCH\\0" + "MISSING_EXTENSION\\0" + "MISSING_KEY_SHARE\\0" + "MISSING_RSA_CERTIFICATE\\0" + "MISSING_TMP_DH_KEY\\0" + "MISSING_TMP_ECDH_KEY\\0" + "MIXED_SPECIAL_OPERATOR_WITH_GROUPS\\0" + "MTU_TOO_SMALL\\0" + "NEGOTIATED_BOTH_NPN_AND_ALPN\\0" + "NESTED_GROUP\\0" + "NO_CERTIFICATES_RETURNED\\0" + "NO_CERTIFICATE_ASSIGNED\\0" + "NO_CERTIFICATE_SET\\0" + "NO_CIPHERS_AVAILABLE\\0" + "NO_CIPHERS_PASSED\\0" + "NO_CIPHERS_SPECIFIED\\0" + "NO_CIPHER_MATCH\\0" + "NO_COMMON_SIGNATURE_ALGORITHMS\\0" + "NO_COMPRESSION_SPECIFIED\\0" + "NO_GROUPS_SPECIFIED\\0" + "NO_METHOD_SPECIFIED\\0" + "NO_P256_SUPPORT\\0" + "NO_PRIVATE_KEY_ASSIGNED\\0" + "NO_RENEGOTIATION\\0" + "NO_REQUIRED_DIGEST\\0" + "NO_SHARED_CIPHER\\0" + "NO_SHARED_GROUP\\0" + "NO_SUPPORTED_VERSIONS_ENABLED\\0" + "NULL_SSL_CTX\\0" + "NULL_SSL_METHOD_PASSED\\0" + "OLD_SESSION_CIPHER_NOT_RETURNED\\0" + "OLD_SESSION_PRF_HASH_MISMATCH\\0" + "OLD_SESSION_VERSION_NOT_RETURNED\\0" + "PARSE_TLSEXT\\0" + "PATH_TOO_LONG\\0" + "PEER_DID_NOT_RETURN_A_CERTIFICATE\\0" + "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE\\0" + "PRE_SHARED_KEY_MUST_BE_LAST\\0" + "PROTOCOL_IS_SHUTDOWN\\0" + "PSK_IDENTITY_BINDER_COUNT_MISMATCH\\0" + "PSK_IDENTITY_NOT_FOUND\\0" + "PSK_NO_CLIENT_CB\\0" + "PSK_NO_SERVER_CB\\0" + "READ_TIMEOUT_EXPIRED\\0" + "RECORD_LENGTH_MISMATCH\\0" + "RECORD_TOO_LARGE\\0" + "RENEGOTIATION_EMS_MISMATCH\\0" + "RENEGOTIATION_ENCODING_ERR\\0" + "RENEGOTIATION_MISMATCH\\0" + "REQUIRED_CIPHER_MISSING\\0" + "RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION\\0" + "RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION\\0" + "SCSV_RECEIVED_WHEN_RENEGOTIATING\\0" + "SERVERHELLO_TLSEXT\\0" + "SERVER_CERT_CHANGED\\0" + "SESSION_ID_CONTEXT_UNINITIALIZED\\0" + "SESSION_MAY_NOT_BE_CREATED\\0" + "SHUTDOWN_WHILE_IN_INIT\\0" + "SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER\\0" + "SRTP_COULD_NOT_ALLOCATE_PROFILES\\0" + "SRTP_UNKNOWN_PROTECTION_PROFILE\\0" + "SSL3_EXT_INVALID_SERVERNAME\\0" + "SSLV3_ALERT_BAD_CERTIFICATE\\0" + "SSLV3_ALERT_BAD_RECORD_MAC\\0" + "SSLV3_ALERT_CERTIFICATE_EXPIRED\\0" + "SSLV3_ALERT_CERTIFICATE_REVOKED\\0" + "SSLV3_ALERT_CERTIFICATE_UNKNOWN\\0" + "SSLV3_ALERT_CLOSE_NOTIFY\\0" + "SSLV3_ALERT_DECOMPRESSION_FAILURE\\0" + "SSLV3_ALERT_HANDSHAKE_FAILURE\\0" + "SSLV3_ALERT_ILLEGAL_PARAMETER\\0" + "SSLV3_ALERT_NO_CERTIFICATE\\0" + "SSLV3_ALERT_UNEXPECTED_MESSAGE\\0" + "SSLV3_ALERT_UNSUPPORTED_CERTIFICATE\\0" + "SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION\\0" + "SSL_HANDSHAKE_FAILURE\\0" + "SSL_SESSION_ID_CONTEXT_TOO_LONG\\0" + "TICKET_ENCRYPTION_FAILED\\0" + "TLSV1_ALERT_ACCESS_DENIED\\0" + "TLSV1_ALERT_DECODE_ERROR\\0" + "TLSV1_ALERT_DECRYPTION_FAILED\\0" + "TLSV1_ALERT_DECRYPT_ERROR\\0" + "TLSV1_ALERT_EXPORT_RESTRICTION\\0" + "TLSV1_ALERT_INAPPROPRIATE_FALLBACK\\0" + "TLSV1_ALERT_INSUFFICIENT_SECURITY\\0" + "TLSV1_ALERT_INTERNAL_ERROR\\0" + "TLSV1_ALERT_NO_RENEGOTIATION\\0" + "TLSV1_ALERT_PROTOCOL_VERSION\\0" + "TLSV1_ALERT_RECORD_OVERFLOW\\0" + "TLSV1_ALERT_UNKNOWN_CA\\0" + "TLSV1_ALERT_USER_CANCELLED\\0" + "TLSV1_BAD_CERTIFICATE_HASH_VALUE\\0" + "TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE\\0" + "TLSV1_CERTIFICATE_REQUIRED\\0" + "TLSV1_CERTIFICATE_UNOBTAINABLE\\0" + "TLSV1_UNKNOWN_PSK_IDENTITY\\0" + "TLSV1_UNRECOGNIZED_NAME\\0" + "TLSV1_UNSUPPORTED_EXTENSION\\0" + "TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST\\0" + "TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG\\0" + "TOO_MANY_EMPTY_FRAGMENTS\\0" + "TOO_MANY_KEY_UPDATES\\0" + "TOO_MANY_WARNING_ALERTS\\0" + "TOO_MUCH_READ_EARLY_DATA\\0" + "TOO_MUCH_SKIPPED_EARLY_DATA\\0" + "UNABLE_TO_FIND_ECDH_PARAMETERS\\0" + "UNEXPECTED_EXTENSION\\0" + "UNEXPECTED_EXTENSION_ON_EARLY_DATA\\0" + "UNEXPECTED_MESSAGE\\0" + "UNEXPECTED_OPERATOR_IN_GROUP\\0" + "UNEXPECTED_RECORD\\0" + "UNKNOWN_ALERT_TYPE\\0" + "UNKNOWN_CERTIFICATE_TYPE\\0" + "UNKNOWN_CIPHER_RETURNED\\0" + "UNKNOWN_CIPHER_TYPE\\0" + "UNKNOWN_KEY_EXCHANGE_TYPE\\0" + "UNKNOWN_PROTOCOL\\0" + "UNKNOWN_SSL_VERSION\\0" + "UNKNOWN_STATE\\0" + "UNSAFE_LEGACY_RENEGOTIATION_DISABLED\\0" + "UNSUPPORTED_COMPRESSION_ALGORITHM\\0" + "UNSUPPORTED_ELLIPTIC_CURVE\\0" + "UNSUPPORTED_PROTOCOL\\0" + "UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY\\0" + "WRONG_CERTIFICATE_TYPE\\0" + "WRONG_CIPHER_RETURNED\\0" + "WRONG_CURVE\\0" + "WRONG_MESSAGE_TYPE\\0" + "WRONG_SIGNATURE_TYPE\\0" + "WRONG_SSL_VERSION\\0" + "WRONG_VERSION_NUMBER\\0" + "WRONG_VERSION_ON_EARLY_DATA\\0" + "X509_LIB\\0" + "X509_VERIFICATION_SETUP_PROBLEMS\\0" + "AKID_MISMATCH\\0" + "BAD_X509_FILETYPE\\0" + "BASE64_DECODE_ERROR\\0" + "CANT_CHECK_DH_KEY\\0" + "CERT_ALREADY_IN_HASH_TABLE\\0" + "CRL_ALREADY_DELTA\\0" + "CRL_VERIFY_FAILURE\\0" + "IDP_MISMATCH\\0" + "INVALID_DIRECTORY\\0" + "INVALID_FIELD_NAME\\0" + "INVALID_PARAMETER\\0" + "INVALID_PSS_PARAMETERS\\0" + "INVALID_TRUST\\0" + "ISSUER_MISMATCH\\0" + "KEY_TYPE_MISMATCH\\0" + "KEY_VALUES_MISMATCH\\0" + "LOADING_CERT_DIR\\0" + "LOADING_DEFAULTS\\0" + "NAME_TOO_LONG\\0" + "NEWER_CRL_NOT_NEWER\\0" + "NO_CERT_SET_FOR_US_TO_VERIFY\\0" + "NO_CRL_NUMBER\\0" + "PUBLIC_KEY_DECODE_ERROR\\0" + "PUBLIC_KEY_ENCODE_ERROR\\0" + "SHOULD_RETRY\\0" + "UNKNOWN_KEY_TYPE\\0" + "UNKNOWN_PURPOSE_ID\\0" + "UNKNOWN_TRUST_ID\\0" + "WRONG_LOOKUP_TYPE\\0" + "BAD_IP_ADDRESS\\0" + "BAD_OBJECT\\0" + "BN_DEC2BN_ERROR\\0" + "BN_TO_ASN1_INTEGER_ERROR\\0" + "CANNOT_FIND_FREE_FUNCTION\\0" + "DIRNAME_ERROR\\0" + "DISTPOINT_ALREADY_SET\\0" + "DUPLICATE_ZONE_ID\\0" + "ERROR_CONVERTING_ZONE\\0" + "ERROR_CREATING_EXTENSION\\0" + "ERROR_IN_EXTENSION\\0" + "EXPECTED_A_SECTION_NAME\\0" + "EXTENSION_EXISTS\\0" + "EXTENSION_NAME_ERROR\\0" + "EXTENSION_NOT_FOUND\\0" + "EXTENSION_SETTING_NOT_SUPPORTED\\0" + "EXTENSION_VALUE_ERROR\\0" + "ILLEGAL_EMPTY_EXTENSION\\0" + "ILLEGAL_HEX_DIGIT\\0" + "INCORRECT_POLICY_SYNTAX_TAG\\0" + "INVALID_BOOLEAN_STRING\\0" + "INVALID_EXTENSION_STRING\\0" + "INVALID_MULTIPLE_RDNS\\0" + "INVALID_NAME\\0" + "INVALID_NULL_ARGUMENT\\0" + "INVALID_NULL_NAME\\0" + "INVALID_NULL_VALUE\\0" + "INVALID_NUMBERS\\0" + "INVALID_OBJECT_IDENTIFIER\\0" + "INVALID_OPTION\\0" + "INVALID_POLICY_IDENTIFIER\\0" + "INVALID_PROXY_POLICY_SETTING\\0" + "INVALID_PURPOSE\\0" + "INVALID_SECTION\\0" + "INVALID_SYNTAX\\0" + "ISSUER_DECODE_ERROR\\0" + "NEED_ORGANIZATION_AND_NUMBERS\\0" + "NO_CONFIG_DATABASE\\0" + "NO_ISSUER_CERTIFICATE\\0" + "NO_ISSUER_DETAILS\\0" + "NO_POLICY_IDENTIFIER\\0" + "NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED\\0" + "NO_PUBLIC_KEY\\0" + "NO_SUBJECT_DETAILS\\0" + "ODD_NUMBER_OF_DIGITS\\0" + "OPERATION_NOT_DEFINED\\0" + "OTHERNAME_ERROR\\0" + "POLICY_LANGUAGE_ALREADY_DEFINED\\0" + "POLICY_PATH_LENGTH\\0" + "POLICY_PATH_LENGTH_ALREADY_DEFINED\\0" + "POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY\\0" + "SECTION_NOT_FOUND\\0" + "UNABLE_TO_GET_ISSUER_DETAILS\\0" + "UNABLE_TO_GET_ISSUER_KEYID\\0" + "UNKNOWN_BIT_STRING_ARGUMENT\\0" + "UNKNOWN_EXTENSION\\0" + "UNKNOWN_EXTENSION_NAME\\0" + "UNKNOWN_OPTION\\0" + "UNSUPPORTED_OPTION\\0" + "USER_TOO_LONG\\0" + ""; + EOF + + sed -i'.back' '/^#define \\([A-Za-z0-9_]*\\) \\1/d' include/openssl/ssl.h + sed -i'.back' 'N;/^#define \\([A-Za-z0-9_]*\\) *\\\\\\n *\\1/d' include/openssl/ssl.h + sed -i'.back' 's/#ifndef md5_block_data_order/#ifndef GRPC_SHADOW_md5_block_data_order/g' crypto/fipsmodule/md5/md5.c + find . -type f \\( -path '*.h' -or -path '*.cc' -or -path '*.c' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/;#include <openssl_grpc/;g' + END_OF_COMMAND + + # Redefine symbols to avoid conflict when the same app also depends on OpenSSL. The list of + # symbols are src/objective-c/grpc_shadow_boringssl_symbol_list. + # This is the last part of this file. + s.prefix_header_contents = + '#define BIO_f_ssl GRPC_SHADOW_BIO_f_ssl', + '#define BIO_set_ssl GRPC_SHADOW_BIO_set_ssl', + '#define SSL_CTX_add_client_custom_ext GRPC_SHADOW_SSL_CTX_add_client_custom_ext', + '#define SSL_CTX_add_server_custom_ext GRPC_SHADOW_SSL_CTX_add_server_custom_ext', + '#define DTLSv1_get_timeout GRPC_SHADOW_DTLSv1_get_timeout', + '#define DTLSv1_handle_timeout GRPC_SHADOW_DTLSv1_handle_timeout', + '#define DTLSv1_set_initial_timeout_duration GRPC_SHADOW_DTLSv1_set_initial_timeout_duration', + '#define SSL_CTX_set_srtp_profiles GRPC_SHADOW_SSL_CTX_set_srtp_profiles', + '#define SSL_CTX_set_tlsext_use_srtp GRPC_SHADOW_SSL_CTX_set_tlsext_use_srtp', + '#define SSL_get_selected_srtp_profile GRPC_SHADOW_SSL_get_selected_srtp_profile', + '#define SSL_get_srtp_profiles GRPC_SHADOW_SSL_get_srtp_profiles', + '#define SSL_set_srtp_profiles GRPC_SHADOW_SSL_set_srtp_profiles', + '#define SSL_set_tlsext_use_srtp GRPC_SHADOW_SSL_set_tlsext_use_srtp', + '#define DTLS_client_method GRPC_SHADOW_DTLS_client_method', + '#define DTLS_method GRPC_SHADOW_DTLS_method', + '#define DTLS_server_method GRPC_SHADOW_DTLS_server_method', + '#define DTLS_with_buffers_method GRPC_SHADOW_DTLS_with_buffers_method', + '#define DTLSv1_2_client_method GRPC_SHADOW_DTLSv1_2_client_method', + '#define DTLSv1_2_method GRPC_SHADOW_DTLSv1_2_method', + '#define DTLSv1_2_server_method GRPC_SHADOW_DTLSv1_2_server_method', + '#define DTLSv1_client_method GRPC_SHADOW_DTLSv1_client_method', + '#define DTLSv1_method GRPC_SHADOW_DTLSv1_method', + '#define DTLSv1_server_method GRPC_SHADOW_DTLSv1_server_method', + '#define SSL_SESSION_from_bytes GRPC_SHADOW_SSL_SESSION_from_bytes', + '#define SSL_SESSION_to_bytes GRPC_SHADOW_SSL_SESSION_to_bytes', + '#define SSL_SESSION_to_bytes_for_ticket GRPC_SHADOW_SSL_SESSION_to_bytes_for_ticket', + '#define i2d_SSL_SESSION GRPC_SHADOW_i2d_SSL_SESSION', + '#define SSL_CTX_set0_client_CAs GRPC_SHADOW_SSL_CTX_set0_client_CAs', + '#define SSL_CTX_set_cert_cb GRPC_SHADOW_SSL_CTX_set_cert_cb', + '#define SSL_CTX_set_chain_and_key GRPC_SHADOW_SSL_CTX_set_chain_and_key', + '#define SSL_CTX_set_ocsp_response GRPC_SHADOW_SSL_CTX_set_ocsp_response', + '#define SSL_CTX_set_signed_cert_timestamp_list GRPC_SHADOW_SSL_CTX_set_signed_cert_timestamp_list', + '#define SSL_CTX_use_certificate_ASN1 GRPC_SHADOW_SSL_CTX_use_certificate_ASN1', + '#define SSL_get0_peer_certificates GRPC_SHADOW_SSL_get0_peer_certificates', + '#define SSL_get0_server_requested_CAs GRPC_SHADOW_SSL_get0_server_requested_CAs', + '#define SSL_set0_client_CAs GRPC_SHADOW_SSL_set0_client_CAs', + '#define SSL_set_cert_cb GRPC_SHADOW_SSL_set_cert_cb', + '#define SSL_set_chain_and_key GRPC_SHADOW_SSL_set_chain_and_key', + '#define SSL_set_ocsp_response GRPC_SHADOW_SSL_set_ocsp_response', + '#define SSL_set_signed_cert_timestamp_list GRPC_SHADOW_SSL_set_signed_cert_timestamp_list', + '#define SSL_use_certificate_ASN1 GRPC_SHADOW_SSL_use_certificate_ASN1', + '#define SSL_CIPHER_description GRPC_SHADOW_SSL_CIPHER_description', + '#define SSL_CIPHER_get_auth_nid GRPC_SHADOW_SSL_CIPHER_get_auth_nid', + '#define SSL_CIPHER_get_bits GRPC_SHADOW_SSL_CIPHER_get_bits', + '#define SSL_CIPHER_get_cipher_nid GRPC_SHADOW_SSL_CIPHER_get_cipher_nid', + '#define SSL_CIPHER_get_digest_nid GRPC_SHADOW_SSL_CIPHER_get_digest_nid', + '#define SSL_CIPHER_get_id GRPC_SHADOW_SSL_CIPHER_get_id', + '#define SSL_CIPHER_get_kx_name GRPC_SHADOW_SSL_CIPHER_get_kx_name', + '#define SSL_CIPHER_get_kx_nid GRPC_SHADOW_SSL_CIPHER_get_kx_nid', + '#define SSL_CIPHER_get_max_version GRPC_SHADOW_SSL_CIPHER_get_max_version', + '#define SSL_CIPHER_get_min_version GRPC_SHADOW_SSL_CIPHER_get_min_version', + '#define SSL_CIPHER_get_name GRPC_SHADOW_SSL_CIPHER_get_name', + '#define SSL_CIPHER_get_prf_nid GRPC_SHADOW_SSL_CIPHER_get_prf_nid', + '#define SSL_CIPHER_get_rfc_name GRPC_SHADOW_SSL_CIPHER_get_rfc_name', + '#define SSL_CIPHER_get_version GRPC_SHADOW_SSL_CIPHER_get_version', + '#define SSL_CIPHER_is_aead GRPC_SHADOW_SSL_CIPHER_is_aead', + '#define SSL_CIPHER_is_block_cipher GRPC_SHADOW_SSL_CIPHER_is_block_cipher', + '#define SSL_CIPHER_standard_name GRPC_SHADOW_SSL_CIPHER_standard_name', + '#define SSL_COMP_add_compression_method GRPC_SHADOW_SSL_COMP_add_compression_method', + '#define SSL_COMP_free_compression_methods GRPC_SHADOW_SSL_COMP_free_compression_methods', + '#define SSL_COMP_get0_name GRPC_SHADOW_SSL_COMP_get0_name', + '#define SSL_COMP_get_compression_methods GRPC_SHADOW_SSL_COMP_get_compression_methods', + '#define SSL_COMP_get_id GRPC_SHADOW_SSL_COMP_get_id', + '#define SSL_COMP_get_name GRPC_SHADOW_SSL_COMP_get_name', + '#define SSL_get_cipher_by_value GRPC_SHADOW_SSL_get_cipher_by_value', + '#define SSL_CTX_get_default_passwd_cb GRPC_SHADOW_SSL_CTX_get_default_passwd_cb', + '#define SSL_CTX_get_default_passwd_cb_userdata GRPC_SHADOW_SSL_CTX_get_default_passwd_cb_userdata', + '#define SSL_CTX_set_default_passwd_cb GRPC_SHADOW_SSL_CTX_set_default_passwd_cb', + '#define SSL_CTX_set_default_passwd_cb_userdata GRPC_SHADOW_SSL_CTX_set_default_passwd_cb_userdata', + '#define SSL_CTX_use_PrivateKey_file GRPC_SHADOW_SSL_CTX_use_PrivateKey_file', + '#define SSL_CTX_use_RSAPrivateKey_file GRPC_SHADOW_SSL_CTX_use_RSAPrivateKey_file', + '#define SSL_CTX_use_certificate_chain_file GRPC_SHADOW_SSL_CTX_use_certificate_chain_file', + '#define SSL_CTX_use_certificate_file GRPC_SHADOW_SSL_CTX_use_certificate_file', + '#define SSL_add_file_cert_subjects_to_stack GRPC_SHADOW_SSL_add_file_cert_subjects_to_stack', + '#define SSL_load_client_CA_file GRPC_SHADOW_SSL_load_client_CA_file', + '#define SSL_use_PrivateKey_file GRPC_SHADOW_SSL_use_PrivateKey_file', + '#define SSL_use_RSAPrivateKey_file GRPC_SHADOW_SSL_use_RSAPrivateKey_file', + '#define SSL_use_certificate_file GRPC_SHADOW_SSL_use_certificate_file', + '#define SSL_get_curve_name GRPC_SHADOW_SSL_get_curve_name', + '#define ERR_load_SSL_strings GRPC_SHADOW_ERR_load_SSL_strings', + '#define OPENSSL_init_ssl GRPC_SHADOW_OPENSSL_init_ssl', + '#define SSL_CTX_check_private_key GRPC_SHADOW_SSL_CTX_check_private_key', + '#define SSL_CTX_cipher_in_group GRPC_SHADOW_SSL_CTX_cipher_in_group', + '#define SSL_CTX_clear_mode GRPC_SHADOW_SSL_CTX_clear_mode', + '#define SSL_CTX_clear_options GRPC_SHADOW_SSL_CTX_clear_options', + '#define SSL_CTX_enable_ocsp_stapling GRPC_SHADOW_SSL_CTX_enable_ocsp_stapling', + '#define SSL_CTX_enable_signed_cert_timestamps GRPC_SHADOW_SSL_CTX_enable_signed_cert_timestamps', + '#define SSL_CTX_enable_tls_channel_id GRPC_SHADOW_SSL_CTX_enable_tls_channel_id', + '#define SSL_CTX_free GRPC_SHADOW_SSL_CTX_free', + '#define SSL_CTX_get0_privatekey GRPC_SHADOW_SSL_CTX_get0_privatekey', + '#define SSL_CTX_get_ciphers GRPC_SHADOW_SSL_CTX_get_ciphers', + '#define SSL_CTX_get_ex_data GRPC_SHADOW_SSL_CTX_get_ex_data', + '#define SSL_CTX_get_ex_new_index GRPC_SHADOW_SSL_CTX_get_ex_new_index', + '#define SSL_CTX_get_keylog_callback GRPC_SHADOW_SSL_CTX_get_keylog_callback', + '#define SSL_CTX_get_max_cert_list GRPC_SHADOW_SSL_CTX_get_max_cert_list', + '#define SSL_CTX_get_mode GRPC_SHADOW_SSL_CTX_get_mode', + '#define SSL_CTX_get_options GRPC_SHADOW_SSL_CTX_get_options', + '#define SSL_CTX_get_quiet_shutdown GRPC_SHADOW_SSL_CTX_get_quiet_shutdown', + '#define SSL_CTX_get_read_ahead GRPC_SHADOW_SSL_CTX_get_read_ahead', + '#define SSL_CTX_get_session_cache_mode GRPC_SHADOW_SSL_CTX_get_session_cache_mode', + '#define SSL_CTX_get_tlsext_ticket_keys GRPC_SHADOW_SSL_CTX_get_tlsext_ticket_keys', + '#define SSL_CTX_need_tmp_RSA GRPC_SHADOW_SSL_CTX_need_tmp_RSA', + '#define SSL_CTX_new GRPC_SHADOW_SSL_CTX_new', + '#define SSL_CTX_sess_accept GRPC_SHADOW_SSL_CTX_sess_accept', + '#define SSL_CTX_sess_accept_good GRPC_SHADOW_SSL_CTX_sess_accept_good', + '#define SSL_CTX_sess_accept_renegotiate GRPC_SHADOW_SSL_CTX_sess_accept_renegotiate', + '#define SSL_CTX_sess_cache_full GRPC_SHADOW_SSL_CTX_sess_cache_full', + '#define SSL_CTX_sess_cb_hits GRPC_SHADOW_SSL_CTX_sess_cb_hits', + '#define SSL_CTX_sess_connect GRPC_SHADOW_SSL_CTX_sess_connect', + '#define SSL_CTX_sess_connect_good GRPC_SHADOW_SSL_CTX_sess_connect_good', + '#define SSL_CTX_sess_connect_renegotiate GRPC_SHADOW_SSL_CTX_sess_connect_renegotiate', + '#define SSL_CTX_sess_get_cache_size GRPC_SHADOW_SSL_CTX_sess_get_cache_size', + '#define SSL_CTX_sess_hits GRPC_SHADOW_SSL_CTX_sess_hits', + '#define SSL_CTX_sess_misses GRPC_SHADOW_SSL_CTX_sess_misses', + '#define SSL_CTX_sess_number GRPC_SHADOW_SSL_CTX_sess_number', + '#define SSL_CTX_sess_set_cache_size GRPC_SHADOW_SSL_CTX_sess_set_cache_size', + '#define SSL_CTX_sess_timeouts GRPC_SHADOW_SSL_CTX_sess_timeouts', + '#define SSL_CTX_set0_buffer_pool GRPC_SHADOW_SSL_CTX_set0_buffer_pool', + '#define SSL_CTX_set1_curves GRPC_SHADOW_SSL_CTX_set1_curves', + '#define SSL_CTX_set1_curves_list GRPC_SHADOW_SSL_CTX_set1_curves_list', + '#define SSL_CTX_set1_tls_channel_id GRPC_SHADOW_SSL_CTX_set1_tls_channel_id', + '#define SSL_CTX_set_allow_unknown_alpn_protos GRPC_SHADOW_SSL_CTX_set_allow_unknown_alpn_protos', + '#define SSL_CTX_set_alpn_protos GRPC_SHADOW_SSL_CTX_set_alpn_protos', + '#define SSL_CTX_set_alpn_select_cb GRPC_SHADOW_SSL_CTX_set_alpn_select_cb', + '#define SSL_CTX_set_cipher_list GRPC_SHADOW_SSL_CTX_set_cipher_list', + '#define SSL_CTX_set_current_time_cb GRPC_SHADOW_SSL_CTX_set_current_time_cb', + '#define SSL_CTX_set_custom_verify GRPC_SHADOW_SSL_CTX_set_custom_verify', + '#define SSL_CTX_set_dos_protection_cb GRPC_SHADOW_SSL_CTX_set_dos_protection_cb', + '#define SSL_CTX_set_early_data_enabled GRPC_SHADOW_SSL_CTX_set_early_data_enabled', + '#define SSL_CTX_set_ex_data GRPC_SHADOW_SSL_CTX_set_ex_data', + '#define SSL_CTX_set_false_start_allowed_without_alpn GRPC_SHADOW_SSL_CTX_set_false_start_allowed_without_alpn', + '#define SSL_CTX_set_grease_enabled GRPC_SHADOW_SSL_CTX_set_grease_enabled', + '#define SSL_CTX_set_keylog_callback GRPC_SHADOW_SSL_CTX_set_keylog_callback', + '#define SSL_CTX_set_max_cert_list GRPC_SHADOW_SSL_CTX_set_max_cert_list', + '#define SSL_CTX_set_max_send_fragment GRPC_SHADOW_SSL_CTX_set_max_send_fragment', + '#define SSL_CTX_set_mode GRPC_SHADOW_SSL_CTX_set_mode', + '#define SSL_CTX_set_msg_callback GRPC_SHADOW_SSL_CTX_set_msg_callback', + '#define SSL_CTX_set_msg_callback_arg GRPC_SHADOW_SSL_CTX_set_msg_callback_arg', + '#define SSL_CTX_set_next_proto_select_cb GRPC_SHADOW_SSL_CTX_set_next_proto_select_cb', + '#define SSL_CTX_set_next_protos_advertised_cb GRPC_SHADOW_SSL_CTX_set_next_protos_advertised_cb', + '#define SSL_CTX_set_options GRPC_SHADOW_SSL_CTX_set_options', + '#define SSL_CTX_set_psk_client_callback GRPC_SHADOW_SSL_CTX_set_psk_client_callback', + '#define SSL_CTX_set_psk_server_callback GRPC_SHADOW_SSL_CTX_set_psk_server_callback', + '#define SSL_CTX_set_quiet_shutdown GRPC_SHADOW_SSL_CTX_set_quiet_shutdown', + '#define SSL_CTX_set_read_ahead GRPC_SHADOW_SSL_CTX_set_read_ahead', + '#define SSL_CTX_set_retain_only_sha256_of_client_certs GRPC_SHADOW_SSL_CTX_set_retain_only_sha256_of_client_certs', + '#define SSL_CTX_set_select_certificate_cb GRPC_SHADOW_SSL_CTX_set_select_certificate_cb', + '#define SSL_CTX_set_session_cache_mode GRPC_SHADOW_SSL_CTX_set_session_cache_mode', + '#define SSL_CTX_set_session_id_context GRPC_SHADOW_SSL_CTX_set_session_id_context', + '#define SSL_CTX_set_strict_cipher_list GRPC_SHADOW_SSL_CTX_set_strict_cipher_list', + '#define SSL_CTX_set_ticket_aead_method GRPC_SHADOW_SSL_CTX_set_ticket_aead_method', + '#define SSL_CTX_set_tls13_variant GRPC_SHADOW_SSL_CTX_set_tls13_variant', + '#define SSL_CTX_set_tls_channel_id_enabled GRPC_SHADOW_SSL_CTX_set_tls_channel_id_enabled', + '#define SSL_CTX_set_tlsext_servername_arg GRPC_SHADOW_SSL_CTX_set_tlsext_servername_arg', + '#define SSL_CTX_set_tlsext_servername_callback GRPC_SHADOW_SSL_CTX_set_tlsext_servername_callback', + '#define SSL_CTX_set_tlsext_ticket_key_cb GRPC_SHADOW_SSL_CTX_set_tlsext_ticket_key_cb', + '#define SSL_CTX_set_tlsext_ticket_keys GRPC_SHADOW_SSL_CTX_set_tlsext_ticket_keys', + '#define SSL_CTX_set_tmp_dh GRPC_SHADOW_SSL_CTX_set_tmp_dh', + '#define SSL_CTX_set_tmp_dh_callback GRPC_SHADOW_SSL_CTX_set_tmp_dh_callback', + '#define SSL_CTX_set_tmp_ecdh GRPC_SHADOW_SSL_CTX_set_tmp_ecdh', + '#define SSL_CTX_set_tmp_rsa GRPC_SHADOW_SSL_CTX_set_tmp_rsa', + '#define SSL_CTX_set_tmp_rsa_callback GRPC_SHADOW_SSL_CTX_set_tmp_rsa_callback', + '#define SSL_CTX_up_ref GRPC_SHADOW_SSL_CTX_up_ref', + '#define SSL_CTX_use_psk_identity_hint GRPC_SHADOW_SSL_CTX_use_psk_identity_hint', + '#define SSL_accept GRPC_SHADOW_SSL_accept', + '#define SSL_cache_hit GRPC_SHADOW_SSL_cache_hit', + '#define SSL_certs_clear GRPC_SHADOW_SSL_certs_clear', + '#define SSL_check_private_key GRPC_SHADOW_SSL_check_private_key', + '#define SSL_clear GRPC_SHADOW_SSL_clear', + '#define SSL_clear_mode GRPC_SHADOW_SSL_clear_mode', + '#define SSL_clear_options GRPC_SHADOW_SSL_clear_options', + '#define SSL_connect GRPC_SHADOW_SSL_connect', + '#define SSL_cutthrough_complete GRPC_SHADOW_SSL_cutthrough_complete', + '#define SSL_do_handshake GRPC_SHADOW_SSL_do_handshake', + '#define SSL_dummy_pq_padding_used GRPC_SHADOW_SSL_dummy_pq_padding_used', + '#define SSL_early_data_accepted GRPC_SHADOW_SSL_early_data_accepted', + '#define SSL_enable_ocsp_stapling GRPC_SHADOW_SSL_enable_ocsp_stapling', + '#define SSL_enable_signed_cert_timestamps GRPC_SHADOW_SSL_enable_signed_cert_timestamps', + '#define SSL_enable_tls_channel_id GRPC_SHADOW_SSL_enable_tls_channel_id', + '#define SSL_free GRPC_SHADOW_SSL_free', + '#define SSL_get0_alpn_selected GRPC_SHADOW_SSL_get0_alpn_selected', + '#define SSL_get0_certificate_types GRPC_SHADOW_SSL_get0_certificate_types', + '#define SSL_get0_next_proto_negotiated GRPC_SHADOW_SSL_get0_next_proto_negotiated', + '#define SSL_get0_ocsp_response GRPC_SHADOW_SSL_get0_ocsp_response', + '#define SSL_get0_session_id_context GRPC_SHADOW_SSL_get0_session_id_context', + '#define SSL_get0_signed_cert_timestamp_list GRPC_SHADOW_SSL_get0_signed_cert_timestamp_list', + '#define SSL_get_SSL_CTX GRPC_SHADOW_SSL_get_SSL_CTX', + '#define SSL_get_cipher_list GRPC_SHADOW_SSL_get_cipher_list', + '#define SSL_get_ciphers GRPC_SHADOW_SSL_get_ciphers', + '#define SSL_get_client_random GRPC_SHADOW_SSL_get_client_random', + '#define SSL_get_current_cipher GRPC_SHADOW_SSL_get_current_cipher', + '#define SSL_get_current_compression GRPC_SHADOW_SSL_get_current_compression', + '#define SSL_get_current_expansion GRPC_SHADOW_SSL_get_current_expansion', + '#define SSL_get_curve_id GRPC_SHADOW_SSL_get_curve_id', + '#define SSL_get_default_timeout GRPC_SHADOW_SSL_get_default_timeout', + '#define SSL_get_error GRPC_SHADOW_SSL_get_error', + '#define SSL_get_ex_data GRPC_SHADOW_SSL_get_ex_data', + '#define SSL_get_ex_new_index GRPC_SHADOW_SSL_get_ex_new_index', + '#define SSL_get_extms_support GRPC_SHADOW_SSL_get_extms_support', + '#define SSL_get_fd GRPC_SHADOW_SSL_get_fd', + '#define SSL_get_finished GRPC_SHADOW_SSL_get_finished', + '#define SSL_get_info_callback GRPC_SHADOW_SSL_get_info_callback', + '#define SSL_get_ivs GRPC_SHADOW_SSL_get_ivs', + '#define SSL_get_max_cert_list GRPC_SHADOW_SSL_get_max_cert_list', + '#define SSL_get_mode GRPC_SHADOW_SSL_get_mode', + '#define SSL_get_negotiated_token_binding_param GRPC_SHADOW_SSL_get_negotiated_token_binding_param', + '#define SSL_get_options GRPC_SHADOW_SSL_get_options', + '#define SSL_get_peer_finished GRPC_SHADOW_SSL_get_peer_finished', + '#define SSL_get_peer_quic_transport_params GRPC_SHADOW_SSL_get_peer_quic_transport_params', + '#define SSL_get_peer_signature_algorithm GRPC_SHADOW_SSL_get_peer_signature_algorithm', + '#define SSL_get_pending_cipher GRPC_SHADOW_SSL_get_pending_cipher', + '#define SSL_get_privatekey GRPC_SHADOW_SSL_get_privatekey', + '#define SSL_get_psk_identity GRPC_SHADOW_SSL_get_psk_identity', + '#define SSL_get_psk_identity_hint GRPC_SHADOW_SSL_get_psk_identity_hint', + '#define SSL_get_quiet_shutdown GRPC_SHADOW_SSL_get_quiet_shutdown', + '#define SSL_get_rbio GRPC_SHADOW_SSL_get_rbio', + '#define SSL_get_read_ahead GRPC_SHADOW_SSL_get_read_ahead', + '#define SSL_get_read_sequence GRPC_SHADOW_SSL_get_read_sequence', + '#define SSL_get_rfd GRPC_SHADOW_SSL_get_rfd', + '#define SSL_get_secure_renegotiation_support GRPC_SHADOW_SSL_get_secure_renegotiation_support', + '#define SSL_get_server_random GRPC_SHADOW_SSL_get_server_random', + '#define SSL_get_server_tmp_key GRPC_SHADOW_SSL_get_server_tmp_key', + '#define SSL_get_servername GRPC_SHADOW_SSL_get_servername', + '#define SSL_get_servername_type GRPC_SHADOW_SSL_get_servername_type', + '#define SSL_get_shared_ciphers GRPC_SHADOW_SSL_get_shared_ciphers', + '#define SSL_get_shutdown GRPC_SHADOW_SSL_get_shutdown', + '#define SSL_get_structure_sizes GRPC_SHADOW_SSL_get_structure_sizes', + '#define SSL_get_ticket_age_skew GRPC_SHADOW_SSL_get_ticket_age_skew', + '#define SSL_get_tls_channel_id GRPC_SHADOW_SSL_get_tls_channel_id', + '#define SSL_get_tls_unique GRPC_SHADOW_SSL_get_tls_unique', + '#define SSL_get_verify_mode GRPC_SHADOW_SSL_get_verify_mode', + '#define SSL_get_wbio GRPC_SHADOW_SSL_get_wbio', + '#define SSL_get_wfd GRPC_SHADOW_SSL_get_wfd', + '#define SSL_get_write_sequence GRPC_SHADOW_SSL_get_write_sequence', + '#define SSL_in_early_data GRPC_SHADOW_SSL_in_early_data', + '#define SSL_in_false_start GRPC_SHADOW_SSL_in_false_start', + '#define SSL_in_init GRPC_SHADOW_SSL_in_init', + '#define SSL_is_draft_downgrade GRPC_SHADOW_SSL_is_draft_downgrade', + '#define SSL_is_dtls GRPC_SHADOW_SSL_is_dtls', + '#define SSL_is_init_finished GRPC_SHADOW_SSL_is_init_finished', + '#define SSL_is_server GRPC_SHADOW_SSL_is_server', + '#define SSL_is_token_binding_negotiated GRPC_SHADOW_SSL_is_token_binding_negotiated', + '#define SSL_library_init GRPC_SHADOW_SSL_library_init', + '#define SSL_load_error_strings GRPC_SHADOW_SSL_load_error_strings', + '#define SSL_need_tmp_RSA GRPC_SHADOW_SSL_need_tmp_RSA', + '#define SSL_new GRPC_SHADOW_SSL_new', + '#define SSL_num_renegotiations GRPC_SHADOW_SSL_num_renegotiations', + '#define SSL_peek GRPC_SHADOW_SSL_peek', + '#define SSL_pending GRPC_SHADOW_SSL_pending', + '#define SSL_read GRPC_SHADOW_SSL_read', + '#define SSL_renegotiate GRPC_SHADOW_SSL_renegotiate', + '#define SSL_renegotiate_pending GRPC_SHADOW_SSL_renegotiate_pending', + '#define SSL_reset_early_data_reject GRPC_SHADOW_SSL_reset_early_data_reject', + '#define SSL_select_next_proto GRPC_SHADOW_SSL_select_next_proto', + '#define SSL_send_fatal_alert GRPC_SHADOW_SSL_send_fatal_alert', + '#define SSL_session_reused GRPC_SHADOW_SSL_session_reused', + '#define SSL_set0_rbio GRPC_SHADOW_SSL_set0_rbio', + '#define SSL_set0_wbio GRPC_SHADOW_SSL_set0_wbio', + '#define SSL_set1_curves GRPC_SHADOW_SSL_set1_curves', + '#define SSL_set1_curves_list GRPC_SHADOW_SSL_set1_curves_list', + '#define SSL_set1_tls_channel_id GRPC_SHADOW_SSL_set1_tls_channel_id', + '#define SSL_set_SSL_CTX GRPC_SHADOW_SSL_set_SSL_CTX', + '#define SSL_set_accept_state GRPC_SHADOW_SSL_set_accept_state', + '#define SSL_set_alpn_protos GRPC_SHADOW_SSL_set_alpn_protos', + '#define SSL_set_bio GRPC_SHADOW_SSL_set_bio', + '#define SSL_set_cipher_list GRPC_SHADOW_SSL_set_cipher_list', + '#define SSL_set_connect_state GRPC_SHADOW_SSL_set_connect_state', + '#define SSL_set_custom_verify GRPC_SHADOW_SSL_set_custom_verify', + '#define SSL_set_dummy_pq_padding_size GRPC_SHADOW_SSL_set_dummy_pq_padding_size', + '#define SSL_set_early_data_enabled GRPC_SHADOW_SSL_set_early_data_enabled', + '#define SSL_set_ex_data GRPC_SHADOW_SSL_set_ex_data', + '#define SSL_set_fd GRPC_SHADOW_SSL_set_fd', + '#define SSL_set_info_callback GRPC_SHADOW_SSL_set_info_callback', + '#define SSL_set_max_cert_list GRPC_SHADOW_SSL_set_max_cert_list', + '#define SSL_set_max_send_fragment GRPC_SHADOW_SSL_set_max_send_fragment', + '#define SSL_set_mode GRPC_SHADOW_SSL_set_mode', + '#define SSL_set_msg_callback GRPC_SHADOW_SSL_set_msg_callback', + '#define SSL_set_msg_callback_arg GRPC_SHADOW_SSL_set_msg_callback_arg', + '#define SSL_set_mtu GRPC_SHADOW_SSL_set_mtu', + '#define SSL_set_options GRPC_SHADOW_SSL_set_options', + '#define SSL_set_psk_client_callback GRPC_SHADOW_SSL_set_psk_client_callback', + '#define SSL_set_psk_server_callback GRPC_SHADOW_SSL_set_psk_server_callback', + '#define SSL_set_quic_transport_params GRPC_SHADOW_SSL_set_quic_transport_params', + '#define SSL_set_quiet_shutdown GRPC_SHADOW_SSL_set_quiet_shutdown', + '#define SSL_set_read_ahead GRPC_SHADOW_SSL_set_read_ahead', + '#define SSL_set_renegotiate_mode GRPC_SHADOW_SSL_set_renegotiate_mode', + '#define SSL_set_retain_only_sha256_of_client_certs GRPC_SHADOW_SSL_set_retain_only_sha256_of_client_certs', + '#define SSL_set_rfd GRPC_SHADOW_SSL_set_rfd', + '#define SSL_set_session_id_context GRPC_SHADOW_SSL_set_session_id_context', + '#define SSL_set_shutdown GRPC_SHADOW_SSL_set_shutdown', + '#define SSL_set_state GRPC_SHADOW_SSL_set_state', + '#define SSL_set_strict_cipher_list GRPC_SHADOW_SSL_set_strict_cipher_list', + '#define SSL_set_tls13_variant GRPC_SHADOW_SSL_set_tls13_variant', + '#define SSL_set_tls_channel_id_enabled GRPC_SHADOW_SSL_set_tls_channel_id_enabled', + '#define SSL_set_tlsext_host_name GRPC_SHADOW_SSL_set_tlsext_host_name', + '#define SSL_set_tmp_dh GRPC_SHADOW_SSL_set_tmp_dh', + '#define SSL_set_tmp_dh_callback GRPC_SHADOW_SSL_set_tmp_dh_callback', + '#define SSL_set_tmp_ecdh GRPC_SHADOW_SSL_set_tmp_ecdh', + '#define SSL_set_tmp_rsa GRPC_SHADOW_SSL_set_tmp_rsa', + '#define SSL_set_tmp_rsa_callback GRPC_SHADOW_SSL_set_tmp_rsa_callback', + '#define SSL_set_token_binding_params GRPC_SHADOW_SSL_set_token_binding_params', + '#define SSL_set_wfd GRPC_SHADOW_SSL_set_wfd', + '#define SSL_shutdown GRPC_SHADOW_SSL_shutdown', + '#define SSL_state GRPC_SHADOW_SSL_state', + '#define SSL_total_renegotiations GRPC_SHADOW_SSL_total_renegotiations', + '#define SSL_use_psk_identity_hint GRPC_SHADOW_SSL_use_psk_identity_hint', + '#define SSL_want GRPC_SHADOW_SSL_want', + '#define SSL_write GRPC_SHADOW_SSL_write', + '#define SSL_CTX_set_private_key_method GRPC_SHADOW_SSL_CTX_set_private_key_method', + '#define SSL_CTX_set_signing_algorithm_prefs GRPC_SHADOW_SSL_CTX_set_signing_algorithm_prefs', + '#define SSL_CTX_set_verify_algorithm_prefs GRPC_SHADOW_SSL_CTX_set_verify_algorithm_prefs', + '#define SSL_CTX_use_PrivateKey GRPC_SHADOW_SSL_CTX_use_PrivateKey', + '#define SSL_CTX_use_PrivateKey_ASN1 GRPC_SHADOW_SSL_CTX_use_PrivateKey_ASN1', + '#define SSL_CTX_use_RSAPrivateKey GRPC_SHADOW_SSL_CTX_use_RSAPrivateKey', + '#define SSL_CTX_use_RSAPrivateKey_ASN1 GRPC_SHADOW_SSL_CTX_use_RSAPrivateKey_ASN1', + '#define SSL_get_signature_algorithm_digest GRPC_SHADOW_SSL_get_signature_algorithm_digest', + '#define SSL_get_signature_algorithm_key_type GRPC_SHADOW_SSL_get_signature_algorithm_key_type', + '#define SSL_get_signature_algorithm_name GRPC_SHADOW_SSL_get_signature_algorithm_name', + '#define SSL_is_signature_algorithm_rsa_pss GRPC_SHADOW_SSL_is_signature_algorithm_rsa_pss', + '#define SSL_set_private_key_method GRPC_SHADOW_SSL_set_private_key_method', + '#define SSL_set_signing_algorithm_prefs GRPC_SHADOW_SSL_set_signing_algorithm_prefs', + '#define SSL_use_PrivateKey GRPC_SHADOW_SSL_use_PrivateKey', + '#define SSL_use_PrivateKey_ASN1 GRPC_SHADOW_SSL_use_PrivateKey_ASN1', + '#define SSL_use_RSAPrivateKey GRPC_SHADOW_SSL_use_RSAPrivateKey', + '#define SSL_use_RSAPrivateKey_ASN1 GRPC_SHADOW_SSL_use_RSAPrivateKey_ASN1', + '#define SSL_CTX_add_session GRPC_SHADOW_SSL_CTX_add_session', + '#define SSL_CTX_flush_sessions GRPC_SHADOW_SSL_CTX_flush_sessions', + '#define SSL_CTX_get_channel_id_cb GRPC_SHADOW_SSL_CTX_get_channel_id_cb', + '#define SSL_CTX_get_info_callback GRPC_SHADOW_SSL_CTX_get_info_callback', + '#define SSL_CTX_get_timeout GRPC_SHADOW_SSL_CTX_get_timeout', + '#define SSL_CTX_remove_session GRPC_SHADOW_SSL_CTX_remove_session', + '#define SSL_CTX_sess_get_get_cb GRPC_SHADOW_SSL_CTX_sess_get_get_cb', + '#define SSL_CTX_sess_get_new_cb GRPC_SHADOW_SSL_CTX_sess_get_new_cb', + '#define SSL_CTX_sess_get_remove_cb GRPC_SHADOW_SSL_CTX_sess_get_remove_cb', + '#define SSL_CTX_sess_set_get_cb GRPC_SHADOW_SSL_CTX_sess_set_get_cb', + '#define SSL_CTX_sess_set_new_cb GRPC_SHADOW_SSL_CTX_sess_set_new_cb', + '#define SSL_CTX_sess_set_remove_cb GRPC_SHADOW_SSL_CTX_sess_set_remove_cb', + '#define SSL_CTX_set_channel_id_cb GRPC_SHADOW_SSL_CTX_set_channel_id_cb', + '#define SSL_CTX_set_info_callback GRPC_SHADOW_SSL_CTX_set_info_callback', + '#define SSL_CTX_set_session_psk_dhe_timeout GRPC_SHADOW_SSL_CTX_set_session_psk_dhe_timeout', + '#define SSL_CTX_set_timeout GRPC_SHADOW_SSL_CTX_set_timeout', + '#define SSL_SESSION_free GRPC_SHADOW_SSL_SESSION_free', + '#define SSL_SESSION_get0_peer GRPC_SHADOW_SSL_SESSION_get0_peer', + '#define SSL_SESSION_get0_ticket GRPC_SHADOW_SSL_SESSION_get0_ticket', + '#define SSL_SESSION_get_ex_data GRPC_SHADOW_SSL_SESSION_get_ex_data', + '#define SSL_SESSION_get_ex_new_index GRPC_SHADOW_SSL_SESSION_get_ex_new_index', + '#define SSL_SESSION_get_id GRPC_SHADOW_SSL_SESSION_get_id', + '#define SSL_SESSION_get_master_key GRPC_SHADOW_SSL_SESSION_get_master_key', + '#define SSL_SESSION_get_ticket_lifetime_hint GRPC_SHADOW_SSL_SESSION_get_ticket_lifetime_hint', + '#define SSL_SESSION_get_time GRPC_SHADOW_SSL_SESSION_get_time', + '#define SSL_SESSION_get_timeout GRPC_SHADOW_SSL_SESSION_get_timeout', + '#define SSL_SESSION_has_ticket GRPC_SHADOW_SSL_SESSION_has_ticket', + '#define SSL_SESSION_is_resumable GRPC_SHADOW_SSL_SESSION_is_resumable', + '#define SSL_SESSION_new GRPC_SHADOW_SSL_SESSION_new', + '#define SSL_SESSION_set1_id_context GRPC_SHADOW_SSL_SESSION_set1_id_context', + '#define SSL_SESSION_set_ex_data GRPC_SHADOW_SSL_SESSION_set_ex_data', + '#define SSL_SESSION_set_time GRPC_SHADOW_SSL_SESSION_set_time', + '#define SSL_SESSION_set_timeout GRPC_SHADOW_SSL_SESSION_set_timeout', + '#define SSL_SESSION_should_be_single_use GRPC_SHADOW_SSL_SESSION_should_be_single_use', + '#define SSL_SESSION_up_ref GRPC_SHADOW_SSL_SESSION_up_ref', + '#define SSL_get1_session GRPC_SHADOW_SSL_get1_session', + '#define SSL_get_session GRPC_SHADOW_SSL_get_session', + '#define SSL_magic_pending_session_ptr GRPC_SHADOW_SSL_magic_pending_session_ptr', + '#define SSL_set_session GRPC_SHADOW_SSL_set_session', + '#define SSL_alert_desc_string GRPC_SHADOW_SSL_alert_desc_string', + '#define SSL_alert_desc_string_long GRPC_SHADOW_SSL_alert_desc_string_long', + '#define SSL_alert_type_string GRPC_SHADOW_SSL_alert_type_string', + '#define SSL_alert_type_string_long GRPC_SHADOW_SSL_alert_type_string_long', + '#define SSL_state_string GRPC_SHADOW_SSL_state_string', + '#define SSL_state_string_long GRPC_SHADOW_SSL_state_string_long', + '#define SSL_CTX_set_max_proto_version GRPC_SHADOW_SSL_CTX_set_max_proto_version', + '#define SSL_CTX_set_min_proto_version GRPC_SHADOW_SSL_CTX_set_min_proto_version', + '#define SSL_SESSION_get_protocol_version GRPC_SHADOW_SSL_SESSION_get_protocol_version', + '#define SSL_SESSION_get_version GRPC_SHADOW_SSL_SESSION_get_version', + '#define SSL_SESSION_set_protocol_version GRPC_SHADOW_SSL_SESSION_set_protocol_version', + '#define SSL_get_version GRPC_SHADOW_SSL_get_version', + '#define SSL_set_max_proto_version GRPC_SHADOW_SSL_set_max_proto_version', + '#define SSL_set_min_proto_version GRPC_SHADOW_SSL_set_min_proto_version', + '#define SSL_version GRPC_SHADOW_SSL_version', + '#define PEM_read_SSL_SESSION GRPC_SHADOW_PEM_read_SSL_SESSION', + '#define PEM_read_bio_SSL_SESSION GRPC_SHADOW_PEM_read_bio_SSL_SESSION', + '#define PEM_write_SSL_SESSION GRPC_SHADOW_PEM_write_SSL_SESSION', + '#define PEM_write_bio_SSL_SESSION GRPC_SHADOW_PEM_write_bio_SSL_SESSION', + '#define SSL_CTX_add0_chain_cert GRPC_SHADOW_SSL_CTX_add0_chain_cert', + '#define SSL_CTX_add1_chain_cert GRPC_SHADOW_SSL_CTX_add1_chain_cert', + '#define SSL_CTX_add_client_CA GRPC_SHADOW_SSL_CTX_add_client_CA', + '#define SSL_CTX_add_extra_chain_cert GRPC_SHADOW_SSL_CTX_add_extra_chain_cert', + '#define SSL_CTX_clear_chain_certs GRPC_SHADOW_SSL_CTX_clear_chain_certs', + '#define SSL_CTX_clear_extra_chain_certs GRPC_SHADOW_SSL_CTX_clear_extra_chain_certs', + '#define SSL_CTX_get0_certificate GRPC_SHADOW_SSL_CTX_get0_certificate', + '#define SSL_CTX_get0_chain_certs GRPC_SHADOW_SSL_CTX_get0_chain_certs', + '#define SSL_CTX_get0_param GRPC_SHADOW_SSL_CTX_get0_param', + '#define SSL_CTX_get_cert_store GRPC_SHADOW_SSL_CTX_get_cert_store', + '#define SSL_CTX_get_client_CA_list GRPC_SHADOW_SSL_CTX_get_client_CA_list', + '#define SSL_CTX_get_extra_chain_certs GRPC_SHADOW_SSL_CTX_get_extra_chain_certs', + '#define SSL_CTX_get_verify_callback GRPC_SHADOW_SSL_CTX_get_verify_callback', + '#define SSL_CTX_get_verify_depth GRPC_SHADOW_SSL_CTX_get_verify_depth', + '#define SSL_CTX_get_verify_mode GRPC_SHADOW_SSL_CTX_get_verify_mode', + '#define SSL_CTX_load_verify_locations GRPC_SHADOW_SSL_CTX_load_verify_locations', + '#define SSL_CTX_set0_chain GRPC_SHADOW_SSL_CTX_set0_chain', + '#define SSL_CTX_set0_verify_cert_store GRPC_SHADOW_SSL_CTX_set0_verify_cert_store', + '#define SSL_CTX_set1_chain GRPC_SHADOW_SSL_CTX_set1_chain', + '#define SSL_CTX_set1_param GRPC_SHADOW_SSL_CTX_set1_param', + '#define SSL_CTX_set1_verify_cert_store GRPC_SHADOW_SSL_CTX_set1_verify_cert_store', + '#define SSL_CTX_set_cert_store GRPC_SHADOW_SSL_CTX_set_cert_store', + '#define SSL_CTX_set_cert_verify_callback GRPC_SHADOW_SSL_CTX_set_cert_verify_callback', + '#define SSL_CTX_set_client_CA_list GRPC_SHADOW_SSL_CTX_set_client_CA_list', + '#define SSL_CTX_set_client_cert_cb GRPC_SHADOW_SSL_CTX_set_client_cert_cb', + '#define SSL_CTX_set_default_verify_paths GRPC_SHADOW_SSL_CTX_set_default_verify_paths', + '#define SSL_CTX_set_purpose GRPC_SHADOW_SSL_CTX_set_purpose', + '#define SSL_CTX_set_trust GRPC_SHADOW_SSL_CTX_set_trust', + '#define SSL_CTX_set_verify GRPC_SHADOW_SSL_CTX_set_verify', + '#define SSL_CTX_set_verify_depth GRPC_SHADOW_SSL_CTX_set_verify_depth', + '#define SSL_CTX_use_certificate GRPC_SHADOW_SSL_CTX_use_certificate', + '#define SSL_add0_chain_cert GRPC_SHADOW_SSL_add0_chain_cert', + '#define SSL_add1_chain_cert GRPC_SHADOW_SSL_add1_chain_cert', + '#define SSL_add_client_CA GRPC_SHADOW_SSL_add_client_CA', + '#define SSL_alert_from_verify_result GRPC_SHADOW_SSL_alert_from_verify_result', + '#define SSL_clear_chain_certs GRPC_SHADOW_SSL_clear_chain_certs', + '#define SSL_dup_CA_list GRPC_SHADOW_SSL_dup_CA_list', + '#define SSL_get0_chain_certs GRPC_SHADOW_SSL_get0_chain_certs', + '#define SSL_get0_param GRPC_SHADOW_SSL_get0_param', + '#define SSL_get_certificate GRPC_SHADOW_SSL_get_certificate', + '#define SSL_get_client_CA_list GRPC_SHADOW_SSL_get_client_CA_list', + '#define SSL_get_ex_data_X509_STORE_CTX_idx GRPC_SHADOW_SSL_get_ex_data_X509_STORE_CTX_idx', + '#define SSL_get_peer_cert_chain GRPC_SHADOW_SSL_get_peer_cert_chain', + '#define SSL_get_peer_certificate GRPC_SHADOW_SSL_get_peer_certificate', + '#define SSL_get_peer_full_cert_chain GRPC_SHADOW_SSL_get_peer_full_cert_chain', + '#define SSL_get_verify_callback GRPC_SHADOW_SSL_get_verify_callback', + '#define SSL_get_verify_depth GRPC_SHADOW_SSL_get_verify_depth', + '#define SSL_get_verify_result GRPC_SHADOW_SSL_get_verify_result', + '#define SSL_set0_chain GRPC_SHADOW_SSL_set0_chain', + '#define SSL_set0_verify_cert_store GRPC_SHADOW_SSL_set0_verify_cert_store', + '#define SSL_set1_chain GRPC_SHADOW_SSL_set1_chain', + '#define SSL_set1_param GRPC_SHADOW_SSL_set1_param', + '#define SSL_set1_verify_cert_store GRPC_SHADOW_SSL_set1_verify_cert_store', + '#define SSL_set_client_CA_list GRPC_SHADOW_SSL_set_client_CA_list', + '#define SSL_set_purpose GRPC_SHADOW_SSL_set_purpose', + '#define SSL_set_trust GRPC_SHADOW_SSL_set_trust', + '#define SSL_set_verify GRPC_SHADOW_SSL_set_verify', + '#define SSL_set_verify_depth GRPC_SHADOW_SSL_set_verify_depth', + '#define SSL_set_verify_result GRPC_SHADOW_SSL_set_verify_result', + '#define SSL_use_certificate GRPC_SHADOW_SSL_use_certificate', + '#define d2i_SSL_SESSION GRPC_SHADOW_d2i_SSL_SESSION', + '#define d2i_SSL_SESSION_bio GRPC_SHADOW_d2i_SSL_SESSION_bio', + '#define i2d_SSL_SESSION_bio GRPC_SHADOW_i2d_SSL_SESSION_bio', + '#define SSL_export_early_keying_material GRPC_SHADOW_SSL_export_early_keying_material', + '#define SSL_export_keying_material GRPC_SHADOW_SSL_export_keying_material', + '#define SSL_generate_key_block GRPC_SHADOW_SSL_generate_key_block', + '#define SSL_get_key_block_len GRPC_SHADOW_SSL_get_key_block_len', + '#define SSL_CTX_set_ed25519_enabled GRPC_SHADOW_SSL_CTX_set_ed25519_enabled', + '#define SSL_early_callback_ctx_extension_get GRPC_SHADOW_SSL_early_callback_ctx_extension_get', + '#define SSL_extension_supported GRPC_SHADOW_SSL_extension_supported', + '#define SSLv23_client_method GRPC_SHADOW_SSLv23_client_method', + '#define SSLv23_method GRPC_SHADOW_SSLv23_method', + '#define SSLv23_server_method GRPC_SHADOW_SSLv23_server_method', + '#define TLS_client_method GRPC_SHADOW_TLS_client_method', + '#define TLS_method GRPC_SHADOW_TLS_method', + '#define TLS_server_method GRPC_SHADOW_TLS_server_method', + '#define TLS_with_buffers_method GRPC_SHADOW_TLS_with_buffers_method', + '#define TLSv1_1_client_method GRPC_SHADOW_TLSv1_1_client_method', + '#define TLSv1_1_method GRPC_SHADOW_TLSv1_1_method', + '#define TLSv1_1_server_method GRPC_SHADOW_TLSv1_1_server_method', + '#define TLSv1_2_client_method GRPC_SHADOW_TLSv1_2_client_method', + '#define TLSv1_2_method GRPC_SHADOW_TLSv1_2_method', + '#define TLSv1_2_server_method GRPC_SHADOW_TLSv1_2_server_method', + '#define TLSv1_client_method GRPC_SHADOW_TLSv1_client_method', + '#define TLSv1_method GRPC_SHADOW_TLSv1_method', + '#define TLSv1_server_method GRPC_SHADOW_TLSv1_server_method', + '#define SSL_max_seal_overhead GRPC_SHADOW_SSL_max_seal_overhead', + '#define OPENSSL_cpuid_setup GRPC_SHADOW_OPENSSL_cpuid_setup', + '#define CRYPTO_has_asm GRPC_SHADOW_CRYPTO_has_asm', + '#define CRYPTO_is_confidential_build GRPC_SHADOW_CRYPTO_is_confidential_build', + '#define CRYPTO_library_init GRPC_SHADOW_CRYPTO_library_init', + '#define CRYPTO_malloc_init GRPC_SHADOW_CRYPTO_malloc_init', + '#define ENGINE_load_builtin_engines GRPC_SHADOW_ENGINE_load_builtin_engines', + '#define ENGINE_register_all_complete GRPC_SHADOW_ENGINE_register_all_complete', + '#define OPENSSL_ia32cap_P GRPC_SHADOW_OPENSSL_ia32cap_P', + '#define OPENSSL_init_crypto GRPC_SHADOW_OPENSSL_init_crypto', + '#define OPENSSL_load_builtin_modules GRPC_SHADOW_OPENSSL_load_builtin_modules', + '#define OpenSSL_version GRPC_SHADOW_OpenSSL_version', + '#define OpenSSL_version_num GRPC_SHADOW_OpenSSL_version_num', + '#define SSLeay GRPC_SHADOW_SSLeay', + '#define SSLeay_version GRPC_SHADOW_SSLeay_version', + '#define CRYPTO_cleanup_all_ex_data GRPC_SHADOW_CRYPTO_cleanup_all_ex_data', + '#define CRYPTO_free_ex_data GRPC_SHADOW_CRYPTO_free_ex_data', + '#define CRYPTO_get_ex_data GRPC_SHADOW_CRYPTO_get_ex_data', + '#define CRYPTO_get_ex_new_index GRPC_SHADOW_CRYPTO_get_ex_new_index', + '#define CRYPTO_new_ex_data GRPC_SHADOW_CRYPTO_new_ex_data', + '#define CRYPTO_set_ex_data GRPC_SHADOW_CRYPTO_set_ex_data', + '#define BIO_snprintf GRPC_SHADOW_BIO_snprintf', + '#define BIO_vsnprintf GRPC_SHADOW_BIO_vsnprintf', + '#define CRYPTO_memcmp GRPC_SHADOW_CRYPTO_memcmp', + '#define OPENSSL_cleanse GRPC_SHADOW_OPENSSL_cleanse', + '#define OPENSSL_free GRPC_SHADOW_OPENSSL_free', + '#define OPENSSL_hash32 GRPC_SHADOW_OPENSSL_hash32', + '#define OPENSSL_malloc GRPC_SHADOW_OPENSSL_malloc', + '#define OPENSSL_realloc GRPC_SHADOW_OPENSSL_realloc', + '#define OPENSSL_strcasecmp GRPC_SHADOW_OPENSSL_strcasecmp', + '#define OPENSSL_strdup GRPC_SHADOW_OPENSSL_strdup', + '#define OPENSSL_strncasecmp GRPC_SHADOW_OPENSSL_strncasecmp', + '#define OPENSSL_strnlen GRPC_SHADOW_OPENSSL_strnlen', + '#define OPENSSL_tolower GRPC_SHADOW_OPENSSL_tolower', + '#define CRYPTO_refcount_dec_and_test_zero GRPC_SHADOW_CRYPTO_refcount_dec_and_test_zero', + '#define CRYPTO_refcount_inc GRPC_SHADOW_CRYPTO_refcount_inc', + '#define CRYPTO_THREADID_current GRPC_SHADOW_CRYPTO_THREADID_current', + '#define CRYPTO_THREADID_set_callback GRPC_SHADOW_CRYPTO_THREADID_set_callback', + '#define CRYPTO_THREADID_set_numeric GRPC_SHADOW_CRYPTO_THREADID_set_numeric', + '#define CRYPTO_THREADID_set_pointer GRPC_SHADOW_CRYPTO_THREADID_set_pointer', + '#define CRYPTO_get_dynlock_create_callback GRPC_SHADOW_CRYPTO_get_dynlock_create_callback', + '#define CRYPTO_get_dynlock_destroy_callback GRPC_SHADOW_CRYPTO_get_dynlock_destroy_callback', + '#define CRYPTO_get_dynlock_lock_callback GRPC_SHADOW_CRYPTO_get_dynlock_lock_callback', + '#define CRYPTO_get_lock_name GRPC_SHADOW_CRYPTO_get_lock_name', + '#define CRYPTO_get_locking_callback GRPC_SHADOW_CRYPTO_get_locking_callback', + '#define CRYPTO_num_locks GRPC_SHADOW_CRYPTO_num_locks', + '#define CRYPTO_set_add_lock_callback GRPC_SHADOW_CRYPTO_set_add_lock_callback', + '#define CRYPTO_set_dynlock_create_callback GRPC_SHADOW_CRYPTO_set_dynlock_create_callback', + '#define CRYPTO_set_dynlock_destroy_callback GRPC_SHADOW_CRYPTO_set_dynlock_destroy_callback', + '#define CRYPTO_set_dynlock_lock_callback GRPC_SHADOW_CRYPTO_set_dynlock_lock_callback', + '#define CRYPTO_set_id_callback GRPC_SHADOW_CRYPTO_set_id_callback', + '#define CRYPTO_set_locking_callback GRPC_SHADOW_CRYPTO_set_locking_callback', + '#define CRYPTO_MUTEX_cleanup GRPC_SHADOW_CRYPTO_MUTEX_cleanup', + '#define CRYPTO_MUTEX_init GRPC_SHADOW_CRYPTO_MUTEX_init', + '#define CRYPTO_MUTEX_lock_read GRPC_SHADOW_CRYPTO_MUTEX_lock_read', + '#define CRYPTO_MUTEX_lock_write GRPC_SHADOW_CRYPTO_MUTEX_lock_write', + '#define CRYPTO_MUTEX_unlock_read GRPC_SHADOW_CRYPTO_MUTEX_unlock_read', + '#define CRYPTO_MUTEX_unlock_write GRPC_SHADOW_CRYPTO_MUTEX_unlock_write', + '#define CRYPTO_STATIC_MUTEX_lock_read GRPC_SHADOW_CRYPTO_STATIC_MUTEX_lock_read', + '#define CRYPTO_STATIC_MUTEX_lock_write GRPC_SHADOW_CRYPTO_STATIC_MUTEX_lock_write', + '#define CRYPTO_STATIC_MUTEX_unlock_read GRPC_SHADOW_CRYPTO_STATIC_MUTEX_unlock_read', + '#define CRYPTO_STATIC_MUTEX_unlock_write GRPC_SHADOW_CRYPTO_STATIC_MUTEX_unlock_write', + '#define CRYPTO_get_thread_local GRPC_SHADOW_CRYPTO_get_thread_local', + '#define CRYPTO_once GRPC_SHADOW_CRYPTO_once', + '#define CRYPTO_set_thread_local GRPC_SHADOW_CRYPTO_set_thread_local', + '#define sk_deep_copy GRPC_SHADOW_sk_deep_copy', + '#define sk_delete GRPC_SHADOW_sk_delete', + '#define sk_delete_ptr GRPC_SHADOW_sk_delete_ptr', + '#define sk_dup GRPC_SHADOW_sk_dup', + '#define sk_find GRPC_SHADOW_sk_find', + '#define sk_free GRPC_SHADOW_sk_free', + '#define sk_insert GRPC_SHADOW_sk_insert', + '#define sk_is_sorted GRPC_SHADOW_sk_is_sorted', + '#define sk_new GRPC_SHADOW_sk_new', + '#define sk_new_null GRPC_SHADOW_sk_new_null', + '#define sk_num GRPC_SHADOW_sk_num', + '#define sk_pop GRPC_SHADOW_sk_pop', + '#define sk_pop_free GRPC_SHADOW_sk_pop_free', + '#define sk_push GRPC_SHADOW_sk_push', + '#define sk_set GRPC_SHADOW_sk_set', + '#define sk_set_cmp_func GRPC_SHADOW_sk_set_cmp_func', + '#define sk_shift GRPC_SHADOW_sk_shift', + '#define sk_sort GRPC_SHADOW_sk_sort', + '#define sk_value GRPC_SHADOW_sk_value', + '#define sk_zero GRPC_SHADOW_sk_zero', + '#define lh_delete GRPC_SHADOW_lh_delete', + '#define lh_doall GRPC_SHADOW_lh_doall', + '#define lh_doall_arg GRPC_SHADOW_lh_doall_arg', + '#define lh_free GRPC_SHADOW_lh_free', + '#define lh_insert GRPC_SHADOW_lh_insert', + '#define lh_new GRPC_SHADOW_lh_new', + '#define lh_num_items GRPC_SHADOW_lh_num_items', + '#define lh_retrieve GRPC_SHADOW_lh_retrieve', + '#define lh_strhash GRPC_SHADOW_lh_strhash', + '#define ERR_SAVE_STATE_free GRPC_SHADOW_ERR_SAVE_STATE_free', + '#define ERR_add_error_data GRPC_SHADOW_ERR_add_error_data', + '#define ERR_add_error_dataf GRPC_SHADOW_ERR_add_error_dataf', + '#define ERR_clear_error GRPC_SHADOW_ERR_clear_error', + '#define ERR_clear_system_error GRPC_SHADOW_ERR_clear_system_error', + '#define ERR_error_string GRPC_SHADOW_ERR_error_string', + '#define ERR_error_string_n GRPC_SHADOW_ERR_error_string_n', + '#define ERR_free_strings GRPC_SHADOW_ERR_free_strings', + '#define ERR_func_error_string GRPC_SHADOW_ERR_func_error_string', + '#define ERR_get_error GRPC_SHADOW_ERR_get_error', + '#define ERR_get_error_line GRPC_SHADOW_ERR_get_error_line', + '#define ERR_get_error_line_data GRPC_SHADOW_ERR_get_error_line_data', + '#define ERR_get_next_error_library GRPC_SHADOW_ERR_get_next_error_library', + '#define ERR_lib_error_string GRPC_SHADOW_ERR_lib_error_string', + '#define ERR_load_BIO_strings GRPC_SHADOW_ERR_load_BIO_strings', + '#define ERR_load_ERR_strings GRPC_SHADOW_ERR_load_ERR_strings', + '#define ERR_load_crypto_strings GRPC_SHADOW_ERR_load_crypto_strings', + '#define ERR_peek_error GRPC_SHADOW_ERR_peek_error', + '#define ERR_peek_error_line GRPC_SHADOW_ERR_peek_error_line', + '#define ERR_peek_error_line_data GRPC_SHADOW_ERR_peek_error_line_data', + '#define ERR_peek_last_error GRPC_SHADOW_ERR_peek_last_error', + '#define ERR_peek_last_error_line GRPC_SHADOW_ERR_peek_last_error_line', + '#define ERR_peek_last_error_line_data GRPC_SHADOW_ERR_peek_last_error_line_data', + '#define ERR_pop_to_mark GRPC_SHADOW_ERR_pop_to_mark', + '#define ERR_print_errors_cb GRPC_SHADOW_ERR_print_errors_cb', + '#define ERR_print_errors_fp GRPC_SHADOW_ERR_print_errors_fp', + '#define ERR_put_error GRPC_SHADOW_ERR_put_error', + '#define ERR_reason_error_string GRPC_SHADOW_ERR_reason_error_string', + '#define ERR_remove_state GRPC_SHADOW_ERR_remove_state', + '#define ERR_remove_thread_state GRPC_SHADOW_ERR_remove_thread_state', + '#define ERR_restore_state GRPC_SHADOW_ERR_restore_state', + '#define ERR_save_state GRPC_SHADOW_ERR_save_state', + '#define ERR_set_mark GRPC_SHADOW_ERR_set_mark', + '#define kOpenSSLReasonStringData GRPC_SHADOW_kOpenSSLReasonStringData', + '#define kOpenSSLReasonValues GRPC_SHADOW_kOpenSSLReasonValues', + '#define kOpenSSLReasonValuesLen GRPC_SHADOW_kOpenSSLReasonValuesLen', + '#define EVP_DecodeBase64 GRPC_SHADOW_EVP_DecodeBase64', + '#define EVP_DecodeBlock GRPC_SHADOW_EVP_DecodeBlock', + '#define EVP_DecodeFinal GRPC_SHADOW_EVP_DecodeFinal', + '#define EVP_DecodeInit GRPC_SHADOW_EVP_DecodeInit', + '#define EVP_DecodeUpdate GRPC_SHADOW_EVP_DecodeUpdate', + '#define EVP_DecodedLength GRPC_SHADOW_EVP_DecodedLength', + '#define EVP_EncodeBlock GRPC_SHADOW_EVP_EncodeBlock', + '#define EVP_EncodeFinal GRPC_SHADOW_EVP_EncodeFinal', + '#define EVP_EncodeInit GRPC_SHADOW_EVP_EncodeInit', + '#define EVP_EncodeUpdate GRPC_SHADOW_EVP_EncodeUpdate', + '#define EVP_EncodedLength GRPC_SHADOW_EVP_EncodedLength', + '#define CBB_finish_i2d GRPC_SHADOW_CBB_finish_i2d', + '#define CBS_asn1_ber_to_der GRPC_SHADOW_CBS_asn1_ber_to_der', + '#define CBS_get_asn1_implicit_string GRPC_SHADOW_CBS_get_asn1_implicit_string', + '#define CBS_asn1_bitstring_has_bit GRPC_SHADOW_CBS_asn1_bitstring_has_bit', + '#define CBS_asn1_oid_to_text GRPC_SHADOW_CBS_asn1_oid_to_text', + '#define CBS_contains_zero_byte GRPC_SHADOW_CBS_contains_zero_byte', + '#define CBS_copy_bytes GRPC_SHADOW_CBS_copy_bytes', + '#define CBS_data GRPC_SHADOW_CBS_data', + '#define CBS_get_any_asn1 GRPC_SHADOW_CBS_get_any_asn1', + '#define CBS_get_any_asn1_element GRPC_SHADOW_CBS_get_any_asn1_element', + '#define CBS_get_any_ber_asn1_element GRPC_SHADOW_CBS_get_any_ber_asn1_element', + '#define CBS_get_asn1 GRPC_SHADOW_CBS_get_asn1', + '#define CBS_get_asn1_bool GRPC_SHADOW_CBS_get_asn1_bool', + '#define CBS_get_asn1_element GRPC_SHADOW_CBS_get_asn1_element', + '#define CBS_get_asn1_uint64 GRPC_SHADOW_CBS_get_asn1_uint64', + '#define CBS_get_bytes GRPC_SHADOW_CBS_get_bytes', + '#define CBS_get_last_u8 GRPC_SHADOW_CBS_get_last_u8', + '#define CBS_get_optional_asn1 GRPC_SHADOW_CBS_get_optional_asn1', + '#define CBS_get_optional_asn1_bool GRPC_SHADOW_CBS_get_optional_asn1_bool', + '#define CBS_get_optional_asn1_octet_string GRPC_SHADOW_CBS_get_optional_asn1_octet_string', + '#define CBS_get_optional_asn1_uint64 GRPC_SHADOW_CBS_get_optional_asn1_uint64', + '#define CBS_get_u16 GRPC_SHADOW_CBS_get_u16', + '#define CBS_get_u16_length_prefixed GRPC_SHADOW_CBS_get_u16_length_prefixed', + '#define CBS_get_u24 GRPC_SHADOW_CBS_get_u24', + '#define CBS_get_u24_length_prefixed GRPC_SHADOW_CBS_get_u24_length_prefixed', + '#define CBS_get_u32 GRPC_SHADOW_CBS_get_u32', + '#define CBS_get_u8 GRPC_SHADOW_CBS_get_u8', + '#define CBS_get_u8_length_prefixed GRPC_SHADOW_CBS_get_u8_length_prefixed', + '#define CBS_init GRPC_SHADOW_CBS_init', + '#define CBS_is_valid_asn1_bitstring GRPC_SHADOW_CBS_is_valid_asn1_bitstring', + '#define CBS_len GRPC_SHADOW_CBS_len', + '#define CBS_mem_equal GRPC_SHADOW_CBS_mem_equal', + '#define CBS_peek_asn1_tag GRPC_SHADOW_CBS_peek_asn1_tag', + '#define CBS_skip GRPC_SHADOW_CBS_skip', + '#define CBS_stow GRPC_SHADOW_CBS_stow', + '#define CBS_strdup GRPC_SHADOW_CBS_strdup', + '#define CBB_add_asn1 GRPC_SHADOW_CBB_add_asn1', + '#define CBB_add_asn1_bool GRPC_SHADOW_CBB_add_asn1_bool', + '#define CBB_add_asn1_octet_string GRPC_SHADOW_CBB_add_asn1_octet_string', + '#define CBB_add_asn1_oid_from_text GRPC_SHADOW_CBB_add_asn1_oid_from_text', + '#define CBB_add_asn1_uint64 GRPC_SHADOW_CBB_add_asn1_uint64', + '#define CBB_add_bytes GRPC_SHADOW_CBB_add_bytes', + '#define CBB_add_space GRPC_SHADOW_CBB_add_space', + '#define CBB_add_u16 GRPC_SHADOW_CBB_add_u16', + '#define CBB_add_u16_length_prefixed GRPC_SHADOW_CBB_add_u16_length_prefixed', + '#define CBB_add_u24 GRPC_SHADOW_CBB_add_u24', + '#define CBB_add_u24_length_prefixed GRPC_SHADOW_CBB_add_u24_length_prefixed', + '#define CBB_add_u32 GRPC_SHADOW_CBB_add_u32', + '#define CBB_add_u8 GRPC_SHADOW_CBB_add_u8', + '#define CBB_add_u8_length_prefixed GRPC_SHADOW_CBB_add_u8_length_prefixed', + '#define CBB_cleanup GRPC_SHADOW_CBB_cleanup', + '#define CBB_data GRPC_SHADOW_CBB_data', + '#define CBB_did_write GRPC_SHADOW_CBB_did_write', + '#define CBB_discard_child GRPC_SHADOW_CBB_discard_child', + '#define CBB_finish GRPC_SHADOW_CBB_finish', + '#define CBB_flush GRPC_SHADOW_CBB_flush', + '#define CBB_flush_asn1_set_of GRPC_SHADOW_CBB_flush_asn1_set_of', + '#define CBB_init GRPC_SHADOW_CBB_init', + '#define CBB_init_fixed GRPC_SHADOW_CBB_init_fixed', + '#define CBB_len GRPC_SHADOW_CBB_len', + '#define CBB_reserve GRPC_SHADOW_CBB_reserve', + '#define CBB_zero GRPC_SHADOW_CBB_zero', + '#define CRYPTO_BUFFER_POOL_free GRPC_SHADOW_CRYPTO_BUFFER_POOL_free', + '#define CRYPTO_BUFFER_POOL_new GRPC_SHADOW_CRYPTO_BUFFER_POOL_new', + '#define CRYPTO_BUFFER_data GRPC_SHADOW_CRYPTO_BUFFER_data', + '#define CRYPTO_BUFFER_free GRPC_SHADOW_CRYPTO_BUFFER_free', + '#define CRYPTO_BUFFER_init_CBS GRPC_SHADOW_CRYPTO_BUFFER_init_CBS', + '#define CRYPTO_BUFFER_len GRPC_SHADOW_CRYPTO_BUFFER_len', + '#define CRYPTO_BUFFER_new GRPC_SHADOW_CRYPTO_BUFFER_new', + '#define CRYPTO_BUFFER_new_from_CBS GRPC_SHADOW_CRYPTO_BUFFER_new_from_CBS', + '#define CRYPTO_BUFFER_up_ref GRPC_SHADOW_CRYPTO_BUFFER_up_ref', + '#define AES_cbc_encrypt GRPC_SHADOW_AES_cbc_encrypt', + '#define AES_cfb128_encrypt GRPC_SHADOW_AES_cfb128_encrypt', + '#define AES_ctr128_encrypt GRPC_SHADOW_AES_ctr128_encrypt', + '#define AES_decrypt GRPC_SHADOW_AES_decrypt', + '#define AES_ecb_encrypt GRPC_SHADOW_AES_ecb_encrypt', + '#define AES_encrypt GRPC_SHADOW_AES_encrypt', + '#define AES_ofb128_encrypt GRPC_SHADOW_AES_ofb128_encrypt', + '#define AES_set_decrypt_key GRPC_SHADOW_AES_set_decrypt_key', + '#define AES_set_encrypt_key GRPC_SHADOW_AES_set_encrypt_key', + '#define AES_unwrap_key GRPC_SHADOW_AES_unwrap_key', + '#define AES_wrap_key GRPC_SHADOW_AES_wrap_key', + '#define BN_BLINDING_convert GRPC_SHADOW_BN_BLINDING_convert', + '#define BN_BLINDING_free GRPC_SHADOW_BN_BLINDING_free', + '#define BN_BLINDING_invert GRPC_SHADOW_BN_BLINDING_invert', + '#define BN_BLINDING_new GRPC_SHADOW_BN_BLINDING_new', + '#define BN_CTX_end GRPC_SHADOW_BN_CTX_end', + '#define BN_CTX_free GRPC_SHADOW_BN_CTX_free', + '#define BN_CTX_get GRPC_SHADOW_BN_CTX_get', + '#define BN_CTX_new GRPC_SHADOW_BN_CTX_new', + '#define BN_CTX_start GRPC_SHADOW_BN_CTX_start', + '#define BN_GENCB_call GRPC_SHADOW_BN_GENCB_call', + '#define BN_GENCB_set GRPC_SHADOW_BN_GENCB_set', + '#define BN_MONT_CTX_copy GRPC_SHADOW_BN_MONT_CTX_copy', + '#define BN_MONT_CTX_free GRPC_SHADOW_BN_MONT_CTX_free', + '#define BN_MONT_CTX_new GRPC_SHADOW_BN_MONT_CTX_new', + '#define BN_MONT_CTX_new_for_modulus GRPC_SHADOW_BN_MONT_CTX_new_for_modulus', + '#define BN_MONT_CTX_set GRPC_SHADOW_BN_MONT_CTX_set', + '#define BN_MONT_CTX_set_locked GRPC_SHADOW_BN_MONT_CTX_set_locked', + '#define BN_abs_is_word GRPC_SHADOW_BN_abs_is_word', + '#define BN_add GRPC_SHADOW_BN_add', + '#define BN_add_word GRPC_SHADOW_BN_add_word', + '#define BN_bin2bn GRPC_SHADOW_BN_bin2bn', + '#define BN_bn2bin GRPC_SHADOW_BN_bn2bin', + '#define BN_bn2bin_padded GRPC_SHADOW_BN_bn2bin_padded', + '#define BN_bn2le_padded GRPC_SHADOW_BN_bn2le_padded', + '#define BN_clear GRPC_SHADOW_BN_clear', + '#define BN_clear_bit GRPC_SHADOW_BN_clear_bit', + '#define BN_clear_free GRPC_SHADOW_BN_clear_free', + '#define BN_cmp GRPC_SHADOW_BN_cmp', + '#define BN_cmp_word GRPC_SHADOW_BN_cmp_word', + '#define BN_copy GRPC_SHADOW_BN_copy', + '#define BN_count_low_zero_bits GRPC_SHADOW_BN_count_low_zero_bits', + '#define BN_div GRPC_SHADOW_BN_div', + '#define BN_div_word GRPC_SHADOW_BN_div_word', + '#define BN_dup GRPC_SHADOW_BN_dup', + '#define BN_enhanced_miller_rabin_primality_test GRPC_SHADOW_BN_enhanced_miller_rabin_primality_test', + '#define BN_equal_consttime GRPC_SHADOW_BN_equal_consttime', + '#define BN_exp GRPC_SHADOW_BN_exp', + '#define BN_free GRPC_SHADOW_BN_free', + '#define BN_from_montgomery GRPC_SHADOW_BN_from_montgomery', + '#define BN_gcd GRPC_SHADOW_BN_gcd', + '#define BN_generate_prime_ex GRPC_SHADOW_BN_generate_prime_ex', + '#define BN_get_u64 GRPC_SHADOW_BN_get_u64', + '#define BN_get_word GRPC_SHADOW_BN_get_word', + '#define BN_init GRPC_SHADOW_BN_init', + '#define BN_is_bit_set GRPC_SHADOW_BN_is_bit_set', + '#define BN_is_negative GRPC_SHADOW_BN_is_negative', + '#define BN_is_odd GRPC_SHADOW_BN_is_odd', + '#define BN_is_one GRPC_SHADOW_BN_is_one', + '#define BN_is_pow2 GRPC_SHADOW_BN_is_pow2', + '#define BN_is_prime_ex GRPC_SHADOW_BN_is_prime_ex', + '#define BN_is_prime_fasttest_ex GRPC_SHADOW_BN_is_prime_fasttest_ex', + '#define BN_is_word GRPC_SHADOW_BN_is_word', + '#define BN_is_zero GRPC_SHADOW_BN_is_zero', + '#define BN_le2bn GRPC_SHADOW_BN_le2bn', + '#define BN_lshift GRPC_SHADOW_BN_lshift', + '#define BN_lshift1 GRPC_SHADOW_BN_lshift1', + '#define BN_mask_bits GRPC_SHADOW_BN_mask_bits', + '#define BN_mod_add GRPC_SHADOW_BN_mod_add', + '#define BN_mod_add_quick GRPC_SHADOW_BN_mod_add_quick', + '#define BN_mod_exp GRPC_SHADOW_BN_mod_exp', + '#define BN_mod_exp2_mont GRPC_SHADOW_BN_mod_exp2_mont', + '#define BN_mod_exp_mont GRPC_SHADOW_BN_mod_exp_mont', + '#define BN_mod_exp_mont_consttime GRPC_SHADOW_BN_mod_exp_mont_consttime', + '#define BN_mod_exp_mont_word GRPC_SHADOW_BN_mod_exp_mont_word', + '#define BN_mod_inverse GRPC_SHADOW_BN_mod_inverse', + '#define BN_mod_inverse_blinded GRPC_SHADOW_BN_mod_inverse_blinded', + '#define BN_mod_inverse_odd GRPC_SHADOW_BN_mod_inverse_odd', + '#define BN_mod_lshift GRPC_SHADOW_BN_mod_lshift', + '#define BN_mod_lshift1 GRPC_SHADOW_BN_mod_lshift1', + '#define BN_mod_lshift1_quick GRPC_SHADOW_BN_mod_lshift1_quick', + '#define BN_mod_lshift_quick GRPC_SHADOW_BN_mod_lshift_quick', + '#define BN_mod_mul GRPC_SHADOW_BN_mod_mul', + '#define BN_mod_mul_montgomery GRPC_SHADOW_BN_mod_mul_montgomery', + '#define BN_mod_pow2 GRPC_SHADOW_BN_mod_pow2', + '#define BN_mod_sqr GRPC_SHADOW_BN_mod_sqr', + '#define BN_mod_sqrt GRPC_SHADOW_BN_mod_sqrt', + '#define BN_mod_sub GRPC_SHADOW_BN_mod_sub', + '#define BN_mod_sub_quick GRPC_SHADOW_BN_mod_sub_quick', + '#define BN_mod_word GRPC_SHADOW_BN_mod_word', + '#define BN_mul GRPC_SHADOW_BN_mul', + '#define BN_mul_word GRPC_SHADOW_BN_mul_word', + '#define BN_new GRPC_SHADOW_BN_new', + '#define BN_nnmod GRPC_SHADOW_BN_nnmod', + '#define BN_nnmod_pow2 GRPC_SHADOW_BN_nnmod_pow2', + '#define BN_num_bits GRPC_SHADOW_BN_num_bits', + '#define BN_num_bits_word GRPC_SHADOW_BN_num_bits_word', + '#define BN_num_bytes GRPC_SHADOW_BN_num_bytes', + '#define BN_one GRPC_SHADOW_BN_one', + '#define BN_primality_test GRPC_SHADOW_BN_primality_test', + '#define BN_pseudo_rand GRPC_SHADOW_BN_pseudo_rand', + '#define BN_pseudo_rand_range GRPC_SHADOW_BN_pseudo_rand_range', + '#define BN_rand GRPC_SHADOW_BN_rand', + '#define BN_rand_range GRPC_SHADOW_BN_rand_range', + '#define BN_rand_range_ex GRPC_SHADOW_BN_rand_range_ex', + '#define BN_rshift GRPC_SHADOW_BN_rshift', + '#define BN_rshift1 GRPC_SHADOW_BN_rshift1', + '#define BN_set_bit GRPC_SHADOW_BN_set_bit', + '#define BN_set_negative GRPC_SHADOW_BN_set_negative', + '#define BN_set_u64 GRPC_SHADOW_BN_set_u64', + '#define BN_set_word GRPC_SHADOW_BN_set_word', + '#define BN_sqr GRPC_SHADOW_BN_sqr', + '#define BN_sqrt GRPC_SHADOW_BN_sqrt', + '#define BN_sub GRPC_SHADOW_BN_sub', + '#define BN_sub_word GRPC_SHADOW_BN_sub_word', + '#define BN_to_montgomery GRPC_SHADOW_BN_to_montgomery', + '#define BN_uadd GRPC_SHADOW_BN_uadd', + '#define BN_ucmp GRPC_SHADOW_BN_ucmp', + '#define BN_usub GRPC_SHADOW_BN_usub', + '#define BN_value_one GRPC_SHADOW_BN_value_one', + '#define BN_zero GRPC_SHADOW_BN_zero', + '#define BORINGSSL_self_test GRPC_SHADOW_BORINGSSL_self_test', + '#define CRYPTO_POLYVAL_finish GRPC_SHADOW_CRYPTO_POLYVAL_finish', + '#define CRYPTO_POLYVAL_init GRPC_SHADOW_CRYPTO_POLYVAL_init', + '#define CRYPTO_POLYVAL_update_blocks GRPC_SHADOW_CRYPTO_POLYVAL_update_blocks', + '#define CRYPTO_cbc128_decrypt GRPC_SHADOW_CRYPTO_cbc128_decrypt', + '#define CRYPTO_cbc128_encrypt GRPC_SHADOW_CRYPTO_cbc128_encrypt', + '#define CRYPTO_ccm128_decrypt GRPC_SHADOW_CRYPTO_ccm128_decrypt', + '#define CRYPTO_ccm128_encrypt GRPC_SHADOW_CRYPTO_ccm128_encrypt', + '#define CRYPTO_ccm128_init GRPC_SHADOW_CRYPTO_ccm128_init', + '#define CRYPTO_ccm128_max_input GRPC_SHADOW_CRYPTO_ccm128_max_input', + '#define CRYPTO_cfb128_1_encrypt GRPC_SHADOW_CRYPTO_cfb128_1_encrypt', + '#define CRYPTO_cfb128_8_encrypt GRPC_SHADOW_CRYPTO_cfb128_8_encrypt', + '#define CRYPTO_cfb128_encrypt GRPC_SHADOW_CRYPTO_cfb128_encrypt', + '#define CRYPTO_ctr128_encrypt GRPC_SHADOW_CRYPTO_ctr128_encrypt', + '#define CRYPTO_ctr128_encrypt_ctr32 GRPC_SHADOW_CRYPTO_ctr128_encrypt_ctr32', + '#define CRYPTO_gcm128_aad GRPC_SHADOW_CRYPTO_gcm128_aad', + '#define CRYPTO_gcm128_decrypt GRPC_SHADOW_CRYPTO_gcm128_decrypt', + '#define CRYPTO_gcm128_decrypt_ctr32 GRPC_SHADOW_CRYPTO_gcm128_decrypt_ctr32', + '#define CRYPTO_gcm128_encrypt GRPC_SHADOW_CRYPTO_gcm128_encrypt', + '#define CRYPTO_gcm128_encrypt_ctr32 GRPC_SHADOW_CRYPTO_gcm128_encrypt_ctr32', + '#define CRYPTO_gcm128_finish GRPC_SHADOW_CRYPTO_gcm128_finish', + '#define CRYPTO_gcm128_init GRPC_SHADOW_CRYPTO_gcm128_init', + '#define CRYPTO_gcm128_setiv GRPC_SHADOW_CRYPTO_gcm128_setiv', + '#define CRYPTO_gcm128_tag GRPC_SHADOW_CRYPTO_gcm128_tag', + '#define CRYPTO_ghash_init GRPC_SHADOW_CRYPTO_ghash_init', + '#define CRYPTO_ofb128_encrypt GRPC_SHADOW_CRYPTO_ofb128_encrypt', + '#define CRYPTO_sysrand GRPC_SHADOW_CRYPTO_sysrand', + '#define CRYPTO_tls1_prf GRPC_SHADOW_CRYPTO_tls1_prf', + '#define CTR_DRBG_clear GRPC_SHADOW_CTR_DRBG_clear', + '#define CTR_DRBG_generate GRPC_SHADOW_CTR_DRBG_generate', + '#define CTR_DRBG_init GRPC_SHADOW_CTR_DRBG_init', + '#define CTR_DRBG_reseed GRPC_SHADOW_CTR_DRBG_reseed', + '#define DES_decrypt3 GRPC_SHADOW_DES_decrypt3', + '#define DES_ecb3_encrypt GRPC_SHADOW_DES_ecb3_encrypt', + '#define DES_ecb_encrypt GRPC_SHADOW_DES_ecb_encrypt', + '#define DES_ede2_cbc_encrypt GRPC_SHADOW_DES_ede2_cbc_encrypt', + '#define DES_ede3_cbc_encrypt GRPC_SHADOW_DES_ede3_cbc_encrypt', + '#define DES_encrypt3 GRPC_SHADOW_DES_encrypt3', + '#define DES_ncbc_encrypt GRPC_SHADOW_DES_ncbc_encrypt', + '#define DES_set_key GRPC_SHADOW_DES_set_key', + '#define DES_set_key_unchecked GRPC_SHADOW_DES_set_key_unchecked', + '#define DES_set_odd_parity GRPC_SHADOW_DES_set_odd_parity', + '#define ECDSA_SIG_free GRPC_SHADOW_ECDSA_SIG_free', + '#define ECDSA_SIG_get0 GRPC_SHADOW_ECDSA_SIG_get0', + '#define ECDSA_SIG_new GRPC_SHADOW_ECDSA_SIG_new', + '#define ECDSA_SIG_set0 GRPC_SHADOW_ECDSA_SIG_set0', + '#define ECDSA_do_sign GRPC_SHADOW_ECDSA_do_sign', + '#define ECDSA_do_verify GRPC_SHADOW_ECDSA_do_verify', + '#define EC_GFp_mont_method GRPC_SHADOW_EC_GFp_mont_method', + '#define EC_GFp_nistp224_method GRPC_SHADOW_EC_GFp_nistp224_method', + '#define EC_GFp_nistp256_method GRPC_SHADOW_EC_GFp_nistp256_method', + '#define EC_GFp_nistz256_method GRPC_SHADOW_EC_GFp_nistz256_method', + '#define EC_GROUP_cmp GRPC_SHADOW_EC_GROUP_cmp', + '#define EC_GROUP_dup GRPC_SHADOW_EC_GROUP_dup', + '#define EC_GROUP_free GRPC_SHADOW_EC_GROUP_free', + '#define EC_GROUP_get0_generator GRPC_SHADOW_EC_GROUP_get0_generator', + '#define EC_GROUP_get0_order GRPC_SHADOW_EC_GROUP_get0_order', + '#define EC_GROUP_get_cofactor GRPC_SHADOW_EC_GROUP_get_cofactor', + '#define EC_GROUP_get_curve_GFp GRPC_SHADOW_EC_GROUP_get_curve_GFp', + '#define EC_GROUP_get_curve_name GRPC_SHADOW_EC_GROUP_get_curve_name', + '#define EC_GROUP_get_degree GRPC_SHADOW_EC_GROUP_get_degree', + '#define EC_GROUP_get_order GRPC_SHADOW_EC_GROUP_get_order', + '#define EC_GROUP_method_of GRPC_SHADOW_EC_GROUP_method_of', + '#define EC_GROUP_new_by_curve_name GRPC_SHADOW_EC_GROUP_new_by_curve_name', + '#define EC_GROUP_new_curve_GFp GRPC_SHADOW_EC_GROUP_new_curve_GFp', + '#define EC_GROUP_set_asn1_flag GRPC_SHADOW_EC_GROUP_set_asn1_flag', + '#define EC_GROUP_set_generator GRPC_SHADOW_EC_GROUP_set_generator', + '#define EC_GROUP_set_point_conversion_form GRPC_SHADOW_EC_GROUP_set_point_conversion_form', + '#define EC_KEY_check_fips GRPC_SHADOW_EC_KEY_check_fips', + '#define EC_KEY_check_key GRPC_SHADOW_EC_KEY_check_key', + '#define EC_KEY_dup GRPC_SHADOW_EC_KEY_dup', + '#define EC_KEY_free GRPC_SHADOW_EC_KEY_free', + '#define EC_KEY_generate_key GRPC_SHADOW_EC_KEY_generate_key', + '#define EC_KEY_generate_key_fips GRPC_SHADOW_EC_KEY_generate_key_fips', + '#define EC_KEY_get0_group GRPC_SHADOW_EC_KEY_get0_group', + '#define EC_KEY_get0_private_key GRPC_SHADOW_EC_KEY_get0_private_key', + '#define EC_KEY_get0_public_key GRPC_SHADOW_EC_KEY_get0_public_key', + '#define EC_KEY_get_conv_form GRPC_SHADOW_EC_KEY_get_conv_form', + '#define EC_KEY_get_enc_flags GRPC_SHADOW_EC_KEY_get_enc_flags', + '#define EC_KEY_get_ex_data GRPC_SHADOW_EC_KEY_get_ex_data', + '#define EC_KEY_get_ex_new_index GRPC_SHADOW_EC_KEY_get_ex_new_index', + '#define EC_KEY_is_opaque GRPC_SHADOW_EC_KEY_is_opaque', + '#define EC_KEY_new GRPC_SHADOW_EC_KEY_new', + '#define EC_KEY_new_by_curve_name GRPC_SHADOW_EC_KEY_new_by_curve_name', + '#define EC_KEY_new_method GRPC_SHADOW_EC_KEY_new_method', + '#define EC_KEY_set_asn1_flag GRPC_SHADOW_EC_KEY_set_asn1_flag', + '#define EC_KEY_set_conv_form GRPC_SHADOW_EC_KEY_set_conv_form', + '#define EC_KEY_set_enc_flags GRPC_SHADOW_EC_KEY_set_enc_flags', + '#define EC_KEY_set_ex_data GRPC_SHADOW_EC_KEY_set_ex_data', + '#define EC_KEY_set_group GRPC_SHADOW_EC_KEY_set_group', + '#define EC_KEY_set_private_key GRPC_SHADOW_EC_KEY_set_private_key', + '#define EC_KEY_set_public_key GRPC_SHADOW_EC_KEY_set_public_key', + '#define EC_KEY_set_public_key_affine_coordinates GRPC_SHADOW_EC_KEY_set_public_key_affine_coordinates', + '#define EC_KEY_up_ref GRPC_SHADOW_EC_KEY_up_ref', + '#define EC_METHOD_get_field_type GRPC_SHADOW_EC_METHOD_get_field_type', + '#define EC_POINT_add GRPC_SHADOW_EC_POINT_add', + '#define EC_POINT_clear_free GRPC_SHADOW_EC_POINT_clear_free', + '#define EC_POINT_cmp GRPC_SHADOW_EC_POINT_cmp', + '#define EC_POINT_copy GRPC_SHADOW_EC_POINT_copy', + '#define EC_POINT_dbl GRPC_SHADOW_EC_POINT_dbl', + '#define EC_POINT_dup GRPC_SHADOW_EC_POINT_dup', + '#define EC_POINT_free GRPC_SHADOW_EC_POINT_free', + '#define EC_POINT_get_affine_coordinates_GFp GRPC_SHADOW_EC_POINT_get_affine_coordinates_GFp', + '#define EC_POINT_invert GRPC_SHADOW_EC_POINT_invert', + '#define EC_POINT_is_at_infinity GRPC_SHADOW_EC_POINT_is_at_infinity', + '#define EC_POINT_is_on_curve GRPC_SHADOW_EC_POINT_is_on_curve', + '#define EC_POINT_make_affine GRPC_SHADOW_EC_POINT_make_affine', + '#define EC_POINT_mul GRPC_SHADOW_EC_POINT_mul', + '#define EC_POINT_new GRPC_SHADOW_EC_POINT_new', + '#define EC_POINT_oct2point GRPC_SHADOW_EC_POINT_oct2point', + '#define EC_POINT_point2oct GRPC_SHADOW_EC_POINT_point2oct', + '#define EC_POINT_set_affine_coordinates_GFp GRPC_SHADOW_EC_POINT_set_affine_coordinates_GFp', + '#define EC_POINT_set_compressed_coordinates_GFp GRPC_SHADOW_EC_POINT_set_compressed_coordinates_GFp', + '#define EC_POINT_set_to_infinity GRPC_SHADOW_EC_POINT_set_to_infinity', + '#define EC_POINTs_make_affine GRPC_SHADOW_EC_POINTs_make_affine', + '#define EC_get_builtin_curves GRPC_SHADOW_EC_get_builtin_curves', + '#define EVP_AEAD_CTX_aead GRPC_SHADOW_EVP_AEAD_CTX_aead', + '#define EVP_AEAD_CTX_cleanup GRPC_SHADOW_EVP_AEAD_CTX_cleanup', + '#define EVP_AEAD_CTX_free GRPC_SHADOW_EVP_AEAD_CTX_free', + '#define EVP_AEAD_CTX_get_iv GRPC_SHADOW_EVP_AEAD_CTX_get_iv', + '#define EVP_AEAD_CTX_init GRPC_SHADOW_EVP_AEAD_CTX_init', + '#define EVP_AEAD_CTX_init_with_direction GRPC_SHADOW_EVP_AEAD_CTX_init_with_direction', + '#define EVP_AEAD_CTX_new GRPC_SHADOW_EVP_AEAD_CTX_new', + '#define EVP_AEAD_CTX_open GRPC_SHADOW_EVP_AEAD_CTX_open', + '#define EVP_AEAD_CTX_open_gather GRPC_SHADOW_EVP_AEAD_CTX_open_gather', + '#define EVP_AEAD_CTX_seal GRPC_SHADOW_EVP_AEAD_CTX_seal', + '#define EVP_AEAD_CTX_seal_scatter GRPC_SHADOW_EVP_AEAD_CTX_seal_scatter', + '#define EVP_AEAD_CTX_tag_len GRPC_SHADOW_EVP_AEAD_CTX_tag_len', + '#define EVP_AEAD_CTX_zero GRPC_SHADOW_EVP_AEAD_CTX_zero', + '#define EVP_AEAD_key_length GRPC_SHADOW_EVP_AEAD_key_length', + '#define EVP_AEAD_max_overhead GRPC_SHADOW_EVP_AEAD_max_overhead', + '#define EVP_AEAD_max_tag_len GRPC_SHADOW_EVP_AEAD_max_tag_len', + '#define EVP_AEAD_nonce_length GRPC_SHADOW_EVP_AEAD_nonce_length', + '#define EVP_CIPHER_CTX_block_size GRPC_SHADOW_EVP_CIPHER_CTX_block_size', + '#define EVP_CIPHER_CTX_cipher GRPC_SHADOW_EVP_CIPHER_CTX_cipher', + '#define EVP_CIPHER_CTX_cleanup GRPC_SHADOW_EVP_CIPHER_CTX_cleanup', + '#define EVP_CIPHER_CTX_copy GRPC_SHADOW_EVP_CIPHER_CTX_copy', + '#define EVP_CIPHER_CTX_ctrl GRPC_SHADOW_EVP_CIPHER_CTX_ctrl', + '#define EVP_CIPHER_CTX_flags GRPC_SHADOW_EVP_CIPHER_CTX_flags', + '#define EVP_CIPHER_CTX_free GRPC_SHADOW_EVP_CIPHER_CTX_free', + '#define EVP_CIPHER_CTX_get_app_data GRPC_SHADOW_EVP_CIPHER_CTX_get_app_data', + '#define EVP_CIPHER_CTX_init GRPC_SHADOW_EVP_CIPHER_CTX_init', + '#define EVP_CIPHER_CTX_iv_length GRPC_SHADOW_EVP_CIPHER_CTX_iv_length', + '#define EVP_CIPHER_CTX_key_length GRPC_SHADOW_EVP_CIPHER_CTX_key_length', + '#define EVP_CIPHER_CTX_mode GRPC_SHADOW_EVP_CIPHER_CTX_mode', + '#define EVP_CIPHER_CTX_new GRPC_SHADOW_EVP_CIPHER_CTX_new', + '#define EVP_CIPHER_CTX_nid GRPC_SHADOW_EVP_CIPHER_CTX_nid', + '#define EVP_CIPHER_CTX_reset GRPC_SHADOW_EVP_CIPHER_CTX_reset', + '#define EVP_CIPHER_CTX_set_app_data GRPC_SHADOW_EVP_CIPHER_CTX_set_app_data', + '#define EVP_CIPHER_CTX_set_flags GRPC_SHADOW_EVP_CIPHER_CTX_set_flags', + '#define EVP_CIPHER_CTX_set_key_length GRPC_SHADOW_EVP_CIPHER_CTX_set_key_length', + '#define EVP_CIPHER_CTX_set_padding GRPC_SHADOW_EVP_CIPHER_CTX_set_padding', + '#define EVP_CIPHER_block_size GRPC_SHADOW_EVP_CIPHER_block_size', + '#define EVP_CIPHER_flags GRPC_SHADOW_EVP_CIPHER_flags', + '#define EVP_CIPHER_iv_length GRPC_SHADOW_EVP_CIPHER_iv_length', + '#define EVP_CIPHER_key_length GRPC_SHADOW_EVP_CIPHER_key_length', + '#define EVP_CIPHER_mode GRPC_SHADOW_EVP_CIPHER_mode', + '#define EVP_CIPHER_nid GRPC_SHADOW_EVP_CIPHER_nid', + '#define EVP_Cipher GRPC_SHADOW_EVP_Cipher', + '#define EVP_CipherFinal_ex GRPC_SHADOW_EVP_CipherFinal_ex', + '#define EVP_CipherInit GRPC_SHADOW_EVP_CipherInit', + '#define EVP_CipherInit_ex GRPC_SHADOW_EVP_CipherInit_ex', + '#define EVP_CipherUpdate GRPC_SHADOW_EVP_CipherUpdate', + '#define EVP_DecryptFinal_ex GRPC_SHADOW_EVP_DecryptFinal_ex', + '#define EVP_DecryptInit GRPC_SHADOW_EVP_DecryptInit', + '#define EVP_DecryptInit_ex GRPC_SHADOW_EVP_DecryptInit_ex', + '#define EVP_DecryptUpdate GRPC_SHADOW_EVP_DecryptUpdate', + '#define EVP_Digest GRPC_SHADOW_EVP_Digest', + '#define EVP_DigestFinal GRPC_SHADOW_EVP_DigestFinal', + '#define EVP_DigestFinal_ex GRPC_SHADOW_EVP_DigestFinal_ex', + '#define EVP_DigestInit GRPC_SHADOW_EVP_DigestInit', + '#define EVP_DigestInit_ex GRPC_SHADOW_EVP_DigestInit_ex', + '#define EVP_DigestUpdate GRPC_SHADOW_EVP_DigestUpdate', + '#define EVP_EncryptFinal_ex GRPC_SHADOW_EVP_EncryptFinal_ex', + '#define EVP_EncryptInit GRPC_SHADOW_EVP_EncryptInit', + '#define EVP_EncryptInit_ex GRPC_SHADOW_EVP_EncryptInit_ex', + '#define EVP_EncryptUpdate GRPC_SHADOW_EVP_EncryptUpdate', + '#define EVP_MD_CTX_block_size GRPC_SHADOW_EVP_MD_CTX_block_size', + '#define EVP_MD_CTX_cleanup GRPC_SHADOW_EVP_MD_CTX_cleanup', + '#define EVP_MD_CTX_copy GRPC_SHADOW_EVP_MD_CTX_copy', + '#define EVP_MD_CTX_copy_ex GRPC_SHADOW_EVP_MD_CTX_copy_ex', + '#define EVP_MD_CTX_create GRPC_SHADOW_EVP_MD_CTX_create', + '#define EVP_MD_CTX_destroy GRPC_SHADOW_EVP_MD_CTX_destroy', + '#define EVP_MD_CTX_free GRPC_SHADOW_EVP_MD_CTX_free', + '#define EVP_MD_CTX_init GRPC_SHADOW_EVP_MD_CTX_init', + '#define EVP_MD_CTX_md GRPC_SHADOW_EVP_MD_CTX_md', + '#define EVP_MD_CTX_new GRPC_SHADOW_EVP_MD_CTX_new', + '#define EVP_MD_CTX_reset GRPC_SHADOW_EVP_MD_CTX_reset', + '#define EVP_MD_CTX_size GRPC_SHADOW_EVP_MD_CTX_size', + '#define EVP_MD_CTX_type GRPC_SHADOW_EVP_MD_CTX_type', + '#define EVP_MD_block_size GRPC_SHADOW_EVP_MD_block_size', + '#define EVP_MD_flags GRPC_SHADOW_EVP_MD_flags', + '#define EVP_MD_size GRPC_SHADOW_EVP_MD_size', + '#define EVP_MD_type GRPC_SHADOW_EVP_MD_type', + '#define EVP_add_cipher_alias GRPC_SHADOW_EVP_add_cipher_alias', + '#define EVP_add_digest GRPC_SHADOW_EVP_add_digest', + '#define EVP_aead_aes_128_gcm GRPC_SHADOW_EVP_aead_aes_128_gcm', + '#define EVP_aead_aes_128_gcm_tls12 GRPC_SHADOW_EVP_aead_aes_128_gcm_tls12', + '#define EVP_aead_aes_256_gcm GRPC_SHADOW_EVP_aead_aes_256_gcm', + '#define EVP_aead_aes_256_gcm_tls12 GRPC_SHADOW_EVP_aead_aes_256_gcm_tls12', + '#define EVP_aes_128_cbc GRPC_SHADOW_EVP_aes_128_cbc', + '#define EVP_aes_128_ctr GRPC_SHADOW_EVP_aes_128_ctr', + '#define EVP_aes_128_ecb GRPC_SHADOW_EVP_aes_128_ecb', + '#define EVP_aes_128_gcm GRPC_SHADOW_EVP_aes_128_gcm', + '#define EVP_aes_128_ofb GRPC_SHADOW_EVP_aes_128_ofb', + '#define EVP_aes_192_cbc GRPC_SHADOW_EVP_aes_192_cbc', + '#define EVP_aes_192_ctr GRPC_SHADOW_EVP_aes_192_ctr', + '#define EVP_aes_192_ecb GRPC_SHADOW_EVP_aes_192_ecb', + '#define EVP_aes_192_gcm GRPC_SHADOW_EVP_aes_192_gcm', + '#define EVP_aes_256_cbc GRPC_SHADOW_EVP_aes_256_cbc', + '#define EVP_aes_256_ctr GRPC_SHADOW_EVP_aes_256_ctr', + '#define EVP_aes_256_ecb GRPC_SHADOW_EVP_aes_256_ecb', + '#define EVP_aes_256_gcm GRPC_SHADOW_EVP_aes_256_gcm', + '#define EVP_aes_256_ofb GRPC_SHADOW_EVP_aes_256_ofb', + '#define EVP_des_cbc GRPC_SHADOW_EVP_des_cbc', + '#define EVP_des_ecb GRPC_SHADOW_EVP_des_ecb', + '#define EVP_des_ede GRPC_SHADOW_EVP_des_ede', + '#define EVP_des_ede3 GRPC_SHADOW_EVP_des_ede3', + '#define EVP_des_ede3_cbc GRPC_SHADOW_EVP_des_ede3_cbc', + '#define EVP_des_ede_cbc GRPC_SHADOW_EVP_des_ede_cbc', + '#define EVP_has_aes_hardware GRPC_SHADOW_EVP_has_aes_hardware', + '#define EVP_md4 GRPC_SHADOW_EVP_md4', + '#define EVP_md5 GRPC_SHADOW_EVP_md5', + '#define EVP_md5_sha1 GRPC_SHADOW_EVP_md5_sha1', + '#define EVP_sha1 GRPC_SHADOW_EVP_sha1', + '#define EVP_sha224 GRPC_SHADOW_EVP_sha224', + '#define EVP_sha256 GRPC_SHADOW_EVP_sha256', + '#define EVP_sha384 GRPC_SHADOW_EVP_sha384', + '#define EVP_sha512 GRPC_SHADOW_EVP_sha512', + '#define HMAC GRPC_SHADOW_HMAC', + '#define HMAC_CTX_cleanup GRPC_SHADOW_HMAC_CTX_cleanup', + '#define HMAC_CTX_copy GRPC_SHADOW_HMAC_CTX_copy', + '#define HMAC_CTX_copy_ex GRPC_SHADOW_HMAC_CTX_copy_ex', + '#define HMAC_CTX_free GRPC_SHADOW_HMAC_CTX_free', + '#define HMAC_CTX_init GRPC_SHADOW_HMAC_CTX_init', + '#define HMAC_CTX_new GRPC_SHADOW_HMAC_CTX_new', + '#define HMAC_CTX_reset GRPC_SHADOW_HMAC_CTX_reset', + '#define HMAC_Final GRPC_SHADOW_HMAC_Final', + '#define HMAC_Init GRPC_SHADOW_HMAC_Init', + '#define HMAC_Init_ex GRPC_SHADOW_HMAC_Init_ex', + '#define HMAC_Update GRPC_SHADOW_HMAC_Update', + '#define HMAC_size GRPC_SHADOW_HMAC_size', + '#define MD4 GRPC_SHADOW_MD4', + '#define MD4_Final GRPC_SHADOW_MD4_Final', + '#define MD4_Init GRPC_SHADOW_MD4_Init', + '#define MD4_Transform GRPC_SHADOW_MD4_Transform', + '#define MD4_Update GRPC_SHADOW_MD4_Update', + '#define MD5 GRPC_SHADOW_MD5', + '#define MD5_Final GRPC_SHADOW_MD5_Final', + '#define MD5_Init GRPC_SHADOW_MD5_Init', + '#define MD5_Transform GRPC_SHADOW_MD5_Transform', + '#define MD5_Update GRPC_SHADOW_MD5_Update', + '#define OPENSSL_built_in_curves GRPC_SHADOW_OPENSSL_built_in_curves', + '#define RAND_bytes GRPC_SHADOW_RAND_bytes', + '#define RAND_bytes_with_additional_data GRPC_SHADOW_RAND_bytes_with_additional_data', + '#define RAND_pseudo_bytes GRPC_SHADOW_RAND_pseudo_bytes', + '#define RAND_set_urandom_fd GRPC_SHADOW_RAND_set_urandom_fd', + '#define RSAZ_1024_mod_exp_avx2 GRPC_SHADOW_RSAZ_1024_mod_exp_avx2', + '#define RSA_add_pkcs1_prefix GRPC_SHADOW_RSA_add_pkcs1_prefix', + '#define RSA_bits GRPC_SHADOW_RSA_bits', + '#define RSA_blinding_on GRPC_SHADOW_RSA_blinding_on', + '#define RSA_check_fips GRPC_SHADOW_RSA_check_fips', + '#define RSA_check_key GRPC_SHADOW_RSA_check_key', + '#define RSA_decrypt GRPC_SHADOW_RSA_decrypt', + '#define RSA_default_method GRPC_SHADOW_RSA_default_method', + '#define RSA_encrypt GRPC_SHADOW_RSA_encrypt', + '#define RSA_flags GRPC_SHADOW_RSA_flags', + '#define RSA_free GRPC_SHADOW_RSA_free', + '#define RSA_generate_key_ex GRPC_SHADOW_RSA_generate_key_ex', + '#define RSA_generate_key_fips GRPC_SHADOW_RSA_generate_key_fips', + '#define RSA_get0_crt_params GRPC_SHADOW_RSA_get0_crt_params', + '#define RSA_get0_factors GRPC_SHADOW_RSA_get0_factors', + '#define RSA_get0_key GRPC_SHADOW_RSA_get0_key', + '#define RSA_get_ex_data GRPC_SHADOW_RSA_get_ex_data', + '#define RSA_get_ex_new_index GRPC_SHADOW_RSA_get_ex_new_index', + '#define RSA_is_opaque GRPC_SHADOW_RSA_is_opaque', + '#define RSA_new GRPC_SHADOW_RSA_new', + '#define RSA_new_method GRPC_SHADOW_RSA_new_method', + '#define RSA_padding_add_PKCS1_OAEP_mgf1 GRPC_SHADOW_RSA_padding_add_PKCS1_OAEP_mgf1', + '#define RSA_padding_add_PKCS1_PSS_mgf1 GRPC_SHADOW_RSA_padding_add_PKCS1_PSS_mgf1', + '#define RSA_padding_add_PKCS1_type_1 GRPC_SHADOW_RSA_padding_add_PKCS1_type_1', + '#define RSA_padding_add_PKCS1_type_2 GRPC_SHADOW_RSA_padding_add_PKCS1_type_2', + '#define RSA_padding_add_none GRPC_SHADOW_RSA_padding_add_none', + '#define RSA_padding_check_PKCS1_OAEP_mgf1 GRPC_SHADOW_RSA_padding_check_PKCS1_OAEP_mgf1', + '#define RSA_padding_check_PKCS1_type_1 GRPC_SHADOW_RSA_padding_check_PKCS1_type_1', + '#define RSA_padding_check_PKCS1_type_2 GRPC_SHADOW_RSA_padding_check_PKCS1_type_2', + '#define RSA_private_decrypt GRPC_SHADOW_RSA_private_decrypt', + '#define RSA_private_encrypt GRPC_SHADOW_RSA_private_encrypt', + '#define RSA_private_transform GRPC_SHADOW_RSA_private_transform', + '#define RSA_public_decrypt GRPC_SHADOW_RSA_public_decrypt', + '#define RSA_public_encrypt GRPC_SHADOW_RSA_public_encrypt', + '#define RSA_set0_crt_params GRPC_SHADOW_RSA_set0_crt_params', + '#define RSA_set0_factors GRPC_SHADOW_RSA_set0_factors', + '#define RSA_set0_key GRPC_SHADOW_RSA_set0_key', + '#define RSA_set_ex_data GRPC_SHADOW_RSA_set_ex_data', + '#define RSA_sign GRPC_SHADOW_RSA_sign', + '#define RSA_sign_pss_mgf1 GRPC_SHADOW_RSA_sign_pss_mgf1', + '#define RSA_sign_raw GRPC_SHADOW_RSA_sign_raw', + '#define RSA_size GRPC_SHADOW_RSA_size', + '#define RSA_up_ref GRPC_SHADOW_RSA_up_ref', + '#define RSA_verify GRPC_SHADOW_RSA_verify', + '#define RSA_verify_PKCS1_PSS_mgf1 GRPC_SHADOW_RSA_verify_PKCS1_PSS_mgf1', + '#define RSA_verify_pss_mgf1 GRPC_SHADOW_RSA_verify_pss_mgf1', + '#define RSA_verify_raw GRPC_SHADOW_RSA_verify_raw', + '#define SHA1 GRPC_SHADOW_SHA1', + '#define SHA1_Final GRPC_SHADOW_SHA1_Final', + '#define SHA1_Init GRPC_SHADOW_SHA1_Init', + '#define SHA1_Transform GRPC_SHADOW_SHA1_Transform', + '#define SHA1_Update GRPC_SHADOW_SHA1_Update', + '#define SHA224 GRPC_SHADOW_SHA224', + '#define SHA224_Final GRPC_SHADOW_SHA224_Final', + '#define SHA224_Init GRPC_SHADOW_SHA224_Init', + '#define SHA224_Update GRPC_SHADOW_SHA224_Update', + '#define SHA256 GRPC_SHADOW_SHA256', + '#define SHA256_Final GRPC_SHADOW_SHA256_Final', + '#define SHA256_Init GRPC_SHADOW_SHA256_Init', + '#define SHA256_Transform GRPC_SHADOW_SHA256_Transform', + '#define SHA256_Update GRPC_SHADOW_SHA256_Update', + '#define SHA384 GRPC_SHADOW_SHA384', + '#define SHA384_Final GRPC_SHADOW_SHA384_Final', + '#define SHA384_Init GRPC_SHADOW_SHA384_Init', + '#define SHA384_Update GRPC_SHADOW_SHA384_Update', + '#define SHA512 GRPC_SHADOW_SHA512', + '#define SHA512_Final GRPC_SHADOW_SHA512_Final', + '#define SHA512_Init GRPC_SHADOW_SHA512_Init', + '#define SHA512_Transform GRPC_SHADOW_SHA512_Transform', + '#define SHA512_Update GRPC_SHADOW_SHA512_Update', + '#define aes_ctr_set_key GRPC_SHADOW_aes_ctr_set_key', + '#define bn_abs_sub_consttime GRPC_SHADOW_bn_abs_sub_consttime', + '#define bn_add_words GRPC_SHADOW_bn_add_words', + '#define bn_copy_words GRPC_SHADOW_bn_copy_words', + '#define bn_div_consttime GRPC_SHADOW_bn_div_consttime', + '#define bn_expand GRPC_SHADOW_bn_expand', + '#define bn_fits_in_words GRPC_SHADOW_bn_fits_in_words', + '#define bn_from_montgomery_small GRPC_SHADOW_bn_from_montgomery_small', + '#define bn_in_range_words GRPC_SHADOW_bn_in_range_words', + '#define bn_is_bit_set_words GRPC_SHADOW_bn_is_bit_set_words', + '#define bn_is_relatively_prime GRPC_SHADOW_bn_is_relatively_prime', + '#define bn_jacobi GRPC_SHADOW_bn_jacobi', + '#define bn_lcm_consttime GRPC_SHADOW_bn_lcm_consttime', + '#define bn_less_than_montgomery_R GRPC_SHADOW_bn_less_than_montgomery_R', + '#define bn_less_than_words GRPC_SHADOW_bn_less_than_words', + '#define bn_minimal_width GRPC_SHADOW_bn_minimal_width', + '#define bn_mod_add_consttime GRPC_SHADOW_bn_mod_add_consttime', + '#define bn_mod_exp_base_2_consttime GRPC_SHADOW_bn_mod_exp_base_2_consttime', + '#define bn_mod_exp_mont_small GRPC_SHADOW_bn_mod_exp_mont_small', + '#define bn_mod_inverse_consttime GRPC_SHADOW_bn_mod_inverse_consttime', + '#define bn_mod_inverse_prime GRPC_SHADOW_bn_mod_inverse_prime', + '#define bn_mod_inverse_prime_mont_small GRPC_SHADOW_bn_mod_inverse_prime_mont_small', + '#define bn_mod_inverse_secret_prime GRPC_SHADOW_bn_mod_inverse_secret_prime', + '#define bn_mod_lshift1_consttime GRPC_SHADOW_bn_mod_lshift1_consttime', + '#define bn_mod_lshift_consttime GRPC_SHADOW_bn_mod_lshift_consttime', + '#define bn_mod_mul_montgomery_small GRPC_SHADOW_bn_mod_mul_montgomery_small', + '#define bn_mod_sub_consttime GRPC_SHADOW_bn_mod_sub_consttime', + '#define bn_mod_u16_consttime GRPC_SHADOW_bn_mod_u16_consttime', + '#define bn_mont_n0 GRPC_SHADOW_bn_mont_n0', + '#define bn_mul_add_words GRPC_SHADOW_bn_mul_add_words', + '#define bn_mul_comba4 GRPC_SHADOW_bn_mul_comba4', + '#define bn_mul_comba8 GRPC_SHADOW_bn_mul_comba8', + '#define bn_mul_consttime GRPC_SHADOW_bn_mul_consttime', + '#define bn_mul_small GRPC_SHADOW_bn_mul_small', + '#define bn_mul_words GRPC_SHADOW_bn_mul_words', + '#define bn_odd_number_is_obviously_composite GRPC_SHADOW_bn_odd_number_is_obviously_composite', + '#define bn_one_to_montgomery GRPC_SHADOW_bn_one_to_montgomery', + '#define bn_one_to_montgomery_small GRPC_SHADOW_bn_one_to_montgomery_small', + '#define bn_rand_range_words GRPC_SHADOW_bn_rand_range_words', + '#define bn_rand_secret_range GRPC_SHADOW_bn_rand_secret_range', + '#define bn_resize_words GRPC_SHADOW_bn_resize_words', + '#define bn_rshift1_words GRPC_SHADOW_bn_rshift1_words', + '#define bn_rshift_secret_shift GRPC_SHADOW_bn_rshift_secret_shift', + '#define bn_select_words GRPC_SHADOW_bn_select_words', + '#define bn_set_minimal_width GRPC_SHADOW_bn_set_minimal_width', + '#define bn_set_words GRPC_SHADOW_bn_set_words', + '#define bn_sqr_comba4 GRPC_SHADOW_bn_sqr_comba4', + '#define bn_sqr_comba8 GRPC_SHADOW_bn_sqr_comba8', + '#define bn_sqr_consttime GRPC_SHADOW_bn_sqr_consttime', + '#define bn_sqr_small GRPC_SHADOW_bn_sqr_small', + '#define bn_sqr_words GRPC_SHADOW_bn_sqr_words', + '#define bn_sub_words GRPC_SHADOW_bn_sub_words', + '#define bn_to_montgomery_small GRPC_SHADOW_bn_to_montgomery_small', + '#define bn_uadd_consttime GRPC_SHADOW_bn_uadd_consttime', + '#define bn_usub_consttime GRPC_SHADOW_bn_usub_consttime', + '#define bn_wexpand GRPC_SHADOW_bn_wexpand', + '#define crypto_gcm_clmul_enabled GRPC_SHADOW_crypto_gcm_clmul_enabled', + '#define ec_GFp_mont_field_decode GRPC_SHADOW_ec_GFp_mont_field_decode', + '#define ec_GFp_mont_field_encode GRPC_SHADOW_ec_GFp_mont_field_encode', + '#define ec_GFp_mont_field_mul GRPC_SHADOW_ec_GFp_mont_field_mul', + '#define ec_GFp_mont_field_sqr GRPC_SHADOW_ec_GFp_mont_field_sqr', + '#define ec_GFp_mont_group_finish GRPC_SHADOW_ec_GFp_mont_group_finish', + '#define ec_GFp_mont_group_init GRPC_SHADOW_ec_GFp_mont_group_init', + '#define ec_GFp_mont_group_set_curve GRPC_SHADOW_ec_GFp_mont_group_set_curve', + '#define ec_GFp_nistp_recode_scalar_bits GRPC_SHADOW_ec_GFp_nistp_recode_scalar_bits', + '#define ec_GFp_simple_add GRPC_SHADOW_ec_GFp_simple_add', + '#define ec_GFp_simple_cmp GRPC_SHADOW_ec_GFp_simple_cmp', + '#define ec_GFp_simple_dbl GRPC_SHADOW_ec_GFp_simple_dbl', + '#define ec_GFp_simple_field_mul GRPC_SHADOW_ec_GFp_simple_field_mul', + '#define ec_GFp_simple_field_sqr GRPC_SHADOW_ec_GFp_simple_field_sqr', + '#define ec_GFp_simple_group_finish GRPC_SHADOW_ec_GFp_simple_group_finish', + '#define ec_GFp_simple_group_get_curve GRPC_SHADOW_ec_GFp_simple_group_get_curve', + '#define ec_GFp_simple_group_get_degree GRPC_SHADOW_ec_GFp_simple_group_get_degree', + '#define ec_GFp_simple_group_init GRPC_SHADOW_ec_GFp_simple_group_init', + '#define ec_GFp_simple_group_set_curve GRPC_SHADOW_ec_GFp_simple_group_set_curve', + '#define ec_GFp_simple_invert GRPC_SHADOW_ec_GFp_simple_invert', + '#define ec_GFp_simple_is_at_infinity GRPC_SHADOW_ec_GFp_simple_is_at_infinity', + '#define ec_GFp_simple_is_on_curve GRPC_SHADOW_ec_GFp_simple_is_on_curve', + '#define ec_GFp_simple_make_affine GRPC_SHADOW_ec_GFp_simple_make_affine', + '#define ec_GFp_simple_point_copy GRPC_SHADOW_ec_GFp_simple_point_copy', + '#define ec_GFp_simple_point_finish GRPC_SHADOW_ec_GFp_simple_point_finish', + '#define ec_GFp_simple_point_init GRPC_SHADOW_ec_GFp_simple_point_init', + '#define ec_GFp_simple_point_set_affine_coordinates GRPC_SHADOW_ec_GFp_simple_point_set_affine_coordinates', + '#define ec_GFp_simple_point_set_to_infinity GRPC_SHADOW_ec_GFp_simple_point_set_to_infinity', + '#define ec_GFp_simple_points_make_affine GRPC_SHADOW_ec_GFp_simple_points_make_affine', + '#define ec_bignum_to_scalar GRPC_SHADOW_ec_bignum_to_scalar', + '#define ec_bignum_to_scalar_unchecked GRPC_SHADOW_ec_bignum_to_scalar_unchecked', + '#define ec_compute_wNAF GRPC_SHADOW_ec_compute_wNAF', + '#define ec_group_new GRPC_SHADOW_ec_group_new', + '#define ec_point_mul_scalar GRPC_SHADOW_ec_point_mul_scalar', + '#define ec_point_mul_scalar_public GRPC_SHADOW_ec_point_mul_scalar_public', + '#define ec_random_nonzero_scalar GRPC_SHADOW_ec_random_nonzero_scalar', + '#define ec_wNAF_mul GRPC_SHADOW_ec_wNAF_mul', + '#define kBoringSSLRSASqrtTwo GRPC_SHADOW_kBoringSSLRSASqrtTwo', + '#define kBoringSSLRSASqrtTwoLen GRPC_SHADOW_kBoringSSLRSASqrtTwoLen', + '#define md4_block_data_order GRPC_SHADOW_md4_block_data_order', + '#define rsa_default_decrypt GRPC_SHADOW_rsa_default_decrypt', + '#define rsa_default_private_transform GRPC_SHADOW_rsa_default_private_transform', + '#define rsa_default_sign_raw GRPC_SHADOW_rsa_default_sign_raw', + '#define rsa_default_size GRPC_SHADOW_rsa_default_size', + '#define FIPS_mode GRPC_SHADOW_FIPS_mode', + '#define aesni_gcm_decrypt GRPC_SHADOW_aesni_gcm_decrypt', + '#define aesni_gcm_encrypt GRPC_SHADOW_aesni_gcm_encrypt', + '#define aesni_cbc_encrypt GRPC_SHADOW_aesni_cbc_encrypt', + '#define aesni_ccm64_decrypt_blocks GRPC_SHADOW_aesni_ccm64_decrypt_blocks', + '#define aesni_ccm64_encrypt_blocks GRPC_SHADOW_aesni_ccm64_encrypt_blocks', + '#define aesni_ctr32_encrypt_blocks GRPC_SHADOW_aesni_ctr32_encrypt_blocks', + '#define aesni_decrypt GRPC_SHADOW_aesni_decrypt', + '#define aesni_ecb_encrypt GRPC_SHADOW_aesni_ecb_encrypt', + '#define aesni_encrypt GRPC_SHADOW_aesni_encrypt', + '#define aesni_ocb_decrypt GRPC_SHADOW_aesni_ocb_decrypt', + '#define aesni_ocb_encrypt GRPC_SHADOW_aesni_ocb_encrypt', + '#define aesni_set_decrypt_key GRPC_SHADOW_aesni_set_decrypt_key', + '#define aesni_set_encrypt_key GRPC_SHADOW_aesni_set_encrypt_key', + '#define aesni_xts_decrypt GRPC_SHADOW_aesni_xts_decrypt', + '#define aesni_xts_encrypt GRPC_SHADOW_aesni_xts_encrypt', + '#define asm_AES_cbc_encrypt GRPC_SHADOW_asm_AES_cbc_encrypt', + '#define asm_AES_decrypt GRPC_SHADOW_asm_AES_decrypt', + '#define asm_AES_encrypt GRPC_SHADOW_asm_AES_encrypt', + '#define asm_AES_set_decrypt_key GRPC_SHADOW_asm_AES_set_decrypt_key', + '#define asm_AES_set_encrypt_key GRPC_SHADOW_asm_AES_set_encrypt_key', + '#define bsaes_cbc_encrypt GRPC_SHADOW_bsaes_cbc_encrypt', + '#define bsaes_ctr32_encrypt_blocks GRPC_SHADOW_bsaes_ctr32_encrypt_blocks', + '#define bsaes_xts_decrypt GRPC_SHADOW_bsaes_xts_decrypt', + '#define bsaes_xts_encrypt GRPC_SHADOW_bsaes_xts_encrypt', + '#define gcm_ghash_4bit GRPC_SHADOW_gcm_ghash_4bit', + '#define gcm_ghash_avx GRPC_SHADOW_gcm_ghash_avx', + '#define gcm_ghash_clmul GRPC_SHADOW_gcm_ghash_clmul', + '#define gcm_gmult_4bit GRPC_SHADOW_gcm_gmult_4bit', + '#define gcm_gmult_avx GRPC_SHADOW_gcm_gmult_avx', + '#define gcm_gmult_clmul GRPC_SHADOW_gcm_gmult_clmul', + '#define gcm_init_avx GRPC_SHADOW_gcm_init_avx', + '#define gcm_init_clmul GRPC_SHADOW_gcm_init_clmul', + '#define md5_block_asm_data_order GRPC_SHADOW_md5_block_asm_data_order', + '#define ecp_nistz256_avx2_select_w7 GRPC_SHADOW_ecp_nistz256_avx2_select_w7', + '#define ecp_nistz256_mul_mont GRPC_SHADOW_ecp_nistz256_mul_mont', + '#define ecp_nistz256_neg GRPC_SHADOW_ecp_nistz256_neg', + '#define ecp_nistz256_point_add GRPC_SHADOW_ecp_nistz256_point_add', + '#define ecp_nistz256_point_add_affine GRPC_SHADOW_ecp_nistz256_point_add_affine', + '#define ecp_nistz256_point_double GRPC_SHADOW_ecp_nistz256_point_double', + '#define ecp_nistz256_select_w5 GRPC_SHADOW_ecp_nistz256_select_w5', + '#define ecp_nistz256_select_w7 GRPC_SHADOW_ecp_nistz256_select_w7', + '#define ecp_nistz256_sqr_mont GRPC_SHADOW_ecp_nistz256_sqr_mont', + '#define CRYPTO_rdrand GRPC_SHADOW_CRYPTO_rdrand', + '#define CRYPTO_rdrand_multiple8_buf GRPC_SHADOW_CRYPTO_rdrand_multiple8_buf', + '#define rsaz_1024_gather5_avx2 GRPC_SHADOW_rsaz_1024_gather5_avx2', + '#define rsaz_1024_mul_avx2 GRPC_SHADOW_rsaz_1024_mul_avx2', + '#define rsaz_1024_norm2red_avx2 GRPC_SHADOW_rsaz_1024_norm2red_avx2', + '#define rsaz_1024_red2norm_avx2 GRPC_SHADOW_rsaz_1024_red2norm_avx2', + '#define rsaz_1024_scatter5_avx2 GRPC_SHADOW_rsaz_1024_scatter5_avx2', + '#define rsaz_1024_sqr_avx2 GRPC_SHADOW_rsaz_1024_sqr_avx2', + '#define rsaz_avx2_eligible GRPC_SHADOW_rsaz_avx2_eligible', + '#define sha1_block_data_order GRPC_SHADOW_sha1_block_data_order', + '#define sha256_block_data_order GRPC_SHADOW_sha256_block_data_order', + '#define sha512_block_data_order GRPC_SHADOW_sha512_block_data_order', + '#define vpaes_cbc_encrypt GRPC_SHADOW_vpaes_cbc_encrypt', + '#define vpaes_decrypt GRPC_SHADOW_vpaes_decrypt', + '#define vpaes_encrypt GRPC_SHADOW_vpaes_encrypt', + '#define vpaes_set_decrypt_key GRPC_SHADOW_vpaes_set_decrypt_key', + '#define vpaes_set_encrypt_key GRPC_SHADOW_vpaes_set_encrypt_key', + '#define bn_from_montgomery GRPC_SHADOW_bn_from_montgomery', + '#define bn_gather5 GRPC_SHADOW_bn_gather5', + '#define bn_mul_mont_gather5 GRPC_SHADOW_bn_mul_mont_gather5', + '#define bn_power5 GRPC_SHADOW_bn_power5', + '#define bn_scatter5 GRPC_SHADOW_bn_scatter5', + '#define bn_sqr8x_internal GRPC_SHADOW_bn_sqr8x_internal', + '#define bn_mul_mont GRPC_SHADOW_bn_mul_mont', + '#define EVP_get_digestbyname GRPC_SHADOW_EVP_get_digestbyname', + '#define EVP_get_digestbynid GRPC_SHADOW_EVP_get_digestbynid', + '#define EVP_get_digestbyobj GRPC_SHADOW_EVP_get_digestbyobj', + '#define EVP_marshal_digest_algorithm GRPC_SHADOW_EVP_marshal_digest_algorithm', + '#define EVP_parse_digest_algorithm GRPC_SHADOW_EVP_parse_digest_algorithm', + '#define EVP_get_cipherbyname GRPC_SHADOW_EVP_get_cipherbyname', + '#define EVP_get_cipherbynid GRPC_SHADOW_EVP_get_cipherbynid', + '#define EVP_BytesToKey GRPC_SHADOW_EVP_BytesToKey', + '#define EVP_enc_null GRPC_SHADOW_EVP_enc_null', + '#define EVP_rc2_40_cbc GRPC_SHADOW_EVP_rc2_40_cbc', + '#define EVP_rc2_cbc GRPC_SHADOW_EVP_rc2_cbc', + '#define EVP_rc4 GRPC_SHADOW_EVP_rc4', + '#define EVP_aead_aes_128_gcm_siv GRPC_SHADOW_EVP_aead_aes_128_gcm_siv', + '#define EVP_aead_aes_256_gcm_siv GRPC_SHADOW_EVP_aead_aes_256_gcm_siv', + '#define EVP_aead_aes_128_ctr_hmac_sha256 GRPC_SHADOW_EVP_aead_aes_128_ctr_hmac_sha256', + '#define EVP_aead_aes_256_ctr_hmac_sha256 GRPC_SHADOW_EVP_aead_aes_256_ctr_hmac_sha256', + '#define EVP_aead_aes_128_ccm_bluetooth GRPC_SHADOW_EVP_aead_aes_128_ccm_bluetooth', + '#define EVP_aead_aes_128_ccm_bluetooth_8 GRPC_SHADOW_EVP_aead_aes_128_ccm_bluetooth_8', + '#define EVP_aead_chacha20_poly1305 GRPC_SHADOW_EVP_aead_chacha20_poly1305', + '#define EVP_tls_cbc_copy_mac GRPC_SHADOW_EVP_tls_cbc_copy_mac', + '#define EVP_tls_cbc_digest_record GRPC_SHADOW_EVP_tls_cbc_digest_record', + '#define EVP_tls_cbc_record_digest_supported GRPC_SHADOW_EVP_tls_cbc_record_digest_supported', + '#define EVP_tls_cbc_remove_padding GRPC_SHADOW_EVP_tls_cbc_remove_padding', + '#define EVP_aead_aes_128_cbc_sha1_tls GRPC_SHADOW_EVP_aead_aes_128_cbc_sha1_tls', + '#define EVP_aead_aes_128_cbc_sha1_tls_implicit_iv GRPC_SHADOW_EVP_aead_aes_128_cbc_sha1_tls_implicit_iv', + '#define EVP_aead_aes_128_cbc_sha256_tls GRPC_SHADOW_EVP_aead_aes_128_cbc_sha256_tls', + '#define EVP_aead_aes_256_cbc_sha1_tls GRPC_SHADOW_EVP_aead_aes_256_cbc_sha1_tls', + '#define EVP_aead_aes_256_cbc_sha1_tls_implicit_iv GRPC_SHADOW_EVP_aead_aes_256_cbc_sha1_tls_implicit_iv', + '#define EVP_aead_aes_256_cbc_sha256_tls GRPC_SHADOW_EVP_aead_aes_256_cbc_sha256_tls', + '#define EVP_aead_aes_256_cbc_sha384_tls GRPC_SHADOW_EVP_aead_aes_256_cbc_sha384_tls', + '#define EVP_aead_des_ede3_cbc_sha1_tls GRPC_SHADOW_EVP_aead_des_ede3_cbc_sha1_tls', + '#define EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv GRPC_SHADOW_EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv', + '#define EVP_aead_null_sha1_tls GRPC_SHADOW_EVP_aead_null_sha1_tls', + '#define EVP_aead_aes_128_cbc_sha1_ssl3 GRPC_SHADOW_EVP_aead_aes_128_cbc_sha1_ssl3', + '#define EVP_aead_aes_256_cbc_sha1_ssl3 GRPC_SHADOW_EVP_aead_aes_256_cbc_sha1_ssl3', + '#define EVP_aead_des_ede3_cbc_sha1_ssl3 GRPC_SHADOW_EVP_aead_des_ede3_cbc_sha1_ssl3', + '#define EVP_aead_null_sha1_ssl3 GRPC_SHADOW_EVP_aead_null_sha1_ssl3', + '#define aes128gcmsiv_aes_ks GRPC_SHADOW_aes128gcmsiv_aes_ks', + '#define aes128gcmsiv_aes_ks_enc_x1 GRPC_SHADOW_aes128gcmsiv_aes_ks_enc_x1', + '#define aes128gcmsiv_dec GRPC_SHADOW_aes128gcmsiv_dec', + '#define aes128gcmsiv_ecb_enc_block GRPC_SHADOW_aes128gcmsiv_ecb_enc_block', + '#define aes128gcmsiv_enc_msg_x4 GRPC_SHADOW_aes128gcmsiv_enc_msg_x4', + '#define aes128gcmsiv_enc_msg_x8 GRPC_SHADOW_aes128gcmsiv_enc_msg_x8', + '#define aes128gcmsiv_kdf GRPC_SHADOW_aes128gcmsiv_kdf', + '#define aes256gcmsiv_aes_ks GRPC_SHADOW_aes256gcmsiv_aes_ks', + '#define aes256gcmsiv_aes_ks_enc_x1 GRPC_SHADOW_aes256gcmsiv_aes_ks_enc_x1', + '#define aes256gcmsiv_dec GRPC_SHADOW_aes256gcmsiv_dec', + '#define aes256gcmsiv_ecb_enc_block GRPC_SHADOW_aes256gcmsiv_ecb_enc_block', + '#define aes256gcmsiv_enc_msg_x4 GRPC_SHADOW_aes256gcmsiv_enc_msg_x4', + '#define aes256gcmsiv_enc_msg_x8 GRPC_SHADOW_aes256gcmsiv_enc_msg_x8', + '#define aes256gcmsiv_kdf GRPC_SHADOW_aes256gcmsiv_kdf', + '#define aesgcmsiv_htable6_init GRPC_SHADOW_aesgcmsiv_htable6_init', + '#define aesgcmsiv_htable_init GRPC_SHADOW_aesgcmsiv_htable_init', + '#define aesgcmsiv_htable_polyval GRPC_SHADOW_aesgcmsiv_htable_polyval', + '#define aesgcmsiv_polyval_horner GRPC_SHADOW_aesgcmsiv_polyval_horner', + '#define chacha20_poly1305_open GRPC_SHADOW_chacha20_poly1305_open', + '#define chacha20_poly1305_seal GRPC_SHADOW_chacha20_poly1305_seal', + '#define RC4 GRPC_SHADOW_RC4', + '#define RC4_set_key GRPC_SHADOW_RC4_set_key', + '#define CONF_VALUE_new GRPC_SHADOW_CONF_VALUE_new', + '#define CONF_modules_free GRPC_SHADOW_CONF_modules_free', + '#define CONF_modules_load_file GRPC_SHADOW_CONF_modules_load_file', + '#define CONF_parse_list GRPC_SHADOW_CONF_parse_list', + '#define NCONF_free GRPC_SHADOW_NCONF_free', + '#define NCONF_get_section GRPC_SHADOW_NCONF_get_section', + '#define NCONF_get_string GRPC_SHADOW_NCONF_get_string', + '#define NCONF_load GRPC_SHADOW_NCONF_load', + '#define NCONF_load_bio GRPC_SHADOW_NCONF_load_bio', + '#define NCONF_new GRPC_SHADOW_NCONF_new', + '#define OPENSSL_config GRPC_SHADOW_OPENSSL_config', + '#define OPENSSL_no_config GRPC_SHADOW_OPENSSL_no_config', + '#define CRYPTO_chacha_20 GRPC_SHADOW_CRYPTO_chacha_20', + '#define ChaCha20_ctr32 GRPC_SHADOW_ChaCha20_ctr32', + '#define CRYPTO_poly1305_finish GRPC_SHADOW_CRYPTO_poly1305_finish', + '#define CRYPTO_poly1305_init GRPC_SHADOW_CRYPTO_poly1305_init', + '#define CRYPTO_poly1305_update GRPC_SHADOW_CRYPTO_poly1305_update', + '#define SPAKE2_CTX_free GRPC_SHADOW_SPAKE2_CTX_free', + '#define SPAKE2_CTX_new GRPC_SHADOW_SPAKE2_CTX_new', + '#define SPAKE2_generate_msg GRPC_SHADOW_SPAKE2_generate_msg', + '#define SPAKE2_process_msg GRPC_SHADOW_SPAKE2_process_msg', + '#define ED25519_keypair GRPC_SHADOW_ED25519_keypair', + '#define ED25519_keypair_from_seed GRPC_SHADOW_ED25519_keypair_from_seed', + '#define ED25519_sign GRPC_SHADOW_ED25519_sign', + '#define ED25519_verify GRPC_SHADOW_ED25519_verify', + '#define X25519 GRPC_SHADOW_X25519', + '#define X25519_keypair GRPC_SHADOW_X25519_keypair', + '#define X25519_public_from_private GRPC_SHADOW_X25519_public_from_private', + '#define x25519_ge_add GRPC_SHADOW_x25519_ge_add', + '#define x25519_ge_frombytes_vartime GRPC_SHADOW_x25519_ge_frombytes_vartime', + '#define x25519_ge_p1p1_to_p2 GRPC_SHADOW_x25519_ge_p1p1_to_p2', + '#define x25519_ge_p1p1_to_p3 GRPC_SHADOW_x25519_ge_p1p1_to_p3', + '#define x25519_ge_p3_to_cached GRPC_SHADOW_x25519_ge_p3_to_cached', + '#define x25519_ge_scalarmult GRPC_SHADOW_x25519_ge_scalarmult', + '#define x25519_ge_scalarmult_base GRPC_SHADOW_x25519_ge_scalarmult_base', + '#define x25519_ge_scalarmult_small_precomp GRPC_SHADOW_x25519_ge_scalarmult_small_precomp', + '#define x25519_ge_sub GRPC_SHADOW_x25519_ge_sub', + '#define x25519_ge_tobytes GRPC_SHADOW_x25519_ge_tobytes', + '#define x25519_sc_reduce GRPC_SHADOW_x25519_sc_reduce', + '#define BUF_MEM_append GRPC_SHADOW_BUF_MEM_append', + '#define BUF_MEM_free GRPC_SHADOW_BUF_MEM_free', + '#define BUF_MEM_grow GRPC_SHADOW_BUF_MEM_grow', + '#define BUF_MEM_grow_clean GRPC_SHADOW_BUF_MEM_grow_clean', + '#define BUF_MEM_new GRPC_SHADOW_BUF_MEM_new', + '#define BUF_MEM_reserve GRPC_SHADOW_BUF_MEM_reserve', + '#define BUF_memdup GRPC_SHADOW_BUF_memdup', + '#define BUF_strdup GRPC_SHADOW_BUF_strdup', + '#define BUF_strlcat GRPC_SHADOW_BUF_strlcat', + '#define BUF_strlcpy GRPC_SHADOW_BUF_strlcpy', + '#define BUF_strndup GRPC_SHADOW_BUF_strndup', + '#define BUF_strnlen GRPC_SHADOW_BUF_strnlen', + '#define BN_marshal_asn1 GRPC_SHADOW_BN_marshal_asn1', + '#define BN_parse_asn1_unsigned GRPC_SHADOW_BN_parse_asn1_unsigned', + '#define BN_asc2bn GRPC_SHADOW_BN_asc2bn', + '#define BN_bn2cbb_padded GRPC_SHADOW_BN_bn2cbb_padded', + '#define BN_bn2dec GRPC_SHADOW_BN_bn2dec', + '#define BN_bn2hex GRPC_SHADOW_BN_bn2hex', + '#define BN_bn2mpi GRPC_SHADOW_BN_bn2mpi', + '#define BN_dec2bn GRPC_SHADOW_BN_dec2bn', + '#define BN_hex2bn GRPC_SHADOW_BN_hex2bn', + '#define BN_mpi2bn GRPC_SHADOW_BN_mpi2bn', + '#define BN_print GRPC_SHADOW_BN_print', + '#define BN_print_fp GRPC_SHADOW_BN_print_fp', + '#define BIO_callback_ctrl GRPC_SHADOW_BIO_callback_ctrl', + '#define BIO_clear_flags GRPC_SHADOW_BIO_clear_flags', + '#define BIO_clear_retry_flags GRPC_SHADOW_BIO_clear_retry_flags', + '#define BIO_copy_next_retry GRPC_SHADOW_BIO_copy_next_retry', + '#define BIO_ctrl GRPC_SHADOW_BIO_ctrl', + '#define BIO_ctrl_pending GRPC_SHADOW_BIO_ctrl_pending', + '#define BIO_eof GRPC_SHADOW_BIO_eof', + '#define BIO_find_type GRPC_SHADOW_BIO_find_type', + '#define BIO_flush GRPC_SHADOW_BIO_flush', + '#define BIO_free GRPC_SHADOW_BIO_free', + '#define BIO_free_all GRPC_SHADOW_BIO_free_all', + '#define BIO_get_data GRPC_SHADOW_BIO_get_data', + '#define BIO_get_init GRPC_SHADOW_BIO_get_init', + '#define BIO_get_new_index GRPC_SHADOW_BIO_get_new_index', + '#define BIO_get_retry_flags GRPC_SHADOW_BIO_get_retry_flags', + '#define BIO_get_retry_reason GRPC_SHADOW_BIO_get_retry_reason', + '#define BIO_get_shutdown GRPC_SHADOW_BIO_get_shutdown', + '#define BIO_gets GRPC_SHADOW_BIO_gets', + '#define BIO_indent GRPC_SHADOW_BIO_indent', + '#define BIO_int_ctrl GRPC_SHADOW_BIO_int_ctrl', + '#define BIO_meth_free GRPC_SHADOW_BIO_meth_free', + '#define BIO_meth_new GRPC_SHADOW_BIO_meth_new', + '#define BIO_meth_set_create GRPC_SHADOW_BIO_meth_set_create', + '#define BIO_meth_set_ctrl GRPC_SHADOW_BIO_meth_set_ctrl', + '#define BIO_meth_set_destroy GRPC_SHADOW_BIO_meth_set_destroy', + '#define BIO_meth_set_gets GRPC_SHADOW_BIO_meth_set_gets', + '#define BIO_meth_set_puts GRPC_SHADOW_BIO_meth_set_puts', + '#define BIO_meth_set_read GRPC_SHADOW_BIO_meth_set_read', + '#define BIO_meth_set_write GRPC_SHADOW_BIO_meth_set_write', + '#define BIO_method_type GRPC_SHADOW_BIO_method_type', + '#define BIO_new GRPC_SHADOW_BIO_new', + '#define BIO_next GRPC_SHADOW_BIO_next', + '#define BIO_number_read GRPC_SHADOW_BIO_number_read', + '#define BIO_number_written GRPC_SHADOW_BIO_number_written', + '#define BIO_pending GRPC_SHADOW_BIO_pending', + '#define BIO_pop GRPC_SHADOW_BIO_pop', + '#define BIO_ptr_ctrl GRPC_SHADOW_BIO_ptr_ctrl', + '#define BIO_push GRPC_SHADOW_BIO_push', + '#define BIO_puts GRPC_SHADOW_BIO_puts', + '#define BIO_read GRPC_SHADOW_BIO_read', + '#define BIO_read_asn1 GRPC_SHADOW_BIO_read_asn1', + '#define BIO_reset GRPC_SHADOW_BIO_reset', + '#define BIO_set_close GRPC_SHADOW_BIO_set_close', + '#define BIO_set_data GRPC_SHADOW_BIO_set_data', + '#define BIO_set_flags GRPC_SHADOW_BIO_set_flags', + '#define BIO_set_init GRPC_SHADOW_BIO_set_init', + '#define BIO_set_retry_read GRPC_SHADOW_BIO_set_retry_read', + '#define BIO_set_retry_special GRPC_SHADOW_BIO_set_retry_special', + '#define BIO_set_retry_write GRPC_SHADOW_BIO_set_retry_write', + '#define BIO_set_shutdown GRPC_SHADOW_BIO_set_shutdown', + '#define BIO_set_write_buffer_size GRPC_SHADOW_BIO_set_write_buffer_size', + '#define BIO_should_io_special GRPC_SHADOW_BIO_should_io_special', + '#define BIO_should_read GRPC_SHADOW_BIO_should_read', + '#define BIO_should_retry GRPC_SHADOW_BIO_should_retry', + '#define BIO_should_write GRPC_SHADOW_BIO_should_write', + '#define BIO_test_flags GRPC_SHADOW_BIO_test_flags', + '#define BIO_up_ref GRPC_SHADOW_BIO_up_ref', + '#define BIO_vfree GRPC_SHADOW_BIO_vfree', + '#define BIO_wpending GRPC_SHADOW_BIO_wpending', + '#define BIO_write GRPC_SHADOW_BIO_write', + '#define ERR_print_errors GRPC_SHADOW_ERR_print_errors', + '#define BIO_get_mem_data GRPC_SHADOW_BIO_get_mem_data', + '#define BIO_get_mem_ptr GRPC_SHADOW_BIO_get_mem_ptr', + '#define BIO_mem_contents GRPC_SHADOW_BIO_mem_contents', + '#define BIO_new_mem_buf GRPC_SHADOW_BIO_new_mem_buf', + '#define BIO_s_mem GRPC_SHADOW_BIO_s_mem', + '#define BIO_set_mem_buf GRPC_SHADOW_BIO_set_mem_buf', + '#define BIO_set_mem_eof_return GRPC_SHADOW_BIO_set_mem_eof_return', + '#define BIO_do_connect GRPC_SHADOW_BIO_do_connect', + '#define BIO_new_connect GRPC_SHADOW_BIO_new_connect', + '#define BIO_s_connect GRPC_SHADOW_BIO_s_connect', + '#define BIO_set_conn_hostname GRPC_SHADOW_BIO_set_conn_hostname', + '#define BIO_set_conn_int_port GRPC_SHADOW_BIO_set_conn_int_port', + '#define BIO_set_conn_port GRPC_SHADOW_BIO_set_conn_port', + '#define BIO_set_nbio GRPC_SHADOW_BIO_set_nbio', + '#define BIO_get_fd GRPC_SHADOW_BIO_get_fd', + '#define BIO_new_fd GRPC_SHADOW_BIO_new_fd', + '#define BIO_s_fd GRPC_SHADOW_BIO_s_fd', + '#define BIO_set_fd GRPC_SHADOW_BIO_set_fd', + '#define bio_fd_should_retry GRPC_SHADOW_bio_fd_should_retry', + '#define BIO_append_filename GRPC_SHADOW_BIO_append_filename', + '#define BIO_get_fp GRPC_SHADOW_BIO_get_fp', + '#define BIO_new_file GRPC_SHADOW_BIO_new_file', + '#define BIO_new_fp GRPC_SHADOW_BIO_new_fp', + '#define BIO_read_filename GRPC_SHADOW_BIO_read_filename', + '#define BIO_rw_filename GRPC_SHADOW_BIO_rw_filename', + '#define BIO_s_file GRPC_SHADOW_BIO_s_file', + '#define BIO_set_fp GRPC_SHADOW_BIO_set_fp', + '#define BIO_write_filename GRPC_SHADOW_BIO_write_filename', + '#define BIO_hexdump GRPC_SHADOW_BIO_hexdump', + '#define BIO_ctrl_get_read_request GRPC_SHADOW_BIO_ctrl_get_read_request', + '#define BIO_ctrl_get_write_guarantee GRPC_SHADOW_BIO_ctrl_get_write_guarantee', + '#define BIO_new_bio_pair GRPC_SHADOW_BIO_new_bio_pair', + '#define BIO_shutdown_wr GRPC_SHADOW_BIO_shutdown_wr', + '#define BIO_printf GRPC_SHADOW_BIO_printf', + '#define BIO_new_socket GRPC_SHADOW_BIO_new_socket', + '#define BIO_s_socket GRPC_SHADOW_BIO_s_socket', + '#define bio_clear_socket_error GRPC_SHADOW_bio_clear_socket_error', + '#define bio_ip_and_port_to_socket_and_addr GRPC_SHADOW_bio_ip_and_port_to_socket_and_addr', + '#define bio_sock_error GRPC_SHADOW_bio_sock_error', + '#define bio_socket_nbio GRPC_SHADOW_bio_socket_nbio', + '#define RAND_enable_fork_unsafe_buffering GRPC_SHADOW_RAND_enable_fork_unsafe_buffering', + '#define rand_fork_unsafe_buffering_enabled GRPC_SHADOW_rand_fork_unsafe_buffering_enabled', + '#define RAND_SSLeay GRPC_SHADOW_RAND_SSLeay', + '#define RAND_add GRPC_SHADOW_RAND_add', + '#define RAND_cleanup GRPC_SHADOW_RAND_cleanup', + '#define RAND_egd GRPC_SHADOW_RAND_egd', + '#define RAND_file_name GRPC_SHADOW_RAND_file_name', + '#define RAND_get_rand_method GRPC_SHADOW_RAND_get_rand_method', + '#define RAND_load_file GRPC_SHADOW_RAND_load_file', + '#define RAND_poll GRPC_SHADOW_RAND_poll', + '#define RAND_seed GRPC_SHADOW_RAND_seed', + '#define RAND_set_rand_method GRPC_SHADOW_RAND_set_rand_method', + '#define RAND_status GRPC_SHADOW_RAND_status', + '#define OBJ_cbs2nid GRPC_SHADOW_OBJ_cbs2nid', + '#define OBJ_cmp GRPC_SHADOW_OBJ_cmp', + '#define OBJ_create GRPC_SHADOW_OBJ_create', + '#define OBJ_dup GRPC_SHADOW_OBJ_dup', + '#define OBJ_get0_data GRPC_SHADOW_OBJ_get0_data', + '#define OBJ_length GRPC_SHADOW_OBJ_length', + '#define OBJ_ln2nid GRPC_SHADOW_OBJ_ln2nid', + '#define OBJ_nid2cbb GRPC_SHADOW_OBJ_nid2cbb', + '#define OBJ_nid2ln GRPC_SHADOW_OBJ_nid2ln', + '#define OBJ_nid2obj GRPC_SHADOW_OBJ_nid2obj', + '#define OBJ_nid2sn GRPC_SHADOW_OBJ_nid2sn', + '#define OBJ_obj2nid GRPC_SHADOW_OBJ_obj2nid', + '#define OBJ_obj2txt GRPC_SHADOW_OBJ_obj2txt', + '#define OBJ_sn2nid GRPC_SHADOW_OBJ_sn2nid', + '#define OBJ_txt2nid GRPC_SHADOW_OBJ_txt2nid', + '#define OBJ_txt2obj GRPC_SHADOW_OBJ_txt2obj', + '#define OBJ_find_sigid_algs GRPC_SHADOW_OBJ_find_sigid_algs', + '#define OBJ_find_sigid_by_algs GRPC_SHADOW_OBJ_find_sigid_by_algs', + '#define ASN1_BIT_STRING_check GRPC_SHADOW_ASN1_BIT_STRING_check', + '#define ASN1_BIT_STRING_get_bit GRPC_SHADOW_ASN1_BIT_STRING_get_bit', + '#define ASN1_BIT_STRING_set GRPC_SHADOW_ASN1_BIT_STRING_set', + '#define ASN1_BIT_STRING_set_bit GRPC_SHADOW_ASN1_BIT_STRING_set_bit', + '#define c2i_ASN1_BIT_STRING GRPC_SHADOW_c2i_ASN1_BIT_STRING', + '#define i2c_ASN1_BIT_STRING GRPC_SHADOW_i2c_ASN1_BIT_STRING', + '#define d2i_ASN1_BOOLEAN GRPC_SHADOW_d2i_ASN1_BOOLEAN', + '#define i2d_ASN1_BOOLEAN GRPC_SHADOW_i2d_ASN1_BOOLEAN', + '#define ASN1_d2i_bio GRPC_SHADOW_ASN1_d2i_bio', + '#define ASN1_d2i_fp GRPC_SHADOW_ASN1_d2i_fp', + '#define ASN1_item_d2i_bio GRPC_SHADOW_ASN1_item_d2i_bio', + '#define ASN1_item_d2i_fp GRPC_SHADOW_ASN1_item_d2i_fp', + '#define ASN1_dup GRPC_SHADOW_ASN1_dup', + '#define ASN1_item_dup GRPC_SHADOW_ASN1_item_dup', + '#define ASN1_ENUMERATED_get GRPC_SHADOW_ASN1_ENUMERATED_get', + '#define ASN1_ENUMERATED_set GRPC_SHADOW_ASN1_ENUMERATED_set', + '#define ASN1_ENUMERATED_to_BN GRPC_SHADOW_ASN1_ENUMERATED_to_BN', + '#define BN_to_ASN1_ENUMERATED GRPC_SHADOW_BN_to_ASN1_ENUMERATED', + '#define ASN1_GENERALIZEDTIME_adj GRPC_SHADOW_ASN1_GENERALIZEDTIME_adj', + '#define ASN1_GENERALIZEDTIME_check GRPC_SHADOW_ASN1_GENERALIZEDTIME_check', + '#define ASN1_GENERALIZEDTIME_set GRPC_SHADOW_ASN1_GENERALIZEDTIME_set', + '#define ASN1_GENERALIZEDTIME_set_string GRPC_SHADOW_ASN1_GENERALIZEDTIME_set_string', + '#define asn1_generalizedtime_to_tm GRPC_SHADOW_asn1_generalizedtime_to_tm', + '#define ASN1_i2d_bio GRPC_SHADOW_ASN1_i2d_bio', + '#define ASN1_i2d_fp GRPC_SHADOW_ASN1_i2d_fp', + '#define ASN1_item_i2d_bio GRPC_SHADOW_ASN1_item_i2d_bio', + '#define ASN1_item_i2d_fp GRPC_SHADOW_ASN1_item_i2d_fp', + '#define ASN1_INTEGER_cmp GRPC_SHADOW_ASN1_INTEGER_cmp', + '#define ASN1_INTEGER_dup GRPC_SHADOW_ASN1_INTEGER_dup', + '#define ASN1_INTEGER_get GRPC_SHADOW_ASN1_INTEGER_get', + '#define ASN1_INTEGER_set GRPC_SHADOW_ASN1_INTEGER_set', + '#define ASN1_INTEGER_set_uint64 GRPC_SHADOW_ASN1_INTEGER_set_uint64', + '#define ASN1_INTEGER_to_BN GRPC_SHADOW_ASN1_INTEGER_to_BN', + '#define BN_to_ASN1_INTEGER GRPC_SHADOW_BN_to_ASN1_INTEGER', + '#define c2i_ASN1_INTEGER GRPC_SHADOW_c2i_ASN1_INTEGER', + '#define d2i_ASN1_UINTEGER GRPC_SHADOW_d2i_ASN1_UINTEGER', + '#define i2c_ASN1_INTEGER GRPC_SHADOW_i2c_ASN1_INTEGER', + '#define ASN1_mbstring_copy GRPC_SHADOW_ASN1_mbstring_copy', + '#define ASN1_mbstring_ncopy GRPC_SHADOW_ASN1_mbstring_ncopy', + '#define ASN1_OBJECT_create GRPC_SHADOW_ASN1_OBJECT_create', + '#define ASN1_OBJECT_free GRPC_SHADOW_ASN1_OBJECT_free', + '#define ASN1_OBJECT_new GRPC_SHADOW_ASN1_OBJECT_new', + '#define c2i_ASN1_OBJECT GRPC_SHADOW_c2i_ASN1_OBJECT', + '#define d2i_ASN1_OBJECT GRPC_SHADOW_d2i_ASN1_OBJECT', + '#define i2a_ASN1_OBJECT GRPC_SHADOW_i2a_ASN1_OBJECT', + '#define i2d_ASN1_OBJECT GRPC_SHADOW_i2d_ASN1_OBJECT', + '#define i2t_ASN1_OBJECT GRPC_SHADOW_i2t_ASN1_OBJECT', + '#define ASN1_OCTET_STRING_cmp GRPC_SHADOW_ASN1_OCTET_STRING_cmp', + '#define ASN1_OCTET_STRING_dup GRPC_SHADOW_ASN1_OCTET_STRING_dup', + '#define ASN1_OCTET_STRING_set GRPC_SHADOW_ASN1_OCTET_STRING_set', + '#define ASN1_PRINTABLE_type GRPC_SHADOW_ASN1_PRINTABLE_type', + '#define ASN1_STRING_TABLE_add GRPC_SHADOW_ASN1_STRING_TABLE_add', + '#define ASN1_STRING_TABLE_cleanup GRPC_SHADOW_ASN1_STRING_TABLE_cleanup', + '#define ASN1_STRING_TABLE_get GRPC_SHADOW_ASN1_STRING_TABLE_get', + '#define ASN1_STRING_get_default_mask GRPC_SHADOW_ASN1_STRING_get_default_mask', + '#define ASN1_STRING_set_by_NID GRPC_SHADOW_ASN1_STRING_set_by_NID', + '#define ASN1_STRING_set_default_mask GRPC_SHADOW_ASN1_STRING_set_default_mask', + '#define ASN1_STRING_set_default_mask_asc GRPC_SHADOW_ASN1_STRING_set_default_mask_asc', + '#define ASN1_TIME_adj GRPC_SHADOW_ASN1_TIME_adj', + '#define ASN1_TIME_check GRPC_SHADOW_ASN1_TIME_check', + '#define ASN1_TIME_diff GRPC_SHADOW_ASN1_TIME_diff', + '#define ASN1_TIME_free GRPC_SHADOW_ASN1_TIME_free', + '#define ASN1_TIME_it GRPC_SHADOW_ASN1_TIME_it', + '#define ASN1_TIME_new GRPC_SHADOW_ASN1_TIME_new', + '#define ASN1_TIME_set GRPC_SHADOW_ASN1_TIME_set', + '#define ASN1_TIME_set_string GRPC_SHADOW_ASN1_TIME_set_string', + '#define ASN1_TIME_to_generalizedtime GRPC_SHADOW_ASN1_TIME_to_generalizedtime', + '#define d2i_ASN1_TIME GRPC_SHADOW_d2i_ASN1_TIME', + '#define i2d_ASN1_TIME GRPC_SHADOW_i2d_ASN1_TIME', + '#define ASN1_TYPE_cmp GRPC_SHADOW_ASN1_TYPE_cmp', + '#define ASN1_TYPE_get GRPC_SHADOW_ASN1_TYPE_get', + '#define ASN1_TYPE_set GRPC_SHADOW_ASN1_TYPE_set', + '#define ASN1_TYPE_set1 GRPC_SHADOW_ASN1_TYPE_set1', + '#define ASN1_UTCTIME_adj GRPC_SHADOW_ASN1_UTCTIME_adj', + '#define ASN1_UTCTIME_check GRPC_SHADOW_ASN1_UTCTIME_check', + '#define ASN1_UTCTIME_cmp_time_t GRPC_SHADOW_ASN1_UTCTIME_cmp_time_t', + '#define ASN1_UTCTIME_set GRPC_SHADOW_ASN1_UTCTIME_set', + '#define ASN1_UTCTIME_set_string GRPC_SHADOW_ASN1_UTCTIME_set_string', + '#define asn1_utctime_to_tm GRPC_SHADOW_asn1_utctime_to_tm', + '#define UTF8_getc GRPC_SHADOW_UTF8_getc', + '#define UTF8_putc GRPC_SHADOW_UTF8_putc', + '#define ASN1_STRING_cmp GRPC_SHADOW_ASN1_STRING_cmp', + '#define ASN1_STRING_copy GRPC_SHADOW_ASN1_STRING_copy', + '#define ASN1_STRING_data GRPC_SHADOW_ASN1_STRING_data', + '#define ASN1_STRING_dup GRPC_SHADOW_ASN1_STRING_dup', + '#define ASN1_STRING_free GRPC_SHADOW_ASN1_STRING_free', + '#define ASN1_STRING_get0_data GRPC_SHADOW_ASN1_STRING_get0_data', + '#define ASN1_STRING_length GRPC_SHADOW_ASN1_STRING_length', + '#define ASN1_STRING_length_set GRPC_SHADOW_ASN1_STRING_length_set', + '#define ASN1_STRING_new GRPC_SHADOW_ASN1_STRING_new', + '#define ASN1_STRING_set GRPC_SHADOW_ASN1_STRING_set', + '#define ASN1_STRING_set0 GRPC_SHADOW_ASN1_STRING_set0', + '#define ASN1_STRING_type GRPC_SHADOW_ASN1_STRING_type', + '#define ASN1_STRING_type_new GRPC_SHADOW_ASN1_STRING_type_new', + '#define ASN1_get_object GRPC_SHADOW_ASN1_get_object', + '#define ASN1_object_size GRPC_SHADOW_ASN1_object_size', + '#define ASN1_put_eoc GRPC_SHADOW_ASN1_put_eoc', + '#define ASN1_put_object GRPC_SHADOW_ASN1_put_object', + '#define ASN1_tag2str GRPC_SHADOW_ASN1_tag2str', + '#define ASN1_item_pack GRPC_SHADOW_ASN1_item_pack', + '#define ASN1_item_unpack GRPC_SHADOW_ASN1_item_unpack', + '#define i2a_ASN1_ENUMERATED GRPC_SHADOW_i2a_ASN1_ENUMERATED', + '#define i2a_ASN1_INTEGER GRPC_SHADOW_i2a_ASN1_INTEGER', + '#define i2a_ASN1_STRING GRPC_SHADOW_i2a_ASN1_STRING', + '#define ASN1_item_d2i GRPC_SHADOW_ASN1_item_d2i', + '#define ASN1_item_ex_d2i GRPC_SHADOW_ASN1_item_ex_d2i', + '#define ASN1_tag2bit GRPC_SHADOW_ASN1_tag2bit', + '#define asn1_ex_c2i GRPC_SHADOW_asn1_ex_c2i', + '#define ASN1_item_ex_i2d GRPC_SHADOW_ASN1_item_ex_i2d', + '#define ASN1_item_i2d GRPC_SHADOW_ASN1_item_i2d', + '#define ASN1_item_ndef_i2d GRPC_SHADOW_ASN1_item_ndef_i2d', + '#define asn1_ex_i2c GRPC_SHADOW_asn1_ex_i2c', + '#define ASN1_item_ex_free GRPC_SHADOW_ASN1_item_ex_free', + '#define ASN1_item_free GRPC_SHADOW_ASN1_item_free', + '#define ASN1_primitive_free GRPC_SHADOW_ASN1_primitive_free', + '#define ASN1_template_free GRPC_SHADOW_ASN1_template_free', + '#define asn1_item_combine_free GRPC_SHADOW_asn1_item_combine_free', + '#define ASN1_item_ex_new GRPC_SHADOW_ASN1_item_ex_new', + '#define ASN1_item_new GRPC_SHADOW_ASN1_item_new', + '#define ASN1_primitive_new GRPC_SHADOW_ASN1_primitive_new', + '#define ASN1_template_new GRPC_SHADOW_ASN1_template_new', + '#define ASN1_ANY_it GRPC_SHADOW_ASN1_ANY_it', + '#define ASN1_BIT_STRING_free GRPC_SHADOW_ASN1_BIT_STRING_free', + '#define ASN1_BIT_STRING_it GRPC_SHADOW_ASN1_BIT_STRING_it', + '#define ASN1_BIT_STRING_new GRPC_SHADOW_ASN1_BIT_STRING_new', + '#define ASN1_BMPSTRING_free GRPC_SHADOW_ASN1_BMPSTRING_free', + '#define ASN1_BMPSTRING_it GRPC_SHADOW_ASN1_BMPSTRING_it', + '#define ASN1_BMPSTRING_new GRPC_SHADOW_ASN1_BMPSTRING_new', + '#define ASN1_BOOLEAN_it GRPC_SHADOW_ASN1_BOOLEAN_it', + '#define ASN1_ENUMERATED_free GRPC_SHADOW_ASN1_ENUMERATED_free', + '#define ASN1_ENUMERATED_it GRPC_SHADOW_ASN1_ENUMERATED_it', + '#define ASN1_ENUMERATED_new GRPC_SHADOW_ASN1_ENUMERATED_new', + '#define ASN1_FBOOLEAN_it GRPC_SHADOW_ASN1_FBOOLEAN_it', + '#define ASN1_GENERALIZEDTIME_free GRPC_SHADOW_ASN1_GENERALIZEDTIME_free', + '#define ASN1_GENERALIZEDTIME_it GRPC_SHADOW_ASN1_GENERALIZEDTIME_it', + '#define ASN1_GENERALIZEDTIME_new GRPC_SHADOW_ASN1_GENERALIZEDTIME_new', + '#define ASN1_GENERALSTRING_free GRPC_SHADOW_ASN1_GENERALSTRING_free', + '#define ASN1_GENERALSTRING_it GRPC_SHADOW_ASN1_GENERALSTRING_it', + '#define ASN1_GENERALSTRING_new GRPC_SHADOW_ASN1_GENERALSTRING_new', + '#define ASN1_IA5STRING_free GRPC_SHADOW_ASN1_IA5STRING_free', + '#define ASN1_IA5STRING_it GRPC_SHADOW_ASN1_IA5STRING_it', + '#define ASN1_IA5STRING_new GRPC_SHADOW_ASN1_IA5STRING_new', + '#define ASN1_INTEGER_free GRPC_SHADOW_ASN1_INTEGER_free', + '#define ASN1_INTEGER_it GRPC_SHADOW_ASN1_INTEGER_it', + '#define ASN1_INTEGER_new GRPC_SHADOW_ASN1_INTEGER_new', + '#define ASN1_NULL_free GRPC_SHADOW_ASN1_NULL_free', + '#define ASN1_NULL_it GRPC_SHADOW_ASN1_NULL_it', + '#define ASN1_NULL_new GRPC_SHADOW_ASN1_NULL_new', + '#define ASN1_OBJECT_it GRPC_SHADOW_ASN1_OBJECT_it', + '#define ASN1_OCTET_STRING_NDEF_it GRPC_SHADOW_ASN1_OCTET_STRING_NDEF_it', + '#define ASN1_OCTET_STRING_free GRPC_SHADOW_ASN1_OCTET_STRING_free', + '#define ASN1_OCTET_STRING_it GRPC_SHADOW_ASN1_OCTET_STRING_it', + '#define ASN1_OCTET_STRING_new GRPC_SHADOW_ASN1_OCTET_STRING_new', + '#define ASN1_PRINTABLESTRING_free GRPC_SHADOW_ASN1_PRINTABLESTRING_free', + '#define ASN1_PRINTABLESTRING_it GRPC_SHADOW_ASN1_PRINTABLESTRING_it', + '#define ASN1_PRINTABLESTRING_new GRPC_SHADOW_ASN1_PRINTABLESTRING_new', + '#define ASN1_PRINTABLE_free GRPC_SHADOW_ASN1_PRINTABLE_free', + '#define ASN1_PRINTABLE_it GRPC_SHADOW_ASN1_PRINTABLE_it', + '#define ASN1_PRINTABLE_new GRPC_SHADOW_ASN1_PRINTABLE_new', + '#define ASN1_SEQUENCE_ANY_it GRPC_SHADOW_ASN1_SEQUENCE_ANY_it', + '#define ASN1_SEQUENCE_it GRPC_SHADOW_ASN1_SEQUENCE_it', + '#define ASN1_SET_ANY_it GRPC_SHADOW_ASN1_SET_ANY_it', + '#define ASN1_T61STRING_free GRPC_SHADOW_ASN1_T61STRING_free', + '#define ASN1_T61STRING_it GRPC_SHADOW_ASN1_T61STRING_it', + '#define ASN1_T61STRING_new GRPC_SHADOW_ASN1_T61STRING_new', + '#define ASN1_TBOOLEAN_it GRPC_SHADOW_ASN1_TBOOLEAN_it', + '#define ASN1_TYPE_free GRPC_SHADOW_ASN1_TYPE_free', + '#define ASN1_TYPE_new GRPC_SHADOW_ASN1_TYPE_new', + '#define ASN1_UNIVERSALSTRING_free GRPC_SHADOW_ASN1_UNIVERSALSTRING_free', + '#define ASN1_UNIVERSALSTRING_it GRPC_SHADOW_ASN1_UNIVERSALSTRING_it', + '#define ASN1_UNIVERSALSTRING_new GRPC_SHADOW_ASN1_UNIVERSALSTRING_new', + '#define ASN1_UTCTIME_free GRPC_SHADOW_ASN1_UTCTIME_free', + '#define ASN1_UTCTIME_it GRPC_SHADOW_ASN1_UTCTIME_it', + '#define ASN1_UTCTIME_new GRPC_SHADOW_ASN1_UTCTIME_new', + '#define ASN1_UTF8STRING_free GRPC_SHADOW_ASN1_UTF8STRING_free', + '#define ASN1_UTF8STRING_it GRPC_SHADOW_ASN1_UTF8STRING_it', + '#define ASN1_UTF8STRING_new GRPC_SHADOW_ASN1_UTF8STRING_new', + '#define ASN1_VISIBLESTRING_free GRPC_SHADOW_ASN1_VISIBLESTRING_free', + '#define ASN1_VISIBLESTRING_it GRPC_SHADOW_ASN1_VISIBLESTRING_it', + '#define ASN1_VISIBLESTRING_new GRPC_SHADOW_ASN1_VISIBLESTRING_new', + '#define DIRECTORYSTRING_free GRPC_SHADOW_DIRECTORYSTRING_free', + '#define DIRECTORYSTRING_it GRPC_SHADOW_DIRECTORYSTRING_it', + '#define DIRECTORYSTRING_new GRPC_SHADOW_DIRECTORYSTRING_new', + '#define DISPLAYTEXT_free GRPC_SHADOW_DISPLAYTEXT_free', + '#define DISPLAYTEXT_it GRPC_SHADOW_DISPLAYTEXT_it', + '#define DISPLAYTEXT_new GRPC_SHADOW_DISPLAYTEXT_new', + '#define d2i_ASN1_BIT_STRING GRPC_SHADOW_d2i_ASN1_BIT_STRING', + '#define d2i_ASN1_BMPSTRING GRPC_SHADOW_d2i_ASN1_BMPSTRING', + '#define d2i_ASN1_ENUMERATED GRPC_SHADOW_d2i_ASN1_ENUMERATED', + '#define d2i_ASN1_GENERALIZEDTIME GRPC_SHADOW_d2i_ASN1_GENERALIZEDTIME', + '#define d2i_ASN1_GENERALSTRING GRPC_SHADOW_d2i_ASN1_GENERALSTRING', + '#define d2i_ASN1_IA5STRING GRPC_SHADOW_d2i_ASN1_IA5STRING', + '#define d2i_ASN1_INTEGER GRPC_SHADOW_d2i_ASN1_INTEGER', + '#define d2i_ASN1_NULL GRPC_SHADOW_d2i_ASN1_NULL', + '#define d2i_ASN1_OCTET_STRING GRPC_SHADOW_d2i_ASN1_OCTET_STRING', + '#define d2i_ASN1_PRINTABLE GRPC_SHADOW_d2i_ASN1_PRINTABLE', + '#define d2i_ASN1_PRINTABLESTRING GRPC_SHADOW_d2i_ASN1_PRINTABLESTRING', + '#define d2i_ASN1_SEQUENCE_ANY GRPC_SHADOW_d2i_ASN1_SEQUENCE_ANY', + '#define d2i_ASN1_SET_ANY GRPC_SHADOW_d2i_ASN1_SET_ANY', + '#define d2i_ASN1_T61STRING GRPC_SHADOW_d2i_ASN1_T61STRING', + '#define d2i_ASN1_TYPE GRPC_SHADOW_d2i_ASN1_TYPE', + '#define d2i_ASN1_UNIVERSALSTRING GRPC_SHADOW_d2i_ASN1_UNIVERSALSTRING', + '#define d2i_ASN1_UTCTIME GRPC_SHADOW_d2i_ASN1_UTCTIME', + '#define d2i_ASN1_UTF8STRING GRPC_SHADOW_d2i_ASN1_UTF8STRING', + '#define d2i_ASN1_VISIBLESTRING GRPC_SHADOW_d2i_ASN1_VISIBLESTRING', + '#define d2i_DIRECTORYSTRING GRPC_SHADOW_d2i_DIRECTORYSTRING', + '#define d2i_DISPLAYTEXT GRPC_SHADOW_d2i_DISPLAYTEXT', + '#define i2d_ASN1_BIT_STRING GRPC_SHADOW_i2d_ASN1_BIT_STRING', + '#define i2d_ASN1_BMPSTRING GRPC_SHADOW_i2d_ASN1_BMPSTRING', + '#define i2d_ASN1_ENUMERATED GRPC_SHADOW_i2d_ASN1_ENUMERATED', + '#define i2d_ASN1_GENERALIZEDTIME GRPC_SHADOW_i2d_ASN1_GENERALIZEDTIME', + '#define i2d_ASN1_GENERALSTRING GRPC_SHADOW_i2d_ASN1_GENERALSTRING', + '#define i2d_ASN1_IA5STRING GRPC_SHADOW_i2d_ASN1_IA5STRING', + '#define i2d_ASN1_INTEGER GRPC_SHADOW_i2d_ASN1_INTEGER', + '#define i2d_ASN1_NULL GRPC_SHADOW_i2d_ASN1_NULL', + '#define i2d_ASN1_OCTET_STRING GRPC_SHADOW_i2d_ASN1_OCTET_STRING', + '#define i2d_ASN1_PRINTABLE GRPC_SHADOW_i2d_ASN1_PRINTABLE', + '#define i2d_ASN1_PRINTABLESTRING GRPC_SHADOW_i2d_ASN1_PRINTABLESTRING', + '#define i2d_ASN1_SEQUENCE_ANY GRPC_SHADOW_i2d_ASN1_SEQUENCE_ANY', + '#define i2d_ASN1_SET_ANY GRPC_SHADOW_i2d_ASN1_SET_ANY', + '#define i2d_ASN1_T61STRING GRPC_SHADOW_i2d_ASN1_T61STRING', + '#define i2d_ASN1_TYPE GRPC_SHADOW_i2d_ASN1_TYPE', + '#define i2d_ASN1_UNIVERSALSTRING GRPC_SHADOW_i2d_ASN1_UNIVERSALSTRING', + '#define i2d_ASN1_UTCTIME GRPC_SHADOW_i2d_ASN1_UTCTIME', + '#define i2d_ASN1_UTF8STRING GRPC_SHADOW_i2d_ASN1_UTF8STRING', + '#define i2d_ASN1_VISIBLESTRING GRPC_SHADOW_i2d_ASN1_VISIBLESTRING', + '#define i2d_DIRECTORYSTRING GRPC_SHADOW_i2d_DIRECTORYSTRING', + '#define i2d_DISPLAYTEXT GRPC_SHADOW_i2d_DISPLAYTEXT', + '#define asn1_do_adb GRPC_SHADOW_asn1_do_adb', + '#define asn1_enc_free GRPC_SHADOW_asn1_enc_free', + '#define asn1_enc_init GRPC_SHADOW_asn1_enc_init', + '#define asn1_enc_restore GRPC_SHADOW_asn1_enc_restore', + '#define asn1_enc_save GRPC_SHADOW_asn1_enc_save', + '#define asn1_get_choice_selector GRPC_SHADOW_asn1_get_choice_selector', + '#define asn1_get_field_ptr GRPC_SHADOW_asn1_get_field_ptr', + '#define asn1_refcount_dec_and_test_zero GRPC_SHADOW_asn1_refcount_dec_and_test_zero', + '#define asn1_refcount_set_one GRPC_SHADOW_asn1_refcount_set_one', + '#define asn1_set_choice_selector GRPC_SHADOW_asn1_set_choice_selector', + '#define OPENSSL_gmtime GRPC_SHADOW_OPENSSL_gmtime', + '#define OPENSSL_gmtime_adj GRPC_SHADOW_OPENSSL_gmtime_adj', + '#define OPENSSL_gmtime_diff GRPC_SHADOW_OPENSSL_gmtime_diff', + '#define ENGINE_free GRPC_SHADOW_ENGINE_free', + '#define ENGINE_get_ECDSA_method GRPC_SHADOW_ENGINE_get_ECDSA_method', + '#define ENGINE_get_RSA_method GRPC_SHADOW_ENGINE_get_RSA_method', + '#define ENGINE_new GRPC_SHADOW_ENGINE_new', + '#define ENGINE_set_ECDSA_method GRPC_SHADOW_ENGINE_set_ECDSA_method', + '#define ENGINE_set_RSA_method GRPC_SHADOW_ENGINE_set_RSA_method', + '#define METHOD_ref GRPC_SHADOW_METHOD_ref', + '#define METHOD_unref GRPC_SHADOW_METHOD_unref', + '#define DH_compute_key GRPC_SHADOW_DH_compute_key', + '#define DH_free GRPC_SHADOW_DH_free', + '#define DH_generate_key GRPC_SHADOW_DH_generate_key', + '#define DH_generate_parameters_ex GRPC_SHADOW_DH_generate_parameters_ex', + '#define DH_get0_key GRPC_SHADOW_DH_get0_key', + '#define DH_get0_pqg GRPC_SHADOW_DH_get0_pqg', + '#define DH_get_ex_data GRPC_SHADOW_DH_get_ex_data', + '#define DH_get_ex_new_index GRPC_SHADOW_DH_get_ex_new_index', + '#define DH_new GRPC_SHADOW_DH_new', + '#define DH_num_bits GRPC_SHADOW_DH_num_bits', + '#define DH_set0_key GRPC_SHADOW_DH_set0_key', + '#define DH_set0_pqg GRPC_SHADOW_DH_set0_pqg', + '#define DH_set_ex_data GRPC_SHADOW_DH_set_ex_data', + '#define DH_size GRPC_SHADOW_DH_size', + '#define DH_up_ref GRPC_SHADOW_DH_up_ref', + '#define DHparams_dup GRPC_SHADOW_DHparams_dup', + '#define BN_get_rfc3526_prime_1536 GRPC_SHADOW_BN_get_rfc3526_prime_1536', + '#define DH_check GRPC_SHADOW_DH_check', + '#define DH_check_pub_key GRPC_SHADOW_DH_check_pub_key', + '#define DH_marshal_parameters GRPC_SHADOW_DH_marshal_parameters', + '#define DH_parse_parameters GRPC_SHADOW_DH_parse_parameters', + '#define d2i_DHparams GRPC_SHADOW_d2i_DHparams', + '#define i2d_DHparams GRPC_SHADOW_i2d_DHparams', + '#define DSA_SIG_free GRPC_SHADOW_DSA_SIG_free', + '#define DSA_SIG_new GRPC_SHADOW_DSA_SIG_new', + '#define DSA_check_signature GRPC_SHADOW_DSA_check_signature', + '#define DSA_do_check_signature GRPC_SHADOW_DSA_do_check_signature', + '#define DSA_do_sign GRPC_SHADOW_DSA_do_sign', + '#define DSA_do_verify GRPC_SHADOW_DSA_do_verify', + '#define DSA_dup_DH GRPC_SHADOW_DSA_dup_DH', + '#define DSA_free GRPC_SHADOW_DSA_free', + '#define DSA_generate_key GRPC_SHADOW_DSA_generate_key', + '#define DSA_generate_parameters_ex GRPC_SHADOW_DSA_generate_parameters_ex', + '#define DSA_get0_key GRPC_SHADOW_DSA_get0_key', + '#define DSA_get0_pqg GRPC_SHADOW_DSA_get0_pqg', + '#define DSA_get_ex_data GRPC_SHADOW_DSA_get_ex_data', + '#define DSA_get_ex_new_index GRPC_SHADOW_DSA_get_ex_new_index', + '#define DSA_new GRPC_SHADOW_DSA_new', + '#define DSA_set0_key GRPC_SHADOW_DSA_set0_key', + '#define DSA_set0_pqg GRPC_SHADOW_DSA_set0_pqg', + '#define DSA_set_ex_data GRPC_SHADOW_DSA_set_ex_data', + '#define DSA_sign GRPC_SHADOW_DSA_sign', + '#define DSA_size GRPC_SHADOW_DSA_size', + '#define DSA_up_ref GRPC_SHADOW_DSA_up_ref', + '#define DSA_verify GRPC_SHADOW_DSA_verify', + '#define DSAparams_dup GRPC_SHADOW_DSAparams_dup', + '#define DSA_SIG_marshal GRPC_SHADOW_DSA_SIG_marshal', + '#define DSA_SIG_parse GRPC_SHADOW_DSA_SIG_parse', + '#define DSA_marshal_parameters GRPC_SHADOW_DSA_marshal_parameters', + '#define DSA_marshal_private_key GRPC_SHADOW_DSA_marshal_private_key', + '#define DSA_marshal_public_key GRPC_SHADOW_DSA_marshal_public_key', + '#define DSA_parse_parameters GRPC_SHADOW_DSA_parse_parameters', + '#define DSA_parse_private_key GRPC_SHADOW_DSA_parse_private_key', + '#define DSA_parse_public_key GRPC_SHADOW_DSA_parse_public_key', + '#define d2i_DSAPrivateKey GRPC_SHADOW_d2i_DSAPrivateKey', + '#define d2i_DSAPublicKey GRPC_SHADOW_d2i_DSAPublicKey', + '#define d2i_DSA_SIG GRPC_SHADOW_d2i_DSA_SIG', + '#define d2i_DSAparams GRPC_SHADOW_d2i_DSAparams', + '#define i2d_DSAPrivateKey GRPC_SHADOW_i2d_DSAPrivateKey', + '#define i2d_DSAPublicKey GRPC_SHADOW_i2d_DSAPublicKey', + '#define i2d_DSA_SIG GRPC_SHADOW_i2d_DSA_SIG', + '#define i2d_DSAparams GRPC_SHADOW_i2d_DSAparams', + '#define RSAPrivateKey_dup GRPC_SHADOW_RSAPrivateKey_dup', + '#define RSAPublicKey_dup GRPC_SHADOW_RSAPublicKey_dup', + '#define RSA_marshal_private_key GRPC_SHADOW_RSA_marshal_private_key', + '#define RSA_marshal_public_key GRPC_SHADOW_RSA_marshal_public_key', + '#define RSA_parse_private_key GRPC_SHADOW_RSA_parse_private_key', + '#define RSA_parse_public_key GRPC_SHADOW_RSA_parse_public_key', + '#define RSA_private_key_from_bytes GRPC_SHADOW_RSA_private_key_from_bytes', + '#define RSA_private_key_to_bytes GRPC_SHADOW_RSA_private_key_to_bytes', + '#define RSA_public_key_from_bytes GRPC_SHADOW_RSA_public_key_from_bytes', + '#define RSA_public_key_to_bytes GRPC_SHADOW_RSA_public_key_to_bytes', + '#define d2i_RSAPrivateKey GRPC_SHADOW_d2i_RSAPrivateKey', + '#define d2i_RSAPublicKey GRPC_SHADOW_d2i_RSAPublicKey', + '#define i2d_RSAPrivateKey GRPC_SHADOW_i2d_RSAPrivateKey', + '#define i2d_RSAPublicKey GRPC_SHADOW_i2d_RSAPublicKey', + '#define EC_KEY_marshal_curve_name GRPC_SHADOW_EC_KEY_marshal_curve_name', + '#define EC_KEY_marshal_private_key GRPC_SHADOW_EC_KEY_marshal_private_key', + '#define EC_KEY_parse_curve_name GRPC_SHADOW_EC_KEY_parse_curve_name', + '#define EC_KEY_parse_parameters GRPC_SHADOW_EC_KEY_parse_parameters', + '#define EC_KEY_parse_private_key GRPC_SHADOW_EC_KEY_parse_private_key', + '#define EC_POINT_point2cbb GRPC_SHADOW_EC_POINT_point2cbb', + '#define d2i_ECParameters GRPC_SHADOW_d2i_ECParameters', + '#define d2i_ECPrivateKey GRPC_SHADOW_d2i_ECPrivateKey', + '#define i2d_ECParameters GRPC_SHADOW_i2d_ECParameters', + '#define i2d_ECPrivateKey GRPC_SHADOW_i2d_ECPrivateKey', + '#define i2o_ECPublicKey GRPC_SHADOW_i2o_ECPublicKey', + '#define o2i_ECPublicKey GRPC_SHADOW_o2i_ECPublicKey', + '#define ECDH_compute_key GRPC_SHADOW_ECDH_compute_key', + '#define ECDSA_SIG_from_bytes GRPC_SHADOW_ECDSA_SIG_from_bytes', + '#define ECDSA_SIG_marshal GRPC_SHADOW_ECDSA_SIG_marshal', + '#define ECDSA_SIG_max_len GRPC_SHADOW_ECDSA_SIG_max_len', + '#define ECDSA_SIG_parse GRPC_SHADOW_ECDSA_SIG_parse', + '#define ECDSA_SIG_to_bytes GRPC_SHADOW_ECDSA_SIG_to_bytes', + '#define ECDSA_sign GRPC_SHADOW_ECDSA_sign', + '#define ECDSA_size GRPC_SHADOW_ECDSA_size', + '#define ECDSA_verify GRPC_SHADOW_ECDSA_verify', + '#define d2i_ECDSA_SIG GRPC_SHADOW_d2i_ECDSA_SIG', + '#define i2d_ECDSA_SIG GRPC_SHADOW_i2d_ECDSA_SIG', + '#define AES_CMAC GRPC_SHADOW_AES_CMAC', + '#define CMAC_CTX_free GRPC_SHADOW_CMAC_CTX_free', + '#define CMAC_CTX_new GRPC_SHADOW_CMAC_CTX_new', + '#define CMAC_Final GRPC_SHADOW_CMAC_Final', + '#define CMAC_Init GRPC_SHADOW_CMAC_Init', + '#define CMAC_Reset GRPC_SHADOW_CMAC_Reset', + '#define CMAC_Update GRPC_SHADOW_CMAC_Update', + '#define EVP_DigestSign GRPC_SHADOW_EVP_DigestSign', + '#define EVP_DigestSignFinal GRPC_SHADOW_EVP_DigestSignFinal', + '#define EVP_DigestSignInit GRPC_SHADOW_EVP_DigestSignInit', + '#define EVP_DigestSignUpdate GRPC_SHADOW_EVP_DigestSignUpdate', + '#define EVP_DigestVerify GRPC_SHADOW_EVP_DigestVerify', + '#define EVP_DigestVerifyFinal GRPC_SHADOW_EVP_DigestVerifyFinal', + '#define EVP_DigestVerifyInit GRPC_SHADOW_EVP_DigestVerifyInit', + '#define EVP_DigestVerifyUpdate GRPC_SHADOW_EVP_DigestVerifyUpdate', + '#define EVP_PKEY_CTX_get_signature_md GRPC_SHADOW_EVP_PKEY_CTX_get_signature_md', + '#define EVP_PKEY_CTX_set_signature_md GRPC_SHADOW_EVP_PKEY_CTX_set_signature_md', + '#define EVP_PKEY_assign GRPC_SHADOW_EVP_PKEY_assign', + '#define EVP_PKEY_assign_DSA GRPC_SHADOW_EVP_PKEY_assign_DSA', + '#define EVP_PKEY_assign_EC_KEY GRPC_SHADOW_EVP_PKEY_assign_EC_KEY', + '#define EVP_PKEY_assign_RSA GRPC_SHADOW_EVP_PKEY_assign_RSA', + '#define EVP_PKEY_bits GRPC_SHADOW_EVP_PKEY_bits', + '#define EVP_PKEY_cmp GRPC_SHADOW_EVP_PKEY_cmp', + '#define EVP_PKEY_cmp_parameters GRPC_SHADOW_EVP_PKEY_cmp_parameters', + '#define EVP_PKEY_copy_parameters GRPC_SHADOW_EVP_PKEY_copy_parameters', + '#define EVP_PKEY_free GRPC_SHADOW_EVP_PKEY_free', + '#define EVP_PKEY_get0_DH GRPC_SHADOW_EVP_PKEY_get0_DH', + '#define EVP_PKEY_get0_DSA GRPC_SHADOW_EVP_PKEY_get0_DSA', + '#define EVP_PKEY_get0_EC_KEY GRPC_SHADOW_EVP_PKEY_get0_EC_KEY', + '#define EVP_PKEY_get0_RSA GRPC_SHADOW_EVP_PKEY_get0_RSA', + '#define EVP_PKEY_get1_DSA GRPC_SHADOW_EVP_PKEY_get1_DSA', + '#define EVP_PKEY_get1_EC_KEY GRPC_SHADOW_EVP_PKEY_get1_EC_KEY', + '#define EVP_PKEY_get1_RSA GRPC_SHADOW_EVP_PKEY_get1_RSA', + '#define EVP_PKEY_id GRPC_SHADOW_EVP_PKEY_id', + '#define EVP_PKEY_is_opaque GRPC_SHADOW_EVP_PKEY_is_opaque', + '#define EVP_PKEY_missing_parameters GRPC_SHADOW_EVP_PKEY_missing_parameters', + '#define EVP_PKEY_new GRPC_SHADOW_EVP_PKEY_new', + '#define EVP_PKEY_set1_DSA GRPC_SHADOW_EVP_PKEY_set1_DSA', + '#define EVP_PKEY_set1_EC_KEY GRPC_SHADOW_EVP_PKEY_set1_EC_KEY', + '#define EVP_PKEY_set1_RSA GRPC_SHADOW_EVP_PKEY_set1_RSA', + '#define EVP_PKEY_set_type GRPC_SHADOW_EVP_PKEY_set_type', + '#define EVP_PKEY_size GRPC_SHADOW_EVP_PKEY_size', + '#define EVP_PKEY_type GRPC_SHADOW_EVP_PKEY_type', + '#define EVP_PKEY_up_ref GRPC_SHADOW_EVP_PKEY_up_ref', + '#define EVP_cleanup GRPC_SHADOW_EVP_cleanup', + '#define OPENSSL_add_all_algorithms_conf GRPC_SHADOW_OPENSSL_add_all_algorithms_conf', + '#define OpenSSL_add_all_algorithms GRPC_SHADOW_OpenSSL_add_all_algorithms', + '#define OpenSSL_add_all_ciphers GRPC_SHADOW_OpenSSL_add_all_ciphers', + '#define OpenSSL_add_all_digests GRPC_SHADOW_OpenSSL_add_all_digests', + '#define EVP_marshal_private_key GRPC_SHADOW_EVP_marshal_private_key', + '#define EVP_marshal_public_key GRPC_SHADOW_EVP_marshal_public_key', + '#define EVP_parse_private_key GRPC_SHADOW_EVP_parse_private_key', + '#define EVP_parse_public_key GRPC_SHADOW_EVP_parse_public_key', + '#define d2i_AutoPrivateKey GRPC_SHADOW_d2i_AutoPrivateKey', + '#define d2i_PrivateKey GRPC_SHADOW_d2i_PrivateKey', + '#define i2d_PublicKey GRPC_SHADOW_i2d_PublicKey', + '#define EVP_PKEY_CTX_ctrl GRPC_SHADOW_EVP_PKEY_CTX_ctrl', + '#define EVP_PKEY_CTX_dup GRPC_SHADOW_EVP_PKEY_CTX_dup', + '#define EVP_PKEY_CTX_free GRPC_SHADOW_EVP_PKEY_CTX_free', + '#define EVP_PKEY_CTX_get0_pkey GRPC_SHADOW_EVP_PKEY_CTX_get0_pkey', + '#define EVP_PKEY_CTX_new GRPC_SHADOW_EVP_PKEY_CTX_new', + '#define EVP_PKEY_CTX_new_id GRPC_SHADOW_EVP_PKEY_CTX_new_id', + '#define EVP_PKEY_decrypt GRPC_SHADOW_EVP_PKEY_decrypt', + '#define EVP_PKEY_decrypt_init GRPC_SHADOW_EVP_PKEY_decrypt_init', + '#define EVP_PKEY_derive GRPC_SHADOW_EVP_PKEY_derive', + '#define EVP_PKEY_derive_init GRPC_SHADOW_EVP_PKEY_derive_init', + '#define EVP_PKEY_derive_set_peer GRPC_SHADOW_EVP_PKEY_derive_set_peer', + '#define EVP_PKEY_encrypt GRPC_SHADOW_EVP_PKEY_encrypt', + '#define EVP_PKEY_encrypt_init GRPC_SHADOW_EVP_PKEY_encrypt_init', + '#define EVP_PKEY_keygen GRPC_SHADOW_EVP_PKEY_keygen', + '#define EVP_PKEY_keygen_init GRPC_SHADOW_EVP_PKEY_keygen_init', + '#define EVP_PKEY_sign GRPC_SHADOW_EVP_PKEY_sign', + '#define EVP_PKEY_sign_init GRPC_SHADOW_EVP_PKEY_sign_init', + '#define EVP_PKEY_verify GRPC_SHADOW_EVP_PKEY_verify', + '#define EVP_PKEY_verify_init GRPC_SHADOW_EVP_PKEY_verify_init', + '#define EVP_PKEY_verify_recover GRPC_SHADOW_EVP_PKEY_verify_recover', + '#define EVP_PKEY_verify_recover_init GRPC_SHADOW_EVP_PKEY_verify_recover_init', + '#define dsa_asn1_meth GRPC_SHADOW_dsa_asn1_meth', + '#define ec_pkey_meth GRPC_SHADOW_ec_pkey_meth', + '#define ec_asn1_meth GRPC_SHADOW_ec_asn1_meth', + '#define ed25519_pkey_meth GRPC_SHADOW_ed25519_pkey_meth', + '#define EVP_PKEY_new_ed25519_private GRPC_SHADOW_EVP_PKEY_new_ed25519_private', + '#define EVP_PKEY_new_ed25519_public GRPC_SHADOW_EVP_PKEY_new_ed25519_public', + '#define ed25519_asn1_meth GRPC_SHADOW_ed25519_asn1_meth', + '#define EVP_PKEY_CTX_get0_rsa_oaep_label GRPC_SHADOW_EVP_PKEY_CTX_get0_rsa_oaep_label', + '#define EVP_PKEY_CTX_get_rsa_mgf1_md GRPC_SHADOW_EVP_PKEY_CTX_get_rsa_mgf1_md', + '#define EVP_PKEY_CTX_get_rsa_oaep_md GRPC_SHADOW_EVP_PKEY_CTX_get_rsa_oaep_md', + '#define EVP_PKEY_CTX_get_rsa_padding GRPC_SHADOW_EVP_PKEY_CTX_get_rsa_padding', + '#define EVP_PKEY_CTX_get_rsa_pss_saltlen GRPC_SHADOW_EVP_PKEY_CTX_get_rsa_pss_saltlen', + '#define EVP_PKEY_CTX_set0_rsa_oaep_label GRPC_SHADOW_EVP_PKEY_CTX_set0_rsa_oaep_label', + '#define EVP_PKEY_CTX_set_rsa_keygen_bits GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_keygen_bits', + '#define EVP_PKEY_CTX_set_rsa_keygen_pubexp GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_keygen_pubexp', + '#define EVP_PKEY_CTX_set_rsa_mgf1_md GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_mgf1_md', + '#define EVP_PKEY_CTX_set_rsa_oaep_md GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_oaep_md', + '#define EVP_PKEY_CTX_set_rsa_padding GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_padding', + '#define EVP_PKEY_CTX_set_rsa_pss_saltlen GRPC_SHADOW_EVP_PKEY_CTX_set_rsa_pss_saltlen', + '#define rsa_pkey_meth GRPC_SHADOW_rsa_pkey_meth', + '#define rsa_asn1_meth GRPC_SHADOW_rsa_asn1_meth', + '#define PKCS5_PBKDF2_HMAC GRPC_SHADOW_PKCS5_PBKDF2_HMAC', + '#define PKCS5_PBKDF2_HMAC_SHA1 GRPC_SHADOW_PKCS5_PBKDF2_HMAC_SHA1', + '#define EVP_PKEY_print_params GRPC_SHADOW_EVP_PKEY_print_params', + '#define EVP_PKEY_print_private GRPC_SHADOW_EVP_PKEY_print_private', + '#define EVP_PKEY_print_public GRPC_SHADOW_EVP_PKEY_print_public', + '#define EVP_PBE_scrypt GRPC_SHADOW_EVP_PBE_scrypt', + '#define EVP_SignFinal GRPC_SHADOW_EVP_SignFinal', + '#define EVP_SignInit GRPC_SHADOW_EVP_SignInit', + '#define EVP_SignInit_ex GRPC_SHADOW_EVP_SignInit_ex', + '#define EVP_SignUpdate GRPC_SHADOW_EVP_SignUpdate', + '#define EVP_VerifyFinal GRPC_SHADOW_EVP_VerifyFinal', + '#define EVP_VerifyInit GRPC_SHADOW_EVP_VerifyInit', + '#define EVP_VerifyInit_ex GRPC_SHADOW_EVP_VerifyInit_ex', + '#define EVP_VerifyUpdate GRPC_SHADOW_EVP_VerifyUpdate', + '#define HKDF GRPC_SHADOW_HKDF', + '#define HKDF_expand GRPC_SHADOW_HKDF_expand', + '#define HKDF_extract GRPC_SHADOW_HKDF_extract', + '#define PEM_read_DSAPrivateKey GRPC_SHADOW_PEM_read_DSAPrivateKey', + '#define PEM_read_DSA_PUBKEY GRPC_SHADOW_PEM_read_DSA_PUBKEY', + '#define PEM_read_DSAparams GRPC_SHADOW_PEM_read_DSAparams', + '#define PEM_read_ECPrivateKey GRPC_SHADOW_PEM_read_ECPrivateKey', + '#define PEM_read_EC_PUBKEY GRPC_SHADOW_PEM_read_EC_PUBKEY', + '#define PEM_read_PUBKEY GRPC_SHADOW_PEM_read_PUBKEY', + '#define PEM_read_RSAPrivateKey GRPC_SHADOW_PEM_read_RSAPrivateKey', + '#define PEM_read_RSAPublicKey GRPC_SHADOW_PEM_read_RSAPublicKey', + '#define PEM_read_RSA_PUBKEY GRPC_SHADOW_PEM_read_RSA_PUBKEY', + '#define PEM_read_X509_CRL GRPC_SHADOW_PEM_read_X509_CRL', + '#define PEM_read_X509_REQ GRPC_SHADOW_PEM_read_X509_REQ', + '#define PEM_read_bio_DSAPrivateKey GRPC_SHADOW_PEM_read_bio_DSAPrivateKey', + '#define PEM_read_bio_DSA_PUBKEY GRPC_SHADOW_PEM_read_bio_DSA_PUBKEY', + '#define PEM_read_bio_DSAparams GRPC_SHADOW_PEM_read_bio_DSAparams', + '#define PEM_read_bio_ECPrivateKey GRPC_SHADOW_PEM_read_bio_ECPrivateKey', + '#define PEM_read_bio_EC_PUBKEY GRPC_SHADOW_PEM_read_bio_EC_PUBKEY', + '#define PEM_read_bio_PUBKEY GRPC_SHADOW_PEM_read_bio_PUBKEY', + '#define PEM_read_bio_RSAPrivateKey GRPC_SHADOW_PEM_read_bio_RSAPrivateKey', + '#define PEM_read_bio_RSAPublicKey GRPC_SHADOW_PEM_read_bio_RSAPublicKey', + '#define PEM_read_bio_RSA_PUBKEY GRPC_SHADOW_PEM_read_bio_RSA_PUBKEY', + '#define PEM_read_bio_X509_CRL GRPC_SHADOW_PEM_read_bio_X509_CRL', + '#define PEM_read_bio_X509_REQ GRPC_SHADOW_PEM_read_bio_X509_REQ', + '#define PEM_write_DHparams GRPC_SHADOW_PEM_write_DHparams', + '#define PEM_write_DSAPrivateKey GRPC_SHADOW_PEM_write_DSAPrivateKey', + '#define PEM_write_DSA_PUBKEY GRPC_SHADOW_PEM_write_DSA_PUBKEY', + '#define PEM_write_DSAparams GRPC_SHADOW_PEM_write_DSAparams', + '#define PEM_write_ECPrivateKey GRPC_SHADOW_PEM_write_ECPrivateKey', + '#define PEM_write_EC_PUBKEY GRPC_SHADOW_PEM_write_EC_PUBKEY', + '#define PEM_write_PUBKEY GRPC_SHADOW_PEM_write_PUBKEY', + '#define PEM_write_RSAPrivateKey GRPC_SHADOW_PEM_write_RSAPrivateKey', + '#define PEM_write_RSAPublicKey GRPC_SHADOW_PEM_write_RSAPublicKey', + '#define PEM_write_RSA_PUBKEY GRPC_SHADOW_PEM_write_RSA_PUBKEY', + '#define PEM_write_X509_CRL GRPC_SHADOW_PEM_write_X509_CRL', + '#define PEM_write_X509_REQ GRPC_SHADOW_PEM_write_X509_REQ', + '#define PEM_write_X509_REQ_NEW GRPC_SHADOW_PEM_write_X509_REQ_NEW', + '#define PEM_write_bio_DHparams GRPC_SHADOW_PEM_write_bio_DHparams', + '#define PEM_write_bio_DSAPrivateKey GRPC_SHADOW_PEM_write_bio_DSAPrivateKey', + '#define PEM_write_bio_DSA_PUBKEY GRPC_SHADOW_PEM_write_bio_DSA_PUBKEY', + '#define PEM_write_bio_DSAparams GRPC_SHADOW_PEM_write_bio_DSAparams', + '#define PEM_write_bio_ECPrivateKey GRPC_SHADOW_PEM_write_bio_ECPrivateKey', + '#define PEM_write_bio_EC_PUBKEY GRPC_SHADOW_PEM_write_bio_EC_PUBKEY', + '#define PEM_write_bio_PUBKEY GRPC_SHADOW_PEM_write_bio_PUBKEY', + '#define PEM_write_bio_RSAPrivateKey GRPC_SHADOW_PEM_write_bio_RSAPrivateKey', + '#define PEM_write_bio_RSAPublicKey GRPC_SHADOW_PEM_write_bio_RSAPublicKey', + '#define PEM_write_bio_RSA_PUBKEY GRPC_SHADOW_PEM_write_bio_RSA_PUBKEY', + '#define PEM_write_bio_X509_CRL GRPC_SHADOW_PEM_write_bio_X509_CRL', + '#define PEM_write_bio_X509_REQ GRPC_SHADOW_PEM_write_bio_X509_REQ', + '#define PEM_write_bio_X509_REQ_NEW GRPC_SHADOW_PEM_write_bio_X509_REQ_NEW', + '#define PEM_X509_INFO_read GRPC_SHADOW_PEM_X509_INFO_read', + '#define PEM_X509_INFO_read_bio GRPC_SHADOW_PEM_X509_INFO_read_bio', + '#define PEM_X509_INFO_write_bio GRPC_SHADOW_PEM_X509_INFO_write_bio', + '#define PEM_ASN1_read GRPC_SHADOW_PEM_ASN1_read', + '#define PEM_ASN1_write GRPC_SHADOW_PEM_ASN1_write', + '#define PEM_ASN1_write_bio GRPC_SHADOW_PEM_ASN1_write_bio', + '#define PEM_bytes_read_bio GRPC_SHADOW_PEM_bytes_read_bio', + '#define PEM_def_callback GRPC_SHADOW_PEM_def_callback', + '#define PEM_dek_info GRPC_SHADOW_PEM_dek_info', + '#define PEM_do_header GRPC_SHADOW_PEM_do_header', + '#define PEM_get_EVP_CIPHER_INFO GRPC_SHADOW_PEM_get_EVP_CIPHER_INFO', + '#define PEM_proc_type GRPC_SHADOW_PEM_proc_type', + '#define PEM_read GRPC_SHADOW_PEM_read', + '#define PEM_read_bio GRPC_SHADOW_PEM_read_bio', + '#define PEM_write GRPC_SHADOW_PEM_write', + '#define PEM_write_bio GRPC_SHADOW_PEM_write_bio', + '#define PEM_ASN1_read_bio GRPC_SHADOW_PEM_ASN1_read_bio', + '#define PEM_read_PKCS8 GRPC_SHADOW_PEM_read_PKCS8', + '#define PEM_read_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_PEM_read_PKCS8_PRIV_KEY_INFO', + '#define PEM_read_bio_PKCS8 GRPC_SHADOW_PEM_read_bio_PKCS8', + '#define PEM_read_bio_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_PEM_read_bio_PKCS8_PRIV_KEY_INFO', + '#define PEM_write_PKCS8 GRPC_SHADOW_PEM_write_PKCS8', + '#define PEM_write_PKCS8PrivateKey GRPC_SHADOW_PEM_write_PKCS8PrivateKey', + '#define PEM_write_PKCS8PrivateKey_nid GRPC_SHADOW_PEM_write_PKCS8PrivateKey_nid', + '#define PEM_write_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_PEM_write_PKCS8_PRIV_KEY_INFO', + '#define PEM_write_bio_PKCS8 GRPC_SHADOW_PEM_write_bio_PKCS8', + '#define PEM_write_bio_PKCS8PrivateKey GRPC_SHADOW_PEM_write_bio_PKCS8PrivateKey', + '#define PEM_write_bio_PKCS8PrivateKey_nid GRPC_SHADOW_PEM_write_bio_PKCS8PrivateKey_nid', + '#define PEM_write_bio_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_PEM_write_bio_PKCS8_PRIV_KEY_INFO', + '#define d2i_PKCS8PrivateKey_bio GRPC_SHADOW_d2i_PKCS8PrivateKey_bio', + '#define d2i_PKCS8PrivateKey_fp GRPC_SHADOW_d2i_PKCS8PrivateKey_fp', + '#define i2d_PKCS8PrivateKey_bio GRPC_SHADOW_i2d_PKCS8PrivateKey_bio', + '#define i2d_PKCS8PrivateKey_fp GRPC_SHADOW_i2d_PKCS8PrivateKey_fp', + '#define i2d_PKCS8PrivateKey_nid_bio GRPC_SHADOW_i2d_PKCS8PrivateKey_nid_bio', + '#define i2d_PKCS8PrivateKey_nid_fp GRPC_SHADOW_i2d_PKCS8PrivateKey_nid_fp', + '#define PEM_read_DHparams GRPC_SHADOW_PEM_read_DHparams', + '#define PEM_read_PrivateKey GRPC_SHADOW_PEM_read_PrivateKey', + '#define PEM_read_bio_DHparams GRPC_SHADOW_PEM_read_bio_DHparams', + '#define PEM_read_bio_PrivateKey GRPC_SHADOW_PEM_read_bio_PrivateKey', + '#define PEM_write_PrivateKey GRPC_SHADOW_PEM_write_PrivateKey', + '#define PEM_write_bio_PrivateKey GRPC_SHADOW_PEM_write_bio_PrivateKey', + '#define PEM_read_X509 GRPC_SHADOW_PEM_read_X509', + '#define PEM_read_bio_X509 GRPC_SHADOW_PEM_read_bio_X509', + '#define PEM_write_X509 GRPC_SHADOW_PEM_write_X509', + '#define PEM_write_bio_X509 GRPC_SHADOW_PEM_write_bio_X509', + '#define PEM_read_X509_AUX GRPC_SHADOW_PEM_read_X509_AUX', + '#define PEM_read_bio_X509_AUX GRPC_SHADOW_PEM_read_bio_X509_AUX', + '#define PEM_write_X509_AUX GRPC_SHADOW_PEM_write_X509_AUX', + '#define PEM_write_bio_X509_AUX GRPC_SHADOW_PEM_write_bio_X509_AUX', + '#define ASN1_digest GRPC_SHADOW_ASN1_digest', + '#define ASN1_item_digest GRPC_SHADOW_ASN1_item_digest', + '#define ASN1_item_sign GRPC_SHADOW_ASN1_item_sign', + '#define ASN1_item_sign_ctx GRPC_SHADOW_ASN1_item_sign_ctx', + '#define ASN1_STRING_print_ex GRPC_SHADOW_ASN1_STRING_print_ex', + '#define ASN1_STRING_print_ex_fp GRPC_SHADOW_ASN1_STRING_print_ex_fp', + '#define ASN1_STRING_to_UTF8 GRPC_SHADOW_ASN1_STRING_to_UTF8', + '#define X509_NAME_print_ex GRPC_SHADOW_X509_NAME_print_ex', + '#define X509_NAME_print_ex_fp GRPC_SHADOW_X509_NAME_print_ex_fp', + '#define ASN1_item_verify GRPC_SHADOW_ASN1_item_verify', + '#define x509_digest_sign_algorithm GRPC_SHADOW_x509_digest_sign_algorithm', + '#define x509_digest_verify_init GRPC_SHADOW_x509_digest_verify_init', + '#define ASN1_generate_nconf GRPC_SHADOW_ASN1_generate_nconf', + '#define ASN1_generate_v3 GRPC_SHADOW_ASN1_generate_v3', + '#define X509_LOOKUP_hash_dir GRPC_SHADOW_X509_LOOKUP_hash_dir', + '#define X509_LOOKUP_file GRPC_SHADOW_X509_LOOKUP_file', + '#define X509_load_cert_crl_file GRPC_SHADOW_X509_load_cert_crl_file', + '#define X509_load_cert_file GRPC_SHADOW_X509_load_cert_file', + '#define X509_load_crl_file GRPC_SHADOW_X509_load_crl_file', + '#define i2d_PrivateKey GRPC_SHADOW_i2d_PrivateKey', + '#define RSA_PSS_PARAMS_free GRPC_SHADOW_RSA_PSS_PARAMS_free', + '#define RSA_PSS_PARAMS_it GRPC_SHADOW_RSA_PSS_PARAMS_it', + '#define RSA_PSS_PARAMS_new GRPC_SHADOW_RSA_PSS_PARAMS_new', + '#define d2i_RSA_PSS_PARAMS GRPC_SHADOW_d2i_RSA_PSS_PARAMS', + '#define i2d_RSA_PSS_PARAMS GRPC_SHADOW_i2d_RSA_PSS_PARAMS', + '#define x509_print_rsa_pss_params GRPC_SHADOW_x509_print_rsa_pss_params', + '#define x509_rsa_ctx_to_pss GRPC_SHADOW_x509_rsa_ctx_to_pss', + '#define x509_rsa_pss_to_ctx GRPC_SHADOW_x509_rsa_pss_to_ctx', + '#define X509_CRL_print GRPC_SHADOW_X509_CRL_print', + '#define X509_CRL_print_fp GRPC_SHADOW_X509_CRL_print_fp', + '#define X509_REQ_print GRPC_SHADOW_X509_REQ_print', + '#define X509_REQ_print_ex GRPC_SHADOW_X509_REQ_print_ex', + '#define X509_REQ_print_fp GRPC_SHADOW_X509_REQ_print_fp', + '#define ASN1_GENERALIZEDTIME_print GRPC_SHADOW_ASN1_GENERALIZEDTIME_print', + '#define ASN1_STRING_print GRPC_SHADOW_ASN1_STRING_print', + '#define ASN1_TIME_print GRPC_SHADOW_ASN1_TIME_print', + '#define ASN1_UTCTIME_print GRPC_SHADOW_ASN1_UTCTIME_print', + '#define X509_NAME_print GRPC_SHADOW_X509_NAME_print', + '#define X509_ocspid_print GRPC_SHADOW_X509_ocspid_print', + '#define X509_print GRPC_SHADOW_X509_print', + '#define X509_print_ex GRPC_SHADOW_X509_print_ex', + '#define X509_print_ex_fp GRPC_SHADOW_X509_print_ex_fp', + '#define X509_print_fp GRPC_SHADOW_X509_print_fp', + '#define X509_signature_print GRPC_SHADOW_X509_signature_print', + '#define X509_CERT_AUX_print GRPC_SHADOW_X509_CERT_AUX_print', + '#define PKCS8_pkey_get0 GRPC_SHADOW_PKCS8_pkey_get0', + '#define PKCS8_pkey_set0 GRPC_SHADOW_PKCS8_pkey_set0', + '#define X509_signature_dump GRPC_SHADOW_X509_signature_dump', + '#define X509_ATTRIBUTE_count GRPC_SHADOW_X509_ATTRIBUTE_count', + '#define X509_ATTRIBUTE_create_by_NID GRPC_SHADOW_X509_ATTRIBUTE_create_by_NID', + '#define X509_ATTRIBUTE_create_by_OBJ GRPC_SHADOW_X509_ATTRIBUTE_create_by_OBJ', + '#define X509_ATTRIBUTE_create_by_txt GRPC_SHADOW_X509_ATTRIBUTE_create_by_txt', + '#define X509_ATTRIBUTE_get0_data GRPC_SHADOW_X509_ATTRIBUTE_get0_data', + '#define X509_ATTRIBUTE_get0_object GRPC_SHADOW_X509_ATTRIBUTE_get0_object', + '#define X509_ATTRIBUTE_get0_type GRPC_SHADOW_X509_ATTRIBUTE_get0_type', + '#define X509_ATTRIBUTE_set1_data GRPC_SHADOW_X509_ATTRIBUTE_set1_data', + '#define X509_ATTRIBUTE_set1_object GRPC_SHADOW_X509_ATTRIBUTE_set1_object', + '#define X509at_add1_attr GRPC_SHADOW_X509at_add1_attr', + '#define X509at_add1_attr_by_NID GRPC_SHADOW_X509at_add1_attr_by_NID', + '#define X509at_add1_attr_by_OBJ GRPC_SHADOW_X509at_add1_attr_by_OBJ', + '#define X509at_add1_attr_by_txt GRPC_SHADOW_X509at_add1_attr_by_txt', + '#define X509at_delete_attr GRPC_SHADOW_X509at_delete_attr', + '#define X509at_get0_data_by_OBJ GRPC_SHADOW_X509at_get0_data_by_OBJ', + '#define X509at_get_attr GRPC_SHADOW_X509at_get_attr', + '#define X509at_get_attr_by_NID GRPC_SHADOW_X509at_get_attr_by_NID', + '#define X509at_get_attr_by_OBJ GRPC_SHADOW_X509at_get_attr_by_OBJ', + '#define X509at_get_attr_count GRPC_SHADOW_X509at_get_attr_count', + '#define X509_CRL_check_suiteb GRPC_SHADOW_X509_CRL_check_suiteb', + '#define X509_CRL_cmp GRPC_SHADOW_X509_CRL_cmp', + '#define X509_CRL_match GRPC_SHADOW_X509_CRL_match', + '#define X509_NAME_cmp GRPC_SHADOW_X509_NAME_cmp', + '#define X509_NAME_hash GRPC_SHADOW_X509_NAME_hash', + '#define X509_NAME_hash_old GRPC_SHADOW_X509_NAME_hash_old', + '#define X509_chain_check_suiteb GRPC_SHADOW_X509_chain_check_suiteb', + '#define X509_chain_up_ref GRPC_SHADOW_X509_chain_up_ref', + '#define X509_check_private_key GRPC_SHADOW_X509_check_private_key', + '#define X509_cmp GRPC_SHADOW_X509_cmp', + '#define X509_find_by_issuer_and_serial GRPC_SHADOW_X509_find_by_issuer_and_serial', + '#define X509_find_by_subject GRPC_SHADOW_X509_find_by_subject', + '#define X509_get0_pubkey_bitstr GRPC_SHADOW_X509_get0_pubkey_bitstr', + '#define X509_get_issuer_name GRPC_SHADOW_X509_get_issuer_name', + '#define X509_get_pubkey GRPC_SHADOW_X509_get_pubkey', + '#define X509_get_serialNumber GRPC_SHADOW_X509_get_serialNumber', + '#define X509_get_subject_name GRPC_SHADOW_X509_get_subject_name', + '#define X509_issuer_and_serial_cmp GRPC_SHADOW_X509_issuer_and_serial_cmp', + '#define X509_issuer_and_serial_hash GRPC_SHADOW_X509_issuer_and_serial_hash', + '#define X509_issuer_name_cmp GRPC_SHADOW_X509_issuer_name_cmp', + '#define X509_issuer_name_hash GRPC_SHADOW_X509_issuer_name_hash', + '#define X509_issuer_name_hash_old GRPC_SHADOW_X509_issuer_name_hash_old', + '#define X509_subject_name_cmp GRPC_SHADOW_X509_subject_name_cmp', + '#define X509_subject_name_hash GRPC_SHADOW_X509_subject_name_hash', + '#define X509_subject_name_hash_old GRPC_SHADOW_X509_subject_name_hash_old', + '#define X509_STORE_load_locations GRPC_SHADOW_X509_STORE_load_locations', + '#define X509_STORE_set_default_paths GRPC_SHADOW_X509_STORE_set_default_paths', + '#define X509_get_default_cert_area GRPC_SHADOW_X509_get_default_cert_area', + '#define X509_get_default_cert_dir GRPC_SHADOW_X509_get_default_cert_dir', + '#define X509_get_default_cert_dir_env GRPC_SHADOW_X509_get_default_cert_dir_env', + '#define X509_get_default_cert_file GRPC_SHADOW_X509_get_default_cert_file', + '#define X509_get_default_cert_file_env GRPC_SHADOW_X509_get_default_cert_file_env', + '#define X509_get_default_private_dir GRPC_SHADOW_X509_get_default_private_dir', + '#define X509_CRL_add1_ext_i2d GRPC_SHADOW_X509_CRL_add1_ext_i2d', + '#define X509_CRL_add_ext GRPC_SHADOW_X509_CRL_add_ext', + '#define X509_CRL_delete_ext GRPC_SHADOW_X509_CRL_delete_ext', + '#define X509_CRL_get_ext GRPC_SHADOW_X509_CRL_get_ext', + '#define X509_CRL_get_ext_by_NID GRPC_SHADOW_X509_CRL_get_ext_by_NID', + '#define X509_CRL_get_ext_by_OBJ GRPC_SHADOW_X509_CRL_get_ext_by_OBJ', + '#define X509_CRL_get_ext_by_critical GRPC_SHADOW_X509_CRL_get_ext_by_critical', + '#define X509_CRL_get_ext_count GRPC_SHADOW_X509_CRL_get_ext_count', + '#define X509_CRL_get_ext_d2i GRPC_SHADOW_X509_CRL_get_ext_d2i', + '#define X509_REVOKED_add1_ext_i2d GRPC_SHADOW_X509_REVOKED_add1_ext_i2d', + '#define X509_REVOKED_add_ext GRPC_SHADOW_X509_REVOKED_add_ext', + '#define X509_REVOKED_delete_ext GRPC_SHADOW_X509_REVOKED_delete_ext', + '#define X509_REVOKED_get_ext GRPC_SHADOW_X509_REVOKED_get_ext', + '#define X509_REVOKED_get_ext_by_NID GRPC_SHADOW_X509_REVOKED_get_ext_by_NID', + '#define X509_REVOKED_get_ext_by_OBJ GRPC_SHADOW_X509_REVOKED_get_ext_by_OBJ', + '#define X509_REVOKED_get_ext_by_critical GRPC_SHADOW_X509_REVOKED_get_ext_by_critical', + '#define X509_REVOKED_get_ext_count GRPC_SHADOW_X509_REVOKED_get_ext_count', + '#define X509_REVOKED_get_ext_d2i GRPC_SHADOW_X509_REVOKED_get_ext_d2i', + '#define X509_add1_ext_i2d GRPC_SHADOW_X509_add1_ext_i2d', + '#define X509_add_ext GRPC_SHADOW_X509_add_ext', + '#define X509_delete_ext GRPC_SHADOW_X509_delete_ext', + '#define X509_get_ext GRPC_SHADOW_X509_get_ext', + '#define X509_get_ext_by_NID GRPC_SHADOW_X509_get_ext_by_NID', + '#define X509_get_ext_by_OBJ GRPC_SHADOW_X509_get_ext_by_OBJ', + '#define X509_get_ext_by_critical GRPC_SHADOW_X509_get_ext_by_critical', + '#define X509_get_ext_count GRPC_SHADOW_X509_get_ext_count', + '#define X509_get_ext_d2i GRPC_SHADOW_X509_get_ext_d2i', + '#define X509_LOOKUP_by_alias GRPC_SHADOW_X509_LOOKUP_by_alias', + '#define X509_LOOKUP_by_fingerprint GRPC_SHADOW_X509_LOOKUP_by_fingerprint', + '#define X509_LOOKUP_by_issuer_serial GRPC_SHADOW_X509_LOOKUP_by_issuer_serial', + '#define X509_LOOKUP_by_subject GRPC_SHADOW_X509_LOOKUP_by_subject', + '#define X509_LOOKUP_ctrl GRPC_SHADOW_X509_LOOKUP_ctrl', + '#define X509_LOOKUP_free GRPC_SHADOW_X509_LOOKUP_free', + '#define X509_LOOKUP_init GRPC_SHADOW_X509_LOOKUP_init', + '#define X509_LOOKUP_new GRPC_SHADOW_X509_LOOKUP_new', + '#define X509_LOOKUP_shutdown GRPC_SHADOW_X509_LOOKUP_shutdown', + '#define X509_OBJECT_free_contents GRPC_SHADOW_X509_OBJECT_free_contents', + '#define X509_OBJECT_get0_X509 GRPC_SHADOW_X509_OBJECT_get0_X509', + '#define X509_OBJECT_get_type GRPC_SHADOW_X509_OBJECT_get_type', + '#define X509_OBJECT_idx_by_subject GRPC_SHADOW_X509_OBJECT_idx_by_subject', + '#define X509_OBJECT_retrieve_by_subject GRPC_SHADOW_X509_OBJECT_retrieve_by_subject', + '#define X509_OBJECT_retrieve_match GRPC_SHADOW_X509_OBJECT_retrieve_match', + '#define X509_OBJECT_up_ref_count GRPC_SHADOW_X509_OBJECT_up_ref_count', + '#define X509_STORE_CTX_get0_store GRPC_SHADOW_X509_STORE_CTX_get0_store', + '#define X509_STORE_CTX_get1_issuer GRPC_SHADOW_X509_STORE_CTX_get1_issuer', + '#define X509_STORE_add_cert GRPC_SHADOW_X509_STORE_add_cert', + '#define X509_STORE_add_crl GRPC_SHADOW_X509_STORE_add_crl', + '#define X509_STORE_add_lookup GRPC_SHADOW_X509_STORE_add_lookup', + '#define X509_STORE_free GRPC_SHADOW_X509_STORE_free', + '#define X509_STORE_get0_objects GRPC_SHADOW_X509_STORE_get0_objects', + '#define X509_STORE_get0_param GRPC_SHADOW_X509_STORE_get0_param', + '#define X509_STORE_get1_certs GRPC_SHADOW_X509_STORE_get1_certs', + '#define X509_STORE_get1_crls GRPC_SHADOW_X509_STORE_get1_crls', + '#define X509_STORE_get_by_subject GRPC_SHADOW_X509_STORE_get_by_subject', + '#define X509_STORE_new GRPC_SHADOW_X509_STORE_new', + '#define X509_STORE_set0_additional_untrusted GRPC_SHADOW_X509_STORE_set0_additional_untrusted', + '#define X509_STORE_set1_param GRPC_SHADOW_X509_STORE_set1_param', + '#define X509_STORE_set_depth GRPC_SHADOW_X509_STORE_set_depth', + '#define X509_STORE_set_flags GRPC_SHADOW_X509_STORE_set_flags', + '#define X509_STORE_set_lookup_crls_cb GRPC_SHADOW_X509_STORE_set_lookup_crls_cb', + '#define X509_STORE_set_purpose GRPC_SHADOW_X509_STORE_set_purpose', + '#define X509_STORE_set_trust GRPC_SHADOW_X509_STORE_set_trust', + '#define X509_STORE_set_verify_cb GRPC_SHADOW_X509_STORE_set_verify_cb', + '#define X509_STORE_up_ref GRPC_SHADOW_X509_STORE_up_ref', + '#define X509_NAME_oneline GRPC_SHADOW_X509_NAME_oneline', + '#define X509_REQ_to_X509 GRPC_SHADOW_X509_REQ_to_X509', + '#define X509_REQ_add1_attr GRPC_SHADOW_X509_REQ_add1_attr', + '#define X509_REQ_add1_attr_by_NID GRPC_SHADOW_X509_REQ_add1_attr_by_NID', + '#define X509_REQ_add1_attr_by_OBJ GRPC_SHADOW_X509_REQ_add1_attr_by_OBJ', + '#define X509_REQ_add1_attr_by_txt GRPC_SHADOW_X509_REQ_add1_attr_by_txt', + '#define X509_REQ_add_extensions GRPC_SHADOW_X509_REQ_add_extensions', + '#define X509_REQ_add_extensions_nid GRPC_SHADOW_X509_REQ_add_extensions_nid', + '#define X509_REQ_check_private_key GRPC_SHADOW_X509_REQ_check_private_key', + '#define X509_REQ_delete_attr GRPC_SHADOW_X509_REQ_delete_attr', + '#define X509_REQ_extension_nid GRPC_SHADOW_X509_REQ_extension_nid', + '#define X509_REQ_get_attr GRPC_SHADOW_X509_REQ_get_attr', + '#define X509_REQ_get_attr_by_NID GRPC_SHADOW_X509_REQ_get_attr_by_NID', + '#define X509_REQ_get_attr_by_OBJ GRPC_SHADOW_X509_REQ_get_attr_by_OBJ', + '#define X509_REQ_get_attr_count GRPC_SHADOW_X509_REQ_get_attr_count', + '#define X509_REQ_get_extension_nids GRPC_SHADOW_X509_REQ_get_extension_nids', + '#define X509_REQ_get_extensions GRPC_SHADOW_X509_REQ_get_extensions', + '#define X509_REQ_get_pubkey GRPC_SHADOW_X509_REQ_get_pubkey', + '#define X509_REQ_set_extension_nids GRPC_SHADOW_X509_REQ_set_extension_nids', + '#define X509_to_X509_REQ GRPC_SHADOW_X509_to_X509_REQ', + '#define X509_get0_extensions GRPC_SHADOW_X509_get0_extensions', + '#define X509_get0_notAfter GRPC_SHADOW_X509_get0_notAfter', + '#define X509_get0_notBefore GRPC_SHADOW_X509_get0_notBefore', + '#define X509_set_issuer_name GRPC_SHADOW_X509_set_issuer_name', + '#define X509_set_notAfter GRPC_SHADOW_X509_set_notAfter', + '#define X509_set_notBefore GRPC_SHADOW_X509_set_notBefore', + '#define X509_set_pubkey GRPC_SHADOW_X509_set_pubkey', + '#define X509_set_serialNumber GRPC_SHADOW_X509_set_serialNumber', + '#define X509_set_subject_name GRPC_SHADOW_X509_set_subject_name', + '#define X509_set_version GRPC_SHADOW_X509_set_version', + '#define X509_TRUST_add GRPC_SHADOW_X509_TRUST_add', + '#define X509_TRUST_cleanup GRPC_SHADOW_X509_TRUST_cleanup', + '#define X509_TRUST_get0 GRPC_SHADOW_X509_TRUST_get0', + '#define X509_TRUST_get0_name GRPC_SHADOW_X509_TRUST_get0_name', + '#define X509_TRUST_get_by_id GRPC_SHADOW_X509_TRUST_get_by_id', + '#define X509_TRUST_get_count GRPC_SHADOW_X509_TRUST_get_count', + '#define X509_TRUST_get_flags GRPC_SHADOW_X509_TRUST_get_flags', + '#define X509_TRUST_get_trust GRPC_SHADOW_X509_TRUST_get_trust', + '#define X509_TRUST_set GRPC_SHADOW_X509_TRUST_set', + '#define X509_TRUST_set_default GRPC_SHADOW_X509_TRUST_set_default', + '#define X509_check_trust GRPC_SHADOW_X509_check_trust', + '#define X509_verify_cert_error_string GRPC_SHADOW_X509_verify_cert_error_string', + '#define X509_EXTENSION_create_by_NID GRPC_SHADOW_X509_EXTENSION_create_by_NID', + '#define X509_EXTENSION_create_by_OBJ GRPC_SHADOW_X509_EXTENSION_create_by_OBJ', + '#define X509_EXTENSION_get_critical GRPC_SHADOW_X509_EXTENSION_get_critical', + '#define X509_EXTENSION_get_data GRPC_SHADOW_X509_EXTENSION_get_data', + '#define X509_EXTENSION_get_object GRPC_SHADOW_X509_EXTENSION_get_object', + '#define X509_EXTENSION_set_critical GRPC_SHADOW_X509_EXTENSION_set_critical', + '#define X509_EXTENSION_set_data GRPC_SHADOW_X509_EXTENSION_set_data', + '#define X509_EXTENSION_set_object GRPC_SHADOW_X509_EXTENSION_set_object', + '#define X509v3_add_ext GRPC_SHADOW_X509v3_add_ext', + '#define X509v3_delete_ext GRPC_SHADOW_X509v3_delete_ext', + '#define X509v3_get_ext GRPC_SHADOW_X509v3_get_ext', + '#define X509v3_get_ext_by_NID GRPC_SHADOW_X509v3_get_ext_by_NID', + '#define X509v3_get_ext_by_OBJ GRPC_SHADOW_X509v3_get_ext_by_OBJ', + '#define X509v3_get_ext_by_critical GRPC_SHADOW_X509v3_get_ext_by_critical', + '#define X509v3_get_ext_count GRPC_SHADOW_X509v3_get_ext_count', + '#define X509_CRL_diff GRPC_SHADOW_X509_CRL_diff', + '#define X509_STORE_CTX_cleanup GRPC_SHADOW_X509_STORE_CTX_cleanup', + '#define X509_STORE_CTX_free GRPC_SHADOW_X509_STORE_CTX_free', + '#define X509_STORE_CTX_get0_current_crl GRPC_SHADOW_X509_STORE_CTX_get0_current_crl', + '#define X509_STORE_CTX_get0_current_issuer GRPC_SHADOW_X509_STORE_CTX_get0_current_issuer', + '#define X509_STORE_CTX_get0_param GRPC_SHADOW_X509_STORE_CTX_get0_param', + '#define X509_STORE_CTX_get0_parent_ctx GRPC_SHADOW_X509_STORE_CTX_get0_parent_ctx', + '#define X509_STORE_CTX_get0_policy_tree GRPC_SHADOW_X509_STORE_CTX_get0_policy_tree', + '#define X509_STORE_CTX_get0_untrusted GRPC_SHADOW_X509_STORE_CTX_get0_untrusted', + '#define X509_STORE_CTX_get1_chain GRPC_SHADOW_X509_STORE_CTX_get1_chain', + '#define X509_STORE_CTX_get_chain GRPC_SHADOW_X509_STORE_CTX_get_chain', + '#define X509_STORE_CTX_get_current_cert GRPC_SHADOW_X509_STORE_CTX_get_current_cert', + '#define X509_STORE_CTX_get_error GRPC_SHADOW_X509_STORE_CTX_get_error', + '#define X509_STORE_CTX_get_error_depth GRPC_SHADOW_X509_STORE_CTX_get_error_depth', + '#define X509_STORE_CTX_get_ex_data GRPC_SHADOW_X509_STORE_CTX_get_ex_data', + '#define X509_STORE_CTX_get_ex_new_index GRPC_SHADOW_X509_STORE_CTX_get_ex_new_index', + '#define X509_STORE_CTX_get_explicit_policy GRPC_SHADOW_X509_STORE_CTX_get_explicit_policy', + '#define X509_STORE_CTX_init GRPC_SHADOW_X509_STORE_CTX_init', + '#define X509_STORE_CTX_new GRPC_SHADOW_X509_STORE_CTX_new', + '#define X509_STORE_CTX_purpose_inherit GRPC_SHADOW_X509_STORE_CTX_purpose_inherit', + '#define X509_STORE_CTX_set0_crls GRPC_SHADOW_X509_STORE_CTX_set0_crls', + '#define X509_STORE_CTX_set0_param GRPC_SHADOW_X509_STORE_CTX_set0_param', + '#define X509_STORE_CTX_set_cert GRPC_SHADOW_X509_STORE_CTX_set_cert', + '#define X509_STORE_CTX_set_chain GRPC_SHADOW_X509_STORE_CTX_set_chain', + '#define X509_STORE_CTX_set_default GRPC_SHADOW_X509_STORE_CTX_set_default', + '#define X509_STORE_CTX_set_depth GRPC_SHADOW_X509_STORE_CTX_set_depth', + '#define X509_STORE_CTX_set_error GRPC_SHADOW_X509_STORE_CTX_set_error', + '#define X509_STORE_CTX_set_ex_data GRPC_SHADOW_X509_STORE_CTX_set_ex_data', + '#define X509_STORE_CTX_set_flags GRPC_SHADOW_X509_STORE_CTX_set_flags', + '#define X509_STORE_CTX_set_purpose GRPC_SHADOW_X509_STORE_CTX_set_purpose', + '#define X509_STORE_CTX_set_time GRPC_SHADOW_X509_STORE_CTX_set_time', + '#define X509_STORE_CTX_set_trust GRPC_SHADOW_X509_STORE_CTX_set_trust', + '#define X509_STORE_CTX_set_verify_cb GRPC_SHADOW_X509_STORE_CTX_set_verify_cb', + '#define X509_STORE_CTX_trusted_stack GRPC_SHADOW_X509_STORE_CTX_trusted_stack', + '#define X509_STORE_CTX_zero GRPC_SHADOW_X509_STORE_CTX_zero', + '#define X509_cmp_current_time GRPC_SHADOW_X509_cmp_current_time', + '#define X509_cmp_time GRPC_SHADOW_X509_cmp_time', + '#define X509_gmtime_adj GRPC_SHADOW_X509_gmtime_adj', + '#define X509_time_adj GRPC_SHADOW_X509_time_adj', + '#define X509_time_adj_ex GRPC_SHADOW_X509_time_adj_ex', + '#define X509_verify_cert GRPC_SHADOW_X509_verify_cert', + '#define X509_VERIFY_PARAM_add0_policy GRPC_SHADOW_X509_VERIFY_PARAM_add0_policy', + '#define X509_VERIFY_PARAM_add0_table GRPC_SHADOW_X509_VERIFY_PARAM_add0_table', + '#define X509_VERIFY_PARAM_add1_host GRPC_SHADOW_X509_VERIFY_PARAM_add1_host', + '#define X509_VERIFY_PARAM_clear_flags GRPC_SHADOW_X509_VERIFY_PARAM_clear_flags', + '#define X509_VERIFY_PARAM_free GRPC_SHADOW_X509_VERIFY_PARAM_free', + '#define X509_VERIFY_PARAM_get0 GRPC_SHADOW_X509_VERIFY_PARAM_get0', + '#define X509_VERIFY_PARAM_get0_name GRPC_SHADOW_X509_VERIFY_PARAM_get0_name', + '#define X509_VERIFY_PARAM_get0_peername GRPC_SHADOW_X509_VERIFY_PARAM_get0_peername', + '#define X509_VERIFY_PARAM_get_count GRPC_SHADOW_X509_VERIFY_PARAM_get_count', + '#define X509_VERIFY_PARAM_get_depth GRPC_SHADOW_X509_VERIFY_PARAM_get_depth', + '#define X509_VERIFY_PARAM_get_flags GRPC_SHADOW_X509_VERIFY_PARAM_get_flags', + '#define X509_VERIFY_PARAM_inherit GRPC_SHADOW_X509_VERIFY_PARAM_inherit', + '#define X509_VERIFY_PARAM_lookup GRPC_SHADOW_X509_VERIFY_PARAM_lookup', + '#define X509_VERIFY_PARAM_new GRPC_SHADOW_X509_VERIFY_PARAM_new', + '#define X509_VERIFY_PARAM_set1 GRPC_SHADOW_X509_VERIFY_PARAM_set1', + '#define X509_VERIFY_PARAM_set1_email GRPC_SHADOW_X509_VERIFY_PARAM_set1_email', + '#define X509_VERIFY_PARAM_set1_host GRPC_SHADOW_X509_VERIFY_PARAM_set1_host', + '#define X509_VERIFY_PARAM_set1_ip GRPC_SHADOW_X509_VERIFY_PARAM_set1_ip', + '#define X509_VERIFY_PARAM_set1_ip_asc GRPC_SHADOW_X509_VERIFY_PARAM_set1_ip_asc', + '#define X509_VERIFY_PARAM_set1_name GRPC_SHADOW_X509_VERIFY_PARAM_set1_name', + '#define X509_VERIFY_PARAM_set1_policies GRPC_SHADOW_X509_VERIFY_PARAM_set1_policies', + '#define X509_VERIFY_PARAM_set_depth GRPC_SHADOW_X509_VERIFY_PARAM_set_depth', + '#define X509_VERIFY_PARAM_set_flags GRPC_SHADOW_X509_VERIFY_PARAM_set_flags', + '#define X509_VERIFY_PARAM_set_hostflags GRPC_SHADOW_X509_VERIFY_PARAM_set_hostflags', + '#define X509_VERIFY_PARAM_set_purpose GRPC_SHADOW_X509_VERIFY_PARAM_set_purpose', + '#define X509_VERIFY_PARAM_set_time GRPC_SHADOW_X509_VERIFY_PARAM_set_time', + '#define X509_VERIFY_PARAM_set_trust GRPC_SHADOW_X509_VERIFY_PARAM_set_trust', + '#define X509_VERIFY_PARAM_table_cleanup GRPC_SHADOW_X509_VERIFY_PARAM_table_cleanup', + '#define X509_CRL_set_issuer_name GRPC_SHADOW_X509_CRL_set_issuer_name', + '#define X509_CRL_set_lastUpdate GRPC_SHADOW_X509_CRL_set_lastUpdate', + '#define X509_CRL_set_nextUpdate GRPC_SHADOW_X509_CRL_set_nextUpdate', + '#define X509_CRL_set_version GRPC_SHADOW_X509_CRL_set_version', + '#define X509_CRL_sort GRPC_SHADOW_X509_CRL_sort', + '#define X509_CRL_up_ref GRPC_SHADOW_X509_CRL_up_ref', + '#define X509_REVOKED_set_revocationDate GRPC_SHADOW_X509_REVOKED_set_revocationDate', + '#define X509_REVOKED_set_serialNumber GRPC_SHADOW_X509_REVOKED_set_serialNumber', + '#define X509_NAME_ENTRY_create_by_NID GRPC_SHADOW_X509_NAME_ENTRY_create_by_NID', + '#define X509_NAME_ENTRY_create_by_OBJ GRPC_SHADOW_X509_NAME_ENTRY_create_by_OBJ', + '#define X509_NAME_ENTRY_create_by_txt GRPC_SHADOW_X509_NAME_ENTRY_create_by_txt', + '#define X509_NAME_ENTRY_get_data GRPC_SHADOW_X509_NAME_ENTRY_get_data', + '#define X509_NAME_ENTRY_get_object GRPC_SHADOW_X509_NAME_ENTRY_get_object', + '#define X509_NAME_ENTRY_set_data GRPC_SHADOW_X509_NAME_ENTRY_set_data', + '#define X509_NAME_ENTRY_set_object GRPC_SHADOW_X509_NAME_ENTRY_set_object', + '#define X509_NAME_add_entry GRPC_SHADOW_X509_NAME_add_entry', + '#define X509_NAME_add_entry_by_NID GRPC_SHADOW_X509_NAME_add_entry_by_NID', + '#define X509_NAME_add_entry_by_OBJ GRPC_SHADOW_X509_NAME_add_entry_by_OBJ', + '#define X509_NAME_add_entry_by_txt GRPC_SHADOW_X509_NAME_add_entry_by_txt', + '#define X509_NAME_delete_entry GRPC_SHADOW_X509_NAME_delete_entry', + '#define X509_NAME_entry_count GRPC_SHADOW_X509_NAME_entry_count', + '#define X509_NAME_get_entry GRPC_SHADOW_X509_NAME_get_entry', + '#define X509_NAME_get_index_by_NID GRPC_SHADOW_X509_NAME_get_index_by_NID', + '#define X509_NAME_get_index_by_OBJ GRPC_SHADOW_X509_NAME_get_index_by_OBJ', + '#define X509_NAME_get_text_by_NID GRPC_SHADOW_X509_NAME_get_text_by_NID', + '#define X509_NAME_get_text_by_OBJ GRPC_SHADOW_X509_NAME_get_text_by_OBJ', + '#define X509_REQ_set_pubkey GRPC_SHADOW_X509_REQ_set_pubkey', + '#define X509_REQ_set_subject_name GRPC_SHADOW_X509_REQ_set_subject_name', + '#define X509_REQ_set_version GRPC_SHADOW_X509_REQ_set_version', + '#define NETSCAPE_SPKI_b64_decode GRPC_SHADOW_NETSCAPE_SPKI_b64_decode', + '#define NETSCAPE_SPKI_b64_encode GRPC_SHADOW_NETSCAPE_SPKI_b64_encode', + '#define NETSCAPE_SPKI_get_pubkey GRPC_SHADOW_NETSCAPE_SPKI_get_pubkey', + '#define NETSCAPE_SPKI_set_pubkey GRPC_SHADOW_NETSCAPE_SPKI_set_pubkey', + '#define X509_ALGORS_it GRPC_SHADOW_X509_ALGORS_it', + '#define X509_ALGOR_cmp GRPC_SHADOW_X509_ALGOR_cmp', + '#define X509_ALGOR_dup GRPC_SHADOW_X509_ALGOR_dup', + '#define X509_ALGOR_free GRPC_SHADOW_X509_ALGOR_free', + '#define X509_ALGOR_get0 GRPC_SHADOW_X509_ALGOR_get0', + '#define X509_ALGOR_it GRPC_SHADOW_X509_ALGOR_it', + '#define X509_ALGOR_new GRPC_SHADOW_X509_ALGOR_new', + '#define X509_ALGOR_set0 GRPC_SHADOW_X509_ALGOR_set0', + '#define X509_ALGOR_set_md GRPC_SHADOW_X509_ALGOR_set_md', + '#define d2i_X509_ALGOR GRPC_SHADOW_d2i_X509_ALGOR', + '#define d2i_X509_ALGORS GRPC_SHADOW_d2i_X509_ALGORS', + '#define i2d_X509_ALGOR GRPC_SHADOW_i2d_X509_ALGOR', + '#define i2d_X509_ALGORS GRPC_SHADOW_i2d_X509_ALGORS', + '#define NETSCAPE_SPKI_sign GRPC_SHADOW_NETSCAPE_SPKI_sign', + '#define NETSCAPE_SPKI_verify GRPC_SHADOW_NETSCAPE_SPKI_verify', + '#define X509_CRL_digest GRPC_SHADOW_X509_CRL_digest', + '#define X509_CRL_sign GRPC_SHADOW_X509_CRL_sign', + '#define X509_CRL_sign_ctx GRPC_SHADOW_X509_CRL_sign_ctx', + '#define X509_NAME_digest GRPC_SHADOW_X509_NAME_digest', + '#define X509_REQ_digest GRPC_SHADOW_X509_REQ_digest', + '#define X509_REQ_sign GRPC_SHADOW_X509_REQ_sign', + '#define X509_REQ_sign_ctx GRPC_SHADOW_X509_REQ_sign_ctx', + '#define X509_REQ_verify GRPC_SHADOW_X509_REQ_verify', + '#define X509_digest GRPC_SHADOW_X509_digest', + '#define X509_pubkey_digest GRPC_SHADOW_X509_pubkey_digest', + '#define X509_sign GRPC_SHADOW_X509_sign', + '#define X509_sign_ctx GRPC_SHADOW_X509_sign_ctx', + '#define X509_verify GRPC_SHADOW_X509_verify', + '#define d2i_DSAPrivateKey_bio GRPC_SHADOW_d2i_DSAPrivateKey_bio', + '#define d2i_DSAPrivateKey_fp GRPC_SHADOW_d2i_DSAPrivateKey_fp', + '#define d2i_DSA_PUBKEY_bio GRPC_SHADOW_d2i_DSA_PUBKEY_bio', + '#define d2i_DSA_PUBKEY_fp GRPC_SHADOW_d2i_DSA_PUBKEY_fp', + '#define d2i_ECPrivateKey_bio GRPC_SHADOW_d2i_ECPrivateKey_bio', + '#define d2i_ECPrivateKey_fp GRPC_SHADOW_d2i_ECPrivateKey_fp', + '#define d2i_EC_PUBKEY_bio GRPC_SHADOW_d2i_EC_PUBKEY_bio', + '#define d2i_EC_PUBKEY_fp GRPC_SHADOW_d2i_EC_PUBKEY_fp', + '#define d2i_PKCS8_PRIV_KEY_INFO_bio GRPC_SHADOW_d2i_PKCS8_PRIV_KEY_INFO_bio', + '#define d2i_PKCS8_PRIV_KEY_INFO_fp GRPC_SHADOW_d2i_PKCS8_PRIV_KEY_INFO_fp', + '#define d2i_PKCS8_bio GRPC_SHADOW_d2i_PKCS8_bio', + '#define d2i_PKCS8_fp GRPC_SHADOW_d2i_PKCS8_fp', + '#define d2i_PUBKEY_bio GRPC_SHADOW_d2i_PUBKEY_bio', + '#define d2i_PUBKEY_fp GRPC_SHADOW_d2i_PUBKEY_fp', + '#define d2i_PrivateKey_bio GRPC_SHADOW_d2i_PrivateKey_bio', + '#define d2i_PrivateKey_fp GRPC_SHADOW_d2i_PrivateKey_fp', + '#define d2i_RSAPrivateKey_bio GRPC_SHADOW_d2i_RSAPrivateKey_bio', + '#define d2i_RSAPrivateKey_fp GRPC_SHADOW_d2i_RSAPrivateKey_fp', + '#define d2i_RSAPublicKey_bio GRPC_SHADOW_d2i_RSAPublicKey_bio', + '#define d2i_RSAPublicKey_fp GRPC_SHADOW_d2i_RSAPublicKey_fp', + '#define d2i_RSA_PUBKEY_bio GRPC_SHADOW_d2i_RSA_PUBKEY_bio', + '#define d2i_RSA_PUBKEY_fp GRPC_SHADOW_d2i_RSA_PUBKEY_fp', + '#define d2i_X509_CRL_bio GRPC_SHADOW_d2i_X509_CRL_bio', + '#define d2i_X509_CRL_fp GRPC_SHADOW_d2i_X509_CRL_fp', + '#define d2i_X509_REQ_bio GRPC_SHADOW_d2i_X509_REQ_bio', + '#define d2i_X509_REQ_fp GRPC_SHADOW_d2i_X509_REQ_fp', + '#define d2i_X509_bio GRPC_SHADOW_d2i_X509_bio', + '#define d2i_X509_fp GRPC_SHADOW_d2i_X509_fp', + '#define i2d_DSAPrivateKey_bio GRPC_SHADOW_i2d_DSAPrivateKey_bio', + '#define i2d_DSAPrivateKey_fp GRPC_SHADOW_i2d_DSAPrivateKey_fp', + '#define i2d_DSA_PUBKEY_bio GRPC_SHADOW_i2d_DSA_PUBKEY_bio', + '#define i2d_DSA_PUBKEY_fp GRPC_SHADOW_i2d_DSA_PUBKEY_fp', + '#define i2d_ECPrivateKey_bio GRPC_SHADOW_i2d_ECPrivateKey_bio', + '#define i2d_ECPrivateKey_fp GRPC_SHADOW_i2d_ECPrivateKey_fp', + '#define i2d_EC_PUBKEY_bio GRPC_SHADOW_i2d_EC_PUBKEY_bio', + '#define i2d_EC_PUBKEY_fp GRPC_SHADOW_i2d_EC_PUBKEY_fp', + '#define i2d_PKCS8PrivateKeyInfo_bio GRPC_SHADOW_i2d_PKCS8PrivateKeyInfo_bio', + '#define i2d_PKCS8PrivateKeyInfo_fp GRPC_SHADOW_i2d_PKCS8PrivateKeyInfo_fp', + '#define i2d_PKCS8_PRIV_KEY_INFO_bio GRPC_SHADOW_i2d_PKCS8_PRIV_KEY_INFO_bio', + '#define i2d_PKCS8_PRIV_KEY_INFO_fp GRPC_SHADOW_i2d_PKCS8_PRIV_KEY_INFO_fp', + '#define i2d_PKCS8_bio GRPC_SHADOW_i2d_PKCS8_bio', + '#define i2d_PKCS8_fp GRPC_SHADOW_i2d_PKCS8_fp', + '#define i2d_PUBKEY_bio GRPC_SHADOW_i2d_PUBKEY_bio', + '#define i2d_PUBKEY_fp GRPC_SHADOW_i2d_PUBKEY_fp', + '#define i2d_PrivateKey_bio GRPC_SHADOW_i2d_PrivateKey_bio', + '#define i2d_PrivateKey_fp GRPC_SHADOW_i2d_PrivateKey_fp', + '#define i2d_RSAPrivateKey_bio GRPC_SHADOW_i2d_RSAPrivateKey_bio', + '#define i2d_RSAPrivateKey_fp GRPC_SHADOW_i2d_RSAPrivateKey_fp', + '#define i2d_RSAPublicKey_bio GRPC_SHADOW_i2d_RSAPublicKey_bio', + '#define i2d_RSAPublicKey_fp GRPC_SHADOW_i2d_RSAPublicKey_fp', + '#define i2d_RSA_PUBKEY_bio GRPC_SHADOW_i2d_RSA_PUBKEY_bio', + '#define i2d_RSA_PUBKEY_fp GRPC_SHADOW_i2d_RSA_PUBKEY_fp', + '#define i2d_X509_CRL_bio GRPC_SHADOW_i2d_X509_CRL_bio', + '#define i2d_X509_CRL_fp GRPC_SHADOW_i2d_X509_CRL_fp', + '#define i2d_X509_REQ_bio GRPC_SHADOW_i2d_X509_REQ_bio', + '#define i2d_X509_REQ_fp GRPC_SHADOW_i2d_X509_REQ_fp', + '#define i2d_X509_bio GRPC_SHADOW_i2d_X509_bio', + '#define i2d_X509_fp GRPC_SHADOW_i2d_X509_fp', + '#define X509_ATTRIBUTE_SET_it GRPC_SHADOW_X509_ATTRIBUTE_SET_it', + '#define X509_ATTRIBUTE_create GRPC_SHADOW_X509_ATTRIBUTE_create', + '#define X509_ATTRIBUTE_dup GRPC_SHADOW_X509_ATTRIBUTE_dup', + '#define X509_ATTRIBUTE_free GRPC_SHADOW_X509_ATTRIBUTE_free', + '#define X509_ATTRIBUTE_it GRPC_SHADOW_X509_ATTRIBUTE_it', + '#define X509_ATTRIBUTE_new GRPC_SHADOW_X509_ATTRIBUTE_new', + '#define d2i_X509_ATTRIBUTE GRPC_SHADOW_d2i_X509_ATTRIBUTE', + '#define i2d_X509_ATTRIBUTE GRPC_SHADOW_i2d_X509_ATTRIBUTE', + '#define X509_CRL_INFO_free GRPC_SHADOW_X509_CRL_INFO_free', + '#define X509_CRL_INFO_it GRPC_SHADOW_X509_CRL_INFO_it', + '#define X509_CRL_INFO_new GRPC_SHADOW_X509_CRL_INFO_new', + '#define X509_CRL_METHOD_free GRPC_SHADOW_X509_CRL_METHOD_free', + '#define X509_CRL_METHOD_new GRPC_SHADOW_X509_CRL_METHOD_new', + '#define X509_CRL_add0_revoked GRPC_SHADOW_X509_CRL_add0_revoked', + '#define X509_CRL_dup GRPC_SHADOW_X509_CRL_dup', + '#define X509_CRL_free GRPC_SHADOW_X509_CRL_free', + '#define X509_CRL_get0_by_cert GRPC_SHADOW_X509_CRL_get0_by_cert', + '#define X509_CRL_get0_by_serial GRPC_SHADOW_X509_CRL_get0_by_serial', + '#define X509_CRL_get_meth_data GRPC_SHADOW_X509_CRL_get_meth_data', + '#define X509_CRL_it GRPC_SHADOW_X509_CRL_it', + '#define X509_CRL_new GRPC_SHADOW_X509_CRL_new', + '#define X509_CRL_set_default_method GRPC_SHADOW_X509_CRL_set_default_method', + '#define X509_CRL_set_meth_data GRPC_SHADOW_X509_CRL_set_meth_data', + '#define X509_CRL_verify GRPC_SHADOW_X509_CRL_verify', + '#define X509_REVOKED_dup GRPC_SHADOW_X509_REVOKED_dup', + '#define X509_REVOKED_free GRPC_SHADOW_X509_REVOKED_free', + '#define X509_REVOKED_it GRPC_SHADOW_X509_REVOKED_it', + '#define X509_REVOKED_new GRPC_SHADOW_X509_REVOKED_new', + '#define d2i_X509_CRL GRPC_SHADOW_d2i_X509_CRL', + '#define d2i_X509_CRL_INFO GRPC_SHADOW_d2i_X509_CRL_INFO', + '#define d2i_X509_REVOKED GRPC_SHADOW_d2i_X509_REVOKED', + '#define i2d_X509_CRL GRPC_SHADOW_i2d_X509_CRL', + '#define i2d_X509_CRL_INFO GRPC_SHADOW_i2d_X509_CRL_INFO', + '#define i2d_X509_REVOKED GRPC_SHADOW_i2d_X509_REVOKED', + '#define X509_EXTENSIONS_it GRPC_SHADOW_X509_EXTENSIONS_it', + '#define X509_EXTENSION_dup GRPC_SHADOW_X509_EXTENSION_dup', + '#define X509_EXTENSION_free GRPC_SHADOW_X509_EXTENSION_free', + '#define X509_EXTENSION_it GRPC_SHADOW_X509_EXTENSION_it', + '#define X509_EXTENSION_new GRPC_SHADOW_X509_EXTENSION_new', + '#define d2i_X509_EXTENSION GRPC_SHADOW_d2i_X509_EXTENSION', + '#define d2i_X509_EXTENSIONS GRPC_SHADOW_d2i_X509_EXTENSIONS', + '#define i2d_X509_EXTENSION GRPC_SHADOW_i2d_X509_EXTENSION', + '#define i2d_X509_EXTENSIONS GRPC_SHADOW_i2d_X509_EXTENSIONS', + '#define X509_INFO_free GRPC_SHADOW_X509_INFO_free', + '#define X509_INFO_new GRPC_SHADOW_X509_INFO_new', + '#define X509_NAME_ENTRIES_it GRPC_SHADOW_X509_NAME_ENTRIES_it', + '#define X509_NAME_ENTRY_dup GRPC_SHADOW_X509_NAME_ENTRY_dup', + '#define X509_NAME_ENTRY_free GRPC_SHADOW_X509_NAME_ENTRY_free', + '#define X509_NAME_ENTRY_it GRPC_SHADOW_X509_NAME_ENTRY_it', + '#define X509_NAME_ENTRY_new GRPC_SHADOW_X509_NAME_ENTRY_new', + '#define X509_NAME_ENTRY_set GRPC_SHADOW_X509_NAME_ENTRY_set', + '#define X509_NAME_INTERNAL_it GRPC_SHADOW_X509_NAME_INTERNAL_it', + '#define X509_NAME_dup GRPC_SHADOW_X509_NAME_dup', + '#define X509_NAME_free GRPC_SHADOW_X509_NAME_free', + '#define X509_NAME_get0_der GRPC_SHADOW_X509_NAME_get0_der', + '#define X509_NAME_it GRPC_SHADOW_X509_NAME_it', + '#define X509_NAME_new GRPC_SHADOW_X509_NAME_new', + '#define X509_NAME_set GRPC_SHADOW_X509_NAME_set', + '#define d2i_X509_NAME GRPC_SHADOW_d2i_X509_NAME', + '#define d2i_X509_NAME_ENTRY GRPC_SHADOW_d2i_X509_NAME_ENTRY', + '#define i2d_X509_NAME GRPC_SHADOW_i2d_X509_NAME', + '#define i2d_X509_NAME_ENTRY GRPC_SHADOW_i2d_X509_NAME_ENTRY', + '#define X509_PKEY_free GRPC_SHADOW_X509_PKEY_free', + '#define X509_PKEY_new GRPC_SHADOW_X509_PKEY_new', + '#define X509_PUBKEY_free GRPC_SHADOW_X509_PUBKEY_free', + '#define X509_PUBKEY_get GRPC_SHADOW_X509_PUBKEY_get', + '#define X509_PUBKEY_get0_param GRPC_SHADOW_X509_PUBKEY_get0_param', + '#define X509_PUBKEY_it GRPC_SHADOW_X509_PUBKEY_it', + '#define X509_PUBKEY_new GRPC_SHADOW_X509_PUBKEY_new', + '#define X509_PUBKEY_set GRPC_SHADOW_X509_PUBKEY_set', + '#define X509_PUBKEY_set0_param GRPC_SHADOW_X509_PUBKEY_set0_param', + '#define d2i_DSA_PUBKEY GRPC_SHADOW_d2i_DSA_PUBKEY', + '#define d2i_EC_PUBKEY GRPC_SHADOW_d2i_EC_PUBKEY', + '#define d2i_PUBKEY GRPC_SHADOW_d2i_PUBKEY', + '#define d2i_RSA_PUBKEY GRPC_SHADOW_d2i_RSA_PUBKEY', + '#define d2i_X509_PUBKEY GRPC_SHADOW_d2i_X509_PUBKEY', + '#define i2d_DSA_PUBKEY GRPC_SHADOW_i2d_DSA_PUBKEY', + '#define i2d_EC_PUBKEY GRPC_SHADOW_i2d_EC_PUBKEY', + '#define i2d_PUBKEY GRPC_SHADOW_i2d_PUBKEY', + '#define i2d_RSA_PUBKEY GRPC_SHADOW_i2d_RSA_PUBKEY', + '#define i2d_X509_PUBKEY GRPC_SHADOW_i2d_X509_PUBKEY', + '#define X509_REQ_INFO_free GRPC_SHADOW_X509_REQ_INFO_free', + '#define X509_REQ_INFO_it GRPC_SHADOW_X509_REQ_INFO_it', + '#define X509_REQ_INFO_new GRPC_SHADOW_X509_REQ_INFO_new', + '#define X509_REQ_dup GRPC_SHADOW_X509_REQ_dup', + '#define X509_REQ_free GRPC_SHADOW_X509_REQ_free', + '#define X509_REQ_it GRPC_SHADOW_X509_REQ_it', + '#define X509_REQ_new GRPC_SHADOW_X509_REQ_new', + '#define d2i_X509_REQ GRPC_SHADOW_d2i_X509_REQ', + '#define d2i_X509_REQ_INFO GRPC_SHADOW_d2i_X509_REQ_INFO', + '#define i2d_X509_REQ GRPC_SHADOW_i2d_X509_REQ', + '#define i2d_X509_REQ_INFO GRPC_SHADOW_i2d_X509_REQ_INFO', + '#define X509_SIG_free GRPC_SHADOW_X509_SIG_free', + '#define X509_SIG_it GRPC_SHADOW_X509_SIG_it', + '#define X509_SIG_new GRPC_SHADOW_X509_SIG_new', + '#define d2i_X509_SIG GRPC_SHADOW_d2i_X509_SIG', + '#define i2d_X509_SIG GRPC_SHADOW_i2d_X509_SIG', + '#define NETSCAPE_SPKAC_free GRPC_SHADOW_NETSCAPE_SPKAC_free', + '#define NETSCAPE_SPKAC_it GRPC_SHADOW_NETSCAPE_SPKAC_it', + '#define NETSCAPE_SPKAC_new GRPC_SHADOW_NETSCAPE_SPKAC_new', + '#define NETSCAPE_SPKI_free GRPC_SHADOW_NETSCAPE_SPKI_free', + '#define NETSCAPE_SPKI_it GRPC_SHADOW_NETSCAPE_SPKI_it', + '#define NETSCAPE_SPKI_new GRPC_SHADOW_NETSCAPE_SPKI_new', + '#define d2i_NETSCAPE_SPKAC GRPC_SHADOW_d2i_NETSCAPE_SPKAC', + '#define d2i_NETSCAPE_SPKI GRPC_SHADOW_d2i_NETSCAPE_SPKI', + '#define i2d_NETSCAPE_SPKAC GRPC_SHADOW_i2d_NETSCAPE_SPKAC', + '#define i2d_NETSCAPE_SPKI GRPC_SHADOW_i2d_NETSCAPE_SPKI', + '#define X509_VAL_free GRPC_SHADOW_X509_VAL_free', + '#define X509_VAL_it GRPC_SHADOW_X509_VAL_it', + '#define X509_VAL_new GRPC_SHADOW_X509_VAL_new', + '#define d2i_X509_VAL GRPC_SHADOW_d2i_X509_VAL', + '#define i2d_X509_VAL GRPC_SHADOW_i2d_X509_VAL', + '#define X509_CINF_free GRPC_SHADOW_X509_CINF_free', + '#define X509_CINF_it GRPC_SHADOW_X509_CINF_it', + '#define X509_CINF_new GRPC_SHADOW_X509_CINF_new', + '#define X509_dup GRPC_SHADOW_X509_dup', + '#define X509_free GRPC_SHADOW_X509_free', + '#define X509_get0_signature GRPC_SHADOW_X509_get0_signature', + '#define X509_get_ex_data GRPC_SHADOW_X509_get_ex_data', + '#define X509_get_ex_new_index GRPC_SHADOW_X509_get_ex_new_index', + '#define X509_get_signature_nid GRPC_SHADOW_X509_get_signature_nid', + '#define X509_it GRPC_SHADOW_X509_it', + '#define X509_new GRPC_SHADOW_X509_new', + '#define X509_parse_from_buffer GRPC_SHADOW_X509_parse_from_buffer', + '#define X509_set_ex_data GRPC_SHADOW_X509_set_ex_data', + '#define X509_up_ref GRPC_SHADOW_X509_up_ref', + '#define d2i_X509 GRPC_SHADOW_d2i_X509', + '#define d2i_X509_AUX GRPC_SHADOW_d2i_X509_AUX', + '#define d2i_X509_CINF GRPC_SHADOW_d2i_X509_CINF', + '#define i2d_X509 GRPC_SHADOW_i2d_X509', + '#define i2d_X509_AUX GRPC_SHADOW_i2d_X509_AUX', + '#define i2d_X509_CINF GRPC_SHADOW_i2d_X509_CINF', + '#define X509_CERT_AUX_free GRPC_SHADOW_X509_CERT_AUX_free', + '#define X509_CERT_AUX_it GRPC_SHADOW_X509_CERT_AUX_it', + '#define X509_CERT_AUX_new GRPC_SHADOW_X509_CERT_AUX_new', + '#define X509_add1_reject_object GRPC_SHADOW_X509_add1_reject_object', + '#define X509_add1_trust_object GRPC_SHADOW_X509_add1_trust_object', + '#define X509_alias_get0 GRPC_SHADOW_X509_alias_get0', + '#define X509_alias_set1 GRPC_SHADOW_X509_alias_set1', + '#define X509_keyid_get0 GRPC_SHADOW_X509_keyid_get0', + '#define X509_keyid_set1 GRPC_SHADOW_X509_keyid_set1', + '#define X509_reject_clear GRPC_SHADOW_X509_reject_clear', + '#define X509_trust_clear GRPC_SHADOW_X509_trust_clear', + '#define d2i_X509_CERT_AUX GRPC_SHADOW_d2i_X509_CERT_AUX', + '#define i2d_X509_CERT_AUX GRPC_SHADOW_i2d_X509_CERT_AUX', + '#define policy_cache_find_data GRPC_SHADOW_policy_cache_find_data', + '#define policy_cache_free GRPC_SHADOW_policy_cache_free', + '#define policy_cache_set GRPC_SHADOW_policy_cache_set', + '#define policy_data_free GRPC_SHADOW_policy_data_free', + '#define policy_data_new GRPC_SHADOW_policy_data_new', + '#define X509_policy_level_get0_node GRPC_SHADOW_X509_policy_level_get0_node', + '#define X509_policy_level_node_count GRPC_SHADOW_X509_policy_level_node_count', + '#define X509_policy_node_get0_parent GRPC_SHADOW_X509_policy_node_get0_parent', + '#define X509_policy_node_get0_policy GRPC_SHADOW_X509_policy_node_get0_policy', + '#define X509_policy_node_get0_qualifiers GRPC_SHADOW_X509_policy_node_get0_qualifiers', + '#define X509_policy_tree_get0_level GRPC_SHADOW_X509_policy_tree_get0_level', + '#define X509_policy_tree_get0_policies GRPC_SHADOW_X509_policy_tree_get0_policies', + '#define X509_policy_tree_get0_user_policies GRPC_SHADOW_X509_policy_tree_get0_user_policies', + '#define X509_policy_tree_level_count GRPC_SHADOW_X509_policy_tree_level_count', + '#define policy_cache_set_mapping GRPC_SHADOW_policy_cache_set_mapping', + '#define level_add_node GRPC_SHADOW_level_add_node', + '#define level_find_node GRPC_SHADOW_level_find_node', + '#define policy_node_cmp_new GRPC_SHADOW_policy_node_cmp_new', + '#define policy_node_free GRPC_SHADOW_policy_node_free', + '#define policy_node_match GRPC_SHADOW_policy_node_match', + '#define tree_find_sk GRPC_SHADOW_tree_find_sk', + '#define X509_policy_check GRPC_SHADOW_X509_policy_check', + '#define X509_policy_tree_free GRPC_SHADOW_X509_policy_tree_free', + '#define v3_akey_id GRPC_SHADOW_v3_akey_id', + '#define AUTHORITY_KEYID_free GRPC_SHADOW_AUTHORITY_KEYID_free', + '#define AUTHORITY_KEYID_it GRPC_SHADOW_AUTHORITY_KEYID_it', + '#define AUTHORITY_KEYID_new GRPC_SHADOW_AUTHORITY_KEYID_new', + '#define d2i_AUTHORITY_KEYID GRPC_SHADOW_d2i_AUTHORITY_KEYID', + '#define i2d_AUTHORITY_KEYID GRPC_SHADOW_i2d_AUTHORITY_KEYID', + '#define GENERAL_NAME_print GRPC_SHADOW_GENERAL_NAME_print', + '#define a2i_GENERAL_NAME GRPC_SHADOW_a2i_GENERAL_NAME', + '#define i2v_GENERAL_NAME GRPC_SHADOW_i2v_GENERAL_NAME', + '#define i2v_GENERAL_NAMES GRPC_SHADOW_i2v_GENERAL_NAMES', + '#define v2i_GENERAL_NAME GRPC_SHADOW_v2i_GENERAL_NAME', + '#define v2i_GENERAL_NAMES GRPC_SHADOW_v2i_GENERAL_NAMES', + '#define v2i_GENERAL_NAME_ex GRPC_SHADOW_v2i_GENERAL_NAME_ex', + '#define v3_alt GRPC_SHADOW_v3_alt', + '#define BASIC_CONSTRAINTS_free GRPC_SHADOW_BASIC_CONSTRAINTS_free', + '#define BASIC_CONSTRAINTS_it GRPC_SHADOW_BASIC_CONSTRAINTS_it', + '#define BASIC_CONSTRAINTS_new GRPC_SHADOW_BASIC_CONSTRAINTS_new', + '#define d2i_BASIC_CONSTRAINTS GRPC_SHADOW_d2i_BASIC_CONSTRAINTS', + '#define i2d_BASIC_CONSTRAINTS GRPC_SHADOW_i2d_BASIC_CONSTRAINTS', + '#define v3_bcons GRPC_SHADOW_v3_bcons', + '#define i2v_ASN1_BIT_STRING GRPC_SHADOW_i2v_ASN1_BIT_STRING', + '#define v2i_ASN1_BIT_STRING GRPC_SHADOW_v2i_ASN1_BIT_STRING', + '#define v3_key_usage GRPC_SHADOW_v3_key_usage', + '#define v3_nscert GRPC_SHADOW_v3_nscert', + '#define X509V3_EXT_CRL_add_nconf GRPC_SHADOW_X509V3_EXT_CRL_add_nconf', + '#define X509V3_EXT_REQ_add_nconf GRPC_SHADOW_X509V3_EXT_REQ_add_nconf', + '#define X509V3_EXT_add_nconf GRPC_SHADOW_X509V3_EXT_add_nconf', + '#define X509V3_EXT_add_nconf_sk GRPC_SHADOW_X509V3_EXT_add_nconf_sk', + '#define X509V3_EXT_i2d GRPC_SHADOW_X509V3_EXT_i2d', + '#define X509V3_EXT_nconf GRPC_SHADOW_X509V3_EXT_nconf', + '#define X509V3_EXT_nconf_nid GRPC_SHADOW_X509V3_EXT_nconf_nid', + '#define X509V3_get_section GRPC_SHADOW_X509V3_get_section', + '#define X509V3_get_string GRPC_SHADOW_X509V3_get_string', + '#define X509V3_section_free GRPC_SHADOW_X509V3_section_free', + '#define X509V3_set_ctx GRPC_SHADOW_X509V3_set_ctx', + '#define X509V3_set_nconf GRPC_SHADOW_X509V3_set_nconf', + '#define X509V3_string_free GRPC_SHADOW_X509V3_string_free', + '#define CERTIFICATEPOLICIES_free GRPC_SHADOW_CERTIFICATEPOLICIES_free', + '#define CERTIFICATEPOLICIES_it GRPC_SHADOW_CERTIFICATEPOLICIES_it', + '#define CERTIFICATEPOLICIES_new GRPC_SHADOW_CERTIFICATEPOLICIES_new', + '#define NOTICEREF_free GRPC_SHADOW_NOTICEREF_free', + '#define NOTICEREF_it GRPC_SHADOW_NOTICEREF_it', + '#define NOTICEREF_new GRPC_SHADOW_NOTICEREF_new', + '#define POLICYINFO_free GRPC_SHADOW_POLICYINFO_free', + '#define POLICYINFO_it GRPC_SHADOW_POLICYINFO_it', + '#define POLICYINFO_new GRPC_SHADOW_POLICYINFO_new', + '#define POLICYQUALINFO_free GRPC_SHADOW_POLICYQUALINFO_free', + '#define POLICYQUALINFO_it GRPC_SHADOW_POLICYQUALINFO_it', + '#define POLICYQUALINFO_new GRPC_SHADOW_POLICYQUALINFO_new', + '#define USERNOTICE_free GRPC_SHADOW_USERNOTICE_free', + '#define USERNOTICE_it GRPC_SHADOW_USERNOTICE_it', + '#define USERNOTICE_new GRPC_SHADOW_USERNOTICE_new', + '#define X509_POLICY_NODE_print GRPC_SHADOW_X509_POLICY_NODE_print', + '#define d2i_CERTIFICATEPOLICIES GRPC_SHADOW_d2i_CERTIFICATEPOLICIES', + '#define d2i_NOTICEREF GRPC_SHADOW_d2i_NOTICEREF', + '#define d2i_POLICYINFO GRPC_SHADOW_d2i_POLICYINFO', + '#define d2i_POLICYQUALINFO GRPC_SHADOW_d2i_POLICYQUALINFO', + '#define d2i_USERNOTICE GRPC_SHADOW_d2i_USERNOTICE', + '#define i2d_CERTIFICATEPOLICIES GRPC_SHADOW_i2d_CERTIFICATEPOLICIES', + '#define i2d_NOTICEREF GRPC_SHADOW_i2d_NOTICEREF', + '#define i2d_POLICYINFO GRPC_SHADOW_i2d_POLICYINFO', + '#define i2d_POLICYQUALINFO GRPC_SHADOW_i2d_POLICYQUALINFO', + '#define i2d_USERNOTICE GRPC_SHADOW_i2d_USERNOTICE', + '#define v3_cpols GRPC_SHADOW_v3_cpols', + '#define CRL_DIST_POINTS_free GRPC_SHADOW_CRL_DIST_POINTS_free', + '#define CRL_DIST_POINTS_it GRPC_SHADOW_CRL_DIST_POINTS_it', + '#define CRL_DIST_POINTS_new GRPC_SHADOW_CRL_DIST_POINTS_new', + '#define DIST_POINT_NAME_free GRPC_SHADOW_DIST_POINT_NAME_free', + '#define DIST_POINT_NAME_it GRPC_SHADOW_DIST_POINT_NAME_it', + '#define DIST_POINT_NAME_new GRPC_SHADOW_DIST_POINT_NAME_new', + '#define DIST_POINT_free GRPC_SHADOW_DIST_POINT_free', + '#define DIST_POINT_it GRPC_SHADOW_DIST_POINT_it', + '#define DIST_POINT_new GRPC_SHADOW_DIST_POINT_new', + '#define DIST_POINT_set_dpname GRPC_SHADOW_DIST_POINT_set_dpname', + '#define ISSUING_DIST_POINT_free GRPC_SHADOW_ISSUING_DIST_POINT_free', + '#define ISSUING_DIST_POINT_it GRPC_SHADOW_ISSUING_DIST_POINT_it', + '#define ISSUING_DIST_POINT_new GRPC_SHADOW_ISSUING_DIST_POINT_new', + '#define d2i_CRL_DIST_POINTS GRPC_SHADOW_d2i_CRL_DIST_POINTS', + '#define d2i_DIST_POINT GRPC_SHADOW_d2i_DIST_POINT', + '#define d2i_DIST_POINT_NAME GRPC_SHADOW_d2i_DIST_POINT_NAME', + '#define d2i_ISSUING_DIST_POINT GRPC_SHADOW_d2i_ISSUING_DIST_POINT', + '#define i2d_CRL_DIST_POINTS GRPC_SHADOW_i2d_CRL_DIST_POINTS', + '#define i2d_DIST_POINT GRPC_SHADOW_i2d_DIST_POINT', + '#define i2d_DIST_POINT_NAME GRPC_SHADOW_i2d_DIST_POINT_NAME', + '#define i2d_ISSUING_DIST_POINT GRPC_SHADOW_i2d_ISSUING_DIST_POINT', + '#define v3_crld GRPC_SHADOW_v3_crld', + '#define v3_freshest_crl GRPC_SHADOW_v3_freshest_crl', + '#define v3_idp GRPC_SHADOW_v3_idp', + '#define i2s_ASN1_ENUMERATED_TABLE GRPC_SHADOW_i2s_ASN1_ENUMERATED_TABLE', + '#define v3_crl_reason GRPC_SHADOW_v3_crl_reason', + '#define EXTENDED_KEY_USAGE_free GRPC_SHADOW_EXTENDED_KEY_USAGE_free', + '#define EXTENDED_KEY_USAGE_it GRPC_SHADOW_EXTENDED_KEY_USAGE_it', + '#define EXTENDED_KEY_USAGE_new GRPC_SHADOW_EXTENDED_KEY_USAGE_new', + '#define d2i_EXTENDED_KEY_USAGE GRPC_SHADOW_d2i_EXTENDED_KEY_USAGE', + '#define i2d_EXTENDED_KEY_USAGE GRPC_SHADOW_i2d_EXTENDED_KEY_USAGE', + '#define v3_ext_ku GRPC_SHADOW_v3_ext_ku', + '#define v3_ocsp_accresp GRPC_SHADOW_v3_ocsp_accresp', + '#define EDIPARTYNAME_free GRPC_SHADOW_EDIPARTYNAME_free', + '#define EDIPARTYNAME_it GRPC_SHADOW_EDIPARTYNAME_it', + '#define EDIPARTYNAME_new GRPC_SHADOW_EDIPARTYNAME_new', + '#define GENERAL_NAMES_free GRPC_SHADOW_GENERAL_NAMES_free', + '#define GENERAL_NAMES_it GRPC_SHADOW_GENERAL_NAMES_it', + '#define GENERAL_NAMES_new GRPC_SHADOW_GENERAL_NAMES_new', + '#define GENERAL_NAME_cmp GRPC_SHADOW_GENERAL_NAME_cmp', + '#define GENERAL_NAME_dup GRPC_SHADOW_GENERAL_NAME_dup', + '#define GENERAL_NAME_free GRPC_SHADOW_GENERAL_NAME_free', + '#define GENERAL_NAME_get0_otherName GRPC_SHADOW_GENERAL_NAME_get0_otherName', + '#define GENERAL_NAME_get0_value GRPC_SHADOW_GENERAL_NAME_get0_value', + '#define GENERAL_NAME_it GRPC_SHADOW_GENERAL_NAME_it', + '#define GENERAL_NAME_new GRPC_SHADOW_GENERAL_NAME_new', + '#define GENERAL_NAME_set0_othername GRPC_SHADOW_GENERAL_NAME_set0_othername', + '#define GENERAL_NAME_set0_value GRPC_SHADOW_GENERAL_NAME_set0_value', + '#define OTHERNAME_cmp GRPC_SHADOW_OTHERNAME_cmp', + '#define OTHERNAME_free GRPC_SHADOW_OTHERNAME_free', + '#define OTHERNAME_it GRPC_SHADOW_OTHERNAME_it', + '#define OTHERNAME_new GRPC_SHADOW_OTHERNAME_new', + '#define d2i_EDIPARTYNAME GRPC_SHADOW_d2i_EDIPARTYNAME', + '#define d2i_GENERAL_NAME GRPC_SHADOW_d2i_GENERAL_NAME', + '#define d2i_GENERAL_NAMES GRPC_SHADOW_d2i_GENERAL_NAMES', + '#define d2i_OTHERNAME GRPC_SHADOW_d2i_OTHERNAME', + '#define i2d_EDIPARTYNAME GRPC_SHADOW_i2d_EDIPARTYNAME', + '#define i2d_GENERAL_NAME GRPC_SHADOW_i2d_GENERAL_NAME', + '#define i2d_GENERAL_NAMES GRPC_SHADOW_i2d_GENERAL_NAMES', + '#define i2d_OTHERNAME GRPC_SHADOW_i2d_OTHERNAME', + '#define v3_ns_ia5_list GRPC_SHADOW_v3_ns_ia5_list', + '#define ACCESS_DESCRIPTION_free GRPC_SHADOW_ACCESS_DESCRIPTION_free', + '#define ACCESS_DESCRIPTION_it GRPC_SHADOW_ACCESS_DESCRIPTION_it', + '#define ACCESS_DESCRIPTION_new GRPC_SHADOW_ACCESS_DESCRIPTION_new', + '#define AUTHORITY_INFO_ACCESS_free GRPC_SHADOW_AUTHORITY_INFO_ACCESS_free', + '#define AUTHORITY_INFO_ACCESS_it GRPC_SHADOW_AUTHORITY_INFO_ACCESS_it', + '#define AUTHORITY_INFO_ACCESS_new GRPC_SHADOW_AUTHORITY_INFO_ACCESS_new', + '#define d2i_ACCESS_DESCRIPTION GRPC_SHADOW_d2i_ACCESS_DESCRIPTION', + '#define d2i_AUTHORITY_INFO_ACCESS GRPC_SHADOW_d2i_AUTHORITY_INFO_ACCESS', + '#define i2a_ACCESS_DESCRIPTION GRPC_SHADOW_i2a_ACCESS_DESCRIPTION', + '#define i2d_ACCESS_DESCRIPTION GRPC_SHADOW_i2d_ACCESS_DESCRIPTION', + '#define i2d_AUTHORITY_INFO_ACCESS GRPC_SHADOW_i2d_AUTHORITY_INFO_ACCESS', + '#define v3_info GRPC_SHADOW_v3_info', + '#define v3_sinfo GRPC_SHADOW_v3_sinfo', + '#define v3_crl_num GRPC_SHADOW_v3_crl_num', + '#define v3_delta_crl GRPC_SHADOW_v3_delta_crl', + '#define v3_inhibit_anyp GRPC_SHADOW_v3_inhibit_anyp', + '#define X509V3_EXT_add GRPC_SHADOW_X509V3_EXT_add', + '#define X509V3_EXT_add_alias GRPC_SHADOW_X509V3_EXT_add_alias', + '#define X509V3_EXT_add_list GRPC_SHADOW_X509V3_EXT_add_list', + '#define X509V3_EXT_cleanup GRPC_SHADOW_X509V3_EXT_cleanup', + '#define X509V3_EXT_d2i GRPC_SHADOW_X509V3_EXT_d2i', + '#define X509V3_EXT_free GRPC_SHADOW_X509V3_EXT_free', + '#define X509V3_EXT_get GRPC_SHADOW_X509V3_EXT_get', + '#define X509V3_EXT_get_nid GRPC_SHADOW_X509V3_EXT_get_nid', + '#define X509V3_add1_i2d GRPC_SHADOW_X509V3_add1_i2d', + '#define X509V3_add_standard_extensions GRPC_SHADOW_X509V3_add_standard_extensions', + '#define X509V3_get_d2i GRPC_SHADOW_X509V3_get_d2i', + '#define GENERAL_SUBTREE_free GRPC_SHADOW_GENERAL_SUBTREE_free', + '#define GENERAL_SUBTREE_it GRPC_SHADOW_GENERAL_SUBTREE_it', + '#define GENERAL_SUBTREE_new GRPC_SHADOW_GENERAL_SUBTREE_new', + '#define NAME_CONSTRAINTS_check GRPC_SHADOW_NAME_CONSTRAINTS_check', + '#define NAME_CONSTRAINTS_free GRPC_SHADOW_NAME_CONSTRAINTS_free', + '#define NAME_CONSTRAINTS_it GRPC_SHADOW_NAME_CONSTRAINTS_it', + '#define NAME_CONSTRAINTS_new GRPC_SHADOW_NAME_CONSTRAINTS_new', + '#define v3_name_constraints GRPC_SHADOW_v3_name_constraints', + '#define v3_pci GRPC_SHADOW_v3_pci', + '#define PROXY_CERT_INFO_EXTENSION_free GRPC_SHADOW_PROXY_CERT_INFO_EXTENSION_free', + '#define PROXY_CERT_INFO_EXTENSION_it GRPC_SHADOW_PROXY_CERT_INFO_EXTENSION_it', + '#define PROXY_CERT_INFO_EXTENSION_new GRPC_SHADOW_PROXY_CERT_INFO_EXTENSION_new', + '#define PROXY_POLICY_free GRPC_SHADOW_PROXY_POLICY_free', + '#define PROXY_POLICY_it GRPC_SHADOW_PROXY_POLICY_it', + '#define PROXY_POLICY_new GRPC_SHADOW_PROXY_POLICY_new', + '#define d2i_PROXY_CERT_INFO_EXTENSION GRPC_SHADOW_d2i_PROXY_CERT_INFO_EXTENSION', + '#define d2i_PROXY_POLICY GRPC_SHADOW_d2i_PROXY_POLICY', + '#define i2d_PROXY_CERT_INFO_EXTENSION GRPC_SHADOW_i2d_PROXY_CERT_INFO_EXTENSION', + '#define i2d_PROXY_POLICY GRPC_SHADOW_i2d_PROXY_POLICY', + '#define POLICY_CONSTRAINTS_free GRPC_SHADOW_POLICY_CONSTRAINTS_free', + '#define POLICY_CONSTRAINTS_it GRPC_SHADOW_POLICY_CONSTRAINTS_it', + '#define POLICY_CONSTRAINTS_new GRPC_SHADOW_POLICY_CONSTRAINTS_new', + '#define v3_policy_constraints GRPC_SHADOW_v3_policy_constraints', + '#define PKEY_USAGE_PERIOD_free GRPC_SHADOW_PKEY_USAGE_PERIOD_free', + '#define PKEY_USAGE_PERIOD_it GRPC_SHADOW_PKEY_USAGE_PERIOD_it', + '#define PKEY_USAGE_PERIOD_new GRPC_SHADOW_PKEY_USAGE_PERIOD_new', + '#define d2i_PKEY_USAGE_PERIOD GRPC_SHADOW_d2i_PKEY_USAGE_PERIOD', + '#define i2d_PKEY_USAGE_PERIOD GRPC_SHADOW_i2d_PKEY_USAGE_PERIOD', + '#define v3_pkey_usage_period GRPC_SHADOW_v3_pkey_usage_period', + '#define POLICY_MAPPINGS_it GRPC_SHADOW_POLICY_MAPPINGS_it', + '#define POLICY_MAPPING_free GRPC_SHADOW_POLICY_MAPPING_free', + '#define POLICY_MAPPING_it GRPC_SHADOW_POLICY_MAPPING_it', + '#define POLICY_MAPPING_new GRPC_SHADOW_POLICY_MAPPING_new', + '#define v3_policy_mappings GRPC_SHADOW_v3_policy_mappings', + '#define X509V3_EXT_print GRPC_SHADOW_X509V3_EXT_print', + '#define X509V3_EXT_print_fp GRPC_SHADOW_X509V3_EXT_print_fp', + '#define X509V3_EXT_val_prn GRPC_SHADOW_X509V3_EXT_val_prn', + '#define X509V3_extensions_print GRPC_SHADOW_X509V3_extensions_print', + '#define X509_PURPOSE_add GRPC_SHADOW_X509_PURPOSE_add', + '#define X509_PURPOSE_cleanup GRPC_SHADOW_X509_PURPOSE_cleanup', + '#define X509_PURPOSE_get0 GRPC_SHADOW_X509_PURPOSE_get0', + '#define X509_PURPOSE_get0_name GRPC_SHADOW_X509_PURPOSE_get0_name', + '#define X509_PURPOSE_get0_sname GRPC_SHADOW_X509_PURPOSE_get0_sname', + '#define X509_PURPOSE_get_by_id GRPC_SHADOW_X509_PURPOSE_get_by_id', + '#define X509_PURPOSE_get_by_sname GRPC_SHADOW_X509_PURPOSE_get_by_sname', + '#define X509_PURPOSE_get_count GRPC_SHADOW_X509_PURPOSE_get_count', + '#define X509_PURPOSE_get_id GRPC_SHADOW_X509_PURPOSE_get_id', + '#define X509_PURPOSE_get_trust GRPC_SHADOW_X509_PURPOSE_get_trust', + '#define X509_PURPOSE_set GRPC_SHADOW_X509_PURPOSE_set', + '#define X509_check_akid GRPC_SHADOW_X509_check_akid', + '#define X509_check_ca GRPC_SHADOW_X509_check_ca', + '#define X509_check_issued GRPC_SHADOW_X509_check_issued', + '#define X509_check_purpose GRPC_SHADOW_X509_check_purpose', + '#define X509_supported_extension GRPC_SHADOW_X509_supported_extension', + '#define i2s_ASN1_OCTET_STRING GRPC_SHADOW_i2s_ASN1_OCTET_STRING', + '#define s2i_ASN1_OCTET_STRING GRPC_SHADOW_s2i_ASN1_OCTET_STRING', + '#define v3_skey_id GRPC_SHADOW_v3_skey_id', + '#define SXNETID_free GRPC_SHADOW_SXNETID_free', + '#define SXNETID_it GRPC_SHADOW_SXNETID_it', + '#define SXNETID_new GRPC_SHADOW_SXNETID_new', + '#define SXNET_add_id_INTEGER GRPC_SHADOW_SXNET_add_id_INTEGER', + '#define SXNET_add_id_asc GRPC_SHADOW_SXNET_add_id_asc', + '#define SXNET_add_id_ulong GRPC_SHADOW_SXNET_add_id_ulong', + '#define SXNET_free GRPC_SHADOW_SXNET_free', + '#define SXNET_get_id_INTEGER GRPC_SHADOW_SXNET_get_id_INTEGER', + '#define SXNET_get_id_asc GRPC_SHADOW_SXNET_get_id_asc', + '#define SXNET_get_id_ulong GRPC_SHADOW_SXNET_get_id_ulong', + '#define SXNET_it GRPC_SHADOW_SXNET_it', + '#define SXNET_new GRPC_SHADOW_SXNET_new', + '#define d2i_SXNET GRPC_SHADOW_d2i_SXNET', + '#define d2i_SXNETID GRPC_SHADOW_d2i_SXNETID', + '#define i2d_SXNET GRPC_SHADOW_i2d_SXNET', + '#define i2d_SXNETID GRPC_SHADOW_i2d_SXNETID', + '#define v3_sxnet GRPC_SHADOW_v3_sxnet', + '#define X509V3_NAME_from_section GRPC_SHADOW_X509V3_NAME_from_section', + '#define X509V3_add_value GRPC_SHADOW_X509V3_add_value', + '#define X509V3_add_value_bool GRPC_SHADOW_X509V3_add_value_bool', + '#define X509V3_add_value_bool_nf GRPC_SHADOW_X509V3_add_value_bool_nf', + '#define X509V3_add_value_int GRPC_SHADOW_X509V3_add_value_int', + '#define X509V3_add_value_uchar GRPC_SHADOW_X509V3_add_value_uchar', + '#define X509V3_conf_free GRPC_SHADOW_X509V3_conf_free', + '#define X509V3_get_value_bool GRPC_SHADOW_X509V3_get_value_bool', + '#define X509V3_get_value_int GRPC_SHADOW_X509V3_get_value_int', + '#define X509V3_parse_list GRPC_SHADOW_X509V3_parse_list', + '#define X509_REQ_get1_email GRPC_SHADOW_X509_REQ_get1_email', + '#define X509_check_email GRPC_SHADOW_X509_check_email', + '#define X509_check_host GRPC_SHADOW_X509_check_host', + '#define X509_check_ip GRPC_SHADOW_X509_check_ip', + '#define X509_check_ip_asc GRPC_SHADOW_X509_check_ip_asc', + '#define X509_email_free GRPC_SHADOW_X509_email_free', + '#define X509_get1_email GRPC_SHADOW_X509_get1_email', + '#define X509_get1_ocsp GRPC_SHADOW_X509_get1_ocsp', + '#define a2i_IPADDRESS GRPC_SHADOW_a2i_IPADDRESS', + '#define a2i_IPADDRESS_NC GRPC_SHADOW_a2i_IPADDRESS_NC', + '#define a2i_ipadd GRPC_SHADOW_a2i_ipadd', + '#define hex_to_string GRPC_SHADOW_hex_to_string', + '#define i2s_ASN1_ENUMERATED GRPC_SHADOW_i2s_ASN1_ENUMERATED', + '#define i2s_ASN1_INTEGER GRPC_SHADOW_i2s_ASN1_INTEGER', + '#define name_cmp GRPC_SHADOW_name_cmp', + '#define s2i_ASN1_INTEGER GRPC_SHADOW_s2i_ASN1_INTEGER', + '#define string_to_hex GRPC_SHADOW_string_to_hex', + '#define PKCS7_get_raw_certificates GRPC_SHADOW_PKCS7_get_raw_certificates', + '#define pkcs7_bundle GRPC_SHADOW_pkcs7_bundle', + '#define pkcs7_parse_header GRPC_SHADOW_pkcs7_parse_header', + '#define PKCS7_bundle_CRLs GRPC_SHADOW_PKCS7_bundle_CRLs', + '#define PKCS7_bundle_certificates GRPC_SHADOW_PKCS7_bundle_certificates', + '#define PKCS7_get_CRLs GRPC_SHADOW_PKCS7_get_CRLs', + '#define PKCS7_get_PEM_CRLs GRPC_SHADOW_PKCS7_get_PEM_CRLs', + '#define PKCS7_get_PEM_certificates GRPC_SHADOW_PKCS7_get_PEM_certificates', + '#define PKCS7_get_certificates GRPC_SHADOW_PKCS7_get_certificates', + '#define PKCS8_marshal_encrypted_private_key GRPC_SHADOW_PKCS8_marshal_encrypted_private_key', + '#define PKCS8_parse_encrypted_private_key GRPC_SHADOW_PKCS8_parse_encrypted_private_key', + '#define pkcs12_key_gen GRPC_SHADOW_pkcs12_key_gen', + '#define pkcs8_pbe_decrypt GRPC_SHADOW_pkcs8_pbe_decrypt', + '#define EVP_PKCS82PKEY GRPC_SHADOW_EVP_PKCS82PKEY', + '#define EVP_PKEY2PKCS8 GRPC_SHADOW_EVP_PKEY2PKCS8', + '#define PKCS12_PBE_add GRPC_SHADOW_PKCS12_PBE_add', + '#define PKCS12_free GRPC_SHADOW_PKCS12_free', + '#define PKCS12_get_key_and_certs GRPC_SHADOW_PKCS12_get_key_and_certs', + '#define PKCS12_parse GRPC_SHADOW_PKCS12_parse', + '#define PKCS12_verify_mac GRPC_SHADOW_PKCS12_verify_mac', + '#define PKCS8_PRIV_KEY_INFO_free GRPC_SHADOW_PKCS8_PRIV_KEY_INFO_free', + '#define PKCS8_PRIV_KEY_INFO_it GRPC_SHADOW_PKCS8_PRIV_KEY_INFO_it', + '#define PKCS8_PRIV_KEY_INFO_new GRPC_SHADOW_PKCS8_PRIV_KEY_INFO_new', + '#define PKCS8_decrypt GRPC_SHADOW_PKCS8_decrypt', + '#define PKCS8_encrypt GRPC_SHADOW_PKCS8_encrypt', + '#define d2i_PKCS12 GRPC_SHADOW_d2i_PKCS12', + '#define d2i_PKCS12_bio GRPC_SHADOW_d2i_PKCS12_bio', + '#define d2i_PKCS12_fp GRPC_SHADOW_d2i_PKCS12_fp', + '#define d2i_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_d2i_PKCS8_PRIV_KEY_INFO', + '#define i2d_PKCS8_PRIV_KEY_INFO GRPC_SHADOW_i2d_PKCS8_PRIV_KEY_INFO', + '#define PKCS5_pbe2_decrypt_init GRPC_SHADOW_PKCS5_pbe2_decrypt_init', + '#define PKCS5_pbe2_encrypt_init GRPC_SHADOW_PKCS5_pbe2_encrypt_init' +end diff --git a/src/objective-c/BoringSSL.podspec b/src/objective-c/BoringSSL.podspec deleted file mode 100644 index dc56680393..0000000000 --- a/src/objective-c/BoringSSL.podspec +++ /dev/null @@ -1,1539 +0,0 @@ -# BoringSSL CocoaPods podspec - -# Copyright 2015, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Pod::Spec.new do |s| - s.name = 'BoringSSL' - version = '10.0.6' - s.version = version - s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.' - # Adapted from the homepage: - s.description = <<-DESC - BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs. - - Although BoringSSL is an open source project, it is not intended for general use, as OpenSSL is. - We don’t recommend that third parties depend upon it. Doing so is likely to be frustrating - because there are no guarantees of API stability. Only the latest version of this pod is - supported, and every new version is a new major version. - - We update Google libraries and programs that use BoringSSL as needed when deciding to make API - changes. This allows us to mostly avoid compromises in the name of compatibility. It works for - us, but it may not work for you. - - As a Cocoapods pod, it has the advantage over OpenSSL's pods that the library doesn't need to - be precompiled. This eliminates the 10 - 20 minutes of wait the first time a user does "pod - install", lets it be used as a dynamic framework (pending solution of Cocoapods' issue #4605), - and works with bitcode automatically. It's also thought to be smaller than OpenSSL (which takes - 1MB - 2MB per ARM architecture), but we don't have specific numbers yet. - - BoringSSL arose because Google used OpenSSL for many years in various ways and, over time, built - up a large number of patches that were maintained while tracking upstream OpenSSL. As Google’s - product portfolio became more complex, more copies of OpenSSL sprung up and the effort involved - in maintaining all these patches in multiple places was growing steadily. - - Currently BoringSSL is the SSL library in Chrome/Chromium, Android (but it’s not part of the - NDK) and a number of other apps/programs. - DESC - s.homepage = 'https://github.com/google/boringssl' - s.license = { :type => 'Mixed', :file => 'LICENSE' } - # "The name and email addresses of the library maintainers, not the Podspec maintainer." - s.authors = 'Adam Langley', 'David Benjamin', 'Matt Braithwaite' - - s.source = { - :git => 'https://github.com/google/boringssl.git', - :commit => "b29b21a81b32ec273f118f589f46d56ad3332420", - } - - s.ios.deployment_target = '5.0' - s.osx.deployment_target = '10.7' - - name = 'openssl' - - # When creating a dynamic framework, name it openssl.framework instead of BoringSSL.framework. - # This lets users write their includes like `#include <openssl/ssl.h>` as opposed to `#include - # <BoringSSL/ssl.h>`. - s.module_name = name - - # When creating a dynamic framework, copy the headers under `include/openssl/` into the root of - # the `Headers/` directory of the framework (i.e., not under `Headers/include/openssl`). - # - # TODO(jcanizales): Debug why this doesn't work on macOS. - s.header_mappings_dir = 'include/openssl' - - # The above has an undesired effect when creating a static library: It forces users to write - # includes like `#include <BoringSSL/ssl.h>`. `s.header_dir` adds a path prefix to that, and - # because Cocoapods lets omit the pod name when including headers of static libraries, the - # following lets users write `#include <openssl/ssl.h>`. - s.header_dir = name - - # The module map and umbrella header created automatically by Cocoapods don't work for C libraries - # like this one. The following file, and a correct umbrella header, are created on the fly by the - # `prepare_command` of this pod. - s.module_map = 'include/openssl/BoringSSL.modulemap' - - # We don't need to inhibit all warnings; only -Wno-shorten-64-to-32. But Cocoapods' linter doesn't - # want that for some reason. - s.compiler_flags = '-DOPENSSL_NO_ASM', '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w' - s.requires_arc = false - - # Like many other C libraries, BoringSSL has its public headers under `include/<libname>/` and its - # sources and private headers in other directories outside `include/`. Cocoapods' linter doesn't - # allow any header to be listed outside the `header_mappings_dir` (even though doing so works in - # practice). Because we need our `header_mappings_dir` to be `include/openssl/` for the reason - # mentioned above, we work around the linter limitation by dividing the pod into two subspecs, one - # for public headers and the other for implementation. Each gets its own `header_mappings_dir`, - # making the linter happy. - s.subspec 'Interface' do |ss| - ss.header_mappings_dir = 'include/openssl' - ss.source_files = 'include/openssl/*.h' - end - s.subspec 'Implementation' do |ss| - ss.header_mappings_dir = '.' - ss.source_files = 'ssl/*.{h,cc}', - 'ssl/**/*.{h,cc}', - '*.{h,c}', - 'crypto/*.{h,c}', - 'crypto/**/*.{h,c}', - 'third_party/fiat/*.{h,c}' - ss.private_header_files = 'ssl/*.h', - 'ssl/**/*.h', - '*.h', - 'crypto/*.h', - 'crypto/**/*.h' - # bcm.c includes other source files, creating duplicated symbols. Since it is not used, we - # explicitly exclude it from the pod. - # TODO (mxyan): Work with BoringSSL team to remove this hack. - ss.exclude_files = 'crypto/fipsmodule/bcm.c', - '**/*_test.*', - '**/test_*.*', - '**/test/*.*' - - ss.dependency "#{s.name}/Interface", version - end - - s.prepare_command = <<-END_OF_COMMAND - # Add a module map and an umbrella header - cat > include/openssl/umbrella.h <<EOF - #include "ssl.h" - #include "crypto.h" - #include "aes.h" - /* The following macros are defined by base.h. The latter is the first file included by the - other headers. */ - #if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) - # include "arm_arch.h" - #endif - #include "asn1.h" - #include "asn1_mac.h" - #include "asn1t.h" - #include "blowfish.h" - #include "cast.h" - #include "chacha.h" - #include "cmac.h" - #include "conf.h" - #include "cpu.h" - #include "curve25519.h" - #include "des.h" - #include "dtls1.h" - #include "hkdf.h" - #include "md4.h" - #include "md5.h" - #include "obj_mac.h" - #include "objects.h" - #include "opensslv.h" - #include "ossl_typ.h" - #include "pkcs12.h" - #include "pkcs7.h" - #include "pkcs8.h" - #include "poly1305.h" - #include "rand.h" - #include "rc4.h" - #include "ripemd.h" - #include "safestack.h" - #include "srtp.h" - #include "x509.h" - #include "x509v3.h" - EOF - cat > include/openssl/BoringSSL.modulemap <<EOF - framework module openssl { - umbrella header "umbrella.h" - textual header "arm_arch.h" - export * - module * { export * } - } - EOF - - # This is a bit ridiculous, but requiring people to install Go in order to build is slightly - # more ridiculous IMO. To save you from scrolling, this is the last part of the podspec. - # TODO(jcanizales): Translate err_data_generate.go into a Bash or Ruby script. - cat > err_data.c <<EOF - /* Copyright (c) 2015, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - - /* This file was generated by err_data_generate.go. */ - - #include <openssl/base.h> - #include <openssl/err.h> - #include <openssl/type_check.h> - - - OPENSSL_COMPILE_ASSERT(ERR_LIB_NONE == 1, library_values_changed_1); - OPENSSL_COMPILE_ASSERT(ERR_LIB_SYS == 2, library_values_changed_2); - OPENSSL_COMPILE_ASSERT(ERR_LIB_BN == 3, library_values_changed_3); - OPENSSL_COMPILE_ASSERT(ERR_LIB_RSA == 4, library_values_changed_4); - OPENSSL_COMPILE_ASSERT(ERR_LIB_DH == 5, library_values_changed_5); - OPENSSL_COMPILE_ASSERT(ERR_LIB_EVP == 6, library_values_changed_6); - OPENSSL_COMPILE_ASSERT(ERR_LIB_BUF == 7, library_values_changed_7); - OPENSSL_COMPILE_ASSERT(ERR_LIB_OBJ == 8, library_values_changed_8); - OPENSSL_COMPILE_ASSERT(ERR_LIB_PEM == 9, library_values_changed_9); - OPENSSL_COMPILE_ASSERT(ERR_LIB_DSA == 10, library_values_changed_10); - OPENSSL_COMPILE_ASSERT(ERR_LIB_X509 == 11, library_values_changed_11); - OPENSSL_COMPILE_ASSERT(ERR_LIB_ASN1 == 12, library_values_changed_12); - OPENSSL_COMPILE_ASSERT(ERR_LIB_CONF == 13, library_values_changed_13); - OPENSSL_COMPILE_ASSERT(ERR_LIB_CRYPTO == 14, library_values_changed_14); - OPENSSL_COMPILE_ASSERT(ERR_LIB_EC == 15, library_values_changed_15); - OPENSSL_COMPILE_ASSERT(ERR_LIB_SSL == 16, library_values_changed_16); - OPENSSL_COMPILE_ASSERT(ERR_LIB_BIO == 17, library_values_changed_17); - OPENSSL_COMPILE_ASSERT(ERR_LIB_PKCS7 == 18, library_values_changed_18); - OPENSSL_COMPILE_ASSERT(ERR_LIB_PKCS8 == 19, library_values_changed_19); - OPENSSL_COMPILE_ASSERT(ERR_LIB_X509V3 == 20, library_values_changed_20); - OPENSSL_COMPILE_ASSERT(ERR_LIB_RAND == 21, library_values_changed_21); - OPENSSL_COMPILE_ASSERT(ERR_LIB_ENGINE == 22, library_values_changed_22); - OPENSSL_COMPILE_ASSERT(ERR_LIB_OCSP == 23, library_values_changed_23); - OPENSSL_COMPILE_ASSERT(ERR_LIB_UI == 24, library_values_changed_24); - OPENSSL_COMPILE_ASSERT(ERR_LIB_COMP == 25, library_values_changed_25); - OPENSSL_COMPILE_ASSERT(ERR_LIB_ECDSA == 26, library_values_changed_26); - OPENSSL_COMPILE_ASSERT(ERR_LIB_ECDH == 27, library_values_changed_27); - OPENSSL_COMPILE_ASSERT(ERR_LIB_HMAC == 28, library_values_changed_28); - OPENSSL_COMPILE_ASSERT(ERR_LIB_DIGEST == 29, library_values_changed_29); - OPENSSL_COMPILE_ASSERT(ERR_LIB_CIPHER == 30, library_values_changed_30); - OPENSSL_COMPILE_ASSERT(ERR_LIB_HKDF == 31, library_values_changed_31); - OPENSSL_COMPILE_ASSERT(ERR_LIB_USER == 32, library_values_changed_32); - OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == 33, library_values_changed_num); - - const uint32_t kOpenSSLReasonValues[] = { - 0xc320838, - 0xc328852, - 0xc330861, - 0xc338871, - 0xc340880, - 0xc348899, - 0xc3508a5, - 0xc3588c2, - 0xc3608e2, - 0xc3688f0, - 0xc370900, - 0xc37890d, - 0xc38091d, - 0xc388928, - 0xc39093e, - 0xc39894d, - 0xc3a0961, - 0xc3a8845, - 0xc3b00ea, - 0xc3b88d4, - 0x10320845, - 0x10329513, - 0x1033151f, - 0x10339538, - 0x1034154b, - 0x10348eed, - 0x10350c5e, - 0x1035955e, - 0x10361573, - 0x10369586, - 0x103715a5, - 0x103795be, - 0x103815d3, - 0x103895f1, - 0x10391600, - 0x1039961c, - 0x103a1637, - 0x103a9646, - 0x103b1662, - 0x103b967d, - 0x103c1694, - 0x103c80ea, - 0x103d16a5, - 0x103d96b9, - 0x103e16d8, - 0x103e96e7, - 0x103f16fe, - 0x103f9711, - 0x10400c22, - 0x10409724, - 0x10411742, - 0x10419755, - 0x1042176f, - 0x1042977f, - 0x10431793, - 0x104397a9, - 0x104417c1, - 0x104497d6, - 0x104517ea, - 0x104597fc, - 0x104605fb, - 0x1046894d, - 0x10471811, - 0x10479828, - 0x1048183d, - 0x1048984b, - 0x10490e4f, - 0x14320c05, - 0x14328c13, - 0x14330c22, - 0x14338c34, - 0x143400ac, - 0x143480ea, - 0x18320083, - 0x18328f43, - 0x183300ac, - 0x18338f59, - 0x18340f6d, - 0x183480ea, - 0x18350f82, - 0x18358f9a, - 0x18360faf, - 0x18368fc3, - 0x18370fe7, - 0x18378ffd, - 0x18381011, - 0x18389021, - 0x18390a73, - 0x18399031, - 0x183a1059, - 0x183a907f, - 0x183b0c6a, - 0x183b90b4, - 0x183c10c6, - 0x183c90d1, - 0x183d10e1, - 0x183d90f2, - 0x183e1103, - 0x183e9115, - 0x183f113e, - 0x183f9157, - 0x1840116f, - 0x184086d3, - 0x184110a2, - 0x1841906d, - 0x1842108c, - 0x18429046, - 0x20321196, - 0x243211a2, - 0x24328993, - 0x243311b4, - 0x243391c1, - 0x243411ce, - 0x243491e0, - 0x243511ef, - 0x2435920c, - 0x24361219, - 0x24369227, - 0x24371235, - 0x24379243, - 0x2438124c, - 0x24389259, - 0x2439126c, - 0x28320c52, - 0x28328c6a, - 0x28330c22, - 0x28338c7d, - 0x28340c5e, - 0x283480ac, - 0x283500ea, - 0x2c322c30, - 0x2c329283, - 0x2c332c3e, - 0x2c33ac50, - 0x2c342c64, - 0x2c34ac76, - 0x2c352c91, - 0x2c35aca3, - 0x2c362cb6, - 0x2c36832d, - 0x2c372cc3, - 0x2c37acd5, - 0x2c382cfa, - 0x2c38ad11, - 0x2c392d1f, - 0x2c39ad2f, - 0x2c3a2d41, - 0x2c3aad55, - 0x2c3b2d66, - 0x2c3bad85, - 0x2c3c1295, - 0x2c3c92ab, - 0x2c3d2d99, - 0x2c3d92c4, - 0x2c3e2db6, - 0x2c3eadc4, - 0x2c3f2ddc, - 0x2c3fadf4, - 0x2c402e01, - 0x2c409196, - 0x2c412e12, - 0x2c41ae25, - 0x2c42116f, - 0x2c42ae36, - 0x2c430720, - 0x2c43ad77, - 0x2c442ce8, - 0x30320000, - 0x30328015, - 0x3033001f, - 0x30338038, - 0x3034004a, - 0x30348064, - 0x3035006b, - 0x30358083, - 0x30360094, - 0x303680ac, - 0x303700b9, - 0x303780c8, - 0x303800ea, - 0x303880f7, - 0x3039010a, - 0x30398125, - 0x303a013a, - 0x303a814e, - 0x303b0162, - 0x303b8173, - 0x303c018c, - 0x303c81a9, - 0x303d01b7, - 0x303d81cb, - 0x303e01db, - 0x303e81f4, - 0x303f0204, - 0x303f8217, - 0x30400226, - 0x30408232, - 0x30410247, - 0x30418257, - 0x3042026e, - 0x3042827b, - 0x3043028e, - 0x3043829d, - 0x304402b2, - 0x304482d3, - 0x304502e6, - 0x304582f9, - 0x30460312, - 0x3046832d, - 0x3047034a, - 0x30478363, - 0x30480371, - 0x30488382, - 0x30490391, - 0x304983a9, - 0x304a03bb, - 0x304a83cf, - 0x304b03ee, - 0x304b8401, - 0x304c040c, - 0x304c841d, - 0x304d0429, - 0x304d843f, - 0x304e044d, - 0x304e8463, - 0x304f0475, - 0x304f8487, - 0x3050049a, - 0x305084ad, - 0x305104be, - 0x305184ce, - 0x305204e6, - 0x305284fb, - 0x30530513, - 0x30538527, - 0x3054053f, - 0x30548558, - 0x30550571, - 0x3055858e, - 0x30560599, - 0x305685b1, - 0x305705c1, - 0x305785d2, - 0x305805e5, - 0x305885fb, - 0x30590604, - 0x30598619, - 0x305a062c, - 0x305a863b, - 0x305b065b, - 0x305b866a, - 0x305c068b, - 0x305c86a7, - 0x305d06b3, - 0x305d86d3, - 0x305e06ef, - 0x305e8700, - 0x305f0716, - 0x305f8720, - 0x34320b63, - 0x34328b77, - 0x34330b94, - 0x34338ba7, - 0x34340bb6, - 0x34348bef, - 0x34350bd3, - 0x3c320083, - 0x3c328ca7, - 0x3c330cc0, - 0x3c338cdb, - 0x3c340cf8, - 0x3c348d22, - 0x3c350d3d, - 0x3c358d63, - 0x3c360d7c, - 0x3c368d94, - 0x3c370da5, - 0x3c378db3, - 0x3c380dc0, - 0x3c388dd4, - 0x3c390c6a, - 0x3c398de8, - 0x3c3a0dfc, - 0x3c3a890d, - 0x3c3b0e0c, - 0x3c3b8e27, - 0x3c3c0e39, - 0x3c3c8e6c, - 0x3c3d0e76, - 0x3c3d8e8a, - 0x3c3e0e98, - 0x3c3e8ebd, - 0x3c3f0c93, - 0x3c3f8ea6, - 0x3c4000ac, - 0x3c4080ea, - 0x3c410d13, - 0x3c418d52, - 0x3c420e4f, - 0x403218a4, - 0x403298ba, - 0x403318e8, - 0x403398f2, - 0x40341909, - 0x40349927, - 0x40351937, - 0x40359949, - 0x40361956, - 0x40369962, - 0x40371977, - 0x40379989, - 0x40381994, - 0x403899a6, - 0x40390eed, - 0x403999b6, - 0x403a19c9, - 0x403a99ea, - 0x403b19fb, - 0x403b9a0b, - 0x403c0064, - 0x403c8083, - 0x403d1a8f, - 0x403d9aa5, - 0x403e1ab4, - 0x403e9aec, - 0x403f1b06, - 0x403f9b14, - 0x40401b29, - 0x40409b3d, - 0x40411b5a, - 0x40419b75, - 0x40421b8e, - 0x40429ba1, - 0x40431bb5, - 0x40439bcd, - 0x40441be4, - 0x404480ac, - 0x40451bf9, - 0x40459c0b, - 0x40461c2f, - 0x40469c4f, - 0x40471c5d, - 0x40479c84, - 0x40481cc1, - 0x40489cda, - 0x40491cf1, - 0x40499d0b, - 0x404a1d22, - 0x404a9d40, - 0x404b1d58, - 0x404b9d6f, - 0x404c1d85, - 0x404c9d97, - 0x404d1db8, - 0x404d9dda, - 0x404e1dee, - 0x404e9dfb, - 0x404f1e28, - 0x404f9e51, - 0x40501e8c, - 0x40509ea0, - 0x40511ebb, - 0x40521ecb, - 0x40529eef, - 0x40531f07, - 0x40539f1a, - 0x40541f2f, - 0x40549f52, - 0x40551f60, - 0x40559f7d, - 0x40561f8a, - 0x40569fa3, - 0x40571fbb, - 0x40579fce, - 0x40581fe3, - 0x4058a00a, - 0x40592039, - 0x4059a066, - 0x405a207a, - 0x405aa08a, - 0x405b20a2, - 0x405ba0b3, - 0x405c20c6, - 0x405ca105, - 0x405d2112, - 0x405da129, - 0x405e2167, - 0x405e8ab1, - 0x405f2188, - 0x405fa195, - 0x406021a3, - 0x4060a1c5, - 0x40612209, - 0x4061a241, - 0x40622258, - 0x4062a269, - 0x4063227a, - 0x4063a28f, - 0x406422a6, - 0x4064a2d2, - 0x406522ed, - 0x4065a304, - 0x4066231c, - 0x4066a346, - 0x40672371, - 0x4067a392, - 0x406823b9, - 0x4068a3da, - 0x4069240c, - 0x4069a43a, - 0x406a245b, - 0x406aa47b, - 0x406b2603, - 0x406ba626, - 0x406c263c, - 0x406ca8b7, - 0x406d28e6, - 0x406da90e, - 0x406e293c, - 0x406ea989, - 0x406f29a8, - 0x406fa9e0, - 0x407029f3, - 0x4070aa10, - 0x40710800, - 0x4071aa22, - 0x40722a35, - 0x4072aa4e, - 0x40732a66, - 0x40739482, - 0x40742a7a, - 0x4074aa94, - 0x40752aa5, - 0x4075aab9, - 0x40762ac7, - 0x40769259, - 0x40772aec, - 0x4077ab0e, - 0x40782b29, - 0x4078ab62, - 0x40792b79, - 0x4079ab8f, - 0x407a2b9b, - 0x407aabae, - 0x407b2bc3, - 0x407babd5, - 0x407c2c06, - 0x407cac0f, - 0x407d23f5, - 0x407d9e61, - 0x407e2b3e, - 0x407ea01a, - 0x407f1c71, - 0x407f9a31, - 0x40801e38, - 0x40809c99, - 0x40811edd, - 0x40819e12, - 0x40822927, - 0x40829a17, - 0x40831ff5, - 0x4083a2b7, - 0x40841cad, - 0x4084a052, - 0x408520d7, - 0x4085a1ed, - 0x40862149, - 0x40869e7b, - 0x4087296d, - 0x4087a21e, - 0x40881a78, - 0x4088a3a5, - 0x40891ac7, - 0x40899a54, - 0x408a265c, - 0x408a9862, - 0x408b2bea, - 0x408ba9bd, - 0x408c20e7, - 0x408c987e, - 0x41f4252e, - 0x41f925c0, - 0x41fe24b3, - 0x41fea6a8, - 0x41ff2799, - 0x42032547, - 0x42082569, - 0x4208a5a5, - 0x42092497, - 0x4209a5df, - 0x420a24ee, - 0x420aa4ce, - 0x420b250e, - 0x420ba587, - 0x420c27b5, - 0x420ca675, - 0x420d268f, - 0x420da6c6, - 0x421226e0, - 0x4217277c, - 0x4217a722, - 0x421c2744, - 0x421f26ff, - 0x422127cc, - 0x4226275f, - 0x422b289b, - 0x422ba849, - 0x422c2883, - 0x422ca808, - 0x422d27e7, - 0x422da868, - 0x422e282e, - 0x422ea954, - 0x4432072b, - 0x4432873a, - 0x44330746, - 0x44338754, - 0x44340767, - 0x44348778, - 0x4435077f, - 0x44358789, - 0x4436079c, - 0x443687b2, - 0x443707c4, - 0x443787d1, - 0x443807e0, - 0x443887e8, - 0x44390800, - 0x4439880e, - 0x443a0821, - 0x48321283, - 0x48329295, - 0x483312ab, - 0x483392c4, - 0x4c3212e9, - 0x4c3292f9, - 0x4c33130c, - 0x4c33932c, - 0x4c3400ac, - 0x4c3480ea, - 0x4c351338, - 0x4c359346, - 0x4c361362, - 0x4c369375, - 0x4c371384, - 0x4c379392, - 0x4c3813a7, - 0x4c3893b3, - 0x4c3913d3, - 0x4c3993fd, - 0x4c3a1416, - 0x4c3a942f, - 0x4c3b05fb, - 0x4c3b9448, - 0x4c3c145a, - 0x4c3c9469, - 0x4c3d1482, - 0x4c3d8c45, - 0x4c3e14db, - 0x4c3e9491, - 0x4c3f14fd, - 0x4c3f9259, - 0x4c4014a7, - 0x4c4092d5, - 0x4c4114cb, - 0x50322e48, - 0x5032ae57, - 0x50332e62, - 0x5033ae72, - 0x50342e8b, - 0x5034aea5, - 0x50352eb3, - 0x5035aec9, - 0x50362edb, - 0x5036aef1, - 0x50372f0a, - 0x5037af1d, - 0x50382f35, - 0x5038af46, - 0x50392f5b, - 0x5039af6f, - 0x503a2f8f, - 0x503aafa5, - 0x503b2fbd, - 0x503bafcf, - 0x503c2feb, - 0x503cb002, - 0x503d301b, - 0x503db031, - 0x503e303e, - 0x503eb054, - 0x503f3066, - 0x503f8382, - 0x50403079, - 0x5040b089, - 0x504130a3, - 0x5041b0b2, - 0x504230cc, - 0x5042b0e9, - 0x504330f9, - 0x5043b109, - 0x50443118, - 0x5044843f, - 0x5045312c, - 0x5045b14a, - 0x5046315d, - 0x5046b173, - 0x50473185, - 0x5047b19a, - 0x504831c0, - 0x5048b1ce, - 0x504931e1, - 0x5049b1f6, - 0x504a320c, - 0x504ab21c, - 0x504b323c, - 0x504bb24f, - 0x504c3272, - 0x504cb2a0, - 0x504d32b2, - 0x504db2cf, - 0x504e32ea, - 0x504eb306, - 0x504f3318, - 0x504fb32f, - 0x5050333e, - 0x505086ef, - 0x50513351, - 0x58320f2b, - 0x68320eed, - 0x68328c6a, - 0x68330c7d, - 0x68338efb, - 0x68340f0b, - 0x683480ea, - 0x6c320ec9, - 0x6c328c34, - 0x6c330ed4, - 0x74320a19, - 0x743280ac, - 0x74330c45, - 0x7832097e, - 0x78328993, - 0x7833099f, - 0x78338083, - 0x783409ae, - 0x783489c3, - 0x783509e2, - 0x78358a04, - 0x78360a19, - 0x78368a2f, - 0x78370a3f, - 0x78378a60, - 0x78380a73, - 0x78388a85, - 0x78390a92, - 0x78398ab1, - 0x783a0ac6, - 0x783a8ad4, - 0x783b0ade, - 0x783b8af2, - 0x783c0b09, - 0x783c8b1e, - 0x783d0b35, - 0x783d8b4a, - 0x783e0aa0, - 0x783e8a52, - 0x7c321185, - }; - - const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]); - - const char kOpenSSLReasonStringData[] = - "ASN1_LENGTH_MISMATCH\\0" - "AUX_ERROR\\0" - "BAD_GET_ASN1_OBJECT_CALL\\0" - "BAD_OBJECT_HEADER\\0" - "BMPSTRING_IS_WRONG_LENGTH\\0" - "BN_LIB\\0" - "BOOLEAN_IS_WRONG_LENGTH\\0" - "BUFFER_TOO_SMALL\\0" - "CONTEXT_NOT_INITIALISED\\0" - "DECODE_ERROR\\0" - "DEPTH_EXCEEDED\\0" - "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED\\0" - "ENCODE_ERROR\\0" - "ERROR_GETTING_TIME\\0" - "EXPECTING_AN_ASN1_SEQUENCE\\0" - "EXPECTING_AN_INTEGER\\0" - "EXPECTING_AN_OBJECT\\0" - "EXPECTING_A_BOOLEAN\\0" - "EXPECTING_A_TIME\\0" - "EXPLICIT_LENGTH_MISMATCH\\0" - "EXPLICIT_TAG_NOT_CONSTRUCTED\\0" - "FIELD_MISSING\\0" - "FIRST_NUM_TOO_LARGE\\0" - "HEADER_TOO_LONG\\0" - "ILLEGAL_BITSTRING_FORMAT\\0" - "ILLEGAL_BOOLEAN\\0" - "ILLEGAL_CHARACTERS\\0" - "ILLEGAL_FORMAT\\0" - "ILLEGAL_HEX\\0" - "ILLEGAL_IMPLICIT_TAG\\0" - "ILLEGAL_INTEGER\\0" - "ILLEGAL_NESTED_TAGGING\\0" - "ILLEGAL_NULL\\0" - "ILLEGAL_NULL_VALUE\\0" - "ILLEGAL_OBJECT\\0" - "ILLEGAL_OPTIONAL_ANY\\0" - "ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE\\0" - "ILLEGAL_TAGGED_ANY\\0" - "ILLEGAL_TIME_VALUE\\0" - "INTEGER_NOT_ASCII_FORMAT\\0" - "INTEGER_TOO_LARGE_FOR_LONG\\0" - "INVALID_BIT_STRING_BITS_LEFT\\0" - "INVALID_BMPSTRING_LENGTH\\0" - "INVALID_DIGIT\\0" - "INVALID_MODIFIER\\0" - "INVALID_NUMBER\\0" - "INVALID_OBJECT_ENCODING\\0" - "INVALID_SEPARATOR\\0" - "INVALID_TIME_FORMAT\\0" - "INVALID_UNIVERSALSTRING_LENGTH\\0" - "INVALID_UTF8STRING\\0" - "LIST_ERROR\\0" - "MISSING_ASN1_EOS\\0" - "MISSING_EOC\\0" - "MISSING_SECOND_NUMBER\\0" - "MISSING_VALUE\\0" - "MSTRING_NOT_UNIVERSAL\\0" - "MSTRING_WRONG_TAG\\0" - "NESTED_ASN1_ERROR\\0" - "NESTED_ASN1_STRING\\0" - "NON_HEX_CHARACTERS\\0" - "NOT_ASCII_FORMAT\\0" - "NOT_ENOUGH_DATA\\0" - "NO_MATCHING_CHOICE_TYPE\\0" - "NULL_IS_WRONG_LENGTH\\0" - "OBJECT_NOT_ASCII_FORMAT\\0" - "ODD_NUMBER_OF_CHARS\\0" - "SECOND_NUMBER_TOO_LARGE\\0" - "SEQUENCE_LENGTH_MISMATCH\\0" - "SEQUENCE_NOT_CONSTRUCTED\\0" - "SEQUENCE_OR_SET_NEEDS_CONFIG\\0" - "SHORT_LINE\\0" - "STREAMING_NOT_SUPPORTED\\0" - "STRING_TOO_LONG\\0" - "STRING_TOO_SHORT\\0" - "TAG_VALUE_TOO_HIGH\\0" - "TIME_NOT_ASCII_FORMAT\\0" - "TOO_LONG\\0" - "TYPE_NOT_CONSTRUCTED\\0" - "TYPE_NOT_PRIMITIVE\\0" - "UNEXPECTED_EOC\\0" - "UNIVERSALSTRING_IS_WRONG_LENGTH\\0" - "UNKNOWN_FORMAT\\0" - "UNKNOWN_MESSAGE_DIGEST_ALGORITHM\\0" - "UNKNOWN_SIGNATURE_ALGORITHM\\0" - "UNKNOWN_TAG\\0" - "UNSUPPORTED_ANY_DEFINED_BY_TYPE\\0" - "UNSUPPORTED_PUBLIC_KEY_TYPE\\0" - "UNSUPPORTED_TYPE\\0" - "WRONG_PUBLIC_KEY_TYPE\\0" - "WRONG_TAG\\0" - "WRONG_TYPE\\0" - "BAD_FOPEN_MODE\\0" - "BROKEN_PIPE\\0" - "CONNECT_ERROR\\0" - "ERROR_SETTING_NBIO\\0" - "INVALID_ARGUMENT\\0" - "IN_USE\\0" - "KEEPALIVE\\0" - "NBIO_CONNECT_ERROR\\0" - "NO_HOSTNAME_SPECIFIED\\0" - "NO_PORT_SPECIFIED\\0" - "NO_SUCH_FILE\\0" - "NULL_PARAMETER\\0" - "SYS_LIB\\0" - "UNABLE_TO_CREATE_SOCKET\\0" - "UNINITIALIZED\\0" - "UNSUPPORTED_METHOD\\0" - "WRITE_TO_READ_ONLY_BIO\\0" - "ARG2_LT_ARG3\\0" - "BAD_ENCODING\\0" - "BAD_RECIPROCAL\\0" - "BIGNUM_TOO_LONG\\0" - "BITS_TOO_SMALL\\0" - "CALLED_WITH_EVEN_MODULUS\\0" - "DIV_BY_ZERO\\0" - "EXPAND_ON_STATIC_BIGNUM_DATA\\0" - "INPUT_NOT_REDUCED\\0" - "INVALID_INPUT\\0" - "INVALID_RANGE\\0" - "NEGATIVE_NUMBER\\0" - "NOT_A_SQUARE\\0" - "NOT_INITIALIZED\\0" - "NO_INVERSE\\0" - "PRIVATE_KEY_TOO_LARGE\\0" - "P_IS_NOT_PRIME\\0" - "TOO_MANY_ITERATIONS\\0" - "TOO_MANY_TEMPORARY_VARIABLES\\0" - "AES_KEY_SETUP_FAILED\\0" - "BAD_DECRYPT\\0" - "BAD_KEY_LENGTH\\0" - "CTRL_NOT_IMPLEMENTED\\0" - "CTRL_OPERATION_NOT_IMPLEMENTED\\0" - "DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH\\0" - "INITIALIZATION_ERROR\\0" - "INPUT_NOT_INITIALIZED\\0" - "INVALID_AD_SIZE\\0" - "INVALID_KEY_LENGTH\\0" - "INVALID_NONCE\\0" - "INVALID_NONCE_SIZE\\0" - "INVALID_OPERATION\\0" - "IV_TOO_LARGE\\0" - "NO_CIPHER_SET\\0" - "NO_DIRECTION_SET\\0" - "OUTPUT_ALIASES_INPUT\\0" - "TAG_TOO_LARGE\\0" - "TOO_LARGE\\0" - "UNSUPPORTED_AD_SIZE\\0" - "UNSUPPORTED_INPUT_SIZE\\0" - "UNSUPPORTED_KEY_SIZE\\0" - "UNSUPPORTED_NONCE_SIZE\\0" - "UNSUPPORTED_TAG_SIZE\\0" - "WRONG_FINAL_BLOCK_LENGTH\\0" - "LIST_CANNOT_BE_NULL\\0" - "MISSING_CLOSE_SQUARE_BRACKET\\0" - "MISSING_EQUAL_SIGN\\0" - "NO_CLOSE_BRACE\\0" - "UNABLE_TO_CREATE_NEW_SECTION\\0" - "VARIABLE_EXPANSION_TOO_LONG\\0" - "VARIABLE_HAS_NO_VALUE\\0" - "BAD_GENERATOR\\0" - "INVALID_PUBKEY\\0" - "MODULUS_TOO_LARGE\\0" - "NO_PRIVATE_VALUE\\0" - "UNKNOWN_HASH\\0" - "BAD_Q_VALUE\\0" - "BAD_VERSION\\0" - "MISSING_PARAMETERS\\0" - "NEED_NEW_SETUP_VALUES\\0" - "BIGNUM_OUT_OF_RANGE\\0" - "COORDINATES_OUT_OF_RANGE\\0" - "D2I_ECPKPARAMETERS_FAILURE\\0" - "EC_GROUP_NEW_BY_NAME_FAILURE\\0" - "GROUP2PKPARAMETERS_FAILURE\\0" - "GROUP_MISMATCH\\0" - "I2D_ECPKPARAMETERS_FAILURE\\0" - "INCOMPATIBLE_OBJECTS\\0" - "INVALID_COFACTOR\\0" - "INVALID_COMPRESSED_POINT\\0" - "INVALID_COMPRESSION_BIT\\0" - "INVALID_ENCODING\\0" - "INVALID_FIELD\\0" - "INVALID_FORM\\0" - "INVALID_GROUP_ORDER\\0" - "INVALID_PRIVATE_KEY\\0" - "MISSING_PRIVATE_KEY\\0" - "NON_NAMED_CURVE\\0" - "PKPARAMETERS2GROUP_FAILURE\\0" - "POINT_AT_INFINITY\\0" - "POINT_IS_NOT_ON_CURVE\\0" - "PUBLIC_KEY_VALIDATION_FAILED\\0" - "SLOT_FULL\\0" - "UNDEFINED_GENERATOR\\0" - "UNKNOWN_GROUP\\0" - "UNKNOWN_ORDER\\0" - "WRONG_CURVE_PARAMETERS\\0" - "WRONG_ORDER\\0" - "KDF_FAILED\\0" - "POINT_ARITHMETIC_FAILURE\\0" - "BAD_SIGNATURE\\0" - "NOT_IMPLEMENTED\\0" - "RANDOM_NUMBER_GENERATION_FAILED\\0" - "OPERATION_NOT_SUPPORTED\\0" - "COMMAND_NOT_SUPPORTED\\0" - "DIFFERENT_KEY_TYPES\\0" - "DIFFERENT_PARAMETERS\\0" - "EXPECTING_AN_EC_KEY_KEY\\0" - "EXPECTING_AN_RSA_KEY\\0" - "EXPECTING_A_DSA_KEY\\0" - "ILLEGAL_OR_UNSUPPORTED_PADDING_MODE\\0" - "INVALID_DIGEST_LENGTH\\0" - "INVALID_DIGEST_TYPE\\0" - "INVALID_KEYBITS\\0" - "INVALID_MGF1_MD\\0" - "INVALID_PADDING_MODE\\0" - "INVALID_PARAMETERS\\0" - "INVALID_PSS_SALTLEN\\0" - "INVALID_SIGNATURE\\0" - "KEYS_NOT_SET\\0" - "MEMORY_LIMIT_EXCEEDED\\0" - "NOT_A_PRIVATE_KEY\\0" - "NO_DEFAULT_DIGEST\\0" - "NO_KEY_SET\\0" - "NO_MDC2_SUPPORT\\0" - "NO_NID_FOR_CURVE\\0" - "NO_OPERATION_SET\\0" - "NO_PARAMETERS_SET\\0" - "OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE\\0" - "OPERATON_NOT_INITIALIZED\\0" - "UNKNOWN_PUBLIC_KEY_TYPE\\0" - "UNSUPPORTED_ALGORITHM\\0" - "OUTPUT_TOO_LARGE\\0" - "UNKNOWN_NID\\0" - "BAD_BASE64_DECODE\\0" - "BAD_END_LINE\\0" - "BAD_IV_CHARS\\0" - "BAD_PASSWORD_READ\\0" - "CIPHER_IS_NULL\\0" - "ERROR_CONVERTING_PRIVATE_KEY\\0" - "NOT_DEK_INFO\\0" - "NOT_ENCRYPTED\\0" - "NOT_PROC_TYPE\\0" - "NO_START_LINE\\0" - "READ_KEY\\0" - "SHORT_HEADER\\0" - "UNSUPPORTED_CIPHER\\0" - "UNSUPPORTED_ENCRYPTION\\0" - "BAD_PKCS7_VERSION\\0" - "NOT_PKCS7_SIGNED_DATA\\0" - "NO_CERTIFICATES_INCLUDED\\0" - "NO_CRLS_INCLUDED\\0" - "BAD_ITERATION_COUNT\\0" - "BAD_PKCS12_DATA\\0" - "BAD_PKCS12_VERSION\\0" - "CIPHER_HAS_NO_OBJECT_IDENTIFIER\\0" - "CRYPT_ERROR\\0" - "ENCRYPT_ERROR\\0" - "ERROR_SETTING_CIPHER_PARAMS\\0" - "INCORRECT_PASSWORD\\0" - "KEYGEN_FAILURE\\0" - "KEY_GEN_ERROR\\0" - "METHOD_NOT_SUPPORTED\\0" - "MISSING_MAC\\0" - "MULTIPLE_PRIVATE_KEYS_IN_PKCS12\\0" - "PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED\\0" - "PKCS12_TOO_DEEPLY_NESTED\\0" - "PRIVATE_KEY_DECODE_ERROR\\0" - "PRIVATE_KEY_ENCODE_ERROR\\0" - "UNKNOWN_ALGORITHM\\0" - "UNKNOWN_CIPHER\\0" - "UNKNOWN_CIPHER_ALGORITHM\\0" - "UNKNOWN_DIGEST\\0" - "UNSUPPORTED_KEYLENGTH\\0" - "UNSUPPORTED_KEY_DERIVATION_FUNCTION\\0" - "UNSUPPORTED_PRF\\0" - "UNSUPPORTED_PRIVATE_KEY_ALGORITHM\\0" - "UNSUPPORTED_SALT_TYPE\\0" - "BAD_E_VALUE\\0" - "BAD_FIXED_HEADER_DECRYPT\\0" - "BAD_PAD_BYTE_COUNT\\0" - "BAD_RSA_PARAMETERS\\0" - "BLOCK_TYPE_IS_NOT_01\\0" - "BN_NOT_INITIALIZED\\0" - "CANNOT_RECOVER_MULTI_PRIME_KEY\\0" - "CRT_PARAMS_ALREADY_GIVEN\\0" - "CRT_VALUES_INCORRECT\\0" - "DATA_LEN_NOT_EQUAL_TO_MOD_LEN\\0" - "DATA_TOO_LARGE\\0" - "DATA_TOO_LARGE_FOR_KEY_SIZE\\0" - "DATA_TOO_LARGE_FOR_MODULUS\\0" - "DATA_TOO_SMALL\\0" - "DATA_TOO_SMALL_FOR_KEY_SIZE\\0" - "DIGEST_TOO_BIG_FOR_RSA_KEY\\0" - "D_E_NOT_CONGRUENT_TO_1\\0" - "EMPTY_PUBLIC_KEY\\0" - "FIRST_OCTET_INVALID\\0" - "INCONSISTENT_SET_OF_CRT_VALUES\\0" - "INTERNAL_ERROR\\0" - "INVALID_MESSAGE_LENGTH\\0" - "KEY_SIZE_TOO_SMALL\\0" - "LAST_OCTET_INVALID\\0" - "MUST_HAVE_AT_LEAST_TWO_PRIMES\\0" - "NO_PUBLIC_EXPONENT\\0" - "NULL_BEFORE_BLOCK_MISSING\\0" - "N_NOT_EQUAL_P_Q\\0" - "OAEP_DECODING_ERROR\\0" - "ONLY_ONE_OF_P_Q_GIVEN\\0" - "OUTPUT_BUFFER_TOO_SMALL\\0" - "PADDING_CHECK_FAILED\\0" - "PKCS_DECODING_ERROR\\0" - "SLEN_CHECK_FAILED\\0" - "SLEN_RECOVERY_FAILED\\0" - "UNKNOWN_ALGORITHM_TYPE\\0" - "UNKNOWN_PADDING_TYPE\\0" - "VALUE_MISSING\\0" - "WRONG_SIGNATURE_LENGTH\\0" - "ALPN_MISMATCH_ON_EARLY_DATA\\0" - "APPLICATION_DATA_INSTEAD_OF_HANDSHAKE\\0" - "APP_DATA_IN_HANDSHAKE\\0" - "ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT\\0" - "BAD_ALERT\\0" - "BAD_CHANGE_CIPHER_SPEC\\0" - "BAD_DATA_RETURNED_BY_CALLBACK\\0" - "BAD_DH_P_LENGTH\\0" - "BAD_DIGEST_LENGTH\\0" - "BAD_ECC_CERT\\0" - "BAD_ECPOINT\\0" - "BAD_HANDSHAKE_RECORD\\0" - "BAD_HELLO_REQUEST\\0" - "BAD_LENGTH\\0" - "BAD_PACKET_LENGTH\\0" - "BAD_RSA_ENCRYPT\\0" - "BAD_SRTP_MKI_VALUE\\0" - "BAD_SRTP_PROTECTION_PROFILE_LIST\\0" - "BAD_SSL_FILETYPE\\0" - "BAD_WRITE_RETRY\\0" - "BIO_NOT_SET\\0" - "BLOCK_CIPHER_PAD_IS_WRONG\\0" - "BUFFERED_MESSAGES_ON_CIPHER_CHANGE\\0" - "CANNOT_HAVE_BOTH_PRIVKEY_AND_METHOD\\0" - "CANNOT_PARSE_LEAF_CERT\\0" - "CA_DN_LENGTH_MISMATCH\\0" - "CA_DN_TOO_LONG\\0" - "CCS_RECEIVED_EARLY\\0" - "CERTIFICATE_AND_PRIVATE_KEY_MISMATCH\\0" - "CERTIFICATE_VERIFY_FAILED\\0" - "CERT_CB_ERROR\\0" - "CERT_LENGTH_MISMATCH\\0" - "CHANNEL_ID_NOT_P256\\0" - "CHANNEL_ID_SIGNATURE_INVALID\\0" - "CIPHER_OR_HASH_UNAVAILABLE\\0" - "CLIENTHELLO_PARSE_FAILED\\0" - "CLIENTHELLO_TLSEXT\\0" - "CONNECTION_REJECTED\\0" - "CONNECTION_TYPE_NOT_SET\\0" - "CUSTOM_EXTENSION_ERROR\\0" - "DATA_LENGTH_TOO_LONG\\0" - "DECRYPTION_FAILED\\0" - "DECRYPTION_FAILED_OR_BAD_RECORD_MAC\\0" - "DH_PUBLIC_VALUE_LENGTH_IS_WRONG\\0" - "DH_P_TOO_LONG\\0" - "DIGEST_CHECK_FAILED\\0" - "DOWNGRADE_DETECTED\\0" - "DTLS_MESSAGE_TOO_BIG\\0" - "DUPLICATE_EXTENSION\\0" - "DUPLICATE_KEY_SHARE\\0" - "ECC_CERT_NOT_FOR_SIGNING\\0" - "EMS_STATE_INCONSISTENT\\0" - "ENCRYPTED_LENGTH_TOO_LONG\\0" - "ERROR_ADDING_EXTENSION\\0" - "ERROR_IN_RECEIVED_CIPHER_LIST\\0" - "ERROR_PARSING_EXTENSION\\0" - "EXCESSIVE_MESSAGE_SIZE\\0" - "EXTRA_DATA_IN_MESSAGE\\0" - "FRAGMENT_MISMATCH\\0" - "GOT_NEXT_PROTO_WITHOUT_EXTENSION\\0" - "HANDSHAKE_FAILURE_ON_CLIENT_HELLO\\0" - "HTTPS_PROXY_REQUEST\\0" - "HTTP_REQUEST\\0" - "INAPPROPRIATE_FALLBACK\\0" - "INVALID_ALPN_PROTOCOL\\0" - "INVALID_COMMAND\\0" - "INVALID_COMPRESSION_LIST\\0" - "INVALID_MESSAGE\\0" - "INVALID_OUTER_RECORD_TYPE\\0" - "INVALID_SCT_LIST\\0" - "INVALID_SSL_SESSION\\0" - "INVALID_TICKET_KEYS_LENGTH\\0" - "LENGTH_MISMATCH\\0" - "MISSING_EXTENSION\\0" - "MISSING_KEY_SHARE\\0" - "MISSING_RSA_CERTIFICATE\\0" - "MISSING_TMP_DH_KEY\\0" - "MISSING_TMP_ECDH_KEY\\0" - "MIXED_SPECIAL_OPERATOR_WITH_GROUPS\\0" - "MTU_TOO_SMALL\\0" - "NEGOTIATED_BOTH_NPN_AND_ALPN\\0" - "NESTED_GROUP\\0" - "NO_CERTIFICATES_RETURNED\\0" - "NO_CERTIFICATE_ASSIGNED\\0" - "NO_CERTIFICATE_SET\\0" - "NO_CIPHERS_AVAILABLE\\0" - "NO_CIPHERS_PASSED\\0" - "NO_CIPHERS_SPECIFIED\\0" - "NO_CIPHER_MATCH\\0" - "NO_COMMON_SIGNATURE_ALGORITHMS\\0" - "NO_COMPRESSION_SPECIFIED\\0" - "NO_GROUPS_SPECIFIED\\0" - "NO_METHOD_SPECIFIED\\0" - "NO_P256_SUPPORT\\0" - "NO_PRIVATE_KEY_ASSIGNED\\0" - "NO_RENEGOTIATION\\0" - "NO_REQUIRED_DIGEST\\0" - "NO_SHARED_CIPHER\\0" - "NO_SHARED_GROUP\\0" - "NO_SUPPORTED_VERSIONS_ENABLED\\0" - "NULL_SSL_CTX\\0" - "NULL_SSL_METHOD_PASSED\\0" - "OLD_SESSION_CIPHER_NOT_RETURNED\\0" - "OLD_SESSION_PRF_HASH_MISMATCH\\0" - "OLD_SESSION_VERSION_NOT_RETURNED\\0" - "PARSE_TLSEXT\\0" - "PATH_TOO_LONG\\0" - "PEER_DID_NOT_RETURN_A_CERTIFICATE\\0" - "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE\\0" - "PRE_SHARED_KEY_MUST_BE_LAST\\0" - "PROTOCOL_IS_SHUTDOWN\\0" - "PSK_IDENTITY_BINDER_COUNT_MISMATCH\\0" - "PSK_IDENTITY_NOT_FOUND\\0" - "PSK_NO_CLIENT_CB\\0" - "PSK_NO_SERVER_CB\\0" - "READ_TIMEOUT_EXPIRED\\0" - "RECORD_LENGTH_MISMATCH\\0" - "RECORD_TOO_LARGE\\0" - "RENEGOTIATION_EMS_MISMATCH\\0" - "RENEGOTIATION_ENCODING_ERR\\0" - "RENEGOTIATION_MISMATCH\\0" - "REQUIRED_CIPHER_MISSING\\0" - "RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION\\0" - "RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION\\0" - "SCSV_RECEIVED_WHEN_RENEGOTIATING\\0" - "SERVERHELLO_TLSEXT\\0" - "SERVER_CERT_CHANGED\\0" - "SESSION_ID_CONTEXT_UNINITIALIZED\\0" - "SESSION_MAY_NOT_BE_CREATED\\0" - "SHUTDOWN_WHILE_IN_INIT\\0" - "SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER\\0" - "SRTP_COULD_NOT_ALLOCATE_PROFILES\\0" - "SRTP_UNKNOWN_PROTECTION_PROFILE\\0" - "SSL3_EXT_INVALID_SERVERNAME\\0" - "SSLV3_ALERT_BAD_CERTIFICATE\\0" - "SSLV3_ALERT_BAD_RECORD_MAC\\0" - "SSLV3_ALERT_CERTIFICATE_EXPIRED\\0" - "SSLV3_ALERT_CERTIFICATE_REVOKED\\0" - "SSLV3_ALERT_CERTIFICATE_UNKNOWN\\0" - "SSLV3_ALERT_CLOSE_NOTIFY\\0" - "SSLV3_ALERT_DECOMPRESSION_FAILURE\\0" - "SSLV3_ALERT_HANDSHAKE_FAILURE\\0" - "SSLV3_ALERT_ILLEGAL_PARAMETER\\0" - "SSLV3_ALERT_NO_CERTIFICATE\\0" - "SSLV3_ALERT_UNEXPECTED_MESSAGE\\0" - "SSLV3_ALERT_UNSUPPORTED_CERTIFICATE\\0" - "SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION\\0" - "SSL_HANDSHAKE_FAILURE\\0" - "SSL_SESSION_ID_CONTEXT_TOO_LONG\\0" - "TICKET_ENCRYPTION_FAILED\\0" - "TLSV1_ALERT_ACCESS_DENIED\\0" - "TLSV1_ALERT_DECODE_ERROR\\0" - "TLSV1_ALERT_DECRYPTION_FAILED\\0" - "TLSV1_ALERT_DECRYPT_ERROR\\0" - "TLSV1_ALERT_EXPORT_RESTRICTION\\0" - "TLSV1_ALERT_INAPPROPRIATE_FALLBACK\\0" - "TLSV1_ALERT_INSUFFICIENT_SECURITY\\0" - "TLSV1_ALERT_INTERNAL_ERROR\\0" - "TLSV1_ALERT_NO_RENEGOTIATION\\0" - "TLSV1_ALERT_PROTOCOL_VERSION\\0" - "TLSV1_ALERT_RECORD_OVERFLOW\\0" - "TLSV1_ALERT_UNKNOWN_CA\\0" - "TLSV1_ALERT_USER_CANCELLED\\0" - "TLSV1_BAD_CERTIFICATE_HASH_VALUE\\0" - "TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE\\0" - "TLSV1_CERTIFICATE_REQUIRED\\0" - "TLSV1_CERTIFICATE_UNOBTAINABLE\\0" - "TLSV1_UNKNOWN_PSK_IDENTITY\\0" - "TLSV1_UNRECOGNIZED_NAME\\0" - "TLSV1_UNSUPPORTED_EXTENSION\\0" - "TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST\\0" - "TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG\\0" - "TOO_MANY_EMPTY_FRAGMENTS\\0" - "TOO_MANY_KEY_UPDATES\\0" - "TOO_MANY_WARNING_ALERTS\\0" - "TOO_MUCH_READ_EARLY_DATA\\0" - "TOO_MUCH_SKIPPED_EARLY_DATA\\0" - "UNABLE_TO_FIND_ECDH_PARAMETERS\\0" - "UNEXPECTED_EXTENSION\\0" - "UNEXPECTED_EXTENSION_ON_EARLY_DATA\\0" - "UNEXPECTED_MESSAGE\\0" - "UNEXPECTED_OPERATOR_IN_GROUP\\0" - "UNEXPECTED_RECORD\\0" - "UNKNOWN_ALERT_TYPE\\0" - "UNKNOWN_CERTIFICATE_TYPE\\0" - "UNKNOWN_CIPHER_RETURNED\\0" - "UNKNOWN_CIPHER_TYPE\\0" - "UNKNOWN_KEY_EXCHANGE_TYPE\\0" - "UNKNOWN_PROTOCOL\\0" - "UNKNOWN_SSL_VERSION\\0" - "UNKNOWN_STATE\\0" - "UNSAFE_LEGACY_RENEGOTIATION_DISABLED\\0" - "UNSUPPORTED_COMPRESSION_ALGORITHM\\0" - "UNSUPPORTED_ELLIPTIC_CURVE\\0" - "UNSUPPORTED_PROTOCOL\\0" - "UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY\\0" - "WRONG_CERTIFICATE_TYPE\\0" - "WRONG_CIPHER_RETURNED\\0" - "WRONG_CURVE\\0" - "WRONG_MESSAGE_TYPE\\0" - "WRONG_SIGNATURE_TYPE\\0" - "WRONG_SSL_VERSION\\0" - "WRONG_VERSION_NUMBER\\0" - "WRONG_VERSION_ON_EARLY_DATA\\0" - "X509_LIB\\0" - "X509_VERIFICATION_SETUP_PROBLEMS\\0" - "AKID_MISMATCH\\0" - "BAD_X509_FILETYPE\\0" - "BASE64_DECODE_ERROR\\0" - "CANT_CHECK_DH_KEY\\0" - "CERT_ALREADY_IN_HASH_TABLE\\0" - "CRL_ALREADY_DELTA\\0" - "CRL_VERIFY_FAILURE\\0" - "IDP_MISMATCH\\0" - "INVALID_DIRECTORY\\0" - "INVALID_FIELD_NAME\\0" - "INVALID_PARAMETER\\0" - "INVALID_PSS_PARAMETERS\\0" - "INVALID_TRUST\\0" - "ISSUER_MISMATCH\\0" - "KEY_TYPE_MISMATCH\\0" - "KEY_VALUES_MISMATCH\\0" - "LOADING_CERT_DIR\\0" - "LOADING_DEFAULTS\\0" - "NAME_TOO_LONG\\0" - "NEWER_CRL_NOT_NEWER\\0" - "NO_CERT_SET_FOR_US_TO_VERIFY\\0" - "NO_CRL_NUMBER\\0" - "PUBLIC_KEY_DECODE_ERROR\\0" - "PUBLIC_KEY_ENCODE_ERROR\\0" - "SHOULD_RETRY\\0" - "UNKNOWN_KEY_TYPE\\0" - "UNKNOWN_PURPOSE_ID\\0" - "UNKNOWN_TRUST_ID\\0" - "WRONG_LOOKUP_TYPE\\0" - "BAD_IP_ADDRESS\\0" - "BAD_OBJECT\\0" - "BN_DEC2BN_ERROR\\0" - "BN_TO_ASN1_INTEGER_ERROR\\0" - "CANNOT_FIND_FREE_FUNCTION\\0" - "DIRNAME_ERROR\\0" - "DISTPOINT_ALREADY_SET\\0" - "DUPLICATE_ZONE_ID\\0" - "ERROR_CONVERTING_ZONE\\0" - "ERROR_CREATING_EXTENSION\\0" - "ERROR_IN_EXTENSION\\0" - "EXPECTED_A_SECTION_NAME\\0" - "EXTENSION_EXISTS\\0" - "EXTENSION_NAME_ERROR\\0" - "EXTENSION_NOT_FOUND\\0" - "EXTENSION_SETTING_NOT_SUPPORTED\\0" - "EXTENSION_VALUE_ERROR\\0" - "ILLEGAL_EMPTY_EXTENSION\\0" - "ILLEGAL_HEX_DIGIT\\0" - "INCORRECT_POLICY_SYNTAX_TAG\\0" - "INVALID_BOOLEAN_STRING\\0" - "INVALID_EXTENSION_STRING\\0" - "INVALID_MULTIPLE_RDNS\\0" - "INVALID_NAME\\0" - "INVALID_NULL_ARGUMENT\\0" - "INVALID_NULL_NAME\\0" - "INVALID_NULL_VALUE\\0" - "INVALID_NUMBERS\\0" - "INVALID_OBJECT_IDENTIFIER\\0" - "INVALID_OPTION\\0" - "INVALID_POLICY_IDENTIFIER\\0" - "INVALID_PROXY_POLICY_SETTING\\0" - "INVALID_PURPOSE\\0" - "INVALID_SECTION\\0" - "INVALID_SYNTAX\\0" - "ISSUER_DECODE_ERROR\\0" - "NEED_ORGANIZATION_AND_NUMBERS\\0" - "NO_CONFIG_DATABASE\\0" - "NO_ISSUER_CERTIFICATE\\0" - "NO_ISSUER_DETAILS\\0" - "NO_POLICY_IDENTIFIER\\0" - "NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED\\0" - "NO_PUBLIC_KEY\\0" - "NO_SUBJECT_DETAILS\\0" - "ODD_NUMBER_OF_DIGITS\\0" - "OPERATION_NOT_DEFINED\\0" - "OTHERNAME_ERROR\\0" - "POLICY_LANGUAGE_ALREADY_DEFINED\\0" - "POLICY_PATH_LENGTH\\0" - "POLICY_PATH_LENGTH_ALREADY_DEFINED\\0" - "POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY\\0" - "SECTION_NOT_FOUND\\0" - "UNABLE_TO_GET_ISSUER_DETAILS\\0" - "UNABLE_TO_GET_ISSUER_KEYID\\0" - "UNKNOWN_BIT_STRING_ARGUMENT\\0" - "UNKNOWN_EXTENSION\\0" - "UNKNOWN_EXTENSION_NAME\\0" - "UNKNOWN_OPTION\\0" - "UNSUPPORTED_OPTION\\0" - "USER_TOO_LONG\\0" - ""; - EOF - END_OF_COMMAND -end diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 862909f238..85b95dee91 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -69,7 +69,7 @@ static NSMutableDictionary *kHostCache; // gRPC library. // TODO(jcanizales): Add unit tests for the types of addresses we want to let pass untouched. NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]]; - if (hostURL.host && !hostURL.port) { + if (hostURL.host && hostURL.port == nil) { address = [hostURL.host stringByAppendingString:@":443"]; } @@ -193,6 +193,7 @@ static NSMutableDictionary *kHostCache; if (pemPrivateKey == nil && pemCertChain == nil) { creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL, NULL); } else { + assert(pemPrivateKey != nil && pemCertChain != nil); grpc_ssl_pem_key_cert_pair key_cert_pair; NSData *privateKeyASCII = [self nullTerminatedDataWithString:pemPrivateKey]; NSData *certChainASCII = [self nullTerminatedDataWithString:pemCertChain]; @@ -226,7 +227,7 @@ static NSMutableDictionary *kHostCache; args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride; } - if (_responseSizeLimitOverride) { + if (_responseSizeLimitOverride != nil) { args[@GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH] = _responseSizeLimitOverride; } diff --git a/src/objective-c/GRPCClient/private/NSError+GRPC.h b/src/objective-c/GRPCClient/private/NSError+GRPC.h index a63e76ee4d..fb05638b78 100644 --- a/src/objective-c/GRPCClient/private/NSError+GRPC.h +++ b/src/objective-c/GRPCClient/private/NSError+GRPC.h @@ -25,6 +25,6 @@ * and whose domain is |kGRPCErrorDomain|. */ + (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode - details:(char *)details + details:(const char *)details errorString:(const char *)errorString; @end diff --git a/src/objective-c/GRPCClient/private/NSError+GRPC.m b/src/objective-c/GRPCClient/private/NSError+GRPC.m index 199b2ebb6c..3eefed88d6 100644 --- a/src/objective-c/GRPCClient/private/NSError+GRPC.m +++ b/src/objective-c/GRPCClient/private/NSError+GRPC.m @@ -24,18 +24,20 @@ NSString *const kGRPCErrorDomain = @"io.grpc"; @implementation NSError (GRPC) + (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode - details:(char *)details + details:(const char *)details errorString:(const char *)errorString { if (statusCode == GRPC_STATUS_OK) { return nil; } - NSString *message = [NSString stringWithCString:details encoding:NSUTF8StringEncoding]; - NSString *debugMessage = [NSString stringWithCString:errorString encoding:NSUTF8StringEncoding]; - return [NSError errorWithDomain:kGRPCErrorDomain - code:statusCode - userInfo:@{ - NSLocalizedDescriptionKey : message, - NSDebugDescriptionErrorKey : debugMessage - }]; + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (details) { + userInfo[NSLocalizedDescriptionKey] = + [NSString stringWithCString:details encoding:NSUTF8StringEncoding]; + } + if (errorString) { + userInfo[NSDebugDescriptionErrorKey] = + [NSString stringWithCString:errorString encoding:NSUTF8StringEncoding]; + } + return [NSError errorWithDomain:kGRPCErrorDomain code:statusCode userInfo:userInfo]; } @end diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index 52fe0dd050..d5463c0b4c 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -22,4 +22,4 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.15.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.17.0-dev" diff --git a/src/objective-c/README.md b/src/objective-c/README.md index 40aba0317b..32e3956a1e 100644 --- a/src/objective-c/README.md +++ b/src/objective-c/README.md @@ -220,3 +220,25 @@ Objective-C Protobuf runtime library. [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install [example Podfile]:https://github.com/grpc/grpc/blob/master/examples/objective-c/helloworld/Podfile [example apps]: https://github.com/grpc/grpc/tree/master/examples/objective-c + +## Use gRPC with OpenSSL +gRPC uses BoringSSL as its dependency, which is a fork of OpenSSL and export a number of symbols +that are the same as OpenSSL. gRPC avoids conflicts of these symbols by renaming BoringSSL symbols. + +If you need gRPC to use OpenSSL instead of BoringSSL (e.g. for the benefit of reducing the binary +size of your product), you need to make a local `gRPC-Core` podspec and tweak it accordingly: +- Copy the version of `/gRPC-Core.podspec` you wish to use from Github into the repository of your + app; +- In your `Podfile`, add the following line: +``` +pod `gRPC-Core`, :podspec => "." # assuming gRPC-Core.podspec is in the same directory as your Podfile +``` +- Remove [the + macro](https://github.com/grpc/grpc/blob/b24b212ee585d376c618235905757b2445ac6461/gRPC-Core.podspec#L186) + `GRPC_SHADOW_BORINGSSL_SYMBOLS` to disable symbol renaming; +- Substitude the `BoringSSL-GRPC` + [dependency](https://github.com/grpc/grpc/blob/b24b212ee585d376c618235905757b2445ac6461/gRPC-Core.podspec#L184) + to whatever pod of OpenSSL your other libraries use. + +These steps should allow gRPC to use OpenSSL and drop BoringSSL dependency. If you see any issue, +file an issue to us. diff --git a/src/objective-c/examples/Sample/Podfile b/src/objective-c/examples/Sample/Podfile index 9ea2f61927..bebd55bd62 100644 --- a/src/objective-c/examples/Sample/Podfile +++ b/src/objective-c/examples/Sample/Podfile @@ -19,7 +19,7 @@ target 'Sample' do pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf" - pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" + pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" pod 'gRPC', :path => GRPC_LOCAL_SRC pod 'gRPC-Core', :path => GRPC_LOCAL_SRC diff --git a/src/objective-c/examples/SwiftSample/Podfile b/src/objective-c/examples/SwiftSample/Podfile index a2c2b82cc9..8214371bc5 100644 --- a/src/objective-c/examples/SwiftSample/Podfile +++ b/src/objective-c/examples/SwiftSample/Podfile @@ -19,7 +19,7 @@ target 'SwiftSample' do pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf" - pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" + pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" pod 'gRPC', :path => GRPC_LOCAL_SRC pod 'gRPC-Core', :path => GRPC_LOCAL_SRC diff --git a/src/objective-c/grpc_shadow_boringssl_symbol_list b/src/objective-c/grpc_shadow_boringssl_symbol_list new file mode 100644 index 0000000000..33a6ed0e25 --- /dev/null +++ b/src/objective-c/grpc_shadow_boringssl_symbol_list @@ -0,0 +1,2974 @@ +# Automatically generated by tools/distrib/generate_grpc_shadow_boringssl_symbol_list.sh +b29b21a81b32ec273f118f589f46d56ad3332420 +BIO_f_ssl +BIO_set_ssl +SSL_CTX_add_client_custom_ext +SSL_CTX_add_server_custom_ext +DTLSv1_get_timeout +DTLSv1_handle_timeout +DTLSv1_set_initial_timeout_duration +SSL_CTX_set_srtp_profiles +SSL_CTX_set_tlsext_use_srtp +SSL_get_selected_srtp_profile +SSL_get_srtp_profiles +SSL_set_srtp_profiles +SSL_set_tlsext_use_srtp +DTLS_client_method +DTLS_method +DTLS_server_method +DTLS_with_buffers_method +DTLSv1_2_client_method +DTLSv1_2_method +DTLSv1_2_server_method +DTLSv1_client_method +DTLSv1_method +DTLSv1_server_method +SSL_SESSION_from_bytes +SSL_SESSION_to_bytes +SSL_SESSION_to_bytes_for_ticket +i2d_SSL_SESSION +SSL_CTX_set0_client_CAs +SSL_CTX_set_cert_cb +SSL_CTX_set_chain_and_key +SSL_CTX_set_ocsp_response +SSL_CTX_set_signed_cert_timestamp_list +SSL_CTX_use_certificate_ASN1 +SSL_get0_peer_certificates +SSL_get0_server_requested_CAs +SSL_set0_client_CAs +SSL_set_cert_cb +SSL_set_chain_and_key +SSL_set_ocsp_response +SSL_set_signed_cert_timestamp_list +SSL_use_certificate_ASN1 +SSL_CIPHER_description +SSL_CIPHER_get_auth_nid +SSL_CIPHER_get_bits +SSL_CIPHER_get_cipher_nid +SSL_CIPHER_get_digest_nid +SSL_CIPHER_get_id +SSL_CIPHER_get_kx_name +SSL_CIPHER_get_kx_nid +SSL_CIPHER_get_max_version +SSL_CIPHER_get_min_version +SSL_CIPHER_get_name +SSL_CIPHER_get_prf_nid +SSL_CIPHER_get_rfc_name +SSL_CIPHER_get_version +SSL_CIPHER_is_aead +SSL_CIPHER_is_block_cipher +SSL_CIPHER_standard_name +SSL_COMP_add_compression_method +SSL_COMP_free_compression_methods +SSL_COMP_get0_name +SSL_COMP_get_compression_methods +SSL_COMP_get_id +SSL_COMP_get_name +SSL_get_cipher_by_value +SSL_CTX_get_default_passwd_cb +SSL_CTX_get_default_passwd_cb_userdata +SSL_CTX_set_default_passwd_cb +SSL_CTX_set_default_passwd_cb_userdata +SSL_CTX_use_PrivateKey_file +SSL_CTX_use_RSAPrivateKey_file +SSL_CTX_use_certificate_chain_file +SSL_CTX_use_certificate_file +SSL_add_file_cert_subjects_to_stack +SSL_load_client_CA_file +SSL_use_PrivateKey_file +SSL_use_RSAPrivateKey_file +SSL_use_certificate_file +SSL_get_curve_name +ERR_load_SSL_strings +OPENSSL_init_ssl +SSL_CTX_check_private_key +SSL_CTX_cipher_in_group +SSL_CTX_clear_mode +SSL_CTX_clear_options +SSL_CTX_enable_ocsp_stapling +SSL_CTX_enable_signed_cert_timestamps +SSL_CTX_enable_tls_channel_id +SSL_CTX_free +SSL_CTX_get0_privatekey +SSL_CTX_get_ciphers +SSL_CTX_get_ex_data +SSL_CTX_get_ex_new_index +SSL_CTX_get_keylog_callback +SSL_CTX_get_max_cert_list +SSL_CTX_get_mode +SSL_CTX_get_options +SSL_CTX_get_quiet_shutdown +SSL_CTX_get_read_ahead +SSL_CTX_get_session_cache_mode +SSL_CTX_get_tlsext_ticket_keys +SSL_CTX_need_tmp_RSA +SSL_CTX_new +SSL_CTX_sess_accept +SSL_CTX_sess_accept_good +SSL_CTX_sess_accept_renegotiate +SSL_CTX_sess_cache_full +SSL_CTX_sess_cb_hits +SSL_CTX_sess_connect +SSL_CTX_sess_connect_good +SSL_CTX_sess_connect_renegotiate +SSL_CTX_sess_get_cache_size +SSL_CTX_sess_hits +SSL_CTX_sess_misses +SSL_CTX_sess_number +SSL_CTX_sess_set_cache_size +SSL_CTX_sess_timeouts +SSL_CTX_set0_buffer_pool +SSL_CTX_set1_curves +SSL_CTX_set1_curves_list +SSL_CTX_set1_tls_channel_id +SSL_CTX_set_allow_unknown_alpn_protos +SSL_CTX_set_alpn_protos +SSL_CTX_set_alpn_select_cb +SSL_CTX_set_cipher_list +SSL_CTX_set_current_time_cb +SSL_CTX_set_custom_verify +SSL_CTX_set_dos_protection_cb +SSL_CTX_set_early_data_enabled +SSL_CTX_set_ex_data +SSL_CTX_set_false_start_allowed_without_alpn +SSL_CTX_set_grease_enabled +SSL_CTX_set_keylog_callback +SSL_CTX_set_max_cert_list +SSL_CTX_set_max_send_fragment +SSL_CTX_set_mode +SSL_CTX_set_msg_callback +SSL_CTX_set_msg_callback_arg +SSL_CTX_set_next_proto_select_cb +SSL_CTX_set_next_protos_advertised_cb +SSL_CTX_set_options +SSL_CTX_set_psk_client_callback +SSL_CTX_set_psk_server_callback +SSL_CTX_set_quiet_shutdown +SSL_CTX_set_read_ahead +SSL_CTX_set_retain_only_sha256_of_client_certs +SSL_CTX_set_select_certificate_cb +SSL_CTX_set_session_cache_mode +SSL_CTX_set_session_id_context +SSL_CTX_set_strict_cipher_list +SSL_CTX_set_ticket_aead_method +SSL_CTX_set_tls13_variant +SSL_CTX_set_tls_channel_id_enabled +SSL_CTX_set_tlsext_servername_arg +SSL_CTX_set_tlsext_servername_callback +SSL_CTX_set_tlsext_ticket_key_cb +SSL_CTX_set_tlsext_ticket_keys +SSL_CTX_set_tmp_dh +SSL_CTX_set_tmp_dh_callback +SSL_CTX_set_tmp_ecdh +SSL_CTX_set_tmp_rsa +SSL_CTX_set_tmp_rsa_callback +SSL_CTX_up_ref +SSL_CTX_use_psk_identity_hint +SSL_accept +SSL_cache_hit +SSL_certs_clear +SSL_check_private_key +SSL_clear +SSL_clear_mode +SSL_clear_options +SSL_connect +SSL_cutthrough_complete +SSL_do_handshake +SSL_dummy_pq_padding_used +SSL_early_data_accepted +SSL_enable_ocsp_stapling +SSL_enable_signed_cert_timestamps +SSL_enable_tls_channel_id +SSL_free +SSL_get0_alpn_selected +SSL_get0_certificate_types +SSL_get0_next_proto_negotiated +SSL_get0_ocsp_response +SSL_get0_session_id_context +SSL_get0_signed_cert_timestamp_list +SSL_get_SSL_CTX +SSL_get_cipher_list +SSL_get_ciphers +SSL_get_client_random +SSL_get_current_cipher +SSL_get_current_compression +SSL_get_current_expansion +SSL_get_curve_id +SSL_get_default_timeout +SSL_get_error +SSL_get_ex_data +SSL_get_ex_new_index +SSL_get_extms_support +SSL_get_fd +SSL_get_finished +SSL_get_info_callback +SSL_get_ivs +SSL_get_max_cert_list +SSL_get_mode +SSL_get_negotiated_token_binding_param +SSL_get_options +SSL_get_peer_finished +SSL_get_peer_quic_transport_params +SSL_get_peer_signature_algorithm +SSL_get_pending_cipher +SSL_get_privatekey +SSL_get_psk_identity +SSL_get_psk_identity_hint +SSL_get_quiet_shutdown +SSL_get_rbio +SSL_get_read_ahead +SSL_get_read_sequence +SSL_get_rfd +SSL_get_secure_renegotiation_support +SSL_get_server_random +SSL_get_server_tmp_key +SSL_get_servername +SSL_get_servername_type +SSL_get_shared_ciphers +SSL_get_shutdown +SSL_get_structure_sizes +SSL_get_ticket_age_skew +SSL_get_tls_channel_id +SSL_get_tls_unique +SSL_get_verify_mode +SSL_get_wbio +SSL_get_wfd +SSL_get_write_sequence +SSL_in_early_data +SSL_in_false_start +SSL_in_init +SSL_is_draft_downgrade +SSL_is_dtls +SSL_is_init_finished +SSL_is_server +SSL_is_token_binding_negotiated +SSL_library_init +SSL_load_error_strings +SSL_need_tmp_RSA +SSL_new +SSL_num_renegotiations +SSL_peek +SSL_pending +SSL_read +SSL_renegotiate +SSL_renegotiate_pending +SSL_reset_early_data_reject +SSL_select_next_proto +SSL_send_fatal_alert +SSL_session_reused +SSL_set0_rbio +SSL_set0_wbio +SSL_set1_curves +SSL_set1_curves_list +SSL_set1_tls_channel_id +SSL_set_SSL_CTX +SSL_set_accept_state +SSL_set_alpn_protos +SSL_set_bio +SSL_set_cipher_list +SSL_set_connect_state +SSL_set_custom_verify +SSL_set_dummy_pq_padding_size +SSL_set_early_data_enabled +SSL_set_ex_data +SSL_set_fd +SSL_set_info_callback +SSL_set_max_cert_list +SSL_set_max_send_fragment +SSL_set_mode +SSL_set_msg_callback +SSL_set_msg_callback_arg +SSL_set_mtu +SSL_set_options +SSL_set_psk_client_callback +SSL_set_psk_server_callback +SSL_set_quic_transport_params +SSL_set_quiet_shutdown +SSL_set_read_ahead +SSL_set_renegotiate_mode +SSL_set_retain_only_sha256_of_client_certs +SSL_set_rfd +SSL_set_session_id_context +SSL_set_shutdown +SSL_set_state +SSL_set_strict_cipher_list +SSL_set_tls13_variant +SSL_set_tls_channel_id_enabled +SSL_set_tlsext_host_name +SSL_set_tmp_dh +SSL_set_tmp_dh_callback +SSL_set_tmp_ecdh +SSL_set_tmp_rsa +SSL_set_tmp_rsa_callback +SSL_set_token_binding_params +SSL_set_wfd +SSL_shutdown +SSL_state +SSL_total_renegotiations +SSL_use_psk_identity_hint +SSL_want +SSL_write +SSL_CTX_set_private_key_method +SSL_CTX_set_signing_algorithm_prefs +SSL_CTX_set_verify_algorithm_prefs +SSL_CTX_use_PrivateKey +SSL_CTX_use_PrivateKey_ASN1 +SSL_CTX_use_RSAPrivateKey +SSL_CTX_use_RSAPrivateKey_ASN1 +SSL_get_signature_algorithm_digest +SSL_get_signature_algorithm_key_type +SSL_get_signature_algorithm_name +SSL_is_signature_algorithm_rsa_pss +SSL_set_private_key_method +SSL_set_signing_algorithm_prefs +SSL_use_PrivateKey +SSL_use_PrivateKey_ASN1 +SSL_use_RSAPrivateKey +SSL_use_RSAPrivateKey_ASN1 +SSL_CTX_add_session +SSL_CTX_flush_sessions +SSL_CTX_get_channel_id_cb +SSL_CTX_get_info_callback +SSL_CTX_get_timeout +SSL_CTX_remove_session +SSL_CTX_sess_get_get_cb +SSL_CTX_sess_get_new_cb +SSL_CTX_sess_get_remove_cb +SSL_CTX_sess_set_get_cb +SSL_CTX_sess_set_new_cb +SSL_CTX_sess_set_remove_cb +SSL_CTX_set_channel_id_cb +SSL_CTX_set_info_callback +SSL_CTX_set_session_psk_dhe_timeout +SSL_CTX_set_timeout +SSL_SESSION_free +SSL_SESSION_get0_peer +SSL_SESSION_get0_ticket +SSL_SESSION_get_ex_data +SSL_SESSION_get_ex_new_index +SSL_SESSION_get_id +SSL_SESSION_get_master_key +SSL_SESSION_get_ticket_lifetime_hint +SSL_SESSION_get_time +SSL_SESSION_get_timeout +SSL_SESSION_has_ticket +SSL_SESSION_is_resumable +SSL_SESSION_new +SSL_SESSION_set1_id_context +SSL_SESSION_set_ex_data +SSL_SESSION_set_time +SSL_SESSION_set_timeout +SSL_SESSION_should_be_single_use +SSL_SESSION_up_ref +SSL_get1_session +SSL_get_session +SSL_magic_pending_session_ptr +SSL_set_session +SSL_alert_desc_string +SSL_alert_desc_string_long +SSL_alert_type_string +SSL_alert_type_string_long +SSL_state_string +SSL_state_string_long +SSL_CTX_set_max_proto_version +SSL_CTX_set_min_proto_version +SSL_SESSION_get_protocol_version +SSL_SESSION_get_version +SSL_SESSION_set_protocol_version +SSL_get_version +SSL_set_max_proto_version +SSL_set_min_proto_version +SSL_version +PEM_read_SSL_SESSION +PEM_read_bio_SSL_SESSION +PEM_write_SSL_SESSION +PEM_write_bio_SSL_SESSION +SSL_CTX_add0_chain_cert +SSL_CTX_add1_chain_cert +SSL_CTX_add_client_CA +SSL_CTX_add_extra_chain_cert +SSL_CTX_clear_chain_certs +SSL_CTX_clear_extra_chain_certs +SSL_CTX_get0_certificate +SSL_CTX_get0_chain_certs +SSL_CTX_get0_param +SSL_CTX_get_cert_store +SSL_CTX_get_client_CA_list +SSL_CTX_get_extra_chain_certs +SSL_CTX_get_verify_callback +SSL_CTX_get_verify_depth +SSL_CTX_get_verify_mode +SSL_CTX_load_verify_locations +SSL_CTX_set0_chain +SSL_CTX_set0_verify_cert_store +SSL_CTX_set1_chain +SSL_CTX_set1_param +SSL_CTX_set1_verify_cert_store +SSL_CTX_set_cert_store +SSL_CTX_set_cert_verify_callback +SSL_CTX_set_client_CA_list +SSL_CTX_set_client_cert_cb +SSL_CTX_set_default_verify_paths +SSL_CTX_set_purpose +SSL_CTX_set_trust +SSL_CTX_set_verify +SSL_CTX_set_verify_depth +SSL_CTX_use_certificate +SSL_add0_chain_cert +SSL_add1_chain_cert +SSL_add_client_CA +SSL_alert_from_verify_result +SSL_clear_chain_certs +SSL_dup_CA_list +SSL_get0_chain_certs +SSL_get0_param +SSL_get_certificate +SSL_get_client_CA_list +SSL_get_ex_data_X509_STORE_CTX_idx +SSL_get_peer_cert_chain +SSL_get_peer_certificate +SSL_get_peer_full_cert_chain +SSL_get_verify_callback +SSL_get_verify_depth +SSL_get_verify_result +SSL_set0_chain +SSL_set0_verify_cert_store +SSL_set1_chain +SSL_set1_param +SSL_set1_verify_cert_store +SSL_set_client_CA_list +SSL_set_purpose +SSL_set_trust +SSL_set_verify +SSL_set_verify_depth +SSL_set_verify_result +SSL_use_certificate +d2i_SSL_SESSION +d2i_SSL_SESSION_bio +i2d_SSL_SESSION_bio +SSL_export_early_keying_material +SSL_export_keying_material +SSL_generate_key_block +SSL_get_key_block_len +SSL_CTX_set_ed25519_enabled +SSL_early_callback_ctx_extension_get +SSL_extension_supported +SSLv23_client_method +SSLv23_method +SSLv23_server_method +TLS_client_method +TLS_method +TLS_server_method +TLS_with_buffers_method +TLSv1_1_client_method +TLSv1_1_method +TLSv1_1_server_method +TLSv1_2_client_method +TLSv1_2_method +TLSv1_2_server_method +TLSv1_client_method +TLSv1_method +TLSv1_server_method +SSL_max_seal_overhead +OPENSSL_cpuid_setup +CRYPTO_has_asm +CRYPTO_is_confidential_build +CRYPTO_library_init +CRYPTO_malloc_init +ENGINE_load_builtin_engines +ENGINE_register_all_complete +OPENSSL_ia32cap_P +OPENSSL_init_crypto +OPENSSL_load_builtin_modules +OpenSSL_version +OpenSSL_version_num +SSLeay +SSLeay_version +CRYPTO_cleanup_all_ex_data +CRYPTO_free_ex_data +CRYPTO_get_ex_data +CRYPTO_get_ex_new_index +CRYPTO_new_ex_data +CRYPTO_set_ex_data +BIO_snprintf +BIO_vsnprintf +CRYPTO_memcmp +OPENSSL_cleanse +OPENSSL_free +OPENSSL_hash32 +OPENSSL_malloc +OPENSSL_realloc +OPENSSL_strcasecmp +OPENSSL_strdup +OPENSSL_strncasecmp +OPENSSL_strnlen +OPENSSL_tolower +CRYPTO_refcount_dec_and_test_zero +CRYPTO_refcount_inc +CRYPTO_THREADID_current +CRYPTO_THREADID_set_callback +CRYPTO_THREADID_set_numeric +CRYPTO_THREADID_set_pointer +CRYPTO_get_dynlock_create_callback +CRYPTO_get_dynlock_destroy_callback +CRYPTO_get_dynlock_lock_callback +CRYPTO_get_lock_name +CRYPTO_get_locking_callback +CRYPTO_num_locks +CRYPTO_set_add_lock_callback +CRYPTO_set_dynlock_create_callback +CRYPTO_set_dynlock_destroy_callback +CRYPTO_set_dynlock_lock_callback +CRYPTO_set_id_callback +CRYPTO_set_locking_callback +CRYPTO_MUTEX_cleanup +CRYPTO_MUTEX_init +CRYPTO_MUTEX_lock_read +CRYPTO_MUTEX_lock_write +CRYPTO_MUTEX_unlock_read +CRYPTO_MUTEX_unlock_write +CRYPTO_STATIC_MUTEX_lock_read +CRYPTO_STATIC_MUTEX_lock_write +CRYPTO_STATIC_MUTEX_unlock_read +CRYPTO_STATIC_MUTEX_unlock_write +CRYPTO_get_thread_local +CRYPTO_once +CRYPTO_set_thread_local +sk_deep_copy +sk_delete +sk_delete_ptr +sk_dup +sk_find +sk_free +sk_insert +sk_is_sorted +sk_new +sk_new_null +sk_num +sk_pop +sk_pop_free +sk_push +sk_set +sk_set_cmp_func +sk_shift +sk_sort +sk_value +sk_zero +lh_delete +lh_doall +lh_doall_arg +lh_free +lh_insert +lh_new +lh_num_items +lh_retrieve +lh_strhash +ERR_SAVE_STATE_free +ERR_add_error_data +ERR_add_error_dataf +ERR_clear_error +ERR_clear_system_error +ERR_error_string +ERR_error_string_n +ERR_free_strings +ERR_func_error_string +ERR_get_error +ERR_get_error_line +ERR_get_error_line_data +ERR_get_next_error_library +ERR_lib_error_string +ERR_load_BIO_strings +ERR_load_ERR_strings +ERR_load_crypto_strings +ERR_peek_error +ERR_peek_error_line +ERR_peek_error_line_data +ERR_peek_last_error +ERR_peek_last_error_line +ERR_peek_last_error_line_data +ERR_pop_to_mark +ERR_print_errors_cb +ERR_print_errors_fp +ERR_put_error +ERR_reason_error_string +ERR_remove_state +ERR_remove_thread_state +ERR_restore_state +ERR_save_state +ERR_set_mark +kOpenSSLReasonStringData +kOpenSSLReasonValues +kOpenSSLReasonValuesLen +EVP_DecodeBase64 +EVP_DecodeBlock +EVP_DecodeFinal +EVP_DecodeInit +EVP_DecodeUpdate +EVP_DecodedLength +EVP_EncodeBlock +EVP_EncodeFinal +EVP_EncodeInit +EVP_EncodeUpdate +EVP_EncodedLength +CBB_finish_i2d +CBS_asn1_ber_to_der +CBS_get_asn1_implicit_string +CBS_asn1_bitstring_has_bit +CBS_asn1_oid_to_text +CBS_contains_zero_byte +CBS_copy_bytes +CBS_data +CBS_get_any_asn1 +CBS_get_any_asn1_element +CBS_get_any_ber_asn1_element +CBS_get_asn1 +CBS_get_asn1_bool +CBS_get_asn1_element +CBS_get_asn1_uint64 +CBS_get_bytes +CBS_get_last_u8 +CBS_get_optional_asn1 +CBS_get_optional_asn1_bool +CBS_get_optional_asn1_octet_string +CBS_get_optional_asn1_uint64 +CBS_get_u16 +CBS_get_u16_length_prefixed +CBS_get_u24 +CBS_get_u24_length_prefixed +CBS_get_u32 +CBS_get_u8 +CBS_get_u8_length_prefixed +CBS_init +CBS_is_valid_asn1_bitstring +CBS_len +CBS_mem_equal +CBS_peek_asn1_tag +CBS_skip +CBS_stow +CBS_strdup +CBB_add_asn1 +CBB_add_asn1_bool +CBB_add_asn1_octet_string +CBB_add_asn1_oid_from_text +CBB_add_asn1_uint64 +CBB_add_bytes +CBB_add_space +CBB_add_u16 +CBB_add_u16_length_prefixed +CBB_add_u24 +CBB_add_u24_length_prefixed +CBB_add_u32 +CBB_add_u8 +CBB_add_u8_length_prefixed +CBB_cleanup +CBB_data +CBB_did_write +CBB_discard_child +CBB_finish +CBB_flush +CBB_flush_asn1_set_of +CBB_init +CBB_init_fixed +CBB_len +CBB_reserve +CBB_zero +CRYPTO_BUFFER_POOL_free +CRYPTO_BUFFER_POOL_new +CRYPTO_BUFFER_data +CRYPTO_BUFFER_free +CRYPTO_BUFFER_init_CBS +CRYPTO_BUFFER_len +CRYPTO_BUFFER_new +CRYPTO_BUFFER_new_from_CBS +CRYPTO_BUFFER_up_ref +AES_cbc_encrypt +AES_cfb128_encrypt +AES_ctr128_encrypt +AES_decrypt +AES_ecb_encrypt +AES_encrypt +AES_ofb128_encrypt +AES_set_decrypt_key +AES_set_encrypt_key +AES_unwrap_key +AES_wrap_key +BN_BLINDING_convert +BN_BLINDING_free +BN_BLINDING_invert +BN_BLINDING_new +BN_CTX_end +BN_CTX_free +BN_CTX_get +BN_CTX_new +BN_CTX_start +BN_GENCB_call +BN_GENCB_set +BN_MONT_CTX_copy +BN_MONT_CTX_free +BN_MONT_CTX_new +BN_MONT_CTX_new_for_modulus +BN_MONT_CTX_set +BN_MONT_CTX_set_locked +BN_abs_is_word +BN_add +BN_add_word +BN_bin2bn +BN_bn2bin +BN_bn2bin_padded +BN_bn2le_padded +BN_clear +BN_clear_bit +BN_clear_free +BN_cmp +BN_cmp_word +BN_copy +BN_count_low_zero_bits +BN_div +BN_div_word +BN_dup +BN_enhanced_miller_rabin_primality_test +BN_equal_consttime +BN_exp +BN_free +BN_from_montgomery +BN_gcd +BN_generate_prime_ex +BN_get_u64 +BN_get_word +BN_init +BN_is_bit_set +BN_is_negative +BN_is_odd +BN_is_one +BN_is_pow2 +BN_is_prime_ex +BN_is_prime_fasttest_ex +BN_is_word +BN_is_zero +BN_le2bn +BN_lshift +BN_lshift1 +BN_mask_bits +BN_mod_add +BN_mod_add_quick +BN_mod_exp +BN_mod_exp2_mont +BN_mod_exp_mont +BN_mod_exp_mont_consttime +BN_mod_exp_mont_word +BN_mod_inverse +BN_mod_inverse_blinded +BN_mod_inverse_odd +BN_mod_lshift +BN_mod_lshift1 +BN_mod_lshift1_quick +BN_mod_lshift_quick +BN_mod_mul +BN_mod_mul_montgomery +BN_mod_pow2 +BN_mod_sqr +BN_mod_sqrt +BN_mod_sub +BN_mod_sub_quick +BN_mod_word +BN_mul +BN_mul_word +BN_new +BN_nnmod +BN_nnmod_pow2 +BN_num_bits +BN_num_bits_word +BN_num_bytes +BN_one +BN_primality_test +BN_pseudo_rand +BN_pseudo_rand_range +BN_rand +BN_rand_range +BN_rand_range_ex +BN_rshift +BN_rshift1 +BN_set_bit +BN_set_negative +BN_set_u64 +BN_set_word +BN_sqr +BN_sqrt +BN_sub +BN_sub_word +BN_to_montgomery +BN_uadd +BN_ucmp +BN_usub +BN_value_one +BN_zero +BORINGSSL_self_test +CRYPTO_POLYVAL_finish +CRYPTO_POLYVAL_init +CRYPTO_POLYVAL_update_blocks +CRYPTO_cbc128_decrypt +CRYPTO_cbc128_encrypt +CRYPTO_ccm128_decrypt +CRYPTO_ccm128_encrypt +CRYPTO_ccm128_init +CRYPTO_ccm128_max_input +CRYPTO_cfb128_1_encrypt +CRYPTO_cfb128_8_encrypt +CRYPTO_cfb128_encrypt +CRYPTO_ctr128_encrypt +CRYPTO_ctr128_encrypt_ctr32 +CRYPTO_gcm128_aad +CRYPTO_gcm128_decrypt +CRYPTO_gcm128_decrypt_ctr32 +CRYPTO_gcm128_encrypt +CRYPTO_gcm128_encrypt_ctr32 +CRYPTO_gcm128_finish +CRYPTO_gcm128_init +CRYPTO_gcm128_setiv +CRYPTO_gcm128_tag +CRYPTO_ghash_init +CRYPTO_ofb128_encrypt +CRYPTO_sysrand +CRYPTO_tls1_prf +CTR_DRBG_clear +CTR_DRBG_generate +CTR_DRBG_init +CTR_DRBG_reseed +DES_decrypt3 +DES_ecb3_encrypt +DES_ecb_encrypt +DES_ede2_cbc_encrypt +DES_ede3_cbc_encrypt +DES_encrypt3 +DES_ncbc_encrypt +DES_set_key +DES_set_key_unchecked +DES_set_odd_parity +ECDSA_SIG_free +ECDSA_SIG_get0 +ECDSA_SIG_new +ECDSA_SIG_set0 +ECDSA_do_sign +ECDSA_do_verify +EC_GFp_mont_method +EC_GFp_nistp224_method +EC_GFp_nistp256_method +EC_GFp_nistz256_method +EC_GROUP_cmp +EC_GROUP_dup +EC_GROUP_free +EC_GROUP_get0_generator +EC_GROUP_get0_order +EC_GROUP_get_cofactor +EC_GROUP_get_curve_GFp +EC_GROUP_get_curve_name +EC_GROUP_get_degree +EC_GROUP_get_order +EC_GROUP_method_of +EC_GROUP_new_by_curve_name +EC_GROUP_new_curve_GFp +EC_GROUP_set_asn1_flag +EC_GROUP_set_generator +EC_GROUP_set_point_conversion_form +EC_KEY_check_fips +EC_KEY_check_key +EC_KEY_dup +EC_KEY_free +EC_KEY_generate_key +EC_KEY_generate_key_fips +EC_KEY_get0_group +EC_KEY_get0_private_key +EC_KEY_get0_public_key +EC_KEY_get_conv_form +EC_KEY_get_enc_flags +EC_KEY_get_ex_data +EC_KEY_get_ex_new_index +EC_KEY_is_opaque +EC_KEY_new +EC_KEY_new_by_curve_name +EC_KEY_new_method +EC_KEY_set_asn1_flag +EC_KEY_set_conv_form +EC_KEY_set_enc_flags +EC_KEY_set_ex_data +EC_KEY_set_group +EC_KEY_set_private_key +EC_KEY_set_public_key +EC_KEY_set_public_key_affine_coordinates +EC_KEY_up_ref +EC_METHOD_get_field_type +EC_POINT_add +EC_POINT_clear_free +EC_POINT_cmp +EC_POINT_copy +EC_POINT_dbl +EC_POINT_dup +EC_POINT_free +EC_POINT_get_affine_coordinates_GFp +EC_POINT_invert +EC_POINT_is_at_infinity +EC_POINT_is_on_curve +EC_POINT_make_affine +EC_POINT_mul +EC_POINT_new +EC_POINT_oct2point +EC_POINT_point2oct +EC_POINT_set_affine_coordinates_GFp +EC_POINT_set_compressed_coordinates_GFp +EC_POINT_set_to_infinity +EC_POINTs_make_affine +EC_get_builtin_curves +EVP_AEAD_CTX_aead +EVP_AEAD_CTX_cleanup +EVP_AEAD_CTX_free +EVP_AEAD_CTX_get_iv +EVP_AEAD_CTX_init +EVP_AEAD_CTX_init_with_direction +EVP_AEAD_CTX_new +EVP_AEAD_CTX_open +EVP_AEAD_CTX_open_gather +EVP_AEAD_CTX_seal +EVP_AEAD_CTX_seal_scatter +EVP_AEAD_CTX_tag_len +EVP_AEAD_CTX_zero +EVP_AEAD_key_length +EVP_AEAD_max_overhead +EVP_AEAD_max_tag_len +EVP_AEAD_nonce_length +EVP_CIPHER_CTX_block_size +EVP_CIPHER_CTX_cipher +EVP_CIPHER_CTX_cleanup +EVP_CIPHER_CTX_copy +EVP_CIPHER_CTX_ctrl +EVP_CIPHER_CTX_flags +EVP_CIPHER_CTX_free +EVP_CIPHER_CTX_get_app_data +EVP_CIPHER_CTX_init +EVP_CIPHER_CTX_iv_length +EVP_CIPHER_CTX_key_length +EVP_CIPHER_CTX_mode +EVP_CIPHER_CTX_new +EVP_CIPHER_CTX_nid +EVP_CIPHER_CTX_reset +EVP_CIPHER_CTX_set_app_data +EVP_CIPHER_CTX_set_flags +EVP_CIPHER_CTX_set_key_length +EVP_CIPHER_CTX_set_padding +EVP_CIPHER_block_size +EVP_CIPHER_flags +EVP_CIPHER_iv_length +EVP_CIPHER_key_length +EVP_CIPHER_mode +EVP_CIPHER_nid +EVP_Cipher +EVP_CipherFinal_ex +EVP_CipherInit +EVP_CipherInit_ex +EVP_CipherUpdate +EVP_DecryptFinal_ex +EVP_DecryptInit +EVP_DecryptInit_ex +EVP_DecryptUpdate +EVP_Digest +EVP_DigestFinal +EVP_DigestFinal_ex +EVP_DigestInit +EVP_DigestInit_ex +EVP_DigestUpdate +EVP_EncryptFinal_ex +EVP_EncryptInit +EVP_EncryptInit_ex +EVP_EncryptUpdate +EVP_MD_CTX_block_size +EVP_MD_CTX_cleanup +EVP_MD_CTX_copy +EVP_MD_CTX_copy_ex +EVP_MD_CTX_create +EVP_MD_CTX_destroy +EVP_MD_CTX_free +EVP_MD_CTX_init +EVP_MD_CTX_md +EVP_MD_CTX_new +EVP_MD_CTX_reset +EVP_MD_CTX_size +EVP_MD_CTX_type +EVP_MD_block_size +EVP_MD_flags +EVP_MD_size +EVP_MD_type +EVP_add_cipher_alias +EVP_add_digest +EVP_aead_aes_128_gcm +EVP_aead_aes_128_gcm_tls12 +EVP_aead_aes_256_gcm +EVP_aead_aes_256_gcm_tls12 +EVP_aes_128_cbc +EVP_aes_128_ctr +EVP_aes_128_ecb +EVP_aes_128_gcm +EVP_aes_128_ofb +EVP_aes_192_cbc +EVP_aes_192_ctr +EVP_aes_192_ecb +EVP_aes_192_gcm +EVP_aes_256_cbc +EVP_aes_256_ctr +EVP_aes_256_ecb +EVP_aes_256_gcm +EVP_aes_256_ofb +EVP_des_cbc +EVP_des_ecb +EVP_des_ede +EVP_des_ede3 +EVP_des_ede3_cbc +EVP_des_ede_cbc +EVP_has_aes_hardware +EVP_md4 +EVP_md5 +EVP_md5_sha1 +EVP_sha1 +EVP_sha224 +EVP_sha256 +EVP_sha384 +EVP_sha512 +HMAC +HMAC_CTX_cleanup +HMAC_CTX_copy +HMAC_CTX_copy_ex +HMAC_CTX_free +HMAC_CTX_init +HMAC_CTX_new +HMAC_CTX_reset +HMAC_Final +HMAC_Init +HMAC_Init_ex +HMAC_Update +HMAC_size +MD4 +MD4_Final +MD4_Init +MD4_Transform +MD4_Update +MD5 +MD5_Final +MD5_Init +MD5_Transform +MD5_Update +OPENSSL_built_in_curves +RAND_bytes +RAND_bytes_with_additional_data +RAND_pseudo_bytes +RAND_set_urandom_fd +RSAZ_1024_mod_exp_avx2 +RSA_add_pkcs1_prefix +RSA_bits +RSA_blinding_on +RSA_check_fips +RSA_check_key +RSA_decrypt +RSA_default_method +RSA_encrypt +RSA_flags +RSA_free +RSA_generate_key_ex +RSA_generate_key_fips +RSA_get0_crt_params +RSA_get0_factors +RSA_get0_key +RSA_get_ex_data +RSA_get_ex_new_index +RSA_is_opaque +RSA_new +RSA_new_method +RSA_padding_add_PKCS1_OAEP_mgf1 +RSA_padding_add_PKCS1_PSS_mgf1 +RSA_padding_add_PKCS1_type_1 +RSA_padding_add_PKCS1_type_2 +RSA_padding_add_none +RSA_padding_check_PKCS1_OAEP_mgf1 +RSA_padding_check_PKCS1_type_1 +RSA_padding_check_PKCS1_type_2 +RSA_private_decrypt +RSA_private_encrypt +RSA_private_transform +RSA_public_decrypt +RSA_public_encrypt +RSA_set0_crt_params +RSA_set0_factors +RSA_set0_key +RSA_set_ex_data +RSA_sign +RSA_sign_pss_mgf1 +RSA_sign_raw +RSA_size +RSA_up_ref +RSA_verify +RSA_verify_PKCS1_PSS_mgf1 +RSA_verify_pss_mgf1 +RSA_verify_raw +SHA1 +SHA1_Final +SHA1_Init +SHA1_Transform +SHA1_Update +SHA224 +SHA224_Final +SHA224_Init +SHA224_Update +SHA256 +SHA256_Final +SHA256_Init +SHA256_Transform +SHA256_Update +SHA384 +SHA384_Final +SHA384_Init +SHA384_Update +SHA512 +SHA512_Final +SHA512_Init +SHA512_Transform +SHA512_Update +aes_ctr_set_key +bn_abs_sub_consttime +bn_add_words +bn_copy_words +bn_div_consttime +bn_expand +bn_fits_in_words +bn_from_montgomery_small +bn_in_range_words +bn_is_bit_set_words +bn_is_relatively_prime +bn_jacobi +bn_lcm_consttime +bn_less_than_montgomery_R +bn_less_than_words +bn_minimal_width +bn_mod_add_consttime +bn_mod_exp_base_2_consttime +bn_mod_exp_mont_small +bn_mod_inverse_consttime +bn_mod_inverse_prime +bn_mod_inverse_prime_mont_small +bn_mod_inverse_secret_prime +bn_mod_lshift1_consttime +bn_mod_lshift_consttime +bn_mod_mul_montgomery_small +bn_mod_sub_consttime +bn_mod_u16_consttime +bn_mont_n0 +bn_mul_add_words +bn_mul_comba4 +bn_mul_comba8 +bn_mul_consttime +bn_mul_small +bn_mul_words +bn_odd_number_is_obviously_composite +bn_one_to_montgomery +bn_one_to_montgomery_small +bn_rand_range_words +bn_rand_secret_range +bn_resize_words +bn_rshift1_words +bn_rshift_secret_shift +bn_select_words +bn_set_minimal_width +bn_set_words +bn_sqr_comba4 +bn_sqr_comba8 +bn_sqr_consttime +bn_sqr_small +bn_sqr_words +bn_sub_words +bn_to_montgomery_small +bn_uadd_consttime +bn_usub_consttime +bn_wexpand +crypto_gcm_clmul_enabled +ec_GFp_mont_field_decode +ec_GFp_mont_field_encode +ec_GFp_mont_field_mul +ec_GFp_mont_field_sqr +ec_GFp_mont_group_finish +ec_GFp_mont_group_init +ec_GFp_mont_group_set_curve +ec_GFp_nistp_recode_scalar_bits +ec_GFp_simple_add +ec_GFp_simple_cmp +ec_GFp_simple_dbl +ec_GFp_simple_field_mul +ec_GFp_simple_field_sqr +ec_GFp_simple_group_finish +ec_GFp_simple_group_get_curve +ec_GFp_simple_group_get_degree +ec_GFp_simple_group_init +ec_GFp_simple_group_set_curve +ec_GFp_simple_invert +ec_GFp_simple_is_at_infinity +ec_GFp_simple_is_on_curve +ec_GFp_simple_make_affine +ec_GFp_simple_point_copy +ec_GFp_simple_point_finish +ec_GFp_simple_point_init +ec_GFp_simple_point_set_affine_coordinates +ec_GFp_simple_point_set_to_infinity +ec_GFp_simple_points_make_affine +ec_bignum_to_scalar +ec_bignum_to_scalar_unchecked +ec_compute_wNAF +ec_group_new +ec_point_mul_scalar +ec_point_mul_scalar_public +ec_random_nonzero_scalar +ec_wNAF_mul +kBoringSSLRSASqrtTwo +kBoringSSLRSASqrtTwoLen +md4_block_data_order +rsa_default_decrypt +rsa_default_private_transform +rsa_default_sign_raw +rsa_default_size +FIPS_mode +aesni_gcm_decrypt +aesni_gcm_encrypt +aesni_cbc_encrypt +aesni_ccm64_decrypt_blocks +aesni_ccm64_encrypt_blocks +aesni_ctr32_encrypt_blocks +aesni_decrypt +aesni_ecb_encrypt +aesni_encrypt +aesni_ocb_decrypt +aesni_ocb_encrypt +aesni_set_decrypt_key +aesni_set_encrypt_key +aesni_xts_decrypt +aesni_xts_encrypt +asm_AES_cbc_encrypt +asm_AES_decrypt +asm_AES_encrypt +asm_AES_set_decrypt_key +asm_AES_set_encrypt_key +bsaes_cbc_encrypt +bsaes_ctr32_encrypt_blocks +bsaes_xts_decrypt +bsaes_xts_encrypt +gcm_ghash_4bit +gcm_ghash_avx +gcm_ghash_clmul +gcm_gmult_4bit +gcm_gmult_avx +gcm_gmult_clmul +gcm_init_avx +gcm_init_clmul +md5_block_asm_data_order +ecp_nistz256_avx2_select_w7 +ecp_nistz256_mul_mont +ecp_nistz256_neg +ecp_nistz256_point_add +ecp_nistz256_point_add_affine +ecp_nistz256_point_double +ecp_nistz256_select_w5 +ecp_nistz256_select_w7 +ecp_nistz256_sqr_mont +CRYPTO_rdrand +CRYPTO_rdrand_multiple8_buf +rsaz_1024_gather5_avx2 +rsaz_1024_mul_avx2 +rsaz_1024_norm2red_avx2 +rsaz_1024_red2norm_avx2 +rsaz_1024_scatter5_avx2 +rsaz_1024_sqr_avx2 +rsaz_avx2_eligible +sha1_block_data_order +sha256_block_data_order +sha512_block_data_order +vpaes_cbc_encrypt +vpaes_decrypt +vpaes_encrypt +vpaes_set_decrypt_key +vpaes_set_encrypt_key +bn_from_montgomery +bn_gather5 +bn_mul_mont_gather5 +bn_power5 +bn_scatter5 +bn_sqr8x_internal +bn_mul_mont +EVP_get_digestbyname +EVP_get_digestbynid +EVP_get_digestbyobj +EVP_marshal_digest_algorithm +EVP_parse_digest_algorithm +EVP_get_cipherbyname +EVP_get_cipherbynid +EVP_BytesToKey +EVP_enc_null +EVP_rc2_40_cbc +EVP_rc2_cbc +EVP_rc4 +EVP_aead_aes_128_gcm_siv +EVP_aead_aes_256_gcm_siv +EVP_aead_aes_128_ctr_hmac_sha256 +EVP_aead_aes_256_ctr_hmac_sha256 +EVP_aead_aes_128_ccm_bluetooth +EVP_aead_aes_128_ccm_bluetooth_8 +EVP_aead_chacha20_poly1305 +EVP_tls_cbc_copy_mac +EVP_tls_cbc_digest_record +EVP_tls_cbc_record_digest_supported +EVP_tls_cbc_remove_padding +EVP_aead_aes_128_cbc_sha1_tls +EVP_aead_aes_128_cbc_sha1_tls_implicit_iv +EVP_aead_aes_128_cbc_sha256_tls +EVP_aead_aes_256_cbc_sha1_tls +EVP_aead_aes_256_cbc_sha1_tls_implicit_iv +EVP_aead_aes_256_cbc_sha256_tls +EVP_aead_aes_256_cbc_sha384_tls +EVP_aead_des_ede3_cbc_sha1_tls +EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv +EVP_aead_null_sha1_tls +EVP_aead_aes_128_cbc_sha1_ssl3 +EVP_aead_aes_256_cbc_sha1_ssl3 +EVP_aead_des_ede3_cbc_sha1_ssl3 +EVP_aead_null_sha1_ssl3 +aes128gcmsiv_aes_ks +aes128gcmsiv_aes_ks_enc_x1 +aes128gcmsiv_dec +aes128gcmsiv_ecb_enc_block +aes128gcmsiv_enc_msg_x4 +aes128gcmsiv_enc_msg_x8 +aes128gcmsiv_kdf +aes256gcmsiv_aes_ks +aes256gcmsiv_aes_ks_enc_x1 +aes256gcmsiv_dec +aes256gcmsiv_ecb_enc_block +aes256gcmsiv_enc_msg_x4 +aes256gcmsiv_enc_msg_x8 +aes256gcmsiv_kdf +aesgcmsiv_htable6_init +aesgcmsiv_htable_init +aesgcmsiv_htable_polyval +aesgcmsiv_polyval_horner +chacha20_poly1305_open +chacha20_poly1305_seal +RC4 +RC4_set_key +CONF_VALUE_new +CONF_modules_free +CONF_modules_load_file +CONF_parse_list +NCONF_free +NCONF_get_section +NCONF_get_string +NCONF_load +NCONF_load_bio +NCONF_new +OPENSSL_config +OPENSSL_no_config +CRYPTO_chacha_20 +ChaCha20_ctr32 +CRYPTO_poly1305_finish +CRYPTO_poly1305_init +CRYPTO_poly1305_update +SPAKE2_CTX_free +SPAKE2_CTX_new +SPAKE2_generate_msg +SPAKE2_process_msg +ED25519_keypair +ED25519_keypair_from_seed +ED25519_sign +ED25519_verify +X25519 +X25519_keypair +X25519_public_from_private +x25519_ge_add +x25519_ge_frombytes_vartime +x25519_ge_p1p1_to_p2 +x25519_ge_p1p1_to_p3 +x25519_ge_p3_to_cached +x25519_ge_scalarmult +x25519_ge_scalarmult_base +x25519_ge_scalarmult_small_precomp +x25519_ge_sub +x25519_ge_tobytes +x25519_sc_reduce +BUF_MEM_append +BUF_MEM_free +BUF_MEM_grow +BUF_MEM_grow_clean +BUF_MEM_new +BUF_MEM_reserve +BUF_memdup +BUF_strdup +BUF_strlcat +BUF_strlcpy +BUF_strndup +BUF_strnlen +BN_marshal_asn1 +BN_parse_asn1_unsigned +BN_asc2bn +BN_bn2cbb_padded +BN_bn2dec +BN_bn2hex +BN_bn2mpi +BN_dec2bn +BN_hex2bn +BN_mpi2bn +BN_print +BN_print_fp +BIO_callback_ctrl +BIO_clear_flags +BIO_clear_retry_flags +BIO_copy_next_retry +BIO_ctrl +BIO_ctrl_pending +BIO_eof +BIO_find_type +BIO_flush +BIO_free +BIO_free_all +BIO_get_data +BIO_get_init +BIO_get_new_index +BIO_get_retry_flags +BIO_get_retry_reason +BIO_get_shutdown +BIO_gets +BIO_indent +BIO_int_ctrl +BIO_meth_free +BIO_meth_new +BIO_meth_set_create +BIO_meth_set_ctrl +BIO_meth_set_destroy +BIO_meth_set_gets +BIO_meth_set_puts +BIO_meth_set_read +BIO_meth_set_write +BIO_method_type +BIO_new +BIO_next +BIO_number_read +BIO_number_written +BIO_pending +BIO_pop +BIO_ptr_ctrl +BIO_push +BIO_puts +BIO_read +BIO_read_asn1 +BIO_reset +BIO_set_close +BIO_set_data +BIO_set_flags +BIO_set_init +BIO_set_retry_read +BIO_set_retry_special +BIO_set_retry_write +BIO_set_shutdown +BIO_set_write_buffer_size +BIO_should_io_special +BIO_should_read +BIO_should_retry +BIO_should_write +BIO_test_flags +BIO_up_ref +BIO_vfree +BIO_wpending +BIO_write +ERR_print_errors +BIO_get_mem_data +BIO_get_mem_ptr +BIO_mem_contents +BIO_new_mem_buf +BIO_s_mem +BIO_set_mem_buf +BIO_set_mem_eof_return +BIO_do_connect +BIO_new_connect +BIO_s_connect +BIO_set_conn_hostname +BIO_set_conn_int_port +BIO_set_conn_port +BIO_set_nbio +BIO_get_fd +BIO_new_fd +BIO_s_fd +BIO_set_fd +bio_fd_should_retry +BIO_append_filename +BIO_get_fp +BIO_new_file +BIO_new_fp +BIO_read_filename +BIO_rw_filename +BIO_s_file +BIO_set_fp +BIO_write_filename +BIO_hexdump +BIO_ctrl_get_read_request +BIO_ctrl_get_write_guarantee +BIO_new_bio_pair +BIO_shutdown_wr +BIO_printf +BIO_new_socket +BIO_s_socket +bio_clear_socket_error +bio_ip_and_port_to_socket_and_addr +bio_sock_error +bio_socket_nbio +RAND_enable_fork_unsafe_buffering +rand_fork_unsafe_buffering_enabled +RAND_SSLeay +RAND_add +RAND_cleanup +RAND_egd +RAND_file_name +RAND_get_rand_method +RAND_load_file +RAND_poll +RAND_seed +RAND_set_rand_method +RAND_status +OBJ_cbs2nid +OBJ_cmp +OBJ_create +OBJ_dup +OBJ_get0_data +OBJ_length +OBJ_ln2nid +OBJ_nid2cbb +OBJ_nid2ln +OBJ_nid2obj +OBJ_nid2sn +OBJ_obj2nid +OBJ_obj2txt +OBJ_sn2nid +OBJ_txt2nid +OBJ_txt2obj +OBJ_find_sigid_algs +OBJ_find_sigid_by_algs +ASN1_BIT_STRING_check +ASN1_BIT_STRING_get_bit +ASN1_BIT_STRING_set +ASN1_BIT_STRING_set_bit +c2i_ASN1_BIT_STRING +i2c_ASN1_BIT_STRING +d2i_ASN1_BOOLEAN +i2d_ASN1_BOOLEAN +ASN1_d2i_bio +ASN1_d2i_fp +ASN1_item_d2i_bio +ASN1_item_d2i_fp +ASN1_dup +ASN1_item_dup +ASN1_ENUMERATED_get +ASN1_ENUMERATED_set +ASN1_ENUMERATED_to_BN +BN_to_ASN1_ENUMERATED +ASN1_GENERALIZEDTIME_adj +ASN1_GENERALIZEDTIME_check +ASN1_GENERALIZEDTIME_set +ASN1_GENERALIZEDTIME_set_string +asn1_generalizedtime_to_tm +ASN1_i2d_bio +ASN1_i2d_fp +ASN1_item_i2d_bio +ASN1_item_i2d_fp +ASN1_INTEGER_cmp +ASN1_INTEGER_dup +ASN1_INTEGER_get +ASN1_INTEGER_set +ASN1_INTEGER_set_uint64 +ASN1_INTEGER_to_BN +BN_to_ASN1_INTEGER +c2i_ASN1_INTEGER +d2i_ASN1_UINTEGER +i2c_ASN1_INTEGER +ASN1_mbstring_copy +ASN1_mbstring_ncopy +ASN1_OBJECT_create +ASN1_OBJECT_free +ASN1_OBJECT_new +c2i_ASN1_OBJECT +d2i_ASN1_OBJECT +i2a_ASN1_OBJECT +i2d_ASN1_OBJECT +i2t_ASN1_OBJECT +ASN1_OCTET_STRING_cmp +ASN1_OCTET_STRING_dup +ASN1_OCTET_STRING_set +ASN1_PRINTABLE_type +ASN1_STRING_TABLE_add +ASN1_STRING_TABLE_cleanup +ASN1_STRING_TABLE_get +ASN1_STRING_get_default_mask +ASN1_STRING_set_by_NID +ASN1_STRING_set_default_mask +ASN1_STRING_set_default_mask_asc +ASN1_TIME_adj +ASN1_TIME_check +ASN1_TIME_diff +ASN1_TIME_free +ASN1_TIME_it +ASN1_TIME_new +ASN1_TIME_set +ASN1_TIME_set_string +ASN1_TIME_to_generalizedtime +d2i_ASN1_TIME +i2d_ASN1_TIME +ASN1_TYPE_cmp +ASN1_TYPE_get +ASN1_TYPE_set +ASN1_TYPE_set1 +ASN1_UTCTIME_adj +ASN1_UTCTIME_check +ASN1_UTCTIME_cmp_time_t +ASN1_UTCTIME_set +ASN1_UTCTIME_set_string +asn1_utctime_to_tm +UTF8_getc +UTF8_putc +ASN1_STRING_cmp +ASN1_STRING_copy +ASN1_STRING_data +ASN1_STRING_dup +ASN1_STRING_free +ASN1_STRING_get0_data +ASN1_STRING_length +ASN1_STRING_length_set +ASN1_STRING_new +ASN1_STRING_set +ASN1_STRING_set0 +ASN1_STRING_type +ASN1_STRING_type_new +ASN1_get_object +ASN1_object_size +ASN1_put_eoc +ASN1_put_object +ASN1_tag2str +ASN1_item_pack +ASN1_item_unpack +i2a_ASN1_ENUMERATED +i2a_ASN1_INTEGER +i2a_ASN1_STRING +ASN1_item_d2i +ASN1_item_ex_d2i +ASN1_tag2bit +asn1_ex_c2i +ASN1_item_ex_i2d +ASN1_item_i2d +ASN1_item_ndef_i2d +asn1_ex_i2c +ASN1_item_ex_free +ASN1_item_free +ASN1_primitive_free +ASN1_template_free +asn1_item_combine_free +ASN1_item_ex_new +ASN1_item_new +ASN1_primitive_new +ASN1_template_new +ASN1_ANY_it +ASN1_BIT_STRING_free +ASN1_BIT_STRING_it +ASN1_BIT_STRING_new +ASN1_BMPSTRING_free +ASN1_BMPSTRING_it +ASN1_BMPSTRING_new +ASN1_BOOLEAN_it +ASN1_ENUMERATED_free +ASN1_ENUMERATED_it +ASN1_ENUMERATED_new +ASN1_FBOOLEAN_it +ASN1_GENERALIZEDTIME_free +ASN1_GENERALIZEDTIME_it +ASN1_GENERALIZEDTIME_new +ASN1_GENERALSTRING_free +ASN1_GENERALSTRING_it +ASN1_GENERALSTRING_new +ASN1_IA5STRING_free +ASN1_IA5STRING_it +ASN1_IA5STRING_new +ASN1_INTEGER_free +ASN1_INTEGER_it +ASN1_INTEGER_new +ASN1_NULL_free +ASN1_NULL_it +ASN1_NULL_new +ASN1_OBJECT_it +ASN1_OCTET_STRING_NDEF_it +ASN1_OCTET_STRING_free +ASN1_OCTET_STRING_it +ASN1_OCTET_STRING_new +ASN1_PRINTABLESTRING_free +ASN1_PRINTABLESTRING_it +ASN1_PRINTABLESTRING_new +ASN1_PRINTABLE_free +ASN1_PRINTABLE_it +ASN1_PRINTABLE_new +ASN1_SEQUENCE_ANY_it +ASN1_SEQUENCE_it +ASN1_SET_ANY_it +ASN1_T61STRING_free +ASN1_T61STRING_it +ASN1_T61STRING_new +ASN1_TBOOLEAN_it +ASN1_TYPE_free +ASN1_TYPE_new +ASN1_UNIVERSALSTRING_free +ASN1_UNIVERSALSTRING_it +ASN1_UNIVERSALSTRING_new +ASN1_UTCTIME_free +ASN1_UTCTIME_it +ASN1_UTCTIME_new +ASN1_UTF8STRING_free +ASN1_UTF8STRING_it +ASN1_UTF8STRING_new +ASN1_VISIBLESTRING_free +ASN1_VISIBLESTRING_it +ASN1_VISIBLESTRING_new +DIRECTORYSTRING_free +DIRECTORYSTRING_it +DIRECTORYSTRING_new +DISPLAYTEXT_free +DISPLAYTEXT_it +DISPLAYTEXT_new +d2i_ASN1_BIT_STRING +d2i_ASN1_BMPSTRING +d2i_ASN1_ENUMERATED +d2i_ASN1_GENERALIZEDTIME +d2i_ASN1_GENERALSTRING +d2i_ASN1_IA5STRING +d2i_ASN1_INTEGER +d2i_ASN1_NULL +d2i_ASN1_OCTET_STRING +d2i_ASN1_PRINTABLE +d2i_ASN1_PRINTABLESTRING +d2i_ASN1_SEQUENCE_ANY +d2i_ASN1_SET_ANY +d2i_ASN1_T61STRING +d2i_ASN1_TYPE +d2i_ASN1_UNIVERSALSTRING +d2i_ASN1_UTCTIME +d2i_ASN1_UTF8STRING +d2i_ASN1_VISIBLESTRING +d2i_DIRECTORYSTRING +d2i_DISPLAYTEXT +i2d_ASN1_BIT_STRING +i2d_ASN1_BMPSTRING +i2d_ASN1_ENUMERATED +i2d_ASN1_GENERALIZEDTIME +i2d_ASN1_GENERALSTRING +i2d_ASN1_IA5STRING +i2d_ASN1_INTEGER +i2d_ASN1_NULL +i2d_ASN1_OCTET_STRING +i2d_ASN1_PRINTABLE +i2d_ASN1_PRINTABLESTRING +i2d_ASN1_SEQUENCE_ANY +i2d_ASN1_SET_ANY +i2d_ASN1_T61STRING +i2d_ASN1_TYPE +i2d_ASN1_UNIVERSALSTRING +i2d_ASN1_UTCTIME +i2d_ASN1_UTF8STRING +i2d_ASN1_VISIBLESTRING +i2d_DIRECTORYSTRING +i2d_DISPLAYTEXT +asn1_do_adb +asn1_enc_free +asn1_enc_init +asn1_enc_restore +asn1_enc_save +asn1_get_choice_selector +asn1_get_field_ptr +asn1_refcount_dec_and_test_zero +asn1_refcount_set_one +asn1_set_choice_selector +OPENSSL_gmtime +OPENSSL_gmtime_adj +OPENSSL_gmtime_diff +ENGINE_free +ENGINE_get_ECDSA_method +ENGINE_get_RSA_method +ENGINE_new +ENGINE_set_ECDSA_method +ENGINE_set_RSA_method +METHOD_ref +METHOD_unref +DH_compute_key +DH_free +DH_generate_key +DH_generate_parameters_ex +DH_get0_key +DH_get0_pqg +DH_get_ex_data +DH_get_ex_new_index +DH_new +DH_num_bits +DH_set0_key +DH_set0_pqg +DH_set_ex_data +DH_size +DH_up_ref +DHparams_dup +BN_get_rfc3526_prime_1536 +DH_check +DH_check_pub_key +DH_marshal_parameters +DH_parse_parameters +d2i_DHparams +i2d_DHparams +DSA_SIG_free +DSA_SIG_new +DSA_check_signature +DSA_do_check_signature +DSA_do_sign +DSA_do_verify +DSA_dup_DH +DSA_free +DSA_generate_key +DSA_generate_parameters_ex +DSA_get0_key +DSA_get0_pqg +DSA_get_ex_data +DSA_get_ex_new_index +DSA_new +DSA_set0_key +DSA_set0_pqg +DSA_set_ex_data +DSA_sign +DSA_size +DSA_up_ref +DSA_verify +DSAparams_dup +DSA_SIG_marshal +DSA_SIG_parse +DSA_marshal_parameters +DSA_marshal_private_key +DSA_marshal_public_key +DSA_parse_parameters +DSA_parse_private_key +DSA_parse_public_key +d2i_DSAPrivateKey +d2i_DSAPublicKey +d2i_DSA_SIG +d2i_DSAparams +i2d_DSAPrivateKey +i2d_DSAPublicKey +i2d_DSA_SIG +i2d_DSAparams +RSAPrivateKey_dup +RSAPublicKey_dup +RSA_marshal_private_key +RSA_marshal_public_key +RSA_parse_private_key +RSA_parse_public_key +RSA_private_key_from_bytes +RSA_private_key_to_bytes +RSA_public_key_from_bytes +RSA_public_key_to_bytes +d2i_RSAPrivateKey +d2i_RSAPublicKey +i2d_RSAPrivateKey +i2d_RSAPublicKey +EC_KEY_marshal_curve_name +EC_KEY_marshal_private_key +EC_KEY_parse_curve_name +EC_KEY_parse_parameters +EC_KEY_parse_private_key +EC_POINT_point2cbb +d2i_ECParameters +d2i_ECPrivateKey +i2d_ECParameters +i2d_ECPrivateKey +i2o_ECPublicKey +o2i_ECPublicKey +ECDH_compute_key +ECDSA_SIG_from_bytes +ECDSA_SIG_marshal +ECDSA_SIG_max_len +ECDSA_SIG_parse +ECDSA_SIG_to_bytes +ECDSA_sign +ECDSA_size +ECDSA_verify +d2i_ECDSA_SIG +i2d_ECDSA_SIG +AES_CMAC +CMAC_CTX_free +CMAC_CTX_new +CMAC_Final +CMAC_Init +CMAC_Reset +CMAC_Update +EVP_DigestSign +EVP_DigestSignFinal +EVP_DigestSignInit +EVP_DigestSignUpdate +EVP_DigestVerify +EVP_DigestVerifyFinal +EVP_DigestVerifyInit +EVP_DigestVerifyUpdate +EVP_PKEY_CTX_get_signature_md +EVP_PKEY_CTX_set_signature_md +EVP_PKEY_assign +EVP_PKEY_assign_DSA +EVP_PKEY_assign_EC_KEY +EVP_PKEY_assign_RSA +EVP_PKEY_bits +EVP_PKEY_cmp +EVP_PKEY_cmp_parameters +EVP_PKEY_copy_parameters +EVP_PKEY_free +EVP_PKEY_get0_DH +EVP_PKEY_get0_DSA +EVP_PKEY_get0_EC_KEY +EVP_PKEY_get0_RSA +EVP_PKEY_get1_DSA +EVP_PKEY_get1_EC_KEY +EVP_PKEY_get1_RSA +EVP_PKEY_id +EVP_PKEY_is_opaque +EVP_PKEY_missing_parameters +EVP_PKEY_new +EVP_PKEY_set1_DSA +EVP_PKEY_set1_EC_KEY +EVP_PKEY_set1_RSA +EVP_PKEY_set_type +EVP_PKEY_size +EVP_PKEY_type +EVP_PKEY_up_ref +EVP_cleanup +OPENSSL_add_all_algorithms_conf +OpenSSL_add_all_algorithms +OpenSSL_add_all_ciphers +OpenSSL_add_all_digests +EVP_marshal_private_key +EVP_marshal_public_key +EVP_parse_private_key +EVP_parse_public_key +d2i_AutoPrivateKey +d2i_PrivateKey +i2d_PublicKey +EVP_PKEY_CTX_ctrl +EVP_PKEY_CTX_dup +EVP_PKEY_CTX_free +EVP_PKEY_CTX_get0_pkey +EVP_PKEY_CTX_new +EVP_PKEY_CTX_new_id +EVP_PKEY_decrypt +EVP_PKEY_decrypt_init +EVP_PKEY_derive +EVP_PKEY_derive_init +EVP_PKEY_derive_set_peer +EVP_PKEY_encrypt +EVP_PKEY_encrypt_init +EVP_PKEY_keygen +EVP_PKEY_keygen_init +EVP_PKEY_sign +EVP_PKEY_sign_init +EVP_PKEY_verify +EVP_PKEY_verify_init +EVP_PKEY_verify_recover +EVP_PKEY_verify_recover_init +dsa_asn1_meth +ec_pkey_meth +ec_asn1_meth +ed25519_pkey_meth +EVP_PKEY_new_ed25519_private +EVP_PKEY_new_ed25519_public +ed25519_asn1_meth +EVP_PKEY_CTX_get0_rsa_oaep_label +EVP_PKEY_CTX_get_rsa_mgf1_md +EVP_PKEY_CTX_get_rsa_oaep_md +EVP_PKEY_CTX_get_rsa_padding +EVP_PKEY_CTX_get_rsa_pss_saltlen +EVP_PKEY_CTX_set0_rsa_oaep_label +EVP_PKEY_CTX_set_rsa_keygen_bits +EVP_PKEY_CTX_set_rsa_keygen_pubexp +EVP_PKEY_CTX_set_rsa_mgf1_md +EVP_PKEY_CTX_set_rsa_oaep_md +EVP_PKEY_CTX_set_rsa_padding +EVP_PKEY_CTX_set_rsa_pss_saltlen +rsa_pkey_meth +rsa_asn1_meth +PKCS5_PBKDF2_HMAC +PKCS5_PBKDF2_HMAC_SHA1 +EVP_PKEY_print_params +EVP_PKEY_print_private +EVP_PKEY_print_public +EVP_PBE_scrypt +EVP_SignFinal +EVP_SignInit +EVP_SignInit_ex +EVP_SignUpdate +EVP_VerifyFinal +EVP_VerifyInit +EVP_VerifyInit_ex +EVP_VerifyUpdate +HKDF +HKDF_expand +HKDF_extract +PEM_read_DSAPrivateKey +PEM_read_DSA_PUBKEY +PEM_read_DSAparams +PEM_read_ECPrivateKey +PEM_read_EC_PUBKEY +PEM_read_PUBKEY +PEM_read_RSAPrivateKey +PEM_read_RSAPublicKey +PEM_read_RSA_PUBKEY +PEM_read_X509_CRL +PEM_read_X509_REQ +PEM_read_bio_DSAPrivateKey +PEM_read_bio_DSA_PUBKEY +PEM_read_bio_DSAparams +PEM_read_bio_ECPrivateKey +PEM_read_bio_EC_PUBKEY +PEM_read_bio_PUBKEY +PEM_read_bio_RSAPrivateKey +PEM_read_bio_RSAPublicKey +PEM_read_bio_RSA_PUBKEY +PEM_read_bio_X509_CRL +PEM_read_bio_X509_REQ +PEM_write_DHparams +PEM_write_DSAPrivateKey +PEM_write_DSA_PUBKEY +PEM_write_DSAparams +PEM_write_ECPrivateKey +PEM_write_EC_PUBKEY +PEM_write_PUBKEY +PEM_write_RSAPrivateKey +PEM_write_RSAPublicKey +PEM_write_RSA_PUBKEY +PEM_write_X509_CRL +PEM_write_X509_REQ +PEM_write_X509_REQ_NEW +PEM_write_bio_DHparams +PEM_write_bio_DSAPrivateKey +PEM_write_bio_DSA_PUBKEY +PEM_write_bio_DSAparams +PEM_write_bio_ECPrivateKey +PEM_write_bio_EC_PUBKEY +PEM_write_bio_PUBKEY +PEM_write_bio_RSAPrivateKey +PEM_write_bio_RSAPublicKey +PEM_write_bio_RSA_PUBKEY +PEM_write_bio_X509_CRL +PEM_write_bio_X509_REQ +PEM_write_bio_X509_REQ_NEW +PEM_X509_INFO_read +PEM_X509_INFO_read_bio +PEM_X509_INFO_write_bio +PEM_ASN1_read +PEM_ASN1_write +PEM_ASN1_write_bio +PEM_bytes_read_bio +PEM_def_callback +PEM_dek_info +PEM_do_header +PEM_get_EVP_CIPHER_INFO +PEM_proc_type +PEM_read +PEM_read_bio +PEM_write +PEM_write_bio +PEM_ASN1_read_bio +PEM_read_PKCS8 +PEM_read_PKCS8_PRIV_KEY_INFO +PEM_read_bio_PKCS8 +PEM_read_bio_PKCS8_PRIV_KEY_INFO +PEM_write_PKCS8 +PEM_write_PKCS8PrivateKey +PEM_write_PKCS8PrivateKey_nid +PEM_write_PKCS8_PRIV_KEY_INFO +PEM_write_bio_PKCS8 +PEM_write_bio_PKCS8PrivateKey +PEM_write_bio_PKCS8PrivateKey_nid +PEM_write_bio_PKCS8_PRIV_KEY_INFO +d2i_PKCS8PrivateKey_bio +d2i_PKCS8PrivateKey_fp +i2d_PKCS8PrivateKey_bio +i2d_PKCS8PrivateKey_fp +i2d_PKCS8PrivateKey_nid_bio +i2d_PKCS8PrivateKey_nid_fp +PEM_read_DHparams +PEM_read_PrivateKey +PEM_read_bio_DHparams +PEM_read_bio_PrivateKey +PEM_write_PrivateKey +PEM_write_bio_PrivateKey +PEM_read_X509 +PEM_read_bio_X509 +PEM_write_X509 +PEM_write_bio_X509 +PEM_read_X509_AUX +PEM_read_bio_X509_AUX +PEM_write_X509_AUX +PEM_write_bio_X509_AUX +ASN1_digest +ASN1_item_digest +ASN1_item_sign +ASN1_item_sign_ctx +ASN1_STRING_print_ex +ASN1_STRING_print_ex_fp +ASN1_STRING_to_UTF8 +X509_NAME_print_ex +X509_NAME_print_ex_fp +ASN1_item_verify +x509_digest_sign_algorithm +x509_digest_verify_init +ASN1_generate_nconf +ASN1_generate_v3 +X509_LOOKUP_hash_dir +X509_LOOKUP_file +X509_load_cert_crl_file +X509_load_cert_file +X509_load_crl_file +i2d_PrivateKey +RSA_PSS_PARAMS_free +RSA_PSS_PARAMS_it +RSA_PSS_PARAMS_new +d2i_RSA_PSS_PARAMS +i2d_RSA_PSS_PARAMS +x509_print_rsa_pss_params +x509_rsa_ctx_to_pss +x509_rsa_pss_to_ctx +X509_CRL_print +X509_CRL_print_fp +X509_REQ_print +X509_REQ_print_ex +X509_REQ_print_fp +ASN1_GENERALIZEDTIME_print +ASN1_STRING_print +ASN1_TIME_print +ASN1_UTCTIME_print +X509_NAME_print +X509_ocspid_print +X509_print +X509_print_ex +X509_print_ex_fp +X509_print_fp +X509_signature_print +X509_CERT_AUX_print +PKCS8_pkey_get0 +PKCS8_pkey_set0 +X509_signature_dump +X509_ATTRIBUTE_count +X509_ATTRIBUTE_create_by_NID +X509_ATTRIBUTE_create_by_OBJ +X509_ATTRIBUTE_create_by_txt +X509_ATTRIBUTE_get0_data +X509_ATTRIBUTE_get0_object +X509_ATTRIBUTE_get0_type +X509_ATTRIBUTE_set1_data +X509_ATTRIBUTE_set1_object +X509at_add1_attr +X509at_add1_attr_by_NID +X509at_add1_attr_by_OBJ +X509at_add1_attr_by_txt +X509at_delete_attr +X509at_get0_data_by_OBJ +X509at_get_attr +X509at_get_attr_by_NID +X509at_get_attr_by_OBJ +X509at_get_attr_count +X509_CRL_check_suiteb +X509_CRL_cmp +X509_CRL_match +X509_NAME_cmp +X509_NAME_hash +X509_NAME_hash_old +X509_chain_check_suiteb +X509_chain_up_ref +X509_check_private_key +X509_cmp +X509_find_by_issuer_and_serial +X509_find_by_subject +X509_get0_pubkey_bitstr +X509_get_issuer_name +X509_get_pubkey +X509_get_serialNumber +X509_get_subject_name +X509_issuer_and_serial_cmp +X509_issuer_and_serial_hash +X509_issuer_name_cmp +X509_issuer_name_hash +X509_issuer_name_hash_old +X509_subject_name_cmp +X509_subject_name_hash +X509_subject_name_hash_old +X509_STORE_load_locations +X509_STORE_set_default_paths +X509_get_default_cert_area +X509_get_default_cert_dir +X509_get_default_cert_dir_env +X509_get_default_cert_file +X509_get_default_cert_file_env +X509_get_default_private_dir +X509_CRL_add1_ext_i2d +X509_CRL_add_ext +X509_CRL_delete_ext +X509_CRL_get_ext +X509_CRL_get_ext_by_NID +X509_CRL_get_ext_by_OBJ +X509_CRL_get_ext_by_critical +X509_CRL_get_ext_count +X509_CRL_get_ext_d2i +X509_REVOKED_add1_ext_i2d +X509_REVOKED_add_ext +X509_REVOKED_delete_ext +X509_REVOKED_get_ext +X509_REVOKED_get_ext_by_NID +X509_REVOKED_get_ext_by_OBJ +X509_REVOKED_get_ext_by_critical +X509_REVOKED_get_ext_count +X509_REVOKED_get_ext_d2i +X509_add1_ext_i2d +X509_add_ext +X509_delete_ext +X509_get_ext +X509_get_ext_by_NID +X509_get_ext_by_OBJ +X509_get_ext_by_critical +X509_get_ext_count +X509_get_ext_d2i +X509_LOOKUP_by_alias +X509_LOOKUP_by_fingerprint +X509_LOOKUP_by_issuer_serial +X509_LOOKUP_by_subject +X509_LOOKUP_ctrl +X509_LOOKUP_free +X509_LOOKUP_init +X509_LOOKUP_new +X509_LOOKUP_shutdown +X509_OBJECT_free_contents +X509_OBJECT_get0_X509 +X509_OBJECT_get_type +X509_OBJECT_idx_by_subject +X509_OBJECT_retrieve_by_subject +X509_OBJECT_retrieve_match +X509_OBJECT_up_ref_count +X509_STORE_CTX_get0_store +X509_STORE_CTX_get1_issuer +X509_STORE_add_cert +X509_STORE_add_crl +X509_STORE_add_lookup +X509_STORE_free +X509_STORE_get0_objects +X509_STORE_get0_param +X509_STORE_get1_certs +X509_STORE_get1_crls +X509_STORE_get_by_subject +X509_STORE_new +X509_STORE_set0_additional_untrusted +X509_STORE_set1_param +X509_STORE_set_depth +X509_STORE_set_flags +X509_STORE_set_lookup_crls_cb +X509_STORE_set_purpose +X509_STORE_set_trust +X509_STORE_set_verify_cb +X509_STORE_up_ref +X509_NAME_oneline +X509_REQ_to_X509 +X509_REQ_add1_attr +X509_REQ_add1_attr_by_NID +X509_REQ_add1_attr_by_OBJ +X509_REQ_add1_attr_by_txt +X509_REQ_add_extensions +X509_REQ_add_extensions_nid +X509_REQ_check_private_key +X509_REQ_delete_attr +X509_REQ_extension_nid +X509_REQ_get_attr +X509_REQ_get_attr_by_NID +X509_REQ_get_attr_by_OBJ +X509_REQ_get_attr_count +X509_REQ_get_extension_nids +X509_REQ_get_extensions +X509_REQ_get_pubkey +X509_REQ_set_extension_nids +X509_to_X509_REQ +X509_get0_extensions +X509_get0_notAfter +X509_get0_notBefore +X509_set_issuer_name +X509_set_notAfter +X509_set_notBefore +X509_set_pubkey +X509_set_serialNumber +X509_set_subject_name +X509_set_version +X509_TRUST_add +X509_TRUST_cleanup +X509_TRUST_get0 +X509_TRUST_get0_name +X509_TRUST_get_by_id +X509_TRUST_get_count +X509_TRUST_get_flags +X509_TRUST_get_trust +X509_TRUST_set +X509_TRUST_set_default +X509_check_trust +X509_verify_cert_error_string +X509_EXTENSION_create_by_NID +X509_EXTENSION_create_by_OBJ +X509_EXTENSION_get_critical +X509_EXTENSION_get_data +X509_EXTENSION_get_object +X509_EXTENSION_set_critical +X509_EXTENSION_set_data +X509_EXTENSION_set_object +X509v3_add_ext +X509v3_delete_ext +X509v3_get_ext +X509v3_get_ext_by_NID +X509v3_get_ext_by_OBJ +X509v3_get_ext_by_critical +X509v3_get_ext_count +X509_CRL_diff +X509_STORE_CTX_cleanup +X509_STORE_CTX_free +X509_STORE_CTX_get0_current_crl +X509_STORE_CTX_get0_current_issuer +X509_STORE_CTX_get0_param +X509_STORE_CTX_get0_parent_ctx +X509_STORE_CTX_get0_policy_tree +X509_STORE_CTX_get0_untrusted +X509_STORE_CTX_get1_chain +X509_STORE_CTX_get_chain +X509_STORE_CTX_get_current_cert +X509_STORE_CTX_get_error +X509_STORE_CTX_get_error_depth +X509_STORE_CTX_get_ex_data +X509_STORE_CTX_get_ex_new_index +X509_STORE_CTX_get_explicit_policy +X509_STORE_CTX_init +X509_STORE_CTX_new +X509_STORE_CTX_purpose_inherit +X509_STORE_CTX_set0_crls +X509_STORE_CTX_set0_param +X509_STORE_CTX_set_cert +X509_STORE_CTX_set_chain +X509_STORE_CTX_set_default +X509_STORE_CTX_set_depth +X509_STORE_CTX_set_error +X509_STORE_CTX_set_ex_data +X509_STORE_CTX_set_flags +X509_STORE_CTX_set_purpose +X509_STORE_CTX_set_time +X509_STORE_CTX_set_trust +X509_STORE_CTX_set_verify_cb +X509_STORE_CTX_trusted_stack +X509_STORE_CTX_zero +X509_cmp_current_time +X509_cmp_time +X509_gmtime_adj +X509_time_adj +X509_time_adj_ex +X509_verify_cert +X509_VERIFY_PARAM_add0_policy +X509_VERIFY_PARAM_add0_table +X509_VERIFY_PARAM_add1_host +X509_VERIFY_PARAM_clear_flags +X509_VERIFY_PARAM_free +X509_VERIFY_PARAM_get0 +X509_VERIFY_PARAM_get0_name +X509_VERIFY_PARAM_get0_peername +X509_VERIFY_PARAM_get_count +X509_VERIFY_PARAM_get_depth +X509_VERIFY_PARAM_get_flags +X509_VERIFY_PARAM_inherit +X509_VERIFY_PARAM_lookup +X509_VERIFY_PARAM_new +X509_VERIFY_PARAM_set1 +X509_VERIFY_PARAM_set1_email +X509_VERIFY_PARAM_set1_host +X509_VERIFY_PARAM_set1_ip +X509_VERIFY_PARAM_set1_ip_asc +X509_VERIFY_PARAM_set1_name +X509_VERIFY_PARAM_set1_policies +X509_VERIFY_PARAM_set_depth +X509_VERIFY_PARAM_set_flags +X509_VERIFY_PARAM_set_hostflags +X509_VERIFY_PARAM_set_purpose +X509_VERIFY_PARAM_set_time +X509_VERIFY_PARAM_set_trust +X509_VERIFY_PARAM_table_cleanup +X509_CRL_set_issuer_name +X509_CRL_set_lastUpdate +X509_CRL_set_nextUpdate +X509_CRL_set_version +X509_CRL_sort +X509_CRL_up_ref +X509_REVOKED_set_revocationDate +X509_REVOKED_set_serialNumber +X509_NAME_ENTRY_create_by_NID +X509_NAME_ENTRY_create_by_OBJ +X509_NAME_ENTRY_create_by_txt +X509_NAME_ENTRY_get_data +X509_NAME_ENTRY_get_object +X509_NAME_ENTRY_set_data +X509_NAME_ENTRY_set_object +X509_NAME_add_entry +X509_NAME_add_entry_by_NID +X509_NAME_add_entry_by_OBJ +X509_NAME_add_entry_by_txt +X509_NAME_delete_entry +X509_NAME_entry_count +X509_NAME_get_entry +X509_NAME_get_index_by_NID +X509_NAME_get_index_by_OBJ +X509_NAME_get_text_by_NID +X509_NAME_get_text_by_OBJ +X509_REQ_set_pubkey +X509_REQ_set_subject_name +X509_REQ_set_version +NETSCAPE_SPKI_b64_decode +NETSCAPE_SPKI_b64_encode +NETSCAPE_SPKI_get_pubkey +NETSCAPE_SPKI_set_pubkey +X509_ALGORS_it +X509_ALGOR_cmp +X509_ALGOR_dup +X509_ALGOR_free +X509_ALGOR_get0 +X509_ALGOR_it +X509_ALGOR_new +X509_ALGOR_set0 +X509_ALGOR_set_md +d2i_X509_ALGOR +d2i_X509_ALGORS +i2d_X509_ALGOR +i2d_X509_ALGORS +NETSCAPE_SPKI_sign +NETSCAPE_SPKI_verify +X509_CRL_digest +X509_CRL_sign +X509_CRL_sign_ctx +X509_NAME_digest +X509_REQ_digest +X509_REQ_sign +X509_REQ_sign_ctx +X509_REQ_verify +X509_digest +X509_pubkey_digest +X509_sign +X509_sign_ctx +X509_verify +d2i_DSAPrivateKey_bio +d2i_DSAPrivateKey_fp +d2i_DSA_PUBKEY_bio +d2i_DSA_PUBKEY_fp +d2i_ECPrivateKey_bio +d2i_ECPrivateKey_fp +d2i_EC_PUBKEY_bio +d2i_EC_PUBKEY_fp +d2i_PKCS8_PRIV_KEY_INFO_bio +d2i_PKCS8_PRIV_KEY_INFO_fp +d2i_PKCS8_bio +d2i_PKCS8_fp +d2i_PUBKEY_bio +d2i_PUBKEY_fp +d2i_PrivateKey_bio +d2i_PrivateKey_fp +d2i_RSAPrivateKey_bio +d2i_RSAPrivateKey_fp +d2i_RSAPublicKey_bio +d2i_RSAPublicKey_fp +d2i_RSA_PUBKEY_bio +d2i_RSA_PUBKEY_fp +d2i_X509_CRL_bio +d2i_X509_CRL_fp +d2i_X509_REQ_bio +d2i_X509_REQ_fp +d2i_X509_bio +d2i_X509_fp +i2d_DSAPrivateKey_bio +i2d_DSAPrivateKey_fp +i2d_DSA_PUBKEY_bio +i2d_DSA_PUBKEY_fp +i2d_ECPrivateKey_bio +i2d_ECPrivateKey_fp +i2d_EC_PUBKEY_bio +i2d_EC_PUBKEY_fp +i2d_PKCS8PrivateKeyInfo_bio +i2d_PKCS8PrivateKeyInfo_fp +i2d_PKCS8_PRIV_KEY_INFO_bio +i2d_PKCS8_PRIV_KEY_INFO_fp +i2d_PKCS8_bio +i2d_PKCS8_fp +i2d_PUBKEY_bio +i2d_PUBKEY_fp +i2d_PrivateKey_bio +i2d_PrivateKey_fp +i2d_RSAPrivateKey_bio +i2d_RSAPrivateKey_fp +i2d_RSAPublicKey_bio +i2d_RSAPublicKey_fp +i2d_RSA_PUBKEY_bio +i2d_RSA_PUBKEY_fp +i2d_X509_CRL_bio +i2d_X509_CRL_fp +i2d_X509_REQ_bio +i2d_X509_REQ_fp +i2d_X509_bio +i2d_X509_fp +X509_ATTRIBUTE_SET_it +X509_ATTRIBUTE_create +X509_ATTRIBUTE_dup +X509_ATTRIBUTE_free +X509_ATTRIBUTE_it +X509_ATTRIBUTE_new +d2i_X509_ATTRIBUTE +i2d_X509_ATTRIBUTE +X509_CRL_INFO_free +X509_CRL_INFO_it +X509_CRL_INFO_new +X509_CRL_METHOD_free +X509_CRL_METHOD_new +X509_CRL_add0_revoked +X509_CRL_dup +X509_CRL_free +X509_CRL_get0_by_cert +X509_CRL_get0_by_serial +X509_CRL_get_meth_data +X509_CRL_it +X509_CRL_new +X509_CRL_set_default_method +X509_CRL_set_meth_data +X509_CRL_verify +X509_REVOKED_dup +X509_REVOKED_free +X509_REVOKED_it +X509_REVOKED_new +d2i_X509_CRL +d2i_X509_CRL_INFO +d2i_X509_REVOKED +i2d_X509_CRL +i2d_X509_CRL_INFO +i2d_X509_REVOKED +X509_EXTENSIONS_it +X509_EXTENSION_dup +X509_EXTENSION_free +X509_EXTENSION_it +X509_EXTENSION_new +d2i_X509_EXTENSION +d2i_X509_EXTENSIONS +i2d_X509_EXTENSION +i2d_X509_EXTENSIONS +X509_INFO_free +X509_INFO_new +X509_NAME_ENTRIES_it +X509_NAME_ENTRY_dup +X509_NAME_ENTRY_free +X509_NAME_ENTRY_it +X509_NAME_ENTRY_new +X509_NAME_ENTRY_set +X509_NAME_INTERNAL_it +X509_NAME_dup +X509_NAME_free +X509_NAME_get0_der +X509_NAME_it +X509_NAME_new +X509_NAME_set +d2i_X509_NAME +d2i_X509_NAME_ENTRY +i2d_X509_NAME +i2d_X509_NAME_ENTRY +X509_PKEY_free +X509_PKEY_new +X509_PUBKEY_free +X509_PUBKEY_get +X509_PUBKEY_get0_param +X509_PUBKEY_it +X509_PUBKEY_new +X509_PUBKEY_set +X509_PUBKEY_set0_param +d2i_DSA_PUBKEY +d2i_EC_PUBKEY +d2i_PUBKEY +d2i_RSA_PUBKEY +d2i_X509_PUBKEY +i2d_DSA_PUBKEY +i2d_EC_PUBKEY +i2d_PUBKEY +i2d_RSA_PUBKEY +i2d_X509_PUBKEY +X509_REQ_INFO_free +X509_REQ_INFO_it +X509_REQ_INFO_new +X509_REQ_dup +X509_REQ_free +X509_REQ_it +X509_REQ_new +d2i_X509_REQ +d2i_X509_REQ_INFO +i2d_X509_REQ +i2d_X509_REQ_INFO +X509_SIG_free +X509_SIG_it +X509_SIG_new +d2i_X509_SIG +i2d_X509_SIG +NETSCAPE_SPKAC_free +NETSCAPE_SPKAC_it +NETSCAPE_SPKAC_new +NETSCAPE_SPKI_free +NETSCAPE_SPKI_it +NETSCAPE_SPKI_new +d2i_NETSCAPE_SPKAC +d2i_NETSCAPE_SPKI +i2d_NETSCAPE_SPKAC +i2d_NETSCAPE_SPKI +X509_VAL_free +X509_VAL_it +X509_VAL_new +d2i_X509_VAL +i2d_X509_VAL +X509_CINF_free +X509_CINF_it +X509_CINF_new +X509_dup +X509_free +X509_get0_signature +X509_get_ex_data +X509_get_ex_new_index +X509_get_signature_nid +X509_it +X509_new +X509_parse_from_buffer +X509_set_ex_data +X509_up_ref +d2i_X509 +d2i_X509_AUX +d2i_X509_CINF +i2d_X509 +i2d_X509_AUX +i2d_X509_CINF +X509_CERT_AUX_free +X509_CERT_AUX_it +X509_CERT_AUX_new +X509_add1_reject_object +X509_add1_trust_object +X509_alias_get0 +X509_alias_set1 +X509_keyid_get0 +X509_keyid_set1 +X509_reject_clear +X509_trust_clear +d2i_X509_CERT_AUX +i2d_X509_CERT_AUX +policy_cache_find_data +policy_cache_free +policy_cache_set +policy_data_free +policy_data_new +X509_policy_level_get0_node +X509_policy_level_node_count +X509_policy_node_get0_parent +X509_policy_node_get0_policy +X509_policy_node_get0_qualifiers +X509_policy_tree_get0_level +X509_policy_tree_get0_policies +X509_policy_tree_get0_user_policies +X509_policy_tree_level_count +policy_cache_set_mapping +level_add_node +level_find_node +policy_node_cmp_new +policy_node_free +policy_node_match +tree_find_sk +X509_policy_check +X509_policy_tree_free +v3_akey_id +AUTHORITY_KEYID_free +AUTHORITY_KEYID_it +AUTHORITY_KEYID_new +d2i_AUTHORITY_KEYID +i2d_AUTHORITY_KEYID +GENERAL_NAME_print +a2i_GENERAL_NAME +i2v_GENERAL_NAME +i2v_GENERAL_NAMES +v2i_GENERAL_NAME +v2i_GENERAL_NAMES +v2i_GENERAL_NAME_ex +v3_alt +BASIC_CONSTRAINTS_free +BASIC_CONSTRAINTS_it +BASIC_CONSTRAINTS_new +d2i_BASIC_CONSTRAINTS +i2d_BASIC_CONSTRAINTS +v3_bcons +i2v_ASN1_BIT_STRING +v2i_ASN1_BIT_STRING +v3_key_usage +v3_nscert +X509V3_EXT_CRL_add_nconf +X509V3_EXT_REQ_add_nconf +X509V3_EXT_add_nconf +X509V3_EXT_add_nconf_sk +X509V3_EXT_i2d +X509V3_EXT_nconf +X509V3_EXT_nconf_nid +X509V3_get_section +X509V3_get_string +X509V3_section_free +X509V3_set_ctx +X509V3_set_nconf +X509V3_string_free +CERTIFICATEPOLICIES_free +CERTIFICATEPOLICIES_it +CERTIFICATEPOLICIES_new +NOTICEREF_free +NOTICEREF_it +NOTICEREF_new +POLICYINFO_free +POLICYINFO_it +POLICYINFO_new +POLICYQUALINFO_free +POLICYQUALINFO_it +POLICYQUALINFO_new +USERNOTICE_free +USERNOTICE_it +USERNOTICE_new +X509_POLICY_NODE_print +d2i_CERTIFICATEPOLICIES +d2i_NOTICEREF +d2i_POLICYINFO +d2i_POLICYQUALINFO +d2i_USERNOTICE +i2d_CERTIFICATEPOLICIES +i2d_NOTICEREF +i2d_POLICYINFO +i2d_POLICYQUALINFO +i2d_USERNOTICE +v3_cpols +CRL_DIST_POINTS_free +CRL_DIST_POINTS_it +CRL_DIST_POINTS_new +DIST_POINT_NAME_free +DIST_POINT_NAME_it +DIST_POINT_NAME_new +DIST_POINT_free +DIST_POINT_it +DIST_POINT_new +DIST_POINT_set_dpname +ISSUING_DIST_POINT_free +ISSUING_DIST_POINT_it +ISSUING_DIST_POINT_new +d2i_CRL_DIST_POINTS +d2i_DIST_POINT +d2i_DIST_POINT_NAME +d2i_ISSUING_DIST_POINT +i2d_CRL_DIST_POINTS +i2d_DIST_POINT +i2d_DIST_POINT_NAME +i2d_ISSUING_DIST_POINT +v3_crld +v3_freshest_crl +v3_idp +i2s_ASN1_ENUMERATED_TABLE +v3_crl_reason +EXTENDED_KEY_USAGE_free +EXTENDED_KEY_USAGE_it +EXTENDED_KEY_USAGE_new +d2i_EXTENDED_KEY_USAGE +i2d_EXTENDED_KEY_USAGE +v3_ext_ku +v3_ocsp_accresp +EDIPARTYNAME_free +EDIPARTYNAME_it +EDIPARTYNAME_new +GENERAL_NAMES_free +GENERAL_NAMES_it +GENERAL_NAMES_new +GENERAL_NAME_cmp +GENERAL_NAME_dup +GENERAL_NAME_free +GENERAL_NAME_get0_otherName +GENERAL_NAME_get0_value +GENERAL_NAME_it +GENERAL_NAME_new +GENERAL_NAME_set0_othername +GENERAL_NAME_set0_value +OTHERNAME_cmp +OTHERNAME_free +OTHERNAME_it +OTHERNAME_new +d2i_EDIPARTYNAME +d2i_GENERAL_NAME +d2i_GENERAL_NAMES +d2i_OTHERNAME +i2d_EDIPARTYNAME +i2d_GENERAL_NAME +i2d_GENERAL_NAMES +i2d_OTHERNAME +v3_ns_ia5_list +ACCESS_DESCRIPTION_free +ACCESS_DESCRIPTION_it +ACCESS_DESCRIPTION_new +AUTHORITY_INFO_ACCESS_free +AUTHORITY_INFO_ACCESS_it +AUTHORITY_INFO_ACCESS_new +d2i_ACCESS_DESCRIPTION +d2i_AUTHORITY_INFO_ACCESS +i2a_ACCESS_DESCRIPTION +i2d_ACCESS_DESCRIPTION +i2d_AUTHORITY_INFO_ACCESS +v3_info +v3_sinfo +v3_crl_num +v3_delta_crl +v3_inhibit_anyp +X509V3_EXT_add +X509V3_EXT_add_alias +X509V3_EXT_add_list +X509V3_EXT_cleanup +X509V3_EXT_d2i +X509V3_EXT_free +X509V3_EXT_get +X509V3_EXT_get_nid +X509V3_add1_i2d +X509V3_add_standard_extensions +X509V3_get_d2i +GENERAL_SUBTREE_free +GENERAL_SUBTREE_it +GENERAL_SUBTREE_new +NAME_CONSTRAINTS_check +NAME_CONSTRAINTS_free +NAME_CONSTRAINTS_it +NAME_CONSTRAINTS_new +v3_name_constraints +v3_pci +PROXY_CERT_INFO_EXTENSION_free +PROXY_CERT_INFO_EXTENSION_it +PROXY_CERT_INFO_EXTENSION_new +PROXY_POLICY_free +PROXY_POLICY_it +PROXY_POLICY_new +d2i_PROXY_CERT_INFO_EXTENSION +d2i_PROXY_POLICY +i2d_PROXY_CERT_INFO_EXTENSION +i2d_PROXY_POLICY +POLICY_CONSTRAINTS_free +POLICY_CONSTRAINTS_it +POLICY_CONSTRAINTS_new +v3_policy_constraints +PKEY_USAGE_PERIOD_free +PKEY_USAGE_PERIOD_it +PKEY_USAGE_PERIOD_new +d2i_PKEY_USAGE_PERIOD +i2d_PKEY_USAGE_PERIOD +v3_pkey_usage_period +POLICY_MAPPINGS_it +POLICY_MAPPING_free +POLICY_MAPPING_it +POLICY_MAPPING_new +v3_policy_mappings +X509V3_EXT_print +X509V3_EXT_print_fp +X509V3_EXT_val_prn +X509V3_extensions_print +X509_PURPOSE_add +X509_PURPOSE_cleanup +X509_PURPOSE_get0 +X509_PURPOSE_get0_name +X509_PURPOSE_get0_sname +X509_PURPOSE_get_by_id +X509_PURPOSE_get_by_sname +X509_PURPOSE_get_count +X509_PURPOSE_get_id +X509_PURPOSE_get_trust +X509_PURPOSE_set +X509_check_akid +X509_check_ca +X509_check_issued +X509_check_purpose +X509_supported_extension +i2s_ASN1_OCTET_STRING +s2i_ASN1_OCTET_STRING +v3_skey_id +SXNETID_free +SXNETID_it +SXNETID_new +SXNET_add_id_INTEGER +SXNET_add_id_asc +SXNET_add_id_ulong +SXNET_free +SXNET_get_id_INTEGER +SXNET_get_id_asc +SXNET_get_id_ulong +SXNET_it +SXNET_new +d2i_SXNET +d2i_SXNETID +i2d_SXNET +i2d_SXNETID +v3_sxnet +X509V3_NAME_from_section +X509V3_add_value +X509V3_add_value_bool +X509V3_add_value_bool_nf +X509V3_add_value_int +X509V3_add_value_uchar +X509V3_conf_free +X509V3_get_value_bool +X509V3_get_value_int +X509V3_parse_list +X509_REQ_get1_email +X509_check_email +X509_check_host +X509_check_ip +X509_check_ip_asc +X509_email_free +X509_get1_email +X509_get1_ocsp +a2i_IPADDRESS +a2i_IPADDRESS_NC +a2i_ipadd +hex_to_string +i2s_ASN1_ENUMERATED +i2s_ASN1_INTEGER +name_cmp +s2i_ASN1_INTEGER +string_to_hex +PKCS7_get_raw_certificates +pkcs7_bundle +pkcs7_parse_header +PKCS7_bundle_CRLs +PKCS7_bundle_certificates +PKCS7_get_CRLs +PKCS7_get_PEM_CRLs +PKCS7_get_PEM_certificates +PKCS7_get_certificates +PKCS8_marshal_encrypted_private_key +PKCS8_parse_encrypted_private_key +pkcs12_key_gen +pkcs8_pbe_decrypt +EVP_PKCS82PKEY +EVP_PKEY2PKCS8 +PKCS12_PBE_add +PKCS12_free +PKCS12_get_key_and_certs +PKCS12_parse +PKCS12_verify_mac +PKCS8_PRIV_KEY_INFO_free +PKCS8_PRIV_KEY_INFO_it +PKCS8_PRIV_KEY_INFO_new +PKCS8_decrypt +PKCS8_encrypt +d2i_PKCS12 +d2i_PKCS12_bio +d2i_PKCS12_fp +d2i_PKCS8_PRIV_KEY_INFO +i2d_PKCS8_PRIV_KEY_INFO +PKCS5_pbe2_decrypt_init +PKCS5_pbe2_encrypt_init diff --git a/src/objective-c/tests/Connectivity/Podfile b/src/objective-c/tests/Connectivity/Podfile index c7127b3e78..2c2344334c 100644 --- a/src/objective-c/tests/Connectivity/Podfile +++ b/src/objective-c/tests/Connectivity/Podfile @@ -10,7 +10,7 @@ target 'ConnectivityTestingApp' do pod 'gRPC-ProtoRPC/CFStream', :path => GRPC_LOCAL_SRC pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf" - pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" + pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" end pre_install do |installer| diff --git a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m index a6dfb154a4..84893b92c1 100644 --- a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m +++ b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m @@ -37,7 +37,9 @@ #import "test/core/end2end/data/ssl_test_data.h" #import "test/core/util/test_config.h" -#import <BoringSSL/openssl/ssl.h> +#import "src/core/tsi/grpc_shadow_boringssl.h" + +#import <openssl_grpc/ssl.h> static void drain_cq(grpc_completion_queue *cq) { grpc_event ev; diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 5750dccd89..9d79606881 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -545,7 +545,7 @@ BOOL isRemoteInteropTest(NSString *host) { } else { // Keepalive should kick after 1s elapsed and fails the call. XCTAssertNotNil(error); - XCTAssertEqual(error.code, GRPC_STATUS_INTERNAL); + XCTAssertEqual(error.code, GRPC_STATUS_UNAVAILABLE); XCTAssertEqualObjects( error.localizedDescription, @"keepalive watchdog timeout", @"Unexpected failure that is not keepalive watchdog timeout."); diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile index 3c2a34fb49..5d2f1340da 100644 --- a/src/objective-c/tests/Podfile +++ b/src/objective-c/tests/Podfile @@ -14,6 +14,7 @@ GRPC_LOCAL_SRC = '../../..' InteropTestsLocalSSL InteropTestsLocalCleartext InteropTestsRemoteWithCronet + UnitTests ).each do |target_name| target target_name do pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true @@ -21,7 +22,7 @@ GRPC_LOCAL_SRC = '../../..' pod '!ProtoCompiler', :path => "#{GRPC_LOCAL_SRC}/src/objective-c" pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c" - pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true + pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true pod 'gRPC', :path => GRPC_LOCAL_SRC pod 'gRPC-Core', :path => GRPC_LOCAL_SRC @@ -47,7 +48,7 @@ end pod '!ProtoCompiler', :path => "#{GRPC_LOCAL_SRC}/src/objective-c" pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c" - pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true + pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true pod 'gRPC/CFStream', :path => GRPC_LOCAL_SRC pod 'gRPC-Core/CFStream-Implementation', :path => GRPC_LOCAL_SRC @@ -62,7 +63,7 @@ end CronetUnitTests ).each do |target_name| target target_name do - pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true + pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" pod 'gRPC-Core', :path => GRPC_LOCAL_SRC pod 'gRPC-Core/Cronet-Interface', :path => GRPC_LOCAL_SRC diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index ea1066219d..f0d8123263 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 16A9E77B6E336B3C0B9BA6E0 /* libPods-InteropTestsLocalSSL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */; }; 20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */; }; 333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; }; + 5E0282E9215AA697007AC99D /* UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* UnitTests.m */; }; + 5E0282EB215AA697007AC99D /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; 5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */; }; 5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; 5EAD6D271E27047400002378 /* CronetUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAD6D261E27047400002378 /* CronetUnitTests.m */; }; @@ -54,10 +56,18 @@ 91D4B3C85B6D8562F409CB48 /* libPods-InteropTestsLocalSSLCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */; }; BC111C80CBF7068B62869352 /* libPods-InteropTestsRemoteCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */; }; C3D6F4270A2FFF634D8849ED /* libPods-InteropTestsLocalCleartextCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */; }; + CCF5C0719EF608276AE16374 /* libPods-UnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */; }; F15EF7852DC70770EFDB1D2C /* libPods-AllTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 5E0282EC215AA697007AC99D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 635697BF1B14FC11007A7283 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 635697C61B14FC11007A7283; + remoteInfo = Tests; + }; 5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 635697BF1B14FC11007A7283 /* Project object */; @@ -138,6 +148,7 @@ 1588C85DEAF7FC0ACDEA4C02 /* Pods-InteropTestsLocalCleartext.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.test.xcconfig"; sourceTree = "<group>"; }; 17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; sourceTree = "<group>"; }; 20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-UnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 2B89F3037963E6EDDD48D8C3 /* Pods-InteropTestsRemoteWithCronet.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.test.xcconfig"; sourceTree = "<group>"; }; 303F4A17EB1650FC44603D17 /* Pods-InteropTestsRemoteCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream.release.xcconfig"; sourceTree = "<group>"; }; 32748C4078AEB05F8F954361 /* Pods-InteropTestsRemoteCFStream.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteCFStream.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream.debug.xcconfig"; sourceTree = "<group>"; }; @@ -155,6 +166,9 @@ 55B630C1FF8C36D1EFC4E0A4 /* Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig"; sourceTree = "<group>"; }; 573450F334B331D0BED8B961 /* Pods-CoreCronetEnd2EndTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; sourceTree = "<group>"; }; 5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.release.xcconfig"; sourceTree = "<group>"; }; + 5E0282E6215AA697007AC99D /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E0282E8215AA697007AC99D /* UnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UnitTests.m; sourceTree = "<group>"; }; + 5E0282EA215AA697007AC99D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreCronetEnd2EndTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreCronetEnd2EndTests.mm; sourceTree = "<group>"; }; 5EA908CF4CDA4CE218352A06 /* Pods-InteropTestsLocalSSLCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; sourceTree = "<group>"; }; @@ -192,7 +206,9 @@ 7BA53C6D224288D5870FE6F3 /* Pods-InteropTestsLocalCleartextCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; sourceTree = "<group>"; }; 8B498B05C6DA0818B2FA91D4 /* Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; sourceTree = "<group>"; }; 943138072A9605B5B8DC1FC0 /* Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig"; sourceTree = "<group>"; }; + 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.test.xcconfig"; sourceTree = "<group>"; }; 9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemoteWithCronet.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.debug.xcconfig"; sourceTree = "<group>"; }; A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RxLibraryUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; A6F832FCEFA6F6881E620F12 /* Pods-InteropTestsRemote.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.test.xcconfig"; sourceTree = "<group>"; }; AA7CB64B4DD9915AE7C03163 /* Pods-InteropTestsLocalCleartext.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.cronet.xcconfig"; sourceTree = "<group>"; }; @@ -208,9 +224,11 @@ DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalSSL.a"; sourceTree = BUILT_PRODUCTS_DIR; }; DC3CA1D948F068E76957A861 /* Pods-InteropTestsRemote.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.debug.xcconfig"; sourceTree = "<group>"; }; E1486220285AF123EB124008 /* Pods-InteropTestsLocalCleartext.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.debug.xcconfig"; sourceTree = "<group>"; }; + E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.cronet.xcconfig"; sourceTree = "<group>"; }; E4275A759BDBDF143B9B438F /* Pods-InteropTestsRemote.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.release.xcconfig"; sourceTree = "<group>"; }; E4FD4606D4AB8D5A314D72F0 /* Pods-InteropTestsLocalCleartextCFStream.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.test.xcconfig"; sourceTree = "<group>"; }; E7E4D3FD76E3B745D992AF5F /* Pods-AllTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.cronet.xcconfig"; sourceTree = "<group>"; }; + EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.release.xcconfig"; sourceTree = "<group>"; }; F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalSSLCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemoteCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; }; FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CoreCronetEnd2EndTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -219,6 +237,15 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 5E0282E3215AA697007AC99D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E0282EB215AA697007AC99D /* libTests.a in Frameworks */, + CCF5C0719EF608276AE16374 /* libPods-UnitTests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E8A5DA11D3840B4000F8BC4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -341,6 +368,7 @@ F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */, 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */, F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */, + 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */, ); name = Frameworks; sourceTree = "<group>"; @@ -394,10 +422,23 @@ 41AA59529240A6BBBD3DB904 /* Pods-InteropTestsLocalSSLCFStream.test.xcconfig */, 55B630C1FF8C36D1EFC4E0A4 /* Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig */, 5EA908CF4CDA4CE218352A06 /* Pods-InteropTestsLocalSSLCFStream.release.xcconfig */, + A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */, + 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */, + E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */, + EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */, ); name = Pods; sourceTree = "<group>"; }; + 5E0282E7215AA697007AC99D /* UnitTests */ = { + isa = PBXGroup; + children = ( + 5E0282E8215AA697007AC99D /* UnitTests.m */, + 5E0282EA215AA697007AC99D /* Info.plist */, + ); + path = UnitTests; + sourceTree = "<group>"; + }; 5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = { isa = PBXGroup; children = ( @@ -432,6 +473,7 @@ 5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */, 5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */, 5EAD6D251E27047400002378 /* CronetUnitTests */, + 5E0282E7215AA697007AC99D /* UnitTests */, 635697C81B14FC11007A7283 /* Products */, 51E4650F34F854F41FF053B3 /* Pods */, 136D535E19727099B941D7B1 /* Frameworks */, @@ -453,6 +495,7 @@ 5EC5E421208177CC000EF4AD /* InteropTestsRemoteCFStream.xctest */, 5EC5E4312081856B000EF4AD /* InteropTestsLocalCleartextCFStream.xctest */, 5EC5E442208185CE000EF4AD /* InteropTestsLocalSSLCFStream.xctest */, + 5E0282E6215AA697007AC99D /* UnitTests.xctest */, ); name = Products; sourceTree = "<group>"; @@ -485,6 +528,26 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 5E0282E5215AA697007AC99D /* UnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E0282F2215AA697007AC99D /* Build configuration list for PBXNativeTarget "UnitTests" */; + buildPhases = ( + F07941C0BAF6A7C67AA60C48 /* [CP] Check Pods Manifest.lock */, + 5E0282E2215AA697007AC99D /* Sources */, + 5E0282E3215AA697007AC99D /* Frameworks */, + 5E0282E4215AA697007AC99D /* Resources */, + 9AD0B5E94F2AA5962EA6AA36 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5E0282ED215AA697007AC99D /* PBXTargetDependency */, + ); + name = UnitTests; + productName = UnitTests; + productReference = 5E0282E6215AA697007AC99D /* UnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = { isa = PBXNativeTarget; buildConfigurationList = 5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */; @@ -729,6 +792,10 @@ LastUpgradeCheck = 0630; ORGANIZATIONNAME = gRPC; TargetAttributes = { + 5E0282E5215AA697007AC99D = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; 5E8A5DA31D3840B4000F8BC4 = { CreatedOnToolsVersion = 7.3.1; }; @@ -794,11 +861,19 @@ 5EC5E420208177CC000EF4AD /* InteropTestsRemoteCFStream */, 5EC5E4302081856B000EF4AD /* InteropTestsLocalCleartextCFStream */, 5EC5E441208185CE000EF4AD /* InteropTestsLocalSSLCFStream */, + 5E0282E5215AA697007AC99D /* UnitTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 5E0282E4215AA697007AC99D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E8A5DA21D3840B4000F8BC4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1098,6 +1173,24 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream-resources.sh\"\n"; showEnvVarsInLog = 0; }; + 9AD0B5E94F2AA5962EA6AA36 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; A023FB55205A7EA37D413549 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1260,6 +1353,24 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + F07941C0BAF6A7C67AA60C48 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-UnitTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; F3D5B2CDA172580341682830 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1299,6 +1410,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 5E0282E2215AA697007AC99D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E0282E9215AA697007AC99D /* UnitTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E8A5DA01D3840B4000F8BC4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1412,6 +1531,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 5E0282ED215AA697007AC99D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 635697C61B14FC11007A7283 /* Tests */; + targetProxy = 5E0282EC215AA697007AC99D /* PBXContainerItemProxy */; + }; 5E8A5DAB1D3840B4000F8BC4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 635697C61B14FC11007A7283 /* Tests */; @@ -1455,6 +1579,128 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + 5E0282EE215AA697007AC99D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = UnitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\""; + }; + name = Debug; + }; + 5E0282EF215AA697007AC99D /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = UnitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\""; + }; + name = Test; + }; + 5E0282F0215AA697007AC99D /* Cronet */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = UnitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\""; + }; + name = Cronet; + }; + 5E0282F1215AA697007AC99D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = UnitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\""; + }; + name = Release; + }; 5E1228981E4D400F00E8504F /* Test */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1716,6 +1962,14 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_TESTABILITY = YES; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "COCOAPODS=1", + "$(inherited)", + "PB_FIELD_32BIT=1", + "PB_NO_PACKED_STRUCTS=1", + "GRPC_SHADOW_BORINGSSL_SYMBOLS=1", + ); INFOPLIST_FILE = CronetUnitTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -2594,6 +2848,17 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 5E0282F2215AA697007AC99D /* Build configuration list for PBXNativeTarget "UnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E0282EE215AA697007AC99D /* Debug */, + 5E0282EF215AA697007AC99D /* Test */, + 5E0282F0215AA697007AC99D /* Cronet */, + 5E0282F1215AA697007AC99D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme new file mode 100644 index 0000000000..3af3555f48 --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0920" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "NO" + buildForArchiving = "NO" + buildForAnalyzing = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "5E0282E5215AA697007AC99D" + BuildableName = "UnitTests.xctest" + BlueprintName = "UnitTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "5E0282E5215AA697007AC99D" + BuildableName = "UnitTests.xctest" + BlueprintName = "UnitTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </TestableReference> + </Testables> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "5E0282E5215AA697007AC99D" + BuildableName = "UnitTests.xctest" + BlueprintName = "UnitTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "5E0282E5215AA697007AC99D" + BuildableName = "UnitTests.xctest" + BlueprintName = "UnitTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/src/objective-c/tests/UnitTests/Info.plist b/src/objective-c/tests/UnitTests/Info.plist new file mode 100644 index 0000000000..6c40a6cd0c --- /dev/null +++ b/src/objective-c/tests/UnitTests/Info.plist @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>$(DEVELOPMENT_LANGUAGE)</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>BNDL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> +</dict> +</plist> diff --git a/src/objective-c/tests/UnitTests/UnitTests.m b/src/objective-c/tests/UnitTests/UnitTests.m new file mode 100644 index 0000000000..57e686d1b6 --- /dev/null +++ b/src/objective-c/tests/UnitTests/UnitTests.m @@ -0,0 +1,62 @@ +/* + * + * Copyright 2018 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. + * + */ + +#import <XCTest/XCTest.h> + +#import <GRPCClient/GRPCCall.h> + +#import "src/objective-c/GRPCClient/private/NSError+GRPC.h" + +@interface UnitTests : XCTestCase + +@end + +@implementation UnitTests + +- (void)testNSError { + const char *kDetails = "test details"; + const char *kErrorString = "test errorString"; + NSError *error1 = [NSError grpc_errorFromStatusCode:GRPC_STATUS_OK details:nil errorString:nil]; + NSError *error2 = [NSError grpc_errorFromStatusCode:GRPC_STATUS_CANCELLED + details:kDetails + errorString:kErrorString]; + NSError *error3 = [NSError grpc_errorFromStatusCode:GRPC_STATUS_UNAUTHENTICATED + details:kDetails + errorString:nil]; + NSError *error4 = + [NSError grpc_errorFromStatusCode:GRPC_STATUS_UNAVAILABLE details:nil errorString:nil]; + + XCTAssertNil(error1); + XCTAssertEqual(error2.code, 1); + XCTAssertEqualObjects(error2.domain, @"io.grpc"); + XCTAssertEqualObjects(error2.userInfo[NSLocalizedDescriptionKey], + [NSString stringWithUTF8String:kDetails]); + XCTAssertEqualObjects(error2.userInfo[NSDebugDescriptionErrorKey], + [NSString stringWithUTF8String:kErrorString]); + XCTAssertEqual(error3.code, 16); + XCTAssertEqualObjects(error3.domain, @"io.grpc"); + XCTAssertEqualObjects(error3.userInfo[NSLocalizedDescriptionKey], + [NSString stringWithUTF8String:kDetails]); + XCTAssertNil(error3.userInfo[NSDebugDescriptionErrorKey]); + XCTAssertEqual(error4.code, 14); + XCTAssertEqualObjects(error4.domain, @"io.grpc"); + XCTAssertNil(error4.userInfo[NSLocalizedDescriptionKey]); + XCTAssertNil(error4.userInfo[NSDebugDescriptionErrorKey]); +} + +@end diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh index 9dde07d55c..f37c6cf9f6 100755 --- a/src/objective-c/tests/run_tests.sh +++ b/src/objective-c/tests/run_tests.sh @@ -163,4 +163,14 @@ xcodebuild \ | egrep -v '^$' \ | egrep -v "(GPBDictionary|GPBArray)" - +echo "TIME: $(date)" +xcodebuild \ + -workspace Tests.xcworkspace \ + -scheme UnitTests \ + -destination name="iPhone 8" \ + test \ + | egrep -v "$XCODEBUILD_FILTER" \ + | egrep -v '^$' \ + | egrep -v "(GPBDictionary|GPBArray)" - + exit 0 diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index d532eed245..ca27c03b3c 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -22,5 +22,5 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.15.0-dev" -#define GRPC_C_VERSION_STRING @"6.0.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.17.0-dev" +#define GRPC_C_VERSION_STRING @"7.0.0-dev" diff --git a/src/php/composer.json b/src/php/composer.json index 91913d73d2..d54db91b5f 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -2,7 +2,7 @@ "name": "grpc/grpc-dev", "description": "gRPC library for PHP - for Developement use only", "license": "Apache-2.0", - "version": "1.15.0", + "version": "1.17.0", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.3.0" diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index 99dd9d68f0..70f8bbbf40 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -20,6 +20,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.15.0dev" +#define PHP_GRPC_VERSION "1.17.0dev" #endif /* VERSION_H */ diff --git a/src/php/tests/unit_tests/ChannelTest.php b/src/php/tests/unit_tests/ChannelTest.php index 49b0e350f7..583c618d32 100644 --- a/src/php/tests/unit_tests/ChannelTest.php +++ b/src/php/tests/unit_tests/ChannelTest.php @@ -599,10 +599,10 @@ class ChannelTest extends PHPUnit_Framework_TestCase public function testPersistentChannelForceNewOldChannelIdle2() { - $this->channel1 = new Grpc\Channel('localhost:50029', [ + $this->channel1 = new Grpc\Channel('localhost:50032', [ "grpc_target_persist_bound" => 2, ]); - $this->channel2 = new Grpc\Channel('localhost:50029', []); + $this->channel2 = new Grpc\Channel('localhost:50032', []); // try to connect on channel2 $state = $this->channel1->getConnectivityState(true); diff --git a/src/php/tests/unit_tests/PersistentChannelTests/PersistentChannelTest.php b/src/php/tests/unit_tests/PersistentChannelTests/PersistentChannelTest.php index 2bb5c4bb85..5423368cdf 100644 --- a/src/php/tests/unit_tests/PersistentChannelTests/PersistentChannelTest.php +++ b/src/php/tests/unit_tests/PersistentChannelTests/PersistentChannelTest.php @@ -174,12 +174,12 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelSharedChannelClose() { // same underlying channel - $this->channel1 = new Grpc\Channel('localhost:10010', [ + $this->channel1 = new Grpc\Channel('localhost:10001', [ "grpc_target_persist_bound" => 2, ]); - $this->channel2 = new Grpc\Channel('localhost:10010', []); + $this->channel2 = new Grpc\Channel('localhost:10001', []); $this->server = new Grpc\Server([]); - $this->port = $this->server->addHttp2Port('localhost:10010'); + $this->port = $this->server->addHttp2Port('localhost:10001'); // channel2 can still be use $state = $this->channel2->getConnectivityState(); @@ -216,7 +216,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelTargetDefaultUpperBound() { - $this->channel1 = new Grpc\Channel('localhost:10011', []); + $this->channel1 = new Grpc\Channel('localhost:10002', []); $channel1_info = $this->channel1->getChannelInfo(); $this->assertEquals($channel1_info['target_upper_bound'], 1); $this->assertEquals($channel1_info['target_current_size'], 1); @@ -224,7 +224,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelTargetUpperBoundZero() { - $this->channel1 = new Grpc\Channel('localhost:10011', [ + $this->channel1 = new Grpc\Channel('localhost:10002', [ "grpc_target_persist_bound" => 0, ]); // channel1 will not be persisted. @@ -237,7 +237,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelTargetUpperBoundNotZero() { - $this->channel1 = new Grpc\Channel('localhost:10011', [ + $this->channel1 = new Grpc\Channel('localhost:10003', [ "grpc_target_persist_bound" => 3, ]); $channel1_info = $this->channel1->getChannelInfo(); @@ -245,7 +245,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase $this->assertEquals($channel1_info['target_current_size'], 1); // The upper bound should not be changed - $this->channel2 = new Grpc\Channel('localhost:10011', []); + $this->channel2 = new Grpc\Channel('localhost:10003', []); $channel2_info = $this->channel2->getChannelInfo(); $this->assertEquals($channel2_info['target_upper_bound'], 3); $this->assertEquals($channel2_info['target_current_size'], 1); @@ -253,14 +253,14 @@ class PersistentListTest extends PHPUnit_Framework_TestCase // The upper bound should not be changed $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, null); - $this->channel3 = new Grpc\Channel('localhost:10011', + $this->channel3 = new Grpc\Channel('localhost:10003', ['credentials' => $channel_credentials]); $channel3_info = $this->channel3->getChannelInfo(); $this->assertEquals($channel3_info['target_upper_bound'], 3); $this->assertEquals($channel3_info['target_current_size'], 2); // The upper bound should not be changed - $this->channel4 = new Grpc\Channel('localhost:10011', [ + $this->channel4 = new Grpc\Channel('localhost:10003', [ "grpc_target_persist_bound" => 5, ]); $channel4_info = $this->channel4->getChannelInfo(); @@ -270,7 +270,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelDefaultOutBound1() { - $this->channel1 = new Grpc\Channel('localhost:10011', []); + $this->channel1 = new Grpc\Channel('localhost:10004', []); // Make channel1 not IDLE. $this->channel1->getConnectivityState(true); $this->waitUntilNotIdle($this->channel1); @@ -280,7 +280,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase // Since channel1 is CONNECTING, channel 2 will not be persisted $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, null); - $this->channel2 = new Grpc\Channel('localhost:10011', + $this->channel2 = new Grpc\Channel('localhost:10004', ['credentials' => $channel_credentials]); $channel2_info = $this->channel2->getChannelInfo(); $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); @@ -295,7 +295,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelDefaultOutBound2() { - $this->channel1 = new Grpc\Channel('localhost:10011', []); + $this->channel1 = new Grpc\Channel('localhost:10005', []); $channel1_info = $this->channel1->getChannelInfo(); $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']); @@ -303,7 +303,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase // gRPC channel. channel2 will not be persisted $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, null); - $this->channel2 = new Grpc\Channel('localhost:10011', + $this->channel2 = new Grpc\Channel('localhost:10005', ['credentials' => $channel_credentials]); $channel2_info = $this->channel2->getChannelInfo(); $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); @@ -318,7 +318,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelDefaultOutBound3() { - $this->channel1 = new Grpc\Channel('localhost:10011', []); + $this->channel1 = new Grpc\Channel('localhost:10006', []); $channel1_info = $this->channel1->getChannelInfo(); $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']); @@ -327,7 +327,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase // channel2 can be persisted. $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, null); - $this->channel2 = new Grpc\Channel('localhost:10011', + $this->channel2 = new Grpc\Channel('localhost:10006', ['credentials' => $channel_credentials]); $channel2_info = $this->channel2->getChannelInfo(); $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); @@ -342,7 +342,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelTwoUpperBound() { - $this->channel1 = new Grpc\Channel('localhost:10011', [ + $this->channel1 = new Grpc\Channel('localhost:10007', [ "grpc_target_persist_bound" => 2, ]); $channel1_info = $this->channel1->getChannelInfo(); @@ -351,7 +351,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase // Since channel1 is IDLE, channel 1 will be deleted $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, null); - $this->channel2 = new Grpc\Channel('localhost:10011', + $this->channel2 = new Grpc\Channel('localhost:10007', ['credentials' => $channel_credentials]); $channel2_info = $this->channel2->getChannelInfo(); $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); @@ -393,14 +393,14 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelTwoUpperBoundOutBound2() { - $this->channel1 = new Grpc\Channel('localhost:10011', [ + $this->channel1 = new Grpc\Channel('localhost:10012', [ "grpc_target_persist_bound" => 2, ]); $channel1_info = $this->channel1->getChannelInfo(); $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, null); - $this->channel2 = new Grpc\Channel('localhost:10011', + $this->channel2 = new Grpc\Channel('localhost:10012', ['credentials' => $channel_credentials]); $channel2_info = $this->channel2->getChannelInfo(); @@ -409,7 +409,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, null); - $this->channel3 = new Grpc\Channel('localhost:10011', + $this->channel3 = new Grpc\Channel('localhost:10012', ['credentials' => $channel_credentials]); $channel3_info = $this->channel3->getChannelInfo(); @@ -422,14 +422,14 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelTwoUpperBoundOutBound3() { - $this->channel1 = new Grpc\Channel('localhost:10011', [ + $this->channel1 = new Grpc\Channel('localhost:10013', [ "grpc_target_persist_bound" => 2, ]); $channel1_info = $this->channel1->getChannelInfo(); $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, null); - $this->channel2 = new Grpc\Channel('localhost:10011', + $this->channel2 = new Grpc\Channel('localhost:10013', ['credentials' => $channel_credentials]); $this->channel2->getConnectivityState(true); $this->waitUntilNotIdle($this->channel2); @@ -442,7 +442,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, null); - $this->channel3 = new Grpc\Channel('localhost:10011', + $this->channel3 = new Grpc\Channel('localhost:10013', ['credentials' => $channel_credentials]); $channel3_info = $this->channel3->getChannelInfo(); @@ -456,7 +456,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase public function testPersistentChannelTwoUpperBoundOutBound4() { - $this->channel1 = new Grpc\Channel('localhost:10011', [ + $this->channel1 = new Grpc\Channel('localhost:10014', [ "grpc_target_persist_bound" => 2, ]); $this->channel1->getConnectivityState(true); @@ -466,7 +466,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, null); - $this->channel2 = new Grpc\Channel('localhost:10011', + $this->channel2 = new Grpc\Channel('localhost:10014', ['credentials' => $channel_credentials]); $this->channel2->getConnectivityState(true); $this->waitUntilNotIdle($this->channel2); @@ -475,7 +475,7 @@ class PersistentListTest extends PHPUnit_Framework_TestCase $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, null); - $this->channel3 = new Grpc\Channel('localhost:10011', + $this->channel3 = new Grpc\Channel('localhost:10014', ['credentials' => $channel_credentials]); $channel3_info = $this->channel3->getChannelInfo(); diff --git a/src/proto/grpc/health/v1/BUILD b/src/proto/grpc/health/v1/BUILD index d234842883..97642985c9 100644 --- a/src/proto/grpc/health/v1/BUILD +++ b/src/proto/grpc/health/v1/BUILD @@ -22,3 +22,11 @@ grpc_proto_library( name = "health_proto", srcs = ["health.proto"], ) + +filegroup( + name = "health_proto_file", + srcs = [ + "health.proto", + ], +) + diff --git a/src/proto/grpc/health/v1/health.proto b/src/proto/grpc/health/v1/health.proto index 4b4677b8a4..38843ff1e7 100644 --- a/src/proto/grpc/health/v1/health.proto +++ b/src/proto/grpc/health/v1/health.proto @@ -34,10 +34,30 @@ message HealthCheckResponse { UNKNOWN = 0; SERVING = 1; NOT_SERVING = 2; + SERVICE_UNKNOWN = 3; // Used only by the Watch method. } ServingStatus status = 1; } service Health { + // If the requested service is unknown, the call will fail with status + // NOT_FOUND. rpc Check(HealthCheckRequest) returns (HealthCheckResponse); + + // Performs a watch for the serving status of the requested service. + // The server will immediately send back a message indicating the current + // serving status. It will then subsequently send a new message whenever + // the service's serving status changes. + // + // If the requested service is unknown when the call is received, the + // server will send a message setting the serving status to + // SERVICE_UNKNOWN but will *not* terminate the call. If at some + // future point, the serving status of the service becomes known, the + // server will send a new message with the service's serving status. + // + // If the call terminates with status UNIMPLEMENTED, then clients + // should assume this method is not supported and should not retry the + // call. If the call terminates with any other status (including OK), + // clients should retry the call with appropriate exponential backoff. + rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); } diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto index 57592662c4..4cfdc2cafb 100644 --- a/src/proto/grpc/testing/control.proto +++ b/src/proto/grpc/testing/control.proto @@ -25,6 +25,7 @@ enum ClientType { SYNC_CLIENT = 0; ASYNC_CLIENT = 1; OTHER_CLIENT = 2; // used for some language-specific variants + CALLBACK_CLIENT = 3; } enum ServerType { @@ -111,6 +112,10 @@ message ClientConfig { // Use coalescing API when possible. bool use_coalesce_api = 19; + + // If 0, disabled. Else, specifies the period between gathering latency + // medians in milliseconds. + int32 median_latency_collection_interval_millis = 20; } message ClientStatus { ClientStats stats = 1; } diff --git a/src/proto/grpc/testing/package_options.proto b/src/proto/grpc/testing/package_options.proto new file mode 100644 index 0000000000..e7ecf8c196 --- /dev/null +++ b/src/proto/grpc/testing/package_options.proto @@ -0,0 +1,28 @@ +// Copyright 2018 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. + +syntax = "proto3"; + +package grpc.testing; + +// For sanity checking package definitions +option ruby_package = "Grpc.Testing.Package.Options"; + +message TestRequest { } + +message TestResponse { } + +service TestService { + rpc GetTest(TestRequest) returns (TestResponse) { } +} diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py index 4c2ebaeaea..0a3097111f 100644 --- a/src/python/grpcio/commands.py +++ b/src/python/grpcio/commands.py @@ -265,8 +265,17 @@ class BuildExt(build_ext.build_ext): os.path.join(target_path, 'libgpr.a'), os.path.join(target_path, 'libgrpc.a') ] + # Running make separately for Mac means we lose all + # Extension.define_macros configured in setup.py. Re-add the macro + # for gRPC Core's fork handlers. + # TODO(ericgribkoff) Decide what to do about the other missing core + # macros, including GRPC_ENABLE_FORK_SUPPORT, which defaults to 1 + # on Linux but remains unset on Mac. + extra_defines = [ + 'EXTRA_DEFINES="GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK=1"' + ] make_process = subprocess.Popen( - ['make'] + targets, + ['make'] + extra_defines + targets, stdout=subprocess.PIPE, stderr=subprocess.PIPE) make_out, make_err = make_process.communicate() diff --git a/src/python/grpcio/grpc/BUILD.bazel b/src/python/grpcio/grpc/BUILD.bazel index 3f214bf3b0..2e6839ef2d 100644 --- a/src/python/grpcio/grpc/BUILD.bazel +++ b/src/python/grpcio/grpc/BUILD.bazel @@ -2,7 +2,7 @@ load("@grpc_python_dependencies//:requirements.bzl", "requirement") package(default_visibility = ["//visibility:public"]) -py_binary( +py_library( name = "grpcio", srcs = ["__init__.py"], deps = [ @@ -22,7 +22,6 @@ py_binary( data = [ "//:grpc", ], - main = "__init__.py", imports = ["../",], ) diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index e9246991df..eeeb4ddb33 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -24,6 +24,7 @@ from grpc import _grpcio_metadata from grpc._cython import cygrpc from grpc.framework.foundation import callable_util +logging.basicConfig() _LOGGER = logging.getLogger(__name__) _USER_AGENT = 'grpc-python/{}'.format(_grpcio_metadata.__version__) @@ -111,6 +112,10 @@ class _RPCState(object): # prior to termination of the RPC. self.cancelled = False self.callbacks = [] + self.fork_epoch = cygrpc.get_fork_epoch() + + def reset_postfork_child(self): + self.condition = threading.Condition() def _abort(state, code, details): @@ -166,21 +171,30 @@ def _event_handler(state, response_deserializer): done = not state.due for callback in callbacks: callback() - return done + return done and state.fork_epoch >= cygrpc.get_fork_epoch() return handle_event def _consume_request_iterator(request_iterator, state, call, request_serializer, event_handler): + if cygrpc.is_fork_support_enabled(): + condition_wait_timeout = 1.0 + else: + condition_wait_timeout = None def consume_request_iterator(): # pylint: disable=too-many-branches while True: + return_from_user_request_generator_invoked = False try: + # The thread may die in user-code. Do not block fork for this. + cygrpc.enter_user_request_generator() request = next(request_iterator) except StopIteration: break except Exception: # pylint: disable=broad-except + cygrpc.return_from_user_request_generator() + return_from_user_request_generator_invoked = True code = grpc.StatusCode.UNKNOWN details = 'Exception iterating requests!' _LOGGER.exception(details) @@ -188,6 +202,9 @@ def _consume_request_iterator(request_iterator, state, call, request_serializer, details) _abort(state, code, details) return + finally: + if not return_from_user_request_generator_invoked: + cygrpc.return_from_user_request_generator() serialized_request = _common.serialize(request, request_serializer) with state.condition: if state.code is None and not state.cancelled: @@ -208,7 +225,8 @@ def _consume_request_iterator(request_iterator, state, call, request_serializer, else: return while True: - state.condition.wait() + state.condition.wait(condition_wait_timeout) + cygrpc.block_if_fork_in_progress(state) if state.code is None: if cygrpc.OperationType.send_message not in state.due: break @@ -224,8 +242,9 @@ def _consume_request_iterator(request_iterator, state, call, request_serializer, if operating: state.due.add(cygrpc.OperationType.send_close_from_client) - consumption_thread = threading.Thread(target=consume_request_iterator) - consumption_thread.daemon = True + consumption_thread = cygrpc.ForkManagedThread( + target=consume_request_iterator) + consumption_thread.setDaemon(True) consumption_thread.start() @@ -671,13 +690,20 @@ class _ChannelCallState(object): self.lock = threading.Lock() self.channel = channel self.managed_calls = 0 + self.threading = False + + def reset_postfork_child(self): + self.managed_calls = 0 def _run_channel_spin_thread(state): def channel_spin(): while True: + cygrpc.block_if_fork_in_progress(state) event = state.channel.next_call_event() + if event.completion_type == cygrpc.CompletionType.queue_timeout: + continue call_completed = event.tag(event) if call_completed: with state.lock: @@ -685,8 +711,8 @@ def _run_channel_spin_thread(state): if state.managed_calls == 0: return - channel_spin_thread = threading.Thread(target=channel_spin) - channel_spin_thread.daemon = True + channel_spin_thread = cygrpc.ForkManagedThread(target=channel_spin) + channel_spin_thread.setDaemon(True) channel_spin_thread.start() @@ -742,6 +768,13 @@ class _ChannelConnectivityState(object): self.callbacks_and_connectivities = [] self.delivering = False + def reset_postfork_child(self): + self.polling = False + self.connectivity = None + self.try_to_connect = False + self.callbacks_and_connectivities = [] + self.delivering = False + def _deliveries(state): callbacks_needing_update = [] @@ -758,6 +791,7 @@ def _deliver(state, initial_connectivity, initial_callbacks): callbacks = initial_callbacks while True: for callback in callbacks: + cygrpc.block_if_fork_in_progress(state) callable_util.call_logging_exceptions( callback, _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE, connectivity) @@ -771,7 +805,7 @@ def _deliver(state, initial_connectivity, initial_callbacks): def _spawn_delivery(state, callbacks): - delivering_thread = threading.Thread( + delivering_thread = cygrpc.ForkManagedThread( target=_deliver, args=( state, state.connectivity, @@ -799,6 +833,7 @@ def _poll_connectivity(state, channel, initial_try_to_connect): while True: event = channel.watch_connectivity_state(connectivity, time.time() + 0.2) + cygrpc.block_if_fork_in_progress(state) with state.lock: if not state.callbacks_and_connectivities and not state.try_to_connect: state.polling = False @@ -826,10 +861,10 @@ def _moot(state): def _subscribe(state, callback, try_to_connect): with state.lock: if not state.callbacks_and_connectivities and not state.polling: - polling_thread = threading.Thread( + polling_thread = cygrpc.ForkManagedThread( target=_poll_connectivity, args=(state, state.channel, bool(try_to_connect))) - polling_thread.daemon = True + polling_thread.setDaemon(True) polling_thread.start() state.polling = True state.callbacks_and_connectivities.append([callback, None]) @@ -876,6 +911,7 @@ class Channel(grpc.Channel): _common.encode(target), _options(options), credentials) self._call_state = _ChannelCallState(self._channel) self._connectivity_state = _ChannelConnectivityState(self._channel) + cygrpc.fork_register_channel(self) def subscribe(self, callback, try_to_connect=None): _subscribe(self._connectivity_state, callback, try_to_connect) @@ -919,6 +955,11 @@ class Channel(grpc.Channel): self._channel.close(cygrpc.StatusCode.cancelled, 'Channel closed!') _moot(self._connectivity_state) + def _close_on_fork(self): + self._channel.close_on_fork(cygrpc.StatusCode.cancelled, + 'Channel closed due to fork') + _moot(self._connectivity_state) + def __enter__(self): return self @@ -939,4 +980,8 @@ class Channel(grpc.Channel): # for as long as they are in use and to close them after using them, # then deletion of this grpc._channel.Channel instance can be made to # effect closure of the underlying cygrpc.Channel instance. - _moot(self._connectivity_state) + cygrpc.fork_unregister_channel(self) + # This prevent the failed-at-initializing object removal from failing. + # Though the __init__ failed, the removal will still trigger __del__. + if hasattr(self, "_connectivity_state"): + _moot(self._connectivity_state) diff --git a/src/python/grpcio/grpc/_common.py b/src/python/grpcio/grpc/_common.py index 8358cbec5b..3805c7e82a 100644 --- a/src/python/grpcio/grpc/_common.py +++ b/src/python/grpcio/grpc/_common.py @@ -20,6 +20,7 @@ import six import grpc from grpc._cython import cygrpc +logging.basicConfig() _LOGGER = logging.getLogger(__name__) CYGRPC_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = { diff --git a/src/python/grpcio/grpc/_cython/BUILD.bazel b/src/python/grpcio/grpc/_cython/BUILD.bazel index 7124e83dee..cfd3a51d9b 100644 --- a/src/python/grpcio/grpc/_cython/BUILD.bazel +++ b/src/python/grpcio/grpc/_cython/BUILD.bazel @@ -8,6 +8,7 @@ pyx_library( "__init__.py", "cygrpc.pxd", "cygrpc.pyx", + "_cygrpc/_hooks.pyx.pxi", "_cygrpc/grpc_string.pyx.pxi", "_cygrpc/arguments.pyx.pxi", "_cygrpc/call.pyx.pxi", @@ -15,6 +16,7 @@ pyx_library( "_cygrpc/credentials.pyx.pxi", "_cygrpc/completion_queue.pyx.pxi", "_cygrpc/event.pyx.pxi", + "_cygrpc/fork_posix.pyx.pxi", "_cygrpc/metadata.pyx.pxi", "_cygrpc/operation.pyx.pxi", "_cygrpc/records.pyx.pxi", @@ -24,12 +26,14 @@ pyx_library( "_cygrpc/time.pyx.pxi", "_cygrpc/grpc_gevent.pyx.pxi", "_cygrpc/grpc.pxi", + "_cygrpc/_hooks.pxd.pxi", "_cygrpc/arguments.pxd.pxi", "_cygrpc/call.pxd.pxi", "_cygrpc/channel.pxd.pxi", "_cygrpc/credentials.pxd.pxi", "_cygrpc/completion_queue.pxd.pxi", "_cygrpc/event.pxd.pxi", + "_cygrpc/fork_posix.pxd.pxi", "_cygrpc/metadata.pxd.pxi", "_cygrpc/operation.pxd.pxi", "_cygrpc/records.pxd.pxi", diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pxd.pxi index 6cb1bc0c05..e0e068e452 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pxd.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pxd.pxi @@ -32,7 +32,7 @@ cdef class _ArgumentProcessor: cdef grpc_arg c_argument - cdef void c(self, argument, grpc_arg_pointer_vtable *vtable, references) + cdef void c(self, argument, grpc_arg_pointer_vtable *vtable, references) except * cdef class _ArgumentsProcessor: @@ -42,5 +42,5 @@ cdef class _ArgumentsProcessor: cdef readonly list _references cdef grpc_channel_args _c_arguments - cdef grpc_channel_args *c(self, grpc_arg_pointer_vtable *vtable) + cdef grpc_channel_args *c(self, grpc_arg_pointer_vtable *vtable) except * cdef un_c(self) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pyx.pxi index 2239e26b32..b7a4277ff6 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pyx.pxi @@ -52,7 +52,7 @@ cdef grpc_arg _unwrap_grpc_arg(tuple wrapped_arg): cdef class _ArgumentProcessor: - cdef void c(self, argument, grpc_arg_pointer_vtable *vtable, references): + cdef void c(self, argument, grpc_arg_pointer_vtable *vtable, references) except *: key, value = argument cdef bytes encoded_key = _encode(key) if encoded_key is not key: @@ -89,7 +89,7 @@ cdef class _ArgumentsProcessor: self._argument_processors = [] self._references = [] - cdef grpc_channel_args *c(self, grpc_arg_pointer_vtable *vtable): + cdef grpc_channel_args *c(self, grpc_arg_pointer_vtable *vtable) except *: self._c_arguments.arguments_length = len(self._arguments) if self._c_arguments.arguments_length == 0: return NULL diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi index a0de862d94..24e85b08e7 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi @@ -19,7 +19,7 @@ cdef class Call: def __cinit__(self): # Create an *empty* call - grpc_init() + fork_handlers_and_grpc_init() self.c_call = NULL self.references = [] diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd.pxi index f067d76fab..ced32abba1 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd.pxi @@ -40,6 +40,7 @@ cdef class _ChannelState: # field and just use the NULLness of c_channel as an indication that the # channel is closed. cdef object open + cdef object closed_reason # A dict from _BatchOperationTag to _CallState cdef dict integrated_call_states diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi index aa187e88a6..a81ff4d823 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi @@ -15,6 +15,7 @@ cimport cpython import threading +import time _INTERNAL_CALL_ERROR_MESSAGE_FORMAT = ( 'Internal gRPC call error %d. ' + @@ -83,6 +84,7 @@ cdef class _ChannelState: self.integrated_call_states = {} self.segregated_call_states = set() self.connectivity_due = set() + self.closed_reason = None cdef tuple _operate(grpc_call *c_call, object operations, object user_tag): @@ -142,10 +144,10 @@ cdef _cancel( _check_and_raise_call_error_no_metadata(c_call_error) -cdef BatchOperationEvent _next_call_event( +cdef _next_call_event( _ChannelState channel_state, grpc_completion_queue *c_completion_queue, - on_success): - tag, event = _latent_event(c_completion_queue, None) + on_success, deadline): + tag, event = _latent_event(c_completion_queue, deadline) with channel_state.condition: on_success(tag) channel_state.condition.notify_all() @@ -229,8 +231,7 @@ cdef void _call( call_state.due.update(started_tags) on_success(started_tags) else: - raise ValueError('Cannot invoke RPC on closed channel!') - + raise ValueError('Cannot invoke RPC: %s' % channel_state.closed_reason) cdef void _process_integrated_call_tag( _ChannelState state, _BatchOperationTag tag) except *: cdef _CallState call_state = state.integrated_call_states.pop(tag) @@ -302,7 +303,7 @@ cdef class SegregatedCall: _process_segregated_call_tag( self._channel_state, self._call_state, self._c_completion_queue, tag) return _next_call_event( - self._channel_state, self._c_completion_queue, on_success) + self._channel_state, self._c_completion_queue, on_success, None) cdef SegregatedCall _segregated_call( @@ -346,7 +347,7 @@ cdef object _watch_connectivity_state( state.c_connectivity_completion_queue, <cpython.PyObject *>tag) state.connectivity_due.add(tag) else: - raise ValueError('Cannot invoke RPC on closed channel!') + raise ValueError('Cannot invoke RPC: %s' % state.closed_reason) completed_tag, event = _latent_event( state.c_connectivity_completion_queue, None) with state.condition: @@ -355,12 +356,15 @@ cdef object _watch_connectivity_state( return event -cdef _close(_ChannelState state, grpc_status_code code, object details): +cdef _close(Channel channel, grpc_status_code code, object details, + drain_calls): + cdef _ChannelState state = channel._state cdef _CallState call_state encoded_details = _encode(details) with state.condition: if state.open: state.open = False + state.closed_reason = details for call_state in set(state.integrated_call_states.values()): grpc_call_cancel_with_status( call_state.c_call, code, encoded_details, NULL) @@ -370,12 +374,19 @@ cdef _close(_ChannelState state, grpc_status_code code, object details): # TODO(https://github.com/grpc/grpc/issues/3064): Cancel connectivity # watching. - while state.integrated_call_states: - state.condition.wait() - while state.segregated_call_states: - state.condition.wait() - while state.connectivity_due: - state.condition.wait() + if drain_calls: + while not _calls_drained(state): + event = channel.next_call_event() + if event.completion_type == CompletionType.queue_timeout: + continue + event.tag(event) + else: + while state.integrated_call_states: + state.condition.wait() + while state.segregated_call_states: + state.condition.wait() + while state.connectivity_due: + state.condition.wait() _destroy_c_completion_queue(state.c_call_completion_queue) _destroy_c_completion_queue(state.c_connectivity_completion_queue) @@ -390,13 +401,17 @@ cdef _close(_ChannelState state, grpc_status_code code, object details): state.condition.wait() +cdef _calls_drained(_ChannelState state): + return not (state.integrated_call_states or state.segregated_call_states or + state.connectivity_due) + cdef class Channel: def __cinit__( self, bytes target, object arguments, ChannelCredentials channel_credentials): arguments = () if arguments is None else tuple(arguments) - grpc_init() + fork_handlers_and_grpc_init() self._state = _ChannelState() self._vtable.copy = &_copy_pointer self._vtable.destroy = &_destroy_pointer @@ -435,9 +450,14 @@ cdef class Channel: def next_call_event(self): def on_success(tag): - _process_integrated_call_tag(self._state, tag) - return _next_call_event( - self._state, self._state.c_call_completion_queue, on_success) + if tag is not None: + _process_integrated_call_tag(self._state, tag) + if is_fork_support_enabled(): + queue_deadline = time.time() + 1.0 + else: + queue_deadline = None + return _next_call_event(self._state, self._state.c_call_completion_queue, + on_success, queue_deadline) def segregated_call( self, int flags, method, host, object deadline, object metadata, @@ -452,11 +472,14 @@ cdef class Channel: return grpc_channel_check_connectivity_state( self._state.c_channel, try_to_connect) else: - raise ValueError('Cannot invoke RPC on closed channel!') + raise ValueError('Cannot invoke RPC: %s' % self._state.closed_reason) def watch_connectivity_state( self, grpc_connectivity_state last_observed_state, object deadline): return _watch_connectivity_state(self._state, last_observed_state, deadline) def close(self, code, details): - _close(self._state, code, details) + _close(self, code, details, False) + + def close_on_fork(self, code, details): + _close(self, code, details, True) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi index a2d765546a..141116df5d 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi @@ -71,7 +71,7 @@ cdef class CompletionQueue: def __cinit__(self, shutdown_cq=False): cdef grpc_completion_queue_attributes c_attrs - grpc_init() + fork_handlers_and_grpc_init() if shutdown_cq: c_attrs.version = 1 c_attrs.cq_completion_type = GRPC_CQ_NEXT diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi index d2c0389ca6..63048e8da0 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi @@ -21,7 +21,7 @@ from libc.stdint cimport uintptr_t def _spawn_callback_in_thread(cb_func, args): - threading.Thread(target=cb_func, args=args).start() + ForkManagedThread(target=cb_func, args=args).start() async_callback_func = _spawn_callback_in_thread @@ -48,7 +48,7 @@ cdef int _get_metadata( cdef size_t metadata_count cdef grpc_metadata *c_metadata def callback(metadata, grpc_status_code status, bytes error_details): - if status is StatusCode.ok: + if status == StatusCode.ok: _store_c_metadata(metadata, &c_metadata, &metadata_count) cb(user_data, c_metadata, metadata_count, status, NULL) _release_c_metadata(c_metadata, metadata_count) @@ -114,7 +114,7 @@ cdef class ChannelCredentials: cdef class SSLSessionCacheLRU: def __cinit__(self, capacity): - grpc_init() + fork_handlers_and_grpc_init() self._cache = grpc_ssl_session_cache_create_lru(capacity) def __int__(self): @@ -144,8 +144,14 @@ cdef class SSLChannelCredentials(ChannelCredentials): return grpc_ssl_credentials_create( c_pem_root_certificates, NULL, NULL, NULL) else: - c_pem_key_certificate_pair.private_key = self._private_key - c_pem_key_certificate_pair.certificate_chain = self._certificate_chain + if self._private_key: + c_pem_key_certificate_pair.private_key = self._private_key + else: + c_pem_key_certificate_pair.private_key = NULL + if self._certificate_chain: + c_pem_key_certificate_pair.certificate_chain = self._certificate_chain + else: + c_pem_key_certificate_pair.certificate_chain = NULL return grpc_ssl_credentials_create( c_pem_root_certificates, &c_pem_key_certificate_pair, NULL, NULL) @@ -172,7 +178,7 @@ cdef class CompositeChannelCredentials(ChannelCredentials): cdef class ServerCertificateConfig: def __cinit__(self): - grpc_init() + fork_handlers_and_grpc_init() self.c_cert_config = NULL self.c_pem_root_certs = NULL self.c_ssl_pem_key_cert_pairs = NULL @@ -187,7 +193,7 @@ cdef class ServerCertificateConfig: cdef class ServerCredentials: def __cinit__(self): - grpc_init() + fork_handlers_and_grpc_init() self.c_credentials = NULL self.references = [] self.initial_cert_config = None @@ -282,3 +288,41 @@ def server_credentials_ssl_dynamic_cert_config(initial_cert_config, # C-core assumes ownership of c_options credentials.c_credentials = grpc_ssl_server_credentials_create_with_options(c_options) return credentials + +cdef grpc_ssl_certificate_config_reload_status _server_cert_config_fetcher_wrapper( + void* user_data, grpc_ssl_server_certificate_config **config) with gil: + # This is a credentials.ServerCertificateConfig + cdef ServerCertificateConfig cert_config = None + if not user_data: + raise ValueError('internal error: user_data must be specified') + credentials = <ServerCredentials>user_data + if not credentials.initial_cert_config_fetched: + # C-core is asking for the initial cert config + credentials.initial_cert_config_fetched = True + cert_config = credentials.initial_cert_config._certificate_configuration + else: + user_cb = credentials.cert_config_fetcher + try: + cert_config_wrapper = user_cb() + except Exception: + _LOGGER.exception('Error fetching certificate config') + return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL + if cert_config_wrapper is None: + return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED + elif not isinstance( + cert_config_wrapper, grpc.ServerCertificateConfiguration): + _LOGGER.error( + 'Error fetching certificate configuration: certificate ' + 'configuration must be of type grpc.ServerCertificateConfiguration, ' + 'not %s' % type(cert_config_wrapper).__name__) + return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL + else: + cert_config = cert_config_wrapper._certificate_configuration + config[0] = <grpc_ssl_server_certificate_config*>cert_config.c_cert_config + # our caller will assume ownership of memory, so we have to recreate + # a copy of c_cert_config here + cert_config.c_cert_config = grpc_ssl_server_certificate_config_create( + cert_config.c_pem_root_certs, cert_config.c_ssl_pem_key_cert_pairs, + cert_config.c_ssl_pem_key_cert_pairs_count) + return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW + diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/fork_posix.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/fork_posix.pxd.pxi new file mode 100644 index 0000000000..a925bdd2e6 --- /dev/null +++ b/src/python/grpcio/grpc/_cython/_cygrpc/fork_posix.pxd.pxi @@ -0,0 +1,29 @@ +# Copyright 2018 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. + + +cdef extern from "pthread.h" nogil: + int pthread_atfork( + void (*prepare)() nogil, + void (*parent)() nogil, + void (*child)() nogil) + + +cdef void __prefork() nogil + + +cdef void __postfork_parent() nogil + + +cdef void __postfork_child() nogil
\ No newline at end of file diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/fork_posix.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/fork_posix.pyx.pxi new file mode 100644 index 0000000000..433ae1f374 --- /dev/null +++ b/src/python/grpcio/grpc/_cython/_cygrpc/fork_posix.pyx.pxi @@ -0,0 +1,198 @@ +# Copyright 2018 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. + + +import logging +import os +import threading + +_LOGGER = logging.getLogger(__name__) + +_AWAIT_THREADS_TIMEOUT_SECONDS = 5 + +_TRUE_VALUES = ['yes', 'Yes', 'YES', 'true', 'True', 'TRUE', '1'] + +# This flag enables experimental support within gRPC Python for applications +# that will fork() without exec(). When enabled, gRPC Python will attempt to +# pause all of its internally created threads before the fork syscall proceeds. +# +# For this to be successful, the application must not have multiple threads of +# its own calling into gRPC when fork is invoked. Any callbacks from gRPC +# Python-spawned threads into user code (e.g., callbacks for asynchronous RPCs) +# must not block and should execute quickly. +# +# This flag is not supported on Windows. +_GRPC_ENABLE_FORK_SUPPORT = ( + os.environ.get('GRPC_ENABLE_FORK_SUPPORT', '0') + .lower() in _TRUE_VALUES) + +cdef void __prefork() nogil: + with gil: + with _fork_state.fork_in_progress_condition: + _fork_state.fork_in_progress = True + if not _fork_state.active_thread_count.await_zero_threads( + _AWAIT_THREADS_TIMEOUT_SECONDS): + _LOGGER.error( + 'Failed to shutdown gRPC Python threads prior to fork. ' + 'Behavior after fork will be undefined.') + + +cdef void __postfork_parent() nogil: + with gil: + with _fork_state.fork_in_progress_condition: + _fork_state.fork_in_progress = False + _fork_state.fork_in_progress_condition.notify_all() + + +cdef void __postfork_child() nogil: + with gil: + # Thread could be holding the fork_in_progress_condition inside of + # block_if_fork_in_progress() when fork occurs. Reset the lock here. + _fork_state.fork_in_progress_condition = threading.Condition() + # A thread in return_from_user_request_generator() may hold this lock + # when fork occurs. + _fork_state.active_thread_count = _ActiveThreadCount() + for state_to_reset in _fork_state.postfork_states_to_reset: + state_to_reset.reset_postfork_child() + _fork_state.fork_epoch += 1 + for channel in _fork_state.channels: + channel._close_on_fork() + # TODO(ericgribkoff) Check and abort if core is not shutdown + with _fork_state.fork_in_progress_condition: + _fork_state.fork_in_progress = False + if grpc_is_initialized() > 0: + with gil: + _LOGGER.error('Failed to shutdown gRPC Core after fork()') + os._exit(os.EX_USAGE) + + +def fork_handlers_and_grpc_init(): + grpc_init() + if _GRPC_ENABLE_FORK_SUPPORT: + with _fork_state.fork_handler_registered_lock: + if not _fork_state.fork_handler_registered: + pthread_atfork(&__prefork, &__postfork_parent, &__postfork_child) + _fork_state.fork_handler_registered = True + + +class ForkManagedThread(object): + def __init__(self, target, args=()): + if _GRPC_ENABLE_FORK_SUPPORT: + def managed_target(*args): + try: + target(*args) + finally: + _fork_state.active_thread_count.decrement() + self._thread = threading.Thread(target=managed_target, args=args) + else: + self._thread = threading.Thread(target=target, args=args) + + def setDaemon(self, daemonic): + self._thread.daemon = daemonic + + def start(self): + if _GRPC_ENABLE_FORK_SUPPORT: + _fork_state.active_thread_count.increment() + self._thread.start() + + def join(self): + self._thread.join() + + +def block_if_fork_in_progress(postfork_state_to_reset=None): + if _GRPC_ENABLE_FORK_SUPPORT: + with _fork_state.fork_in_progress_condition: + if not _fork_state.fork_in_progress: + return + if postfork_state_to_reset is not None: + _fork_state.postfork_states_to_reset.append(postfork_state_to_reset) + _fork_state.active_thread_count.decrement() + _fork_state.fork_in_progress_condition.wait() + _fork_state.active_thread_count.increment() + + +def enter_user_request_generator(): + if _GRPC_ENABLE_FORK_SUPPORT: + _fork_state.active_thread_count.decrement() + + +def return_from_user_request_generator(): + if _GRPC_ENABLE_FORK_SUPPORT: + _fork_state.active_thread_count.increment() + block_if_fork_in_progress() + + +def get_fork_epoch(): + return _fork_state.fork_epoch + + +def is_fork_support_enabled(): + return _GRPC_ENABLE_FORK_SUPPORT + + +def fork_register_channel(channel): + if _GRPC_ENABLE_FORK_SUPPORT: + _fork_state.channels.add(channel) + + +def fork_unregister_channel(channel): + if _GRPC_ENABLE_FORK_SUPPORT: + _fork_state.channels.remove(channel) + + +class _ActiveThreadCount(object): + def __init__(self): + self._num_active_threads = 0 + self._condition = threading.Condition() + + def increment(self): + with self._condition: + self._num_active_threads += 1 + + def decrement(self): + with self._condition: + self._num_active_threads -= 1 + if self._num_active_threads == 0: + self._condition.notify_all() + + def await_zero_threads(self, timeout_secs): + end_time = time.time() + timeout_secs + wait_time = timeout_secs + with self._condition: + while True: + if self._num_active_threads > 0: + self._condition.wait(wait_time) + if self._num_active_threads == 0: + return True + # Thread count may have increased before this re-obtains the + # lock after a notify(). Wait again until timeout_secs has + # elapsed. + wait_time = end_time - time.time() + if wait_time <= 0: + return False + + +class _ForkState(object): + def __init__(self): + self.fork_in_progress_condition = threading.Condition() + self.fork_in_progress = False + self.postfork_states_to_reset = [] + self.fork_handler_registered_lock = threading.Lock() + self.fork_handler_registered = False + self.active_thread_count = _ActiveThreadCount() + self.fork_epoch = 0 + self.channels = set() + + +_fork_state = _ForkState() diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/fork_windows.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/fork_windows.pyx.pxi new file mode 100644 index 0000000000..8dc1ef3b1a --- /dev/null +++ b/src/python/grpcio/grpc/_cython/_cygrpc/fork_windows.pyx.pxi @@ -0,0 +1,63 @@ +# Copyright 2018 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. + + +import threading + +# No-op implementations for Windows. + +def fork_handlers_and_grpc_init(): + grpc_init() + + +class ForkManagedThread(object): + def __init__(self, target, args=()): + self._thread = threading.Thread(target=target, args=args) + + def setDaemon(self, daemonic): + self._thread.daemon = daemonic + + def start(self): + self._thread.start() + + def join(self): + self._thread.join() + + +def block_if_fork_in_progress(postfork_state_to_reset=None): + pass + + +def enter_user_request_generator(): + pass + + +def return_from_user_request_generator(): + pass + + +def get_fork_epoch(): + return 0 + + +def is_fork_support_enabled(): + return False + + +def fork_register_channel(channel): + pass + + +def fork_unregister_channel(channel): + pass diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi index bcbfec0c9f..4781219319 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi @@ -322,6 +322,7 @@ cdef extern from "grpc/grpc.h": void grpc_init() nogil void grpc_shutdown() nogil + int grpc_is_initialized() nogil ctypedef struct grpc_completion_queue_factory: pass diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi index 00a1b23a67..334e561baa 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi @@ -14,6 +14,7 @@ import logging +logging.basicConfig() _LOGGER = logging.getLogger(__name__) # This function will ascii encode unicode string inputs if neccesary. diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi index 37b98ebbdb..fe98d559f3 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi @@ -127,7 +127,7 @@ class CompressionLevel: cdef class CallDetails: def __cinit__(self): - grpc_init() + fork_handlers_and_grpc_init() with nogil: grpc_call_details_init(&self.c_details) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi index da3dd21244..5779437b92 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi @@ -18,49 +18,13 @@ import logging import time import grpc +logging.basicConfig() _LOGGER = logging.getLogger(__name__) -cdef grpc_ssl_certificate_config_reload_status _server_cert_config_fetcher_wrapper( - void* user_data, grpc_ssl_server_certificate_config **config) with gil: - # This is a credentials.ServerCertificateConfig - cdef ServerCertificateConfig cert_config = None - if not user_data: - raise ValueError('internal error: user_data must be specified') - credentials = <ServerCredentials>user_data - if not credentials.initial_cert_config_fetched: - # C-core is asking for the initial cert config - credentials.initial_cert_config_fetched = True - cert_config = credentials.initial_cert_config._certificate_configuration - else: - user_cb = credentials.cert_config_fetcher - try: - cert_config_wrapper = user_cb() - except Exception: - _LOGGER.exception('Error fetching certificate config') - return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL - if cert_config_wrapper is None: - return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED - elif not isinstance( - cert_config_wrapper, grpc.ServerCertificateConfiguration): - _LOGGER.error( - 'Error fetching certificate configuration: certificate ' - 'configuration must be of type grpc.ServerCertificateConfiguration, ' - 'not %s' % type(cert_config_wrapper).__name__) - return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL - else: - cert_config = cert_config_wrapper._certificate_configuration - config[0] = <grpc_ssl_server_certificate_config*>cert_config.c_cert_config - # our caller will assume ownership of memory, so we have to recreate - # a copy of c_cert_config here - cert_config.c_cert_config = grpc_ssl_server_certificate_config_create( - cert_config.c_pem_root_certs, cert_config.c_ssl_pem_key_cert_pairs, - cert_config.c_ssl_pem_key_cert_pairs_count) - return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW - cdef class Server: def __cinit__(self, object arguments): - grpc_init() + fork_handlers_and_grpc_init() self.references = [] self.registered_completion_queues = [] self._vtable.copy = &_copy_pointer diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pxd b/src/python/grpcio/grpc/_cython/cygrpc.pxd index 0cc26bc0d0..8258b857bc 100644 --- a/src/python/grpcio/grpc/_cython/cygrpc.pxd +++ b/src/python/grpcio/grpc/_cython/cygrpc.pxd @@ -31,3 +31,6 @@ include "_cygrpc/time.pxd.pxi" include "_cygrpc/_hooks.pxd.pxi" include "_cygrpc/grpc_gevent.pxd.pxi" + +IF UNAME_SYSNAME != "Windows": + include "_cygrpc/fork_posix.pxd.pxi" diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx index 3cac406687..026f7ba2e3 100644 --- a/src/python/grpcio/grpc/_cython/cygrpc.pyx +++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx @@ -39,6 +39,11 @@ include "_cygrpc/_hooks.pyx.pxi" include "_cygrpc/grpc_gevent.pyx.pxi" +IF UNAME_SYSNAME == "Windows": + include "_cygrpc/fork_windows.pyx.pxi" +ELSE: + include "_cygrpc/fork_posix.pyx.pxi" + # # initialize gRPC # diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index c33911ebc1..42b3a1ad49 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.15.0.dev0""" +__version__ = """1.17.0.dev0""" diff --git a/src/python/grpcio/grpc/_plugin_wrapping.py b/src/python/grpcio/grpc/_plugin_wrapping.py index 916ee080b6..88ab4d8371 100644 --- a/src/python/grpcio/grpc/_plugin_wrapping.py +++ b/src/python/grpcio/grpc/_plugin_wrapping.py @@ -20,6 +20,7 @@ import grpc from grpc import _common from grpc._cython import cygrpc +logging.basicConfig() _LOGGER = logging.getLogger(__name__) diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py index 7276a7fd90..daa000a6e1 100644 --- a/src/python/grpcio/grpc/_server.py +++ b/src/python/grpcio/grpc/_server.py @@ -27,6 +27,7 @@ from grpc import _interceptor from grpc._cython import cygrpc from grpc.framework.foundation import callable_util +logging.basicConfig() _LOGGER = logging.getLogger(__name__) _SHUTDOWN_TAG = 'shutdown' diff --git a/src/python/grpcio/grpc/framework/foundation/callable_util.py b/src/python/grpcio/grpc/framework/foundation/callable_util.py index 24daf3406f..fb8d5f7c1e 100644 --- a/src/python/grpcio/grpc/framework/foundation/callable_util.py +++ b/src/python/grpcio/grpc/framework/foundation/callable_util.py @@ -21,6 +21,7 @@ import logging import six +logging.basicConfig() _LOGGER = logging.getLogger(__name__) diff --git a/src/python/grpcio/grpc/framework/foundation/logging_pool.py b/src/python/grpcio/grpc/framework/foundation/logging_pool.py index 216e3990db..7702d1785f 100644 --- a/src/python/grpcio/grpc/framework/foundation/logging_pool.py +++ b/src/python/grpcio/grpc/framework/foundation/logging_pool.py @@ -17,6 +17,7 @@ import logging from concurrent import futures +logging.basicConfig() _LOGGER = logging.getLogger(__name__) diff --git a/src/python/grpcio/grpc/framework/foundation/stream_util.py b/src/python/grpcio/grpc/framework/foundation/stream_util.py index 1faaf29bd7..9184f95873 100644 --- a/src/python/grpcio/grpc/framework/foundation/stream_util.py +++ b/src/python/grpcio/grpc/framework/foundation/stream_util.py @@ -19,6 +19,7 @@ import threading from grpc.framework.foundation import stream _NO_VALUE = object() +logging.basicConfig() _LOGGER = logging.getLogger(__name__) diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index a8158311fb..932621a38d 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -82,6 +82,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/http/format_request.cc', 'src/core/lib/http/httpcli.cc', 'src/core/lib/http/parser.cc', + 'src/core/lib/iomgr/buffer_list.cc', 'src/core/lib/iomgr/call_combiner.cc', 'src/core/lib/iomgr/combiner.cc', 'src/core/lib/iomgr/endpoint.cc', @@ -91,7 +92,6 @@ CORE_SOURCE_FILES = [ 'src/core/lib/iomgr/error.cc', 'src/core/lib/iomgr/ev_epoll1_linux.cc', 'src/core/lib/iomgr/ev_epollex_linux.cc', - 'src/core/lib/iomgr/ev_epollsig_linux.cc', 'src/core/lib/iomgr/ev_poll_posix.cc', 'src/core/lib/iomgr/ev_posix.cc', 'src/core/lib/iomgr/ev_windows.cc', @@ -102,6 +102,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/iomgr/gethostname_fallback.cc', 'src/core/lib/iomgr/gethostname_host_name_max.cc', 'src/core/lib/iomgr/gethostname_sysconf.cc', + 'src/core/lib/iomgr/internal_errqueue.cc', 'src/core/lib/iomgr/iocp_windows.cc', 'src/core/lib/iomgr/iomgr.cc', 'src/core/lib/iomgr/iomgr_custom.cc', @@ -363,7 +364,7 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', - 'src/cpp/ext/filters/census/grpc_context.cc', + 'src/core/ext/filters/census/grpc_context.cc', 'src/core/ext/filters/max_age/max_age_filter.cc', 'src/core/ext/filters/message_size/message_size_filter.cc', 'src/core/ext/filters/http/client_authority_filter.cc', diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 9337800a33..71113e68d9 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION = '1.15.0.dev0' +VERSION = '1.17.0.dev0' diff --git a/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel b/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel new file mode 100644 index 0000000000..ce3121fa90 --- /dev/null +++ b/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel @@ -0,0 +1,33 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") +load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") + +package(default_visibility = ["//visibility:public"]) + +genrule( + name = "mv_health_proto", + srcs = [ + "//src/proto/grpc/health/v1:health_proto_file", + ], + outs = ["health.proto",], + cmd = "cp $< $@", +) + +py_proto_library( + name = "py_health_proto", + protos = [":mv_health_proto",], + with_grpc = True, + deps = [ + requirement('protobuf'), + ], +) + +py_library( + name = "grpc_health", + srcs = ["health.py",], + deps = [ + ":py_health_proto", + "//src/python/grpcio/grpc:grpcio", + ], + imports=["../../",], +) + diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 3b84f7a4c5..a30aac2e0b 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION = '1.15.0.dev0' +VERSION = '1.17.0.dev0' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 7b0e48ea23..aafea9fe76 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION = '1.15.0.dev0' +VERSION = '1.17.0.dev0' diff --git a/src/python/grpcio_testing/grpc_testing/_channel/_invocation.py b/src/python/grpcio_testing/grpc_testing/_channel/_invocation.py index 191b1c1726..d7205ca579 100644 --- a/src/python/grpcio_testing/grpc_testing/_channel/_invocation.py +++ b/src/python/grpcio_testing/grpc_testing/_channel/_invocation.py @@ -18,6 +18,7 @@ import threading import grpc _NOT_YET_OBSERVED = object() +logging.basicConfig() _LOGGER = logging.getLogger(__name__) diff --git a/src/python/grpcio_testing/grpc_testing/_server/_rpc.py b/src/python/grpcio_testing/grpc_testing/_server/_rpc.py index b856da100f..736b714dc6 100644 --- a/src/python/grpcio_testing/grpc_testing/_server/_rpc.py +++ b/src/python/grpcio_testing/grpc_testing/_server/_rpc.py @@ -18,6 +18,7 @@ import threading import grpc from grpc_testing import _common +logging.basicConfig() _LOGGER = logging.getLogger(__name__) diff --git a/src/python/grpcio_testing/grpc_testing/_time.py b/src/python/grpcio_testing/grpc_testing/_time.py index 75e6db3458..9692c34e6f 100644 --- a/src/python/grpcio_testing/grpc_testing/_time.py +++ b/src/python/grpcio_testing/grpc_testing/_time.py @@ -21,6 +21,7 @@ import time as _time import grpc import grpc_testing +logging.basicConfig() _LOGGER = logging.getLogger(__name__) diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py index df9953fa25..876acd3142 100644 --- a/src/python/grpcio_testing/grpc_version.py +++ b/src/python/grpcio_testing/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!! -VERSION = '1.15.0.dev0' +VERSION = '1.17.0.dev0' diff --git a/src/python/grpcio_tests/commands.py b/src/python/grpcio_tests/commands.py index a23c980017..6931d93ef0 100644 --- a/src/python/grpcio_tests/commands.py +++ b/src/python/grpcio_tests/commands.py @@ -116,6 +116,8 @@ class TestGevent(setuptools.Command): # eventually succeed, but need to dig into performance issues. 'unit._cython._no_messages_server_completion_queue_per_call_test.Test.test_rpcs', 'unit._cython._no_messages_single_server_completion_queue_test.Test.test_rpcs', + # TODO(https://github.com/grpc/grpc/issues/16890) enable this test + 'unit._cython._channel_test.ChannelTest.test_multiple_channels_lonely_connectivity', # I have no idea why this doesn't work in gevent, but it shouldn't even be # using the c-core 'testing._client_test.ClientTest.test_infinite_request_stream_real_time', @@ -202,3 +204,28 @@ class RunInterop(test.test): from tests.interop import client sys.argv[1:] = self.args.split() client.test_interoperability() + + +class RunFork(test.test): + + description = 'run fork test client' + user_options = [('args=', 'a', 'pass-thru arguments for the client')] + + def initialize_options(self): + self.args = '' + + def finalize_options(self): + # distutils requires this override. + pass + + def run(self): + if self.distribution.install_requires: + self.distribution.fetch_build_eggs( + self.distribution.install_requires) + if self.distribution.tests_require: + self.distribution.fetch_build_eggs(self.distribution.tests_require) + # We import here to ensure that our setuptools parent has had a chance to + # edit the Python system path. + from tests.fork import client + sys.argv[1:] = self.args.split() + client.test_fork() diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index b2cf129e4f..cc9b41587c 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION = '1.15.0.dev0' +VERSION = '1.17.0.dev0' diff --git a/src/python/grpcio_tests/setup.py b/src/python/grpcio_tests/setup.py index a94c0963ec..61c98fa038 100644 --- a/src/python/grpcio_tests/setup.py +++ b/src/python/grpcio_tests/setup.py @@ -52,6 +52,7 @@ COMMAND_CLASS = { 'preprocess': commands.GatherProto, 'build_package_protos': grpc_tools.command.BuildPackageProtos, 'build_py': commands.BuildPy, + 'run_fork': commands.RunFork, 'run_interop': commands.RunInterop, 'test_lite': commands.TestLite, 'test_gevent': commands.TestGevent, diff --git a/src/python/grpcio_tests/tests/fork/__init__.py b/src/python/grpcio_tests/tests/fork/__init__.py new file mode 100644 index 0000000000..9a26bac010 --- /dev/null +++ b/src/python/grpcio_tests/tests/fork/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018 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. diff --git a/src/python/grpcio_tests/tests/fork/client.py b/src/python/grpcio_tests/tests/fork/client.py new file mode 100644 index 0000000000..9a32629ed5 --- /dev/null +++ b/src/python/grpcio_tests/tests/fork/client.py @@ -0,0 +1,76 @@ +# Copyright 2018 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. +"""The Python implementation of the GRPC interoperability test client.""" + +import argparse +import logging +import sys + +from tests.fork import methods + + +def _args(): + + def parse_bool(value): + if value == 'true': + return True + if value == 'false': + return False + raise argparse.ArgumentTypeError('Only true/false allowed') + + parser = argparse.ArgumentParser() + parser.add_argument( + '--server_host', + default="localhost", + type=str, + help='the host to which to connect') + parser.add_argument( + '--server_port', + type=int, + required=True, + help='the port to which to connect') + parser.add_argument( + '--test_case', + default='large_unary', + type=str, + help='the test case to execute') + parser.add_argument( + '--use_tls', + default=False, + type=parse_bool, + help='require a secure connection') + return parser.parse_args() + + +def _test_case_from_arg(test_case_arg): + for test_case in methods.TestCase: + if test_case_arg == test_case.value: + return test_case + else: + raise ValueError('No test case "%s"!' % test_case_arg) + + +def test_fork(): + logging.basicConfig(level=logging.INFO) + args = _args() + if args.test_case == "all": + for test_case in methods.TestCase: + test_case.run_test(args) + else: + test_case = _test_case_from_arg(args.test_case) + test_case.run_test(args) + + +if __name__ == '__main__': + test_fork() diff --git a/src/python/grpcio_tests/tests/fork/methods.py b/src/python/grpcio_tests/tests/fork/methods.py new file mode 100644 index 0000000000..889ef13cb2 --- /dev/null +++ b/src/python/grpcio_tests/tests/fork/methods.py @@ -0,0 +1,445 @@ +# Copyright 2018 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. +"""Implementations of fork support test methods.""" + +import enum +import json +import logging +import multiprocessing +import os +import threading +import time + +import grpc + +from six.moves import queue + +from src.proto.grpc.testing import empty_pb2 +from src.proto.grpc.testing import messages_pb2 +from src.proto.grpc.testing import test_pb2_grpc + +_LOGGER = logging.getLogger(__name__) + + +def _channel(args): + target = '{}:{}'.format(args.server_host, args.server_port) + if args.use_tls: + channel_credentials = grpc.ssl_channel_credentials() + channel = grpc.secure_channel(target, channel_credentials) + else: + channel = grpc.insecure_channel(target) + return channel + + +def _validate_payload_type_and_length(response, expected_type, expected_length): + if response.payload.type is not expected_type: + raise ValueError('expected payload type %s, got %s' % + (expected_type, type(response.payload.type))) + elif len(response.payload.body) != expected_length: + raise ValueError('expected payload body size %d, got %d' % + (expected_length, len(response.payload.body))) + + +def _async_unary(stub): + size = 314159 + request = messages_pb2.SimpleRequest( + response_type=messages_pb2.COMPRESSABLE, + response_size=size, + payload=messages_pb2.Payload(body=b'\x00' * 271828)) + response_future = stub.UnaryCall.future(request) + response = response_future.result() + _validate_payload_type_and_length(response, messages_pb2.COMPRESSABLE, size) + + +def _blocking_unary(stub): + size = 314159 + request = messages_pb2.SimpleRequest( + response_type=messages_pb2.COMPRESSABLE, + response_size=size, + payload=messages_pb2.Payload(body=b'\x00' * 271828)) + response = stub.UnaryCall(request) + _validate_payload_type_and_length(response, messages_pb2.COMPRESSABLE, size) + + +class _Pipe(object): + + def __init__(self): + self._condition = threading.Condition() + self._values = [] + self._open = True + + def __iter__(self): + return self + + def __next__(self): + return self.next() + + def next(self): + with self._condition: + while not self._values and self._open: + self._condition.wait() + if self._values: + return self._values.pop(0) + else: + raise StopIteration() + + def add(self, value): + with self._condition: + self._values.append(value) + self._condition.notify() + + def close(self): + with self._condition: + self._open = False + self._condition.notify() + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() + + +class _ChildProcess(object): + + def __init__(self, task, args=None): + if args is None: + args = () + self._exceptions = multiprocessing.Queue() + + def record_exceptions(): + try: + task(*args) + except Exception as e: # pylint: disable=broad-except + self._exceptions.put(e) + + self._process = multiprocessing.Process(target=record_exceptions) + + def start(self): + self._process.start() + + def finish(self): + self._process.join() + if self._process.exitcode != 0: + raise ValueError('Child process failed with exitcode %d' % + self._process.exitcode) + try: + exception = self._exceptions.get(block=False) + raise ValueError('Child process failed: %s' % exception) + except queue.Empty: + pass + + +def _async_unary_same_channel(channel): + + def child_target(): + try: + _async_unary(stub) + raise Exception( + 'Child should not be able to re-use channel after fork') + except ValueError as expected_value_error: + pass + + stub = test_pb2_grpc.TestServiceStub(channel) + _async_unary(stub) + child_process = _ChildProcess(child_target) + child_process.start() + _async_unary(stub) + child_process.finish() + + +def _async_unary_new_channel(channel, args): + + def child_target(): + child_channel = _channel(args) + child_stub = test_pb2_grpc.TestServiceStub(child_channel) + _async_unary(child_stub) + child_channel.close() + + stub = test_pb2_grpc.TestServiceStub(channel) + _async_unary(stub) + child_process = _ChildProcess(child_target) + child_process.start() + _async_unary(stub) + child_process.finish() + + +def _blocking_unary_same_channel(channel): + + def child_target(): + try: + _blocking_unary(stub) + raise Exception( + 'Child should not be able to re-use channel after fork') + except ValueError as expected_value_error: + pass + + stub = test_pb2_grpc.TestServiceStub(channel) + _blocking_unary(stub) + child_process = _ChildProcess(child_target) + child_process.start() + child_process.finish() + + +def _blocking_unary_new_channel(channel, args): + + def child_target(): + child_channel = _channel(args) + child_stub = test_pb2_grpc.TestServiceStub(child_channel) + _blocking_unary(child_stub) + child_channel.close() + + stub = test_pb2_grpc.TestServiceStub(channel) + _blocking_unary(stub) + child_process = _ChildProcess(child_target) + child_process.start() + _blocking_unary(stub) + child_process.finish() + + +# Verify that the fork channel registry can handle already closed channels +def _close_channel_before_fork(channel, args): + + def child_target(): + new_channel.close() + child_channel = _channel(args) + child_stub = test_pb2_grpc.TestServiceStub(child_channel) + _blocking_unary(child_stub) + child_channel.close() + + stub = test_pb2_grpc.TestServiceStub(channel) + _blocking_unary(stub) + channel.close() + + new_channel = _channel(args) + new_stub = test_pb2_grpc.TestServiceStub(new_channel) + child_process = _ChildProcess(child_target) + child_process.start() + _blocking_unary(new_stub) + child_process.finish() + + +def _connectivity_watch(channel, args): + + def child_target(): + + def child_connectivity_callback(state): + child_states.append(state) + + child_states = [] + child_channel = _channel(args) + child_stub = test_pb2_grpc.TestServiceStub(child_channel) + child_channel.subscribe(child_connectivity_callback) + _async_unary(child_stub) + if len(child_states + ) < 2 or child_states[-1] != grpc.ChannelConnectivity.READY: + raise ValueError('Channel did not move to READY') + if len(parent_states) > 1: + raise ValueError('Received connectivity updates on parent callback') + child_channel.unsubscribe(child_connectivity_callback) + child_channel.close() + + def parent_connectivity_callback(state): + parent_states.append(state) + + parent_states = [] + channel.subscribe(parent_connectivity_callback) + stub = test_pb2_grpc.TestServiceStub(channel) + child_process = _ChildProcess(child_target) + child_process.start() + _async_unary(stub) + if len(parent_states + ) < 2 or parent_states[-1] != grpc.ChannelConnectivity.READY: + raise ValueError('Channel did not move to READY') + channel.unsubscribe(parent_connectivity_callback) + child_process.finish() + + # Need to unsubscribe or _channel.py in _poll_connectivity triggers a + # "Cannot invoke RPC on closed channel!" error. + # TODO(ericgribkoff) Fix issue with channel.close() and connectivity polling + channel.unsubscribe(parent_connectivity_callback) + + +def _ping_pong_with_child_processes_after_first_response( + channel, args, child_target, run_after_close=True): + request_response_sizes = ( + 31415, + 9, + 2653, + 58979, + ) + request_payload_sizes = ( + 27182, + 8, + 1828, + 45904, + ) + stub = test_pb2_grpc.TestServiceStub(channel) + pipe = _Pipe() + parent_bidi_call = stub.FullDuplexCall(pipe) + child_processes = [] + first_message_received = False + for response_size, payload_size in zip(request_response_sizes, + request_payload_sizes): + request = messages_pb2.StreamingOutputCallRequest( + response_type=messages_pb2.COMPRESSABLE, + response_parameters=( + messages_pb2.ResponseParameters(size=response_size),), + payload=messages_pb2.Payload(body=b'\x00' * payload_size)) + pipe.add(request) + if first_message_received: + child_process = _ChildProcess(child_target, + (parent_bidi_call, channel, args)) + child_process.start() + child_processes.append(child_process) + response = next(parent_bidi_call) + first_message_received = True + child_process = _ChildProcess(child_target, + (parent_bidi_call, channel, args)) + child_process.start() + child_processes.append(child_process) + _validate_payload_type_and_length(response, messages_pb2.COMPRESSABLE, + response_size) + pipe.close() + if run_after_close: + child_process = _ChildProcess(child_target, + (parent_bidi_call, channel, args)) + child_process.start() + child_processes.append(child_process) + for child_process in child_processes: + child_process.finish() + + +def _in_progress_bidi_continue_call(channel): + + def child_target(parent_bidi_call, parent_channel, args): + stub = test_pb2_grpc.TestServiceStub(parent_channel) + try: + _async_unary(stub) + raise Exception( + 'Child should not be able to re-use channel after fork') + except ValueError as expected_value_error: + pass + inherited_code = parent_bidi_call.code() + inherited_details = parent_bidi_call.details() + if inherited_code != grpc.StatusCode.CANCELLED: + raise ValueError( + 'Expected inherited code CANCELLED, got %s' % inherited_code) + if inherited_details != 'Channel closed due to fork': + raise ValueError( + 'Expected inherited details Channel closed due to fork, got %s' + % inherited_details) + + # Don't run child_target after closing the parent call, as the call may have + # received a status from the server before fork occurs. + _ping_pong_with_child_processes_after_first_response( + channel, None, child_target, run_after_close=False) + + +def _in_progress_bidi_same_channel_async_call(channel): + + def child_target(parent_bidi_call, parent_channel, args): + stub = test_pb2_grpc.TestServiceStub(parent_channel) + try: + _async_unary(stub) + raise Exception( + 'Child should not be able to re-use channel after fork') + except ValueError as expected_value_error: + pass + + _ping_pong_with_child_processes_after_first_response( + channel, None, child_target) + + +def _in_progress_bidi_same_channel_blocking_call(channel): + + def child_target(parent_bidi_call, parent_channel, args): + stub = test_pb2_grpc.TestServiceStub(parent_channel) + try: + _blocking_unary(stub) + raise Exception( + 'Child should not be able to re-use channel after fork') + except ValueError as expected_value_error: + pass + + _ping_pong_with_child_processes_after_first_response( + channel, None, child_target) + + +def _in_progress_bidi_new_channel_async_call(channel, args): + + def child_target(parent_bidi_call, parent_channel, args): + channel = _channel(args) + stub = test_pb2_grpc.TestServiceStub(channel) + _async_unary(stub) + + _ping_pong_with_child_processes_after_first_response( + channel, args, child_target) + + +def _in_progress_bidi_new_channel_blocking_call(channel, args): + + def child_target(parent_bidi_call, parent_channel, args): + channel = _channel(args) + stub = test_pb2_grpc.TestServiceStub(channel) + _blocking_unary(stub) + + _ping_pong_with_child_processes_after_first_response( + channel, args, child_target) + + +@enum.unique +class TestCase(enum.Enum): + + CONNECTIVITY_WATCH = 'connectivity_watch' + CLOSE_CHANNEL_BEFORE_FORK = 'close_channel_before_fork' + ASYNC_UNARY_SAME_CHANNEL = 'async_unary_same_channel' + ASYNC_UNARY_NEW_CHANNEL = 'async_unary_new_channel' + BLOCKING_UNARY_SAME_CHANNEL = 'blocking_unary_same_channel' + BLOCKING_UNARY_NEW_CHANNEL = 'blocking_unary_new_channel' + IN_PROGRESS_BIDI_CONTINUE_CALL = 'in_progress_bidi_continue_call' + IN_PROGRESS_BIDI_SAME_CHANNEL_ASYNC_CALL = 'in_progress_bidi_same_channel_async_call' + IN_PROGRESS_BIDI_SAME_CHANNEL_BLOCKING_CALL = 'in_progress_bidi_same_channel_blocking_call' + IN_PROGRESS_BIDI_NEW_CHANNEL_ASYNC_CALL = 'in_progress_bidi_new_channel_async_call' + IN_PROGRESS_BIDI_NEW_CHANNEL_BLOCKING_CALL = 'in_progress_bidi_new_channel_blocking_call' + + def run_test(self, args): + _LOGGER.info("Running %s", self) + channel = _channel(args) + if self is TestCase.ASYNC_UNARY_SAME_CHANNEL: + _async_unary_same_channel(channel) + elif self is TestCase.ASYNC_UNARY_NEW_CHANNEL: + _async_unary_new_channel(channel, args) + elif self is TestCase.BLOCKING_UNARY_SAME_CHANNEL: + _blocking_unary_same_channel(channel) + elif self is TestCase.BLOCKING_UNARY_NEW_CHANNEL: + _blocking_unary_new_channel(channel, args) + elif self is TestCase.CLOSE_CHANNEL_BEFORE_FORK: + _close_channel_before_fork(channel, args) + elif self is TestCase.CONNECTIVITY_WATCH: + _connectivity_watch(channel, args) + elif self is TestCase.IN_PROGRESS_BIDI_CONTINUE_CALL: + _in_progress_bidi_continue_call(channel) + elif self is TestCase.IN_PROGRESS_BIDI_SAME_CHANNEL_ASYNC_CALL: + _in_progress_bidi_same_channel_async_call(channel) + elif self is TestCase.IN_PROGRESS_BIDI_SAME_CHANNEL_BLOCKING_CALL: + _in_progress_bidi_same_channel_blocking_call(channel) + elif self is TestCase.IN_PROGRESS_BIDI_NEW_CHANNEL_ASYNC_CALL: + _in_progress_bidi_new_channel_async_call(channel, args) + elif self is TestCase.IN_PROGRESS_BIDI_NEW_CHANNEL_BLOCKING_CALL: + _in_progress_bidi_new_channel_blocking_call(channel, args) + else: + raise NotImplementedError( + 'Test case "%s" not implemented!' % self.name) + channel.close() diff --git a/src/python/grpcio_tests/tests/health_check/BUILD.bazel b/src/python/grpcio_tests/tests/health_check/BUILD.bazel new file mode 100644 index 0000000000..19e1e1b2e1 --- /dev/null +++ b/src/python/grpcio_tests/tests/health_check/BUILD.bazel @@ -0,0 +1,15 @@ +package(default_visibility = ["//visibility:public"]) + +py_test( + name = "health_servicer_test", + srcs = ["_health_servicer_test.py"], + main = "_health_servicer_test.py", + size = "small", + deps = [ + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_health_checking/grpc_health/v1:grpc_health", + "//src/python/grpcio_tests/tests/unit:test_common", + ], + imports = ["../../",], +) + diff --git a/src/python/grpcio_tests/tests/interop/server.py b/src/python/grpcio_tests/tests/interop/server.py index fd28d498a1..768cdaf468 100644 --- a/src/python/grpcio_tests/tests/interop/server.py +++ b/src/python/grpcio_tests/tests/interop/server.py @@ -25,6 +25,7 @@ from tests.interop import methods from tests.interop import resources from tests.unit import test_common +logging.basicConfig() _ONE_DAY_IN_SECONDS = 60 * 60 * 24 _LOGGER = logging.getLogger(__name__) diff --git a/src/python/grpcio_tests/tests/stress/test_runner.py b/src/python/grpcio_tests/tests/stress/test_runner.py index 764cda17fb..e66eda64a8 100644 --- a/src/python/grpcio_tests/tests/stress/test_runner.py +++ b/src/python/grpcio_tests/tests/stress/test_runner.py @@ -53,5 +53,5 @@ class TestRunner(threading.Thread): except Exception as e: # pylint: disable=broad-except traceback.print_exc() self._exception_queue.put( - Exception("An exception occured during test {}" + Exception("An exception occurred during test {}" .format(test_case), e)) diff --git a/src/python/grpcio_tests/tests/testing/BUILD.bazel b/src/python/grpcio_tests/tests/testing/BUILD.bazel new file mode 100644 index 0000000000..9bdd616c56 --- /dev/null +++ b/src/python/grpcio_tests/tests/testing/BUILD.bazel @@ -0,0 +1,30 @@ +package(default_visibility = ["//visibility:public"]) + +py_library( + name = "testing", + srcs = ["__init__.py",], + deps = [ + # ":_application_common", + ":_server_application", + ], +) + +# TODO(ghostwriternr): To be added later. +# py_library( +# name = "_application_common", +# srcs = ["_application_common.py",], +# deps = [ +# "//src/python/grpcio_tests/tests/testing/proto:requests", +# "//src/python/grpcio_tests/tests/testing/proto:services", +# ], +# imports = ["../../",], +# ) + +py_library( + name = "_server_application", + srcs = ["_server_application.py",], + imports = ["../../",], +) + + + diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json index ebc41c63f0..76d5d22d57 100644 --- a/src/python/grpcio_tests/tests/tests.json +++ b/src/python/grpcio_tests/tests/tests.json @@ -32,6 +32,8 @@ "unit._credentials_test.CredentialsTest", "unit._cython._cancel_many_calls_test.CancelManyCallsTest", "unit._cython._channel_test.ChannelTest", + "unit._cython._fork_test.ForkPosixTester", + "unit._cython._fork_test.ForkWindowsTester", "unit._cython._no_messages_server_completion_queue_per_call_test.Test", "unit._cython._no_messages_single_server_completion_queue_test.Test", "unit._cython._read_some_but_not_all_responses_test.ReadSomeButNotAllResponsesTest", diff --git a/src/python/grpcio_tests/tests/unit/BUILD.bazel b/src/python/grpcio_tests/tests/unit/BUILD.bazel new file mode 100644 index 0000000000..dcd6d9fbb2 --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/BUILD.bazel @@ -0,0 +1,83 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") + +package(default_visibility = ["//visibility:public"]) + +GRPCIO_TESTS_UNIT = [ + "_api_test.py", + "_auth_context_test.py", + "_auth_test.py", + "_channel_args_test.py", + "_channel_close_test.py", + "_channel_connectivity_test.py", + "_channel_ready_future_test.py", + "_compression_test.py", + "_credentials_test.py", + "_empty_message_test.py", + "_exit_test.py", + "_interceptor_test.py", + "_invalid_metadata_test.py", + "_invocation_defects_test.py", + "_metadata_code_details_test.py", + "_metadata_test.py", + # TODO: Issue 16336 + # "_reconnect_test.py", + "_resource_exhausted_test.py", + "_rpc_test.py", + # TODO(ghostwriternr): To be added later. + # "_server_ssl_cert_config_test.py", + "_server_test.py", + "_session_cache_test.py", +] + +py_library( + name = "resources", + srcs = ["resources.py"], + data=[ + "//src/python/grpcio_tests/tests/unit/credentials", + ], +) + +py_library( + name = "test_common", + srcs = ["test_common.py"], +) + +py_library( + name = "_exit_scenarios", + srcs = ["_exit_scenarios.py"], +) + +py_library( + name = "_thread_pool", + srcs = ["_thread_pool.py"], +) + +py_library( + name = "_from_grpc_import_star", + srcs = ["_from_grpc_import_star.py"], +) + +[ + py_test( + name=test_file_name[:-3], + size="small", + srcs=[test_file_name], + main=test_file_name, + deps=[ + "//src/python/grpcio/grpc:grpcio", + ":resources", + ":test_common", + ":_exit_scenarios", + ":_thread_pool", + ":_from_grpc_import_star", + "//src/python/grpcio_tests/tests/unit/framework/common", + "//src/python/grpcio_tests/tests/testing", + requirement('six'), + ], + imports=["../../",], + data=[ + "//src/python/grpcio_tests/tests/unit/credentials", + ], + ) for test_file_name in GRPCIO_TESTS_UNIT +] + diff --git a/src/python/grpcio_tests/tests/unit/_channel_args_test.py b/src/python/grpcio_tests/tests/unit/_channel_args_test.py index 1a2d2c0117..dd1d2969a2 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_args_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_args_test.py @@ -13,6 +13,7 @@ # limitations under the License. """Tests of Channel Args on client/server side.""" +from concurrent import futures import unittest import grpc @@ -32,6 +33,14 @@ TEST_CHANNEL_ARGS = ( ('arg6', TestPointerWrapper()), ) +INVALID_TEST_CHANNEL_ARGS = [ + { + 'foo': 'bar' + }, + (('key',),), + 'str', +] + class ChannelArgsTest(unittest.TestCase): @@ -39,7 +48,17 @@ class ChannelArgsTest(unittest.TestCase): grpc.insecure_channel('localhost:8080', options=TEST_CHANNEL_ARGS) def test_server(self): - grpc.server(None, options=TEST_CHANNEL_ARGS) + grpc.server( + futures.ThreadPoolExecutor(max_workers=1), + options=TEST_CHANNEL_ARGS) + + def test_invalid_client_args(self): + for invalid_arg in INVALID_TEST_CHANNEL_ARGS: + self.assertRaises( + ValueError, + grpc.insecure_channel, + 'localhost:8080', + options=invalid_arg) if __name__ == '__main__': diff --git a/src/python/grpcio_tests/tests/unit/_cython/BUILD.bazel b/src/python/grpcio_tests/tests/unit/_cython/BUILD.bazel new file mode 100644 index 0000000000..458a6b1fb8 --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/_cython/BUILD.bazel @@ -0,0 +1,46 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") + +package(default_visibility = ["//visibility:public"]) + +GRPCIO_TESTS_UNIT_CYTHON = [ + "_cancel_many_calls_test.py", + "_channel_test.py", + "_no_messages_server_completion_queue_per_call_test.py", + "_no_messages_single_server_completion_queue_test.py", + "_read_some_but_not_all_responses_test.py", + "_server_test.py", + "cygrpc_test.py", +] + +py_library( + name = "common", + srcs = ["_common.py"], +) + +py_library( + name = "test_utilities", + srcs = ["test_utilities.py"], +) + +[ + py_test( + name=test_file_name[:-3], + size="small", + srcs=[test_file_name], + main=test_file_name, + deps=[ + "//src/python/grpcio/grpc:grpcio", + ":common", + ":test_utilities", + "//src/python/grpcio_tests/tests/unit/framework/common", + "//src/python/grpcio_tests/tests/unit:test_common", + "//src/python/grpcio_tests/tests/unit:resources", + ], + imports=["../../../",], + data=[ + "//src/python/grpcio_tests/tests/unit/credentials", + ], + ) for test_file_name in GRPCIO_TESTS_UNIT_CYTHON +] + + diff --git a/src/python/grpcio_tests/tests/unit/_cython/_fork_test.py b/src/python/grpcio_tests/tests/unit/_cython/_fork_test.py new file mode 100644 index 0000000000..aeb02458a7 --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/_cython/_fork_test.py @@ -0,0 +1,68 @@ +# Copyright 2018 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. + +import os +import threading +import unittest + +from grpc._cython import cygrpc + + +def _get_number_active_threads(): + return cygrpc._fork_state.active_thread_count._num_active_threads + + +@unittest.skipIf(os.name == 'nt', 'Posix-specific tests') +class ForkPosixTester(unittest.TestCase): + + def setUp(self): + cygrpc._GRPC_ENABLE_FORK_SUPPORT = True + + def testForkManagedThread(self): + + def cb(): + self.assertEqual(1, _get_number_active_threads()) + + thread = cygrpc.ForkManagedThread(cb) + thread.start() + thread.join() + self.assertEqual(0, _get_number_active_threads()) + + def testForkManagedThreadThrowsException(self): + + def cb(): + self.assertEqual(1, _get_number_active_threads()) + raise Exception("expected exception") + + thread = cygrpc.ForkManagedThread(cb) + thread.start() + thread.join() + self.assertEqual(0, _get_number_active_threads()) + + +@unittest.skipUnless(os.name == 'nt', 'Windows-specific tests') +class ForkWindowsTester(unittest.TestCase): + + def testForkManagedThreadIsNoOp(self): + + def cb(): + pass + + thread = cygrpc.ForkManagedThread(cb) + thread.start() + thread.join() + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/beta/BUILD.bazel b/src/python/grpcio_tests/tests/unit/beta/BUILD.bazel new file mode 100644 index 0000000000..d3e0fe20eb --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/beta/BUILD.bazel @@ -0,0 +1,75 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") + +package(default_visibility = ["//visibility:public"]) + +py_library( + name = "test_utilities", + srcs = ["test_utilities.py"], + deps = [ + "//src/python/grpcio/grpc:grpcio", + ], +) + +py_test( + name = "_beta_features_test", + srcs = ["_beta_features_test.py"], + main = "_beta_features_test.py", + size = "small", + deps = [ + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_tests/tests/unit:resources", + "//src/python/grpcio_tests/tests/unit/framework/common", + ":test_utilities", + ], + imports=["../../../",], +) + +py_test( + name = "_connectivity_channel_test", + srcs = ["_connectivity_channel_test.py"], + main = "_connectivity_channel_test.py", + size = "small", + deps = [ + "//src/python/grpcio/grpc:grpcio", + ], +) + +# TODO(ghostwriternr): To be added later. +#py_test( +# name = "_implementations_test", +# srcs = ["_implementations_test.py"], +# main = "_implementations_test.py", +# size = "small", +# deps = [ +# "//src/python/grpcio/grpc:grpcio", +# "//src/python/grpcio_tests/tests/unit:resources", +# requirement('oauth2client'), +# ], +# imports=["../../../",], +#) + +py_test( + name = "_not_found_test", + srcs = ["_not_found_test.py"], + main = "_not_found_test.py", + size = "small", + deps = [ + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_tests/tests/unit/framework/common", + ], + imports=["../../../",], +) + +py_test( + name = "_utilities_test", + srcs = ["_utilities_test.py"], + main = "_utilities_test.py", + size = "small", + deps = [ + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_tests/tests/unit/framework/common", + ], + imports=["../../../",], +) + + diff --git a/src/python/grpcio_tests/tests/unit/credentials/BUILD.bazel b/src/python/grpcio_tests/tests/unit/credentials/BUILD.bazel new file mode 100644 index 0000000000..358216db58 --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/credentials/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name="credentials", + srcs=glob([ + "**", + ]), +) + + diff --git a/src/python/grpcio_tests/tests/unit/framework/common/BUILD.bazel b/src/python/grpcio_tests/tests/unit/framework/common/BUILD.bazel new file mode 100644 index 0000000000..c206a04fad --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/framework/common/BUILD.bazel @@ -0,0 +1,11 @@ +package(default_visibility = ["//visibility:public"]) + +py_library( + name = "common", + srcs = [ + "test_constants.py", + "test_control.py", + "test_coverage.py", + ], +) + diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index b6c0791469..fc641dae80 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -819,6 +819,7 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) { unsigned write_flag = 0; void* tag = (void*)&st; + grpc_ruby_fork_guard(); if (RTYPEDDATA_DATA(self) == NULL) { rb_raise(grpc_rb_eCallError, "Cannot run batch on closed call"); return Qnil; diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 3f0dc530cf..6d4b2293a2 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -217,6 +217,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE* argv, VALUE self) { MEMZERO(&args, grpc_channel_args, 1); grpc_ruby_once_init(); + grpc_ruby_fork_guard(); rb_thread_call_without_gvl( wait_until_channel_polling_thread_started_no_gil, &stop_waiting_for_thread_start, @@ -374,6 +375,7 @@ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, watch_state_stack stack; void* op_success = 0; + grpc_ruby_fork_guard(); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); if (wrapper->bg_wrapped == NULL) { @@ -415,6 +417,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, grpc_slice* host_slice_ptr = NULL; char* tmp_str = NULL; + grpc_ruby_fork_guard(); if (host != Qnil) { host_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(host), RSTRING_LEN(host)); diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index f065a857db..872aed0cfc 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -23,9 +23,13 @@ #include <math.h> #include <ruby/vm.h> +#include <stdbool.h> #include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> #include <grpc/grpc.h> +#include <grpc/support/log.h> #include <grpc/support/time.h> #include "rb_call.h" #include "rb_call_credentials.h" @@ -255,7 +259,26 @@ static void Init_grpc_time_consts() { id_tv_nsec = rb_intern("tv_nsec"); } -static void grpc_rb_shutdown(void) { grpc_shutdown(); } +#if GPR_WINDOWS +static void grpc_ruby_set_init_pid(void) {} +static bool grpc_ruby_forked_after_init(void) { return false; } +#else +static pid_t grpc_init_pid; + +static void grpc_ruby_set_init_pid(void) { + GPR_ASSERT(grpc_init_pid == 0); + grpc_init_pid = getpid(); +} + +static bool grpc_ruby_forked_after_init(void) { + GPR_ASSERT(grpc_init_pid != 0); + return grpc_init_pid != getpid(); +} +#endif + +static void grpc_rb_shutdown(void) { + if (!grpc_ruby_forked_after_init()) grpc_shutdown(); +} /* Initialize the GRPC module structs */ @@ -276,10 +299,17 @@ VALUE sym_metadata = Qundef; static gpr_once g_once_init = GPR_ONCE_INIT; static void grpc_ruby_once_init_internal() { + grpc_ruby_set_init_pid(); grpc_init(); atexit(grpc_rb_shutdown); } +void grpc_ruby_fork_guard() { + if (grpc_ruby_forked_after_init()) { + rb_raise(rb_eRuntimeError, "grpc cannot be used before and after forking"); + } +} + static VALUE bg_thread_init_rb_mu = Qundef; static int bg_thread_init_done = 0; diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h index 577902319e..4118435ecf 100644 --- a/src/ruby/ext/grpc/rb_grpc.h +++ b/src/ruby/ext/grpc/rb_grpc.h @@ -69,4 +69,6 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval); void grpc_ruby_once_init(); +void grpc_ruby_fork_guard(); + #endif /* GRPC_RB_H_ */ diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 37b97aabd4..0e192b6201 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -38,6 +38,7 @@ grpc_call_details_destroy_type grpc_call_details_destroy_import; grpc_register_plugin_type grpc_register_plugin_import; grpc_init_type grpc_init_import; grpc_shutdown_type grpc_shutdown_import; +grpc_is_initialized_type grpc_is_initialized_import; grpc_version_string_type grpc_version_string_import; grpc_g_stands_for_type grpc_g_stands_for_import; grpc_completion_queue_factory_lookup_type grpc_completion_queue_factory_lookup_import; @@ -96,10 +97,13 @@ grpc_resource_quota_resize_type grpc_resource_quota_resize_import; grpc_resource_quota_set_max_threads_type grpc_resource_quota_set_max_threads_import; grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import; grpc_channelz_get_top_channels_type grpc_channelz_get_top_channels_import; +grpc_channelz_get_servers_type grpc_channelz_get_servers_import; +grpc_channelz_get_server_sockets_type grpc_channelz_get_server_sockets_import; grpc_channelz_get_channel_type grpc_channelz_get_channel_import; +grpc_channelz_get_subchannel_type grpc_channelz_get_subchannel_import; +grpc_channelz_get_socket_type grpc_channelz_get_socket_import; grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import; grpc_server_add_insecure_channel_from_fd_type grpc_server_add_insecure_channel_from_fd_import; -grpc_use_signal_type grpc_use_signal_import; grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import; grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import; grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import; @@ -291,6 +295,7 @@ void grpc_rb_load_imports(HMODULE library) { grpc_register_plugin_import = (grpc_register_plugin_type) GetProcAddress(library, "grpc_register_plugin"); grpc_init_import = (grpc_init_type) GetProcAddress(library, "grpc_init"); grpc_shutdown_import = (grpc_shutdown_type) GetProcAddress(library, "grpc_shutdown"); + grpc_is_initialized_import = (grpc_is_initialized_type) GetProcAddress(library, "grpc_is_initialized"); grpc_version_string_import = (grpc_version_string_type) GetProcAddress(library, "grpc_version_string"); grpc_g_stands_for_import = (grpc_g_stands_for_type) GetProcAddress(library, "grpc_g_stands_for"); grpc_completion_queue_factory_lookup_import = (grpc_completion_queue_factory_lookup_type) GetProcAddress(library, "grpc_completion_queue_factory_lookup"); @@ -349,10 +354,13 @@ void grpc_rb_load_imports(HMODULE library) { grpc_resource_quota_set_max_threads_import = (grpc_resource_quota_set_max_threads_type) GetProcAddress(library, "grpc_resource_quota_set_max_threads"); grpc_resource_quota_arg_vtable_import = (grpc_resource_quota_arg_vtable_type) GetProcAddress(library, "grpc_resource_quota_arg_vtable"); grpc_channelz_get_top_channels_import = (grpc_channelz_get_top_channels_type) GetProcAddress(library, "grpc_channelz_get_top_channels"); + grpc_channelz_get_servers_import = (grpc_channelz_get_servers_type) GetProcAddress(library, "grpc_channelz_get_servers"); + grpc_channelz_get_server_sockets_import = (grpc_channelz_get_server_sockets_type) GetProcAddress(library, "grpc_channelz_get_server_sockets"); grpc_channelz_get_channel_import = (grpc_channelz_get_channel_type) GetProcAddress(library, "grpc_channelz_get_channel"); + grpc_channelz_get_subchannel_import = (grpc_channelz_get_subchannel_type) GetProcAddress(library, "grpc_channelz_get_subchannel"); + grpc_channelz_get_socket_import = (grpc_channelz_get_socket_type) GetProcAddress(library, "grpc_channelz_get_socket"); grpc_insecure_channel_create_from_fd_import = (grpc_insecure_channel_create_from_fd_type) GetProcAddress(library, "grpc_insecure_channel_create_from_fd"); grpc_server_add_insecure_channel_from_fd_import = (grpc_server_add_insecure_channel_from_fd_type) GetProcAddress(library, "grpc_server_add_insecure_channel_from_fd"); - grpc_use_signal_import = (grpc_use_signal_type) GetProcAddress(library, "grpc_use_signal"); grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next"); grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator"); grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index f7a00046e3..e075db89e8 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -89,6 +89,9 @@ extern grpc_init_type grpc_init_import; typedef void(*grpc_shutdown_type)(void); extern grpc_shutdown_type grpc_shutdown_import; #define grpc_shutdown grpc_shutdown_import +typedef int(*grpc_is_initialized_type)(void); +extern grpc_is_initialized_type grpc_is_initialized_import; +#define grpc_is_initialized grpc_is_initialized_import typedef const char*(*grpc_version_string_type)(void); extern grpc_version_string_type grpc_version_string_import; #define grpc_version_string grpc_version_string_import @@ -104,7 +107,7 @@ extern grpc_completion_queue_create_for_next_type grpc_completion_queue_create_f typedef grpc_completion_queue*(*grpc_completion_queue_create_for_pluck_type)(void* reserved); extern grpc_completion_queue_create_for_pluck_type grpc_completion_queue_create_for_pluck_import; #define grpc_completion_queue_create_for_pluck grpc_completion_queue_create_for_pluck_import -typedef grpc_completion_queue*(*grpc_completion_queue_create_for_callback_type)(void* shutdown_callback, void* reserved); +typedef grpc_completion_queue*(*grpc_completion_queue_create_for_callback_type)(grpc_experimental_completion_queue_functor* shutdown_callback, void* reserved); extern grpc_completion_queue_create_for_callback_type grpc_completion_queue_create_for_callback_import; #define grpc_completion_queue_create_for_callback grpc_completion_queue_create_for_callback_import typedef grpc_completion_queue*(*grpc_completion_queue_create_type)(const grpc_completion_queue_factory* factory, const grpc_completion_queue_attributes* attributes, void* reserved); @@ -263,18 +266,27 @@ extern grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import typedef char*(*grpc_channelz_get_top_channels_type)(intptr_t start_channel_id); extern grpc_channelz_get_top_channels_type grpc_channelz_get_top_channels_import; #define grpc_channelz_get_top_channels grpc_channelz_get_top_channels_import +typedef char*(*grpc_channelz_get_servers_type)(intptr_t start_server_id); +extern grpc_channelz_get_servers_type grpc_channelz_get_servers_import; +#define grpc_channelz_get_servers grpc_channelz_get_servers_import +typedef char*(*grpc_channelz_get_server_sockets_type)(intptr_t server_id, intptr_t start_socket_id); +extern grpc_channelz_get_server_sockets_type grpc_channelz_get_server_sockets_import; +#define grpc_channelz_get_server_sockets grpc_channelz_get_server_sockets_import typedef char*(*grpc_channelz_get_channel_type)(intptr_t channel_id); extern grpc_channelz_get_channel_type grpc_channelz_get_channel_import; #define grpc_channelz_get_channel grpc_channelz_get_channel_import +typedef char*(*grpc_channelz_get_subchannel_type)(intptr_t subchannel_id); +extern grpc_channelz_get_subchannel_type grpc_channelz_get_subchannel_import; +#define grpc_channelz_get_subchannel grpc_channelz_get_subchannel_import +typedef char*(*grpc_channelz_get_socket_type)(intptr_t socket_id); +extern grpc_channelz_get_socket_type grpc_channelz_get_socket_import; +#define grpc_channelz_get_socket grpc_channelz_get_socket_import typedef grpc_channel*(*grpc_insecure_channel_create_from_fd_type)(const char* target, int fd, const grpc_channel_args* args); extern grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import; #define grpc_insecure_channel_create_from_fd grpc_insecure_channel_create_from_fd_import typedef void(*grpc_server_add_insecure_channel_from_fd_type)(grpc_server* server, void* reserved, int fd); extern grpc_server_add_insecure_channel_from_fd_type grpc_server_add_insecure_channel_from_fd_import; #define grpc_server_add_insecure_channel_from_fd grpc_server_add_insecure_channel_from_fd_import -typedef void(*grpc_use_signal_type)(int signum); -extern grpc_use_signal_type grpc_use_signal_import; -#define grpc_use_signal grpc_use_signal_import typedef const grpc_auth_property*(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator* it); extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import; #define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import @@ -398,10 +410,10 @@ extern grpc_call_set_credentials_type grpc_call_set_credentials_import; typedef void(*grpc_server_credentials_set_auth_metadata_processor_type)(grpc_server_credentials* creds, grpc_auth_metadata_processor processor); extern grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import; #define grpc_server_credentials_set_auth_metadata_processor grpc_server_credentials_set_auth_metadata_processor_import -typedef grpc_alts_credentials_options*(*grpc_alts_credentials_client_options_create_type)(); +typedef grpc_alts_credentials_options*(*grpc_alts_credentials_client_options_create_type)(void); extern grpc_alts_credentials_client_options_create_type grpc_alts_credentials_client_options_create_import; #define grpc_alts_credentials_client_options_create grpc_alts_credentials_client_options_create_import -typedef grpc_alts_credentials_options*(*grpc_alts_credentials_server_options_create_type)(); +typedef grpc_alts_credentials_options*(*grpc_alts_credentials_server_options_create_type)(void); extern grpc_alts_credentials_server_options_create_type grpc_alts_credentials_server_options_create_import; #define grpc_alts_credentials_server_options_create grpc_alts_credentials_server_options_create_import typedef void(*grpc_alts_credentials_client_options_add_target_service_account_type)(grpc_alts_credentials_options* options, const char* service_account); diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index 88e6a0cfd5..2931f34409 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -243,6 +243,8 @@ static VALUE grpc_rb_server_request_call(VALUE self) { static VALUE grpc_rb_server_start(VALUE self) { grpc_rb_server* s = NULL; TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); + + grpc_ruby_fork_guard(); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "destroyed!"); } else { diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb index 8f6aea30ad..0c15c2f3ba 100644 --- a/src/ruby/lib/grpc/errors.rb +++ b/src/ruby/lib/grpc/errors.rb @@ -68,7 +68,6 @@ module GRPC codes[OUT_OF_RANGE] = OutOfRange codes[UNIMPLEMENTED] = Unimplemented codes[INTERNAL] = Internal - codes[UNIMPLEMENTED] = Unimplemented codes[UNAVAILABLE] = Unavailable codes[DATA_LOSS] = DataLoss diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb index 5fd1805aab..efb0e4233d 100644 --- a/src/ruby/lib/grpc/generic/rpc_desc.rb +++ b/src/ruby/lib/grpc/generic/rpc_desc.rb @@ -32,7 +32,7 @@ module GRPC # @return [Proc] { |instance| marshalled(instance) } def marshal_proc - proc { |o| o.class.method(marshal_method).call(o).to_s } + proc { |o| o.class.send(marshal_method, o).to_s } end # @param [:input, :output] target determines whether to produce the an @@ -42,9 +42,9 @@ module GRPC # @return [Proc] An unmarshal proc { |marshalled(instance)| instance } def unmarshal_proc(target) fail ArgumentError unless [:input, :output].include?(target) - unmarshal_class = method(target).call + unmarshal_class = send(target) unmarshal_class = unmarshal_class.type if unmarshal_class.is_a? Stream - proc { |o| unmarshal_class.method(unmarshal_method).call(o) } + proc { |o| unmarshal_class.send(unmarshal_method, o) } end def handle_request_response(active_call, mth, inter_ctx) diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb index 838ac45927..3b5a0ce27f 100644 --- a/src/ruby/lib/grpc/generic/rpc_server.rb +++ b/src/ruby/lib/grpc/generic/rpc_server.rb @@ -136,7 +136,7 @@ module GRPC begin blk, args = worker_queue.pop blk.call(*args) - rescue StandardError => e + rescue StandardError, GRPC::Core::CallError => e GRPC.logger.warn('Error in worker thread') GRPC.logger.warn(e) end diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 5c21a5b168..243d566645 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -14,5 +14,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.15.0.dev' + VERSION = '1.17.0.dev' end diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb index 1b9d7cbbe6..b2303c6e14 100755 --- a/src/ruby/pb/test/client.rb +++ b/src/ruby/pb/test/client.rb @@ -95,7 +95,7 @@ end # creates a test stub that accesses host:port securely. def create_stub(opts) - address = "#{opts.host}:#{opts.port}" + address = "#{opts.server_host}:#{opts.server_port}" # Provide channel args that request compression by default # for compression interop tests @@ -112,7 +112,7 @@ def create_stub(opts) creds = ssl_creds(opts.use_test_ca) stub_opts = { channel_args: { - GRPC::Core::Channel::SSL_TARGET => opts.host_override + GRPC::Core::Channel::SSL_TARGET => opts.server_host_override } } @@ -681,13 +681,13 @@ class NamedTests # Send probing message for compressed request on the server, to see # if it's implemented. def send_probe_for_compressed_request_support(&send_probe) - bad_status_occured = false + bad_status_occurred = false begin send_probe.call rescue GRPC::BadStatus => e if e.code == GRPC::Core::StatusCodes::INVALID_ARGUMENT - bad_status_occured = true + bad_status_occurred = true else fail AssertionError, "Bad status received but code is #{e.code}" end @@ -696,26 +696,26 @@ class NamedTests end assert('CompressedRequest probe failed') do - bad_status_occured + bad_status_occurred end end end # Args is used to hold the command line info. -Args = Struct.new(:default_service_account, :host, :host_override, - :oauth_scope, :port, :secure, :test_case, +Args = Struct.new(:default_service_account, :server_host, :server_host_override, + :oauth_scope, :server_port, :secure, :test_case, :use_test_ca) # validates the command line options, returning them as a Hash. def parse_args args = Args.new - args.host_override = 'foo.test.google.fr' + args.server_host_override = 'foo.test.google.fr' OptionParser.new do |opts| opts.on('--oauth_scope scope', 'Scope for OAuth tokens') { |v| args['oauth_scope'] = v } opts.on('--server_host SERVER_HOST', 'server hostname') do |v| - args['host'] = v + args['server_host'] = v end opts.on('--default_service_account email_address', 'email address of the default service account') do |v| @@ -723,9 +723,11 @@ def parse_args end opts.on('--server_host_override HOST_OVERRIDE', 'override host via a HTTP header') do |v| - args['host_override'] = v + args['server_host_override'] = v + end + opts.on('--server_port SERVER_PORT', 'server port') do |v| + args['server_port'] = v end - opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v } # instance_methods(false) gives only the methods defined in that class test_cases = NamedTests.instance_methods(false).map(&:to_s) test_case_list = test_cases.join(',') @@ -744,7 +746,7 @@ def parse_args end def _check_args(args) - %w(host port test_case).each do |a| + %w(server_host server_port test_case).each do |a| if args[a].nil? fail(OptionParser::MissingArgument, "please specify --#{a}") end diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb index 3c9eca47ec..adba6db99c 100644 --- a/src/ruby/spec/channel_spec.rb +++ b/src/ruby/spec/channel_spec.rb @@ -13,6 +13,7 @@ # limitations under the License. require 'spec_helper' +require 'English' def load_test_certs test_root = File.join(File.dirname(__FILE__), 'testdata') @@ -27,6 +28,28 @@ describe GRPC::Core::Channel do GRPC::Core::ChannelCredentials.new(load_test_certs[0]) end + def fork_with_propagated_error_message + pipe_read, pipe_write = IO.pipe + pid = fork do + pipe_read.close + begin + yield + rescue => exc + pipe_write.syswrite(exc.message) + end + pipe_write.close + end + pipe_write.close + + exc_message = pipe_read.read + Process.wait(pid) + + unless $CHILD_STATUS.success? + raise "forked process failed with #{$CHILD_STATUS}" + end + raise exc_message unless exc_message.empty? + end + shared_examples '#new' do it 'take a host name without channel args' do blk = proc do @@ -79,6 +102,14 @@ describe GRPC::Core::Channel do blk = construct_with_args(args) expect(&blk).to_not raise_error end + + it 'raises if grpc was initialized in another process' do + blk = construct_with_args({}) + expect(&blk).not_to raise_error + expect do + fork_with_propagated_error_message(&blk) + end.to raise_error(RuntimeError, 'grpc cannot be used before and after forking') + end end describe '#new for secure channels' do @@ -121,6 +152,19 @@ describe GRPC::Core::Channel do end expect(&blk).to raise_error(RuntimeError) end + + it 'raises if grpc was initialized in another process' do + ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) + + deadline = Time.now + 5 + + blk = proc do + fork_with_propagated_error_message do + ch.create_call(nil, nil, 'dummy_method', nil, deadline) + end + end + expect(&blk).to raise_error(RuntimeError, 'grpc cannot be used before and after forking') + end end describe '#destroy' do diff --git a/src/ruby/spec/client_auth_spec.rb b/src/ruby/spec/client_auth_spec.rb index c563ed3227..5d2e6d24ec 100644 --- a/src/ruby/spec/client_auth_spec.rb +++ b/src/ruby/spec/client_auth_spec.rb @@ -30,7 +30,7 @@ end def create_server_creds test_root = File.join(File.dirname(__FILE__), 'testdata') - p "test root: #{test_root}" + GRPC.logger.info("test root: #{test_root}") files = ['ca.pem', 'server1.key', 'server1.pem'] creds = files.map { |f| File.open(File.join(test_root, f)).read } GRPC::Core::ServerCredentials.new( @@ -59,7 +59,7 @@ class SslTestService def a_client_streaming_rpc(call) check_peer_cert(call) - call.each_remote_read.each { |r| p r } + call.each_remote_read.each { |r| GRPC.logger.info(r) } EchoMsg.new end @@ -70,7 +70,7 @@ class SslTestService def a_bidi_rpc(requests, call) check_peer_cert(call) - requests.each { |r| p r } + requests.each { |r| GRPC.logger.info(r) } [EchoMsg.new, EchoMsg.new] end end @@ -116,11 +116,11 @@ describe 'client-server auth' do it 'client-server auth with server streaming RPCs' do responses = @stub.a_server_streaming_rpc(EchoMsg.new) - responses.each { |r| p r } + responses.each { |r| GRPC.logger.info(r) } end it 'client-server auth with bidi RPCs' do responses = @stub.a_bidi_rpc([EchoMsg.new, EchoMsg.new]) - responses.each { |r| p r } + responses.each { |r| GRPC.logger.info(r) } end end diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index fbf594a655..200139d849 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -265,14 +265,14 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength end creds = GRPC::Core::CallCredentials.new(failing_auth) - unavailable_error_occured = false + unavailable_error_occurred = false begin get_response(stub, credentials: creds) rescue GRPC::Unavailable => e - unavailable_error_occured = true + unavailable_error_occurred = true expect(e.details.include?(error_message)).to be true end - expect(unavailable_error_occured).to eq(true) + expect(unavailable_error_occurred).to eq(true) @server.shutdown_and_notify(Time.now + 3) th.join @@ -293,7 +293,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength describe 'without a call operation' do def get_response(stub, credentials: nil) - puts credentials.inspect + GRPC.logger.info(credentials.inspect) stub.request_response(@method, @sent_msg, noop, noop, metadata: @metadata, credentials: credentials) @@ -342,13 +342,15 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength it 'sends metadata to the server ok when running start_call first' do run_op_view_metadata_test(true) check_op_view_of_finished_client_call( - @op, @server_initial_md, @server_trailing_md) { |r| p r } + @op, @server_initial_md, @server_trailing_md + ) { |r| GRPC.logger.info(r) } end it 'does not crash when used after the call has been finished' do run_op_view_metadata_test(false) check_op_view_of_finished_client_call( - @op, @server_initial_md, @server_trailing_md) { |r| p r } + @op, @server_initial_md, @server_trailing_md + ) { |r| GRPC.logger.info(r) } end end end @@ -435,13 +437,15 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength it 'sends metadata to the server ok when running start_call first' do run_op_view_metadata_test(true) check_op_view_of_finished_client_call( - @op, @server_initial_md, @server_trailing_md) { |r| p r } + @op, @server_initial_md, @server_trailing_md + ) { |r| GRPC.logger.info(r) } end it 'does not crash when used after the call has been finished' do run_op_view_metadata_test(false) check_op_view_of_finished_client_call( - @op, @server_initial_md, @server_trailing_md) { |r| p r } + @op, @server_initial_md, @server_trailing_md + ) { |r| GRPC.logger.info(r) } end end end @@ -578,7 +582,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength run_op_view_metadata_test(true) check_op_view_of_finished_client_call( @op, @server_initial_md, @server_trailing_md) do |responses| - responses.each { |r| p r } + responses.each { |r| GRPC.logger.info(r) } end end @@ -586,7 +590,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength run_op_view_metadata_test(false) check_op_view_of_finished_client_call( @op, @server_initial_md, @server_trailing_md) do |responses| - responses.each { |r| p r } + responses.each { |r| GRPC.logger.info(r) } end end @@ -895,7 +899,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength run_op_view_metadata_test(true) check_op_view_of_finished_client_call( @op, @server_initial_md, @server_trailing_md) do |responses| - responses.each { |r| p r } + responses.each { |r| GRPC.logger.info(r) } end end @@ -903,7 +907,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength run_op_view_metadata_test(false) check_op_view_of_finished_client_call( @op, @server_initial_md, @server_trailing_md) do |responses| - responses.each { |r| p r } + responses.each { |r| GRPC.logger.info(r) } end end diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb index e072d0c45f..44a6134086 100644 --- a/src/ruby/spec/generic/rpc_server_spec.rb +++ b/src/ruby/spec/generic/rpc_server_spec.rb @@ -125,7 +125,7 @@ class CheckCallAfterFinishedService fail 'shouldnt reuse service' unless @server_side_call.nil? @server_side_call = call # iterate through requests so call can complete - call.each_remote_read.each { |r| p r } + call.each_remote_read.each { |r| GRPC.logger.info(r) } EchoMsg.new end @@ -138,7 +138,7 @@ class CheckCallAfterFinishedService def a_bidi_rpc(requests, call) fail 'shouldnt reuse service' unless @server_side_call.nil? @server_side_call = call - requests.each { |r| p r } + requests.each { |r| GRPC.logger.info(r) } [EchoMsg.new, EchoMsg.new] end end @@ -560,7 +560,7 @@ describe GRPC::RpcServer do 'connect_k1' => 'connect_v1' } wanted_md.each do |key, value| - puts "key: #{key}" + GRPC.logger.info("key: #{key}") expect(op.metadata[key]).to eq(value) end @srv.stop diff --git a/src/ruby/spec/pb/codegen/package_option_spec.rb b/src/ruby/spec/pb/codegen/package_option_spec.rb new file mode 100644 index 0000000000..46d23cd651 --- /dev/null +++ b/src/ruby/spec/pb/codegen/package_option_spec.rb @@ -0,0 +1,53 @@ +# Copyright 2018 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. + +require 'spec_helper' +require 'open3' +require 'tmpdir' + +describe 'Code Generation Options' do + it 'should generate and respect package options' do + fail 'CONFIG env variable unexpectedly unset' unless ENV['CONFIG'] + bins_sub_dir = ENV['CONFIG'] + + src_dir = File.join(File.dirname(__FILE__), '..', '..', '..', '..') + pb_dir = File.join(src_dir, 'proto') + bins_dir = File.join(src_dir, '..', 'bins', bins_sub_dir) + + plugin = File.join(bins_dir, 'grpc_ruby_plugin') + protoc = File.join(bins_dir, 'protobuf', 'protoc') + + # Generate the service from the proto + Dir.mktmpdir(nil, File.dirname(__FILE__)) do |tmp_dir| + gen_file = system(protoc, + '-I.', + 'grpc/testing/package_options.proto', + "--grpc_out=#{tmp_dir}", # generate the service + "--ruby_out=#{tmp_dir}", # generate the definitions + "--plugin=protoc-gen-grpc=#{plugin}", + chdir: pb_dir, + out: File::NULL) + + expect(gen_file).to be_truthy + begin + $LOAD_PATH.push(tmp_dir) + expect { Grpc::Testing::Package::Options::TestService::Service }.to raise_error(NameError) + expect(require('grpc/testing/package_options_services_pb')).to be_truthy + expect { Grpc::Testing::Package::Options::TestService::Service }.to_not raise_error + ensure + $LOAD_PATH.delete(tmp_dir) + end + end + end +end diff --git a/src/ruby/spec/support/services.rb b/src/ruby/spec/support/services.rb index 27239cd66c..6e693f1cde 100644 --- a/src/ruby/spec/support/services.rb +++ b/src/ruby/spec/support/services.rb @@ -50,7 +50,9 @@ class EchoService def a_client_streaming_rpc(call) # iterate through requests so call can complete call.output_metadata.update(@trailing_metadata) - call.each_remote_read.each { |r| p r } + call.each_remote_read.each do |r| + GRPC.logger.info(r) + end EchoMsg.new end @@ -61,7 +63,9 @@ class EchoService def a_bidi_rpc(requests, call) call.output_metadata.update(@trailing_metadata) - requests.each { |r| p r } + requests.each do |r| + GRPC.logger.info(r) + end [EchoMsg.new, EchoMsg.new] end end @@ -71,35 +75,37 @@ EchoStub = EchoService.rpc_stub_class # For testing server interceptors class TestServerInterceptor < GRPC::ServerInterceptor def request_response(request:, call:, method:) - p "Received request/response call at method #{method}" \ - " with request #{request} for call #{call}" + GRPC.logger.info("Received request/response call at method #{method}" \ + " with request #{request} for call #{call}") call.output_metadata[:interc] = 'from_request_response' - p "[GRPC::Ok] (#{method.owner.name}.#{method.name})" + GRPC.logger.info("[GRPC::Ok] (#{method.owner.name}.#{method.name})") yield end def client_streamer(call:, method:) call.output_metadata[:interc] = 'from_client_streamer' call.each_remote_read.each do |r| - p "In interceptor: #{r}" + GRPC.logger.info("In interceptor: #{r}") end - p "Received client streamer call at method #{method} for call #{call}" + GRPC.logger.info( + "Received client streamer call at method #{method} for call #{call}" + ) yield end def server_streamer(request:, call:, method:) - p "Received server streamer call at method #{method} with request" \ - " #{request} for call #{call}" + GRPC.logger.info("Received server streamer call at method #{method} with request" \ + " #{request} for call #{call}") call.output_metadata[:interc] = 'from_server_streamer' yield end def bidi_streamer(requests:, call:, method:) requests.each do |r| - p "Bidi request: #{r}" + GRPC.logger.info("Bidi request: #{r}") end - p "Received bidi streamer call at method #{method} with requests" \ - " #{requests} for call #{call}" + GRPC.logger.info("Received bidi streamer call at method #{method} with requests" \ + " #{requests} for call #{call}") call.output_metadata[:interc] = 'from_bidi_streamer' yield end @@ -108,38 +114,38 @@ end # For testing client interceptors class TestClientInterceptor < GRPC::ClientInterceptor def request_response(request:, call:, method:, metadata: {}) - p "Intercepted request/response call at method #{method}" \ + GRPC.logger.info("Intercepted request/response call at method #{method}" \ " with request #{request} for call #{call}" \ - " and metadata: #{metadata}" + " and metadata: #{metadata}") metadata['foo'] = 'bar_from_request_response' yield end def client_streamer(requests:, call:, method:, metadata: {}) - p "Received client streamer call at method #{method}" \ + GRPC.logger.info("Received client streamer call at method #{method}" \ " with requests #{requests} for call #{call}" \ - " and metadata: #{metadata}" + " and metadata: #{metadata}") requests.each do |r| - p "In client interceptor: #{r}" + GRPC.logger.info("In client interceptor: #{r}") end metadata['foo'] = 'bar_from_client_streamer' yield end def server_streamer(request:, call:, method:, metadata: {}) - p "Received server streamer call at method #{method}" \ + GRPC.logger.info("Received server streamer call at method #{method}" \ " with request #{request} for call #{call}" \ - " and metadata: #{metadata}" + " and metadata: #{metadata}") metadata['foo'] = 'bar_from_server_streamer' yield end def bidi_streamer(requests:, call:, method:, metadata: {}) - p "Received bidi streamer call at method #{method}" \ + GRPC.logger.info("Received bidi streamer call at method #{method}" \ "with requests #{requests} for call #{call}" \ - " and metadata: #{metadata}" + " and metadata: #{metadata}") requests.each do |r| - p "In client interceptor: #{r}" + GRPC.logger.info("In client interceptor: #{r}") end metadata['foo'] = 'bar_from_bidi_streamer' yield diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index 1b5e2c362b..92e85eb882 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -14,6 +14,6 @@ module GRPC module Tools - VERSION = '1.15.0.dev' + VERSION = '1.17.0.dev' end end |