diff options
Diffstat (limited to 'src')
145 files changed, 2537 insertions, 1552 deletions
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 97295bed45..206a6e1fe5 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -83,6 +83,28 @@ grpc::string FilenameIdentifier(const grpc::string &filename) { } } // namespace +template<class T, size_t N> +T *array_end(T (&array)[N]) { return array + N; } + +void PrintIncludes(grpc::protobuf::io::Printer *printer, const std::vector<grpc::string>& headers, const Parameters ¶ms) { + std::map<grpc::string, grpc::string> vars; + + vars["l"] = params.use_system_headers ? '<' : '"'; + vars["r"] = params.use_system_headers ? '>' : '"'; + + if (!params.grpc_search_path.empty()) { + vars["l"] += params.grpc_search_path; + if (params.grpc_search_path.back() != '/') { + vars["l"] += '/'; + } + } + + for (auto i = headers.begin(); i != headers.end(); i++) { + vars["h"] = *i; + printer->Print(vars, "#include $l$$h$$r$\n"); + } +} + grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file, const Parameters ¶ms) { grpc::string output; @@ -111,36 +133,46 @@ grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file, grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file, const Parameters ¶ms) { - grpc::string temp = - "#include <grpc++/impl/codegen/async_stream.h>\n" - "#include <grpc++/impl/codegen/async_unary_call.h>\n" - "#include <grpc++/impl/codegen/proto_utils.h>\n" - "#include <grpc++/impl/codegen/rpc_method.h>\n" - "#include <grpc++/impl/codegen/service_type.h>\n" - "#include <grpc++/impl/codegen/status.h>\n" - "#include <grpc++/impl/codegen/stub_options.h>\n" - "#include <grpc++/impl/codegen/sync_stream.h>\n" - "\n" - "namespace grpc {\n" - "class CompletionQueue;\n" - "class RpcService;\n" - "class ServerCompletionQueue;\n" - "class ServerContext;\n" - "} // namespace grpc\n\n"; + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + grpc::protobuf::io::StringOutputStream output_stream(&output); + grpc::protobuf::io::Printer printer(&output_stream, '$'); + std::map<grpc::string, grpc::string> vars; - if (!file->package().empty()) { - std::vector<grpc::string> parts = - grpc_generator::tokenize(file->package(), "."); + static const char *headers_strs[] = { + "grpc++/impl/codegen/async_stream.h", + "grpc++/impl/codegen/async_unary_call.h", + "grpc++/impl/codegen/proto_utils.h", + "grpc++/impl/codegen/rpc_method.h", + "grpc++/impl/codegen/service_type.h", + "grpc++/impl/codegen/status.h", + "grpc++/impl/codegen/stub_options.h", + "grpc++/impl/codegen/sync_stream.h" + }; + std::vector<grpc::string> headers(headers_strs, array_end(headers_strs)); + PrintIncludes(&printer, headers, params); + printer.Print(vars, "\n"); + printer.Print(vars, "namespace grpc {\n"); + printer.Print(vars, "class CompletionQueue;\n"); + printer.Print(vars, "class Channel;\n"); + printer.Print(vars, "class RpcService;\n"); + printer.Print(vars, "class ServerCompletionQueue;\n"); + printer.Print(vars, "class ServerContext;\n"); + printer.Print(vars, "} // namespace grpc\n\n"); - for (auto part = parts.begin(); part != parts.end(); part++) { - temp.append("namespace "); - temp.append(*part); - temp.append(" {\n"); + if (!file->package().empty()) { + std::vector<grpc::string> parts = + grpc_generator::tokenize(file->package(), "."); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer.Print(vars, "namespace $part$ {\n"); + } + printer.Print(vars, "\n"); } - temp.append("\n"); } - - return temp; + return output; } void PrintHeaderClientMethodInterfaces( @@ -852,7 +884,7 @@ grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file, } grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file, - const Parameters ¶m) { + const Parameters ¶ms) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -860,16 +892,18 @@ grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file, grpc::protobuf::io::Printer printer(&output_stream, '$'); std::map<grpc::string, grpc::string> vars; - printer.Print(vars, "#include <grpc++/impl/codegen/async_stream.h>\n"); - printer.Print(vars, "#include <grpc++/impl/codegen/async_unary_call.h>\n"); - printer.Print(vars, "#include <grpc++/impl/codegen/channel_interface.h>\n"); - printer.Print(vars, "#include <grpc++/impl/codegen/client_unary_call.h>\n"); - printer.Print(vars, - "#include <grpc++/impl/codegen/method_handler_impl.h>\n"); - printer.Print(vars, - "#include <grpc++/impl/codegen/rpc_service_method.h>\n"); - printer.Print(vars, "#include <grpc++/impl/codegen/service_type.h>\n"); - printer.Print(vars, "#include <grpc++/impl/codegen/sync_stream.h>\n"); + static const char *headers_strs[] = { + "grpc++/impl/codegen/async_stream.h", + "grpc++/impl/codegen/async_unary_call.h", + "grpc++/impl/codegen/channel_interface.h", + "grpc++/impl/codegen/client_unary_call.h", + "grpc++/impl/codegen/method_handler_impl.h", + "grpc++/impl/codegen/rpc_service_method.h", + "grpc++/impl/codegen/service_type.h", + "grpc++/impl/codegen/sync_stream.h" + }; + std::vector<grpc::string> headers(headers_strs, array_end(headers_strs)); + PrintIncludes(&printer, headers, params); if (!file->package().empty()) { std::vector<grpc::string> parts = diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h index 70c2e985f6..4f9de9d11a 100644 --- a/src/compiler/cpp_generator.h +++ b/src/compiler/cpp_generator.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,10 @@ namespace grpc_cpp_generator { struct Parameters { // Puts the service into a namespace grpc::string services_namespace; + // Use system includes (<>) or local includes ("") + bool use_system_headers; + // Prefix to any grpc include + grpc::string grpc_search_path; }; // Return the prologue of the generated header file. diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc index 88c704948e..d8ada4835c 100644 --- a/src/compiler/cpp_plugin.cc +++ b/src/compiler/cpp_plugin.cc @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,6 +59,7 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { } grpc_cpp_generator::Parameters generator_parameters; + generator_parameters.use_system_headers = true; if (!parameter.empty()) { std::vector<grpc::string> parameters_list = @@ -70,6 +71,17 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { grpc_generator::tokenize(*parameter_string, "="); if (param[0] == "services_namespace") { generator_parameters.services_namespace = param[1]; + } else if (param[0] == "use_system_headers") { + if (param[1] == "true") { + generator_parameters.use_system_headers = true; + } else if (param[1] == "false") { + generator_parameters.use_system_headers = false; + } else { + *error = grpc::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else if (param[0] == "grpc_search_path") { + generator_parameters.grpc_search_path = param[1]; } else { *error = grpc::string("Unknown parameter: ") + *parameter_string; return false; diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc index 4fd5dfbecb..5a2ecce1d4 100644 --- a/src/compiler/python_generator.cc +++ b/src/compiler/python_generator.cc @@ -190,11 +190,10 @@ bool PrintBetaServicer(const ServiceDescriptor* service, "Documentation", doc, }); out->Print("\n"); - out->Print(dict, "class Beta$Service$Servicer(object):\n"); + out->Print(dict, "class Beta$Service$Servicer(six.with_metaclass(abc.ABCMeta, object)):\n"); { IndentScope raii_class_indent(out); out->Print(dict, "\"\"\"$Documentation$\"\"\"\n"); - out->Print("__metaclass__ = abc.ABCMeta\n"); for (int i = 0; i < service->method_count(); ++i) { auto meth = service->method(i); grpc::string arg_name = meth->client_streaming() ? @@ -219,11 +218,10 @@ bool PrintBetaStub(const ServiceDescriptor* service, "Documentation", doc, }); out->Print("\n"); - out->Print(dict, "class Beta$Service$Stub(object):\n"); + out->Print(dict, "class Beta$Service$Stub(six.with_metaclass(abc.ABCMeta, object)):\n"); { IndentScope raii_class_indent(out); out->Print(dict, "\"\"\"$Documentation$\"\"\"\n"); - out->Print("__metaclass__ = abc.ABCMeta\n"); for (int i = 0; i < service->method_count(); ++i) { const MethodDescriptor* meth = service->method(i); grpc::string arg_name = meth->client_streaming() ? @@ -449,6 +447,7 @@ bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name, bool PrintPreamble(const FileDescriptor* file, const GeneratorConfiguration& config, Printer* out) { out->Print("import abc\n"); + out->Print("import six\n"); out->Print("from $Package$ import implementations as beta_implementations\n", "Package", config.beta_package_root); out->Print("from grpc.framework.common import cardinality\n"); diff --git a/src/core/census/grpc_plugin.c b/src/core/census/grpc_plugin.c new file mode 100644 index 0000000000..8d60a5197e --- /dev/null +++ b/src/core/census/grpc_plugin.c @@ -0,0 +1,70 @@ +/* + * + * Copyright 2015-2016, 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. + * + */ + +#include "src/core/census/grpc_plugin.h" + +#include <limits.h> + +#include <grpc/census.h> + +#include "src/core/census/grpc_filter.h" +#include "src/core/surface/channel_init.h" +#include "src/core/channel/channel_stack_builder.h" + +static bool maybe_add_census_filter(grpc_channel_stack_builder *builder, + void *arg_must_be_null) { + const grpc_channel_args *args = + grpc_channel_stack_builder_get_channel_arguments(builder); + if (grpc_channel_args_is_census_enabled(args)) { + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_client_census_filter, NULL, NULL); + } + return true; +} + +void census_grpc_plugin_init(void) { + /* Only initialize census if no one else has and some features are + * available. */ + if (census_enabled() == CENSUS_FEATURE_NONE && + census_supported() != CENSUS_FEATURE_NONE) { + if (census_initialize(census_supported())) { /* enable all features. */ + gpr_log(GPR_ERROR, "Could not initialize census."); + } + } + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, + maybe_add_census_filter, NULL); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + maybe_add_census_filter, NULL); +} + +void census_grpc_plugin_destroy(void) { census_shutdown(); } diff --git a/src/core/surface/server_create.c b/src/core/census/grpc_plugin.h index 5e37e80948..9321c2c30f 100644 --- a/src/core/surface/server_create.c +++ b/src/core/census/grpc_plugin.h @@ -31,18 +31,10 @@ * */ -#include <grpc/grpc.h> -#include "src/core/census/grpc_filter.h" -#include "src/core/channel/channel_args.h" -#include "src/core/channel/compress_filter.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/completion_queue.h" -#include "src/core/surface/server.h" +#ifndef GRPC_CORE_CENSUS_GRPC_PLUGIN_H +#define GRPC_CORE_CENSUS_GRPC_PLUGIN_H -grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { - const grpc_channel_filter *filters[3]; - size_t num_filters = 0; - filters[num_filters++] = &grpc_compress_filter; - GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved)); - return grpc_server_create_from_filters(filters, num_filters, args); -} +void census_grpc_plugin_init(void); +void census_grpc_plugin_destroy(void); + +#endif /* GRPC_CORE_CENSUS_GRPC_PLUGIN_H */ diff --git a/src/core/channel/channel_stack_builder.c b/src/core/channel/channel_stack_builder.c new file mode 100644 index 0000000000..1b1004e5f9 --- /dev/null +++ b/src/core/channel/channel_stack_builder.c @@ -0,0 +1,258 @@ +/* + * + * Copyright 2016, 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. + * + */ + +#include "src/core/channel/channel_stack_builder.h" + +#include <string.h> + +#include <grpc/support/alloc.h> + +int grpc_trace_channel_stack_builder = 0; + +typedef struct filter_node { + struct filter_node *next; + struct filter_node *prev; + const grpc_channel_filter *filter; + grpc_post_filter_create_init_func init; + void *init_arg; +} filter_node; + +struct grpc_channel_stack_builder { + // sentinel nodes for filters that have been added + filter_node begin; + filter_node end; + // various set/get-able parameters + const grpc_channel_args *args; + grpc_transport *transport; + const char *name; +}; + +struct grpc_channel_stack_builder_iterator { + grpc_channel_stack_builder *builder; + filter_node *node; +}; + +grpc_channel_stack_builder *grpc_channel_stack_builder_create(void) { + grpc_channel_stack_builder *b = gpr_malloc(sizeof(*b)); + memset(b, 0, sizeof(*b)); + + b->begin.filter = NULL; + b->end.filter = NULL; + b->begin.next = &b->end; + b->begin.prev = &b->end; + b->end.next = &b->begin; + b->end.prev = &b->begin; + + return b; +} + +static grpc_channel_stack_builder_iterator *create_iterator_at_filter_node( + grpc_channel_stack_builder *builder, filter_node *node) { + grpc_channel_stack_builder_iterator *it = gpr_malloc(sizeof(*it)); + it->builder = builder; + it->node = node; + return it; +} + +void grpc_channel_stack_builder_iterator_destroy( + grpc_channel_stack_builder_iterator *it) { + gpr_free(it); +} + +grpc_channel_stack_builder_iterator * +grpc_channel_stack_builder_create_iterator_at_first( + grpc_channel_stack_builder *builder) { + return create_iterator_at_filter_node(builder, &builder->begin); +} + +grpc_channel_stack_builder_iterator * +grpc_channel_stack_builder_create_iterator_at_last( + grpc_channel_stack_builder *builder) { + return create_iterator_at_filter_node(builder, &builder->end); +} + +bool grpc_channel_stack_builder_move_next( + grpc_channel_stack_builder_iterator *iterator) { + if (iterator->node == &iterator->builder->end) return false; + iterator->node = iterator->node->next; + return true; +} + +bool grpc_channel_stack_builder_move_prev( + grpc_channel_stack_builder_iterator *iterator) { + if (iterator->node == &iterator->builder->begin) return false; + iterator->node = iterator->node->prev; + return true; +} + +bool grpc_channel_stack_builder_move_prev( + grpc_channel_stack_builder_iterator *iterator); + +void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder, + const char *name) { + GPR_ASSERT(builder->name == NULL); + builder->name = name; +} + +void grpc_channel_stack_builder_set_channel_arguments( + grpc_channel_stack_builder *builder, const grpc_channel_args *args) { + GPR_ASSERT(builder->args == NULL); + builder->args = args; +} + +void grpc_channel_stack_builder_set_transport( + grpc_channel_stack_builder *builder, grpc_transport *transport) { + GPR_ASSERT(builder->transport == NULL); + builder->transport = transport; +} + +grpc_transport *grpc_channel_stack_builder_get_transport( + grpc_channel_stack_builder *builder) { + return builder->transport; +} + +const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments( + grpc_channel_stack_builder *builder) { + return builder->args; +} + +bool grpc_channel_stack_builder_append_filter( + grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, void *user_data) { + grpc_channel_stack_builder_iterator *it = + grpc_channel_stack_builder_create_iterator_at_last(builder); + bool ok = grpc_channel_stack_builder_add_filter_before( + it, filter, post_init_func, user_data); + grpc_channel_stack_builder_iterator_destroy(it); + return ok; +} + +bool grpc_channel_stack_builder_prepend_filter( + grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, void *user_data) { + grpc_channel_stack_builder_iterator *it = + grpc_channel_stack_builder_create_iterator_at_first(builder); + bool ok = grpc_channel_stack_builder_add_filter_after( + it, filter, post_init_func, user_data); + grpc_channel_stack_builder_iterator_destroy(it); + return ok; +} + +static void add_after(filter_node *before, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) { + filter_node *new = gpr_malloc(sizeof(*new)); + new->next = before->next; + new->prev = before; + new->next->prev = new->prev->next = new; + new->filter = filter; + new->init = post_init_func; + new->init_arg = user_data; +} + +bool grpc_channel_stack_builder_add_filter_before( + grpc_channel_stack_builder_iterator *iterator, + const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, void *user_data) { + if (iterator->node == &iterator->builder->begin) return false; + add_after(iterator->node->prev, filter, post_init_func, user_data); + return true; +} + +bool grpc_channel_stack_builder_add_filter_after( + grpc_channel_stack_builder_iterator *iterator, + const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, void *user_data) { + if (iterator->node == &iterator->builder->end) return false; + add_after(iterator->node, filter, post_init_func, user_data); + return true; +} + +void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder) { + filter_node *p = builder->begin.next; + while (p != &builder->end) { + filter_node *next = p->next; + gpr_free(p); + p = next; + } + gpr_free(builder); +} + +void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + size_t prefix_bytes, int initial_refs, + grpc_iomgr_cb_func destroy, + void *destroy_arg) { + // count the number of filters + size_t num_filters = 0; + for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { + num_filters++; + } + + // create an array of filters + const grpc_channel_filter **filters = + gpr_malloc(sizeof(*filters) * num_filters); + size_t i = 0; + for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { + filters[i++] = p->filter; + } + + // calculate the size of the channel stack + size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters); + + // allocate memory, with prefix_bytes followed by channel_stack_size + char *result = gpr_malloc(prefix_bytes + channel_stack_size); + // fetch a pointer to the channel stack + grpc_channel_stack *channel_stack = + (grpc_channel_stack *)(result + prefix_bytes); + // and initialize it + grpc_channel_stack_init(exec_ctx, initial_refs, destroy, + destroy_arg == NULL ? result : destroy_arg, filters, + num_filters, builder->args, builder->name, + channel_stack); + + // run post-initialization functions + i = 0; + for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { + if (p->init != NULL) { + p->init(channel_stack, grpc_channel_stack_element(channel_stack, i), + p->init_arg); + } + i++; + } + + grpc_channel_stack_builder_destroy(builder); + gpr_free((grpc_channel_filter **)filters); + + return result; +} diff --git a/src/core/channel/channel_stack_builder.h b/src/core/channel/channel_stack_builder.h new file mode 100644 index 0000000000..15f395e8b8 --- /dev/null +++ b/src/core/channel/channel_stack_builder.h @@ -0,0 +1,155 @@ +/* + * + * Copyright 2016, 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. + * + */ + +#ifndef GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H +#define GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H + +#include <stdbool.h> + +#include "src/core/channel/channel_args.h" +#include "src/core/channel/channel_stack.h" + +/// grpc_channel_stack_builder offers a programmatic interface to selected +/// and order channel filters +typedef struct grpc_channel_stack_builder grpc_channel_stack_builder; +typedef struct grpc_channel_stack_builder_iterator + grpc_channel_stack_builder_iterator; + +/// Create a new channel stack builder +grpc_channel_stack_builder *grpc_channel_stack_builder_create(void); + +/// Assign a name to the channel stack: \a name must be statically allocated +void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder, + const char *name); + +/// Attach \a transport to the builder (does not take ownership) +void grpc_channel_stack_builder_set_transport( + grpc_channel_stack_builder *builder, grpc_transport *transport); + +/// Fetch attached transport +grpc_transport *grpc_channel_stack_builder_get_transport( + grpc_channel_stack_builder *builder); + +/// Set channel arguments: \a args must continue to exist until after +/// grpc_channel_stack_builder_finish returns +void grpc_channel_stack_builder_set_channel_arguments( + grpc_channel_stack_builder *builder, const grpc_channel_args *args); + +/// Return a borrowed pointer to the channel arguments +const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments( + grpc_channel_stack_builder *builder); + +/// Begin iterating over already defined filters in the builder at the beginning +grpc_channel_stack_builder_iterator * +grpc_channel_stack_builder_create_iterator_at_first( + grpc_channel_stack_builder *builder); + +/// Begin iterating over already defined filters in the builder at the end +grpc_channel_stack_builder_iterator * +grpc_channel_stack_builder_create_iterator_at_last( + grpc_channel_stack_builder *builder); + +/// Is an iterator at the first element? +bool grpc_channel_stack_builder_iterator_is_first( + grpc_channel_stack_builder_iterator *iterator); + +/// Is an iterator at the end? +bool grpc_channel_stack_builder_iterator_is_end( + grpc_channel_stack_builder_iterator *iterator); + +/// Move an iterator to the next item +bool grpc_channel_stack_builder_move_next( + grpc_channel_stack_builder_iterator *iterator); + +/// Move an iterator to the previous item +bool grpc_channel_stack_builder_move_prev( + grpc_channel_stack_builder_iterator *iterator); + +typedef void (*grpc_post_filter_create_init_func)( + grpc_channel_stack *channel_stack, grpc_channel_element *elem, void *arg); + +/// Add \a filter to the stack, after \a iterator. +/// Call \a post_init_func(..., \a user_data) once the channel stack is +/// created. +bool grpc_channel_stack_builder_add_filter_after( + grpc_channel_stack_builder_iterator *iterator, + const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) GRPC_MUST_USE_RESULT; + +/// Add \a filter to the stack, before \a iterator. +/// Call \a post_init_func(..., \a user_data) once the channel stack is +/// created. +bool grpc_channel_stack_builder_add_filter_before( + grpc_channel_stack_builder_iterator *iterator, + const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) GRPC_MUST_USE_RESULT; + +/// Add \a filter to the beginning of the filter list. +/// Call \a post_init_func(..., \a user_data) once the channel stack is +/// created. +bool grpc_channel_stack_builder_prepend_filter( + grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) GRPC_MUST_USE_RESULT; + +/// Add \a filter to the end of the filter list. +/// Call \a post_init_func(..., \a user_data) once the channel stack is +/// created. +bool grpc_channel_stack_builder_append_filter( + grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) GRPC_MUST_USE_RESULT; + +/// Terminate iteration and destroy \a iterator +void grpc_channel_stack_builder_iterator_destroy( + grpc_channel_stack_builder_iterator *iterator); + +/// Destroy the builder, return the freshly minted channel stack +/// Allocates \a prefix_bytes bytes before the channel stack +/// Returns the base pointer of the allocated block +/// \a initial_refs, \a destroy, \a destroy_arg are as per +/// grpc_channel_stack_init +void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + size_t prefix_bytes, int initial_refs, + grpc_iomgr_cb_func destroy, + void *destroy_arg); + +/// Destroy the builder without creating a channel stack +void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder); + +extern int grpc_trace_channel_stack_builder; + +#endif /* GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H */ diff --git a/src/core/channel/client_uchannel.c b/src/core/channel/client_uchannel.c deleted file mode 100644 index 83fcc3a87f..0000000000 --- a/src/core/channel/client_uchannel.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * - * Copyright 2015-2016, 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. - * - */ - -#include "src/core/channel/client_uchannel.h" - -#include <string.h> - -#include "src/core/census/grpc_filter.h" -#include "src/core/channel/channel_args.h" -#include "src/core/channel/client_channel.h" -#include "src/core/channel/compress_filter.h" -#include "src/core/channel/subchannel_call_holder.h" -#include "src/core/iomgr/iomgr.h" -#include "src/core/support/string.h" -#include "src/core/surface/channel.h" -#include "src/core/transport/connectivity_state.h" - -#include <grpc/support/alloc.h> -#include <grpc/support/log.h> -#include <grpc/support/sync.h> -#include <grpc/support/useful.h> - -/** Microchannel (uchannel) implementation: a lightweight channel without any - * load-balancing mechanisms meant for communication from within the core. */ - -typedef struct client_uchannel_channel_data { - /** master channel - the grpc_channel instance that ultimately owns - this channel_data via its channel stack. - We occasionally use this to bump the refcount on the master channel - to keep ourselves alive through an asynchronous operation. */ - grpc_channel_stack *owning_stack; - - /** connectivity state being tracked */ - grpc_connectivity_state_tracker state_tracker; - - /** the subchannel wrapped by the microchannel */ - grpc_connected_subchannel *connected_subchannel; - - /** the callback used to stay subscribed to subchannel connectivity - * notifications */ - grpc_closure connectivity_cb; - - /** the current connectivity state of the wrapped subchannel */ - grpc_connectivity_state subchannel_connectivity; - - gpr_mu mu_state; -} channel_data; - -typedef grpc_subchannel_call_holder call_data; - -static void monitor_subchannel(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_success) { - channel_data *chand = arg; - grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, - chand->subchannel_connectivity, - "uchannel_monitor_subchannel"); - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, chand->connected_subchannel, NULL, - &chand->subchannel_connectivity, &chand->connectivity_cb); -} - -static char *cuc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { - return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data); -} - -static void cuc_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - grpc_subchannel_call_holder_perform_op(exec_ctx, elem->call_data, op); -} - -static void cuc_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_transport_op *op) { - channel_data *chand = elem->channel_data; - - grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL); - - GPR_ASSERT(op->set_accept_stream == false); - GPR_ASSERT(op->bind_pollset == NULL); - - if (op->on_connectivity_state_change != NULL) { - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &chand->state_tracker, op->connectivity_state, - op->on_connectivity_state_change); - op->on_connectivity_state_change = NULL; - op->connectivity_state = NULL; - } - - if (op->disconnect) { - grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, - GRPC_CHANNEL_FATAL_FAILURE, "disconnect"); - } -} - -static int cuc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg, - grpc_metadata_batch *initial_metadata, - grpc_connected_subchannel **connected_subchannel, - grpc_closure *on_ready) { - channel_data *chand = arg; - GPR_ASSERT(initial_metadata != NULL); - *connected_subchannel = chand->connected_subchannel; - return 1; -} - -/* Constructor for call_data */ -static void cuc_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - grpc_subchannel_call_holder_init(elem->call_data, cuc_pick_subchannel, - elem->channel_data, args->call_stack); -} - -/* Destructor for call_data */ -static void cuc_destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data); -} - -/* Constructor for channel_data */ -static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - channel_data *chand = elem->channel_data; - memset(chand, 0, sizeof(*chand)); - grpc_closure_init(&chand->connectivity_cb, monitor_subchannel, chand); - GPR_ASSERT(args->is_last); - GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter); - chand->owning_stack = args->channel_stack; - grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, - "client_uchannel"); - gpr_mu_init(&chand->mu_state); -} - -/* Destructor for channel_data */ -static void cuc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - channel_data *chand = elem->channel_data; - /* cancel subscription */ - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, chand->connected_subchannel, NULL, NULL, - &chand->connectivity_cb); - grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); - gpr_mu_destroy(&chand->mu_state); - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, chand->connected_subchannel, - "uchannel"); -} - -static void cuc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_pollset *pollset) { - call_data *calld = elem->call_data; - calld->pollset = pollset; -} - -const grpc_channel_filter grpc_client_uchannel_filter = { - cuc_start_transport_stream_op, cuc_start_transport_op, sizeof(call_data), - cuc_init_call_elem, cuc_set_pollset, cuc_destroy_call_elem, - sizeof(channel_data), cuc_init_channel_elem, cuc_destroy_channel_elem, - cuc_get_peer, "client-uchannel", -}; - -grpc_connectivity_state grpc_client_uchannel_check_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) { - channel_data *chand = elem->channel_data; - grpc_connectivity_state out; - gpr_mu_lock(&chand->mu_state); - out = grpc_connectivity_state_check(&chand->state_tracker); - gpr_mu_unlock(&chand->mu_state); - return out; -} - -void grpc_client_uchannel_watch_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete) { - channel_data *chand = elem->channel_data; - gpr_mu_lock(&chand->mu_state); - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &chand->state_tracker, state, on_complete); - gpr_mu_unlock(&chand->mu_state); -} - -grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel, - grpc_channel_args *args) { - grpc_channel *channel = NULL; -#define MAX_FILTERS 3 - const grpc_channel_filter *filters[MAX_FILTERS]; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - size_t n = 0; - - if (grpc_channel_args_is_census_enabled(args)) { - filters[n++] = &grpc_client_census_filter; - } - filters[n++] = &grpc_compress_filter; - filters[n++] = &grpc_client_uchannel_filter; - GPR_ASSERT(n <= MAX_FILTERS); - - channel = - grpc_channel_create_from_filters(&exec_ctx, NULL, filters, n, args, 1); - - return channel; -} - -void grpc_client_uchannel_set_connected_subchannel( - grpc_channel *uchannel, grpc_connected_subchannel *connected_subchannel) { - grpc_channel_element *elem = - grpc_channel_stack_last_element(grpc_channel_get_channel_stack(uchannel)); - channel_data *chand = elem->channel_data; - GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter); - gpr_mu_lock(&chand->mu_state); - chand->connected_subchannel = connected_subchannel; - GRPC_CONNECTED_SUBCHANNEL_REF(connected_subchannel, "uchannel"); - gpr_mu_unlock(&chand->mu_state); -} diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c index e8eb9dcfc5..e7ed3ccfeb 100644 --- a/src/core/channel/connected_channel.c +++ b/src/core/channel/connected_channel.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,7 +67,6 @@ static void con_start_transport_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; - GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); GRPC_CALL_LOG_OP(GPR_INFO, elem, op); grpc_transport_perform_stream_op(exec_ctx, chand->transport, @@ -88,7 +87,6 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, channel_data *chand = elem->channel_data; int r; - GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); r = grpc_transport_init_stream( exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), &args->call_stack->refcount, args->server_transport_data); @@ -108,7 +106,6 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; - GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); grpc_transport_destroy_stream(exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld)); } @@ -119,7 +116,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element_args *args) { channel_data *cd = (channel_data *)elem->channel_data; GPR_ASSERT(args->is_last); - GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); cd->transport = NULL; } @@ -127,7 +123,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx, static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem) { channel_data *cd = (channel_data *)elem->channel_data; - GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); grpc_transport_destroy(exec_ctx, cd->transport); } @@ -136,21 +131,18 @@ static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { return grpc_transport_get_peer(exec_ctx, chand->transport); } -const grpc_channel_filter grpc_connected_channel_filter = { +static const grpc_channel_filter connected_channel_filter = { con_start_transport_stream_op, con_start_transport_op, sizeof(call_data), init_call_elem, set_pollset, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, con_get_peer, "connected", }; -void grpc_connected_channel_bind_transport(grpc_channel_stack *channel_stack, - grpc_transport *transport) { - /* Assumes that the connected channel filter is always the last filter - in a channel stack */ - grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack); +static void bind_transport(grpc_channel_stack *channel_stack, + grpc_channel_element *elem, void *t) { channel_data *cd = (channel_data *)elem->channel_data; - GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); + GPR_ASSERT(elem->filter == &connected_channel_filter); GPR_ASSERT(cd->transport == NULL); - cd->transport = transport; + cd->transport = t; /* HACK(ctiller): increase call stack size for the channel to make space for channel data. We need a cleaner (but performant) way to do this, @@ -158,7 +150,16 @@ void grpc_connected_channel_bind_transport(grpc_channel_stack *channel_stack, This is only "safe" because call stacks place no additional data after the last call element, and the last call element MUST be the connected channel. */ - channel_stack->call_stack_size += grpc_transport_stream_size(transport); + channel_stack->call_stack_size += grpc_transport_stream_size(t); +} + +bool grpc_add_connected_filter(grpc_channel_stack_builder *builder, + void *arg_must_be_null) { + GPR_ASSERT(arg_must_be_null == NULL); + grpc_transport *t = grpc_channel_stack_builder_get_transport(builder); + GPR_ASSERT(t != NULL); + return grpc_channel_stack_builder_append_filter( + builder, &connected_channel_filter, bind_transport, t); } grpc_stream *grpc_connected_channel_get_stream(grpc_call_element *elem) { diff --git a/src/core/channel/connected_channel.h b/src/core/channel/connected_channel.h index 7978ab3b80..7c0c8359a4 100644 --- a/src/core/channel/connected_channel.h +++ b/src/core/channel/connected_channel.h @@ -34,18 +34,9 @@ #ifndef GRPC_CORE_CHANNEL_CONNECTED_CHANNEL_H #define GRPC_CORE_CHANNEL_CONNECTED_CHANNEL_H -#include "src/core/channel/channel_stack.h" +#include "src/core/channel/channel_stack_builder.h" -/* A channel filter representing a channel that is on a connected transport. - This filter performs actual sending and receiving of messages. */ - -extern const grpc_channel_filter grpc_connected_channel_filter; - -/* Post construction fixup: set the transport in the connected channel. - Must be called before any call stack using this filter is used. */ -void grpc_connected_channel_bind_transport(grpc_channel_stack* channel_stack, - grpc_transport* transport); - -grpc_stream* grpc_connected_channel_get_stream(grpc_call_element* elem); +bool grpc_add_connected_filter(grpc_channel_stack_builder *builder, + void *arg_must_be_null); #endif /* GRPC_CORE_CHANNEL_CONNECTED_CHANNEL_H */ diff --git a/src/core/channel/subchannel_call_holder.h b/src/core/channel/subchannel_call_holder.h index 9086cdc882..84b4657db4 100644 --- a/src/core/channel/subchannel_call_holder.h +++ b/src/core/channel/subchannel_call_holder.h @@ -55,15 +55,14 @@ typedef enum { for initial metadata before trying to create a call object, and handling cancellation gracefully. - Both the channel and uchannel filter use this as their call_data. */ + The channel filter uses this as their call_data. */ typedef struct grpc_subchannel_call_holder { /** either 0 for no call, 1 for cancelled, or a pointer to a grpc_subchannel_call */ gpr_atm subchannel_call; /** Helper function to choose the subchannel on which to create the call object. Channel filter delegates to the load - balancing policy (once it's ready); uchannel returns - immediately */ + balancing policy (once it's ready). */ grpc_subchannel_call_holder_pick_subchannel pick_subchannel; void *pick_subchannel_arg; diff --git a/src/core/client_config/connector.h b/src/core/client_config/connector.h index 953ab96eb2..93248fca4b 100644 --- a/src/core/client_config/connector.h +++ b/src/core/client_config/connector.h @@ -62,9 +62,6 @@ typedef struct { typedef struct { /** the connected transport */ grpc_transport *transport; - /** any additional filters (owned by the caller of connect) */ - const grpc_channel_filter **filters; - size_t num_filters; /** channel arguments (to be passed to the filters) */ const grpc_channel_args *channel_args; diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c index e28e4757a1..2b2ee97e12 100644 --- a/src/core/client_config/resolvers/dns_resolver.c +++ b/src/core/client_config/resolvers/dns_resolver.c @@ -42,8 +42,14 @@ #include "src/core/client_config/lb_policy_registry.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/timer.h" +#include "src/core/support/backoff.h" #include "src/core/support/string.h" +#define BACKOFF_MULTIPLIER 1.6 +#define BACKOFF_JITTER 0.2 +#define BACKOFF_MIN_SECONDS 1 +#define BACKOFF_MAX_SECONDS 120 + typedef struct { /** base class: must be first */ grpc_resolver base; @@ -75,6 +81,8 @@ typedef struct { /** retry timer */ bool have_retry_timer; grpc_timer retry_timer; + /** retry backoff state */ + gpr_backoff backoff_state; } dns_resolver; static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); @@ -111,6 +119,7 @@ static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, dns_resolver *r = (dns_resolver *)resolver; gpr_mu_lock(&r->mu); if (!r->resolving) { + gpr_backoff_reset(&r->backoff_state); dns_start_resolving_locked(r); } gpr_mu_unlock(&r->mu); @@ -125,6 +134,7 @@ static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, r->next_completion = on_complete; r->target_config = target_config; if (r->resolved_version == 0 && !r->resolving) { + gpr_backoff_reset(&r->backoff_state); dns_start_resolving_locked(r); } else { dns_maybe_finish_next_locked(exec_ctx, r); @@ -185,17 +195,16 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_resolved_addresses_destroy(addresses); gpr_free(subchannels); } else { - int retry_seconds = 15; - gpr_log(GPR_DEBUG, "dns resolution failed: retrying in %d seconds", - retry_seconds); + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now); + gpr_timespec timeout = gpr_time_sub(next_try, now); + gpr_log(GPR_DEBUG, "dns resolution failed: retrying in %d.%09d seconds", + timeout.tv_sec, timeout.tv_nsec); GPR_ASSERT(!r->have_retry_timer); r->have_retry_timer = true; - gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); GRPC_RESOLVER_REF(&r->base, "retry-timer"); - grpc_timer_init( - exec_ctx, &r->retry_timer, - gpr_time_add(now, gpr_time_from_seconds(retry_seconds, GPR_TIMESPAN)), - dns_on_retry_timer, r, now); + grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r, + now); } if (r->resolved_config) { grpc_client_config_unref(exec_ctx, r->resolved_config); @@ -263,6 +272,8 @@ static grpc_resolver *dns_create(grpc_resolver_args *args, r->name = gpr_strdup(path); r->default_port = gpr_strdup(default_port); r->subchannel_factory = args->subchannel_factory; + gpr_backoff_init(&r->backoff_state, BACKOFF_MULTIPLIER, BACKOFF_JITTER, + BACKOFF_MIN_SECONDS * 1000, BACKOFF_MAX_SECONDS * 1000); grpc_subchannel_factory_ref(r->subchannel_factory); r->lb_policy_name = gpr_strdup(lb_policy_name); return &r->base; diff --git a/src/core/client_config/resolvers/sockaddr_resolver.c b/src/core/client_config/resolvers/sockaddr_resolver.c index 68910ad975..3cb7d79b67 100644 --- a/src/core/client_config/resolvers/sockaddr_resolver.c +++ b/src/core/client_config/resolvers/sockaddr_resolver.c @@ -37,9 +37,6 @@ #include <stdio.h> #include <string.h> -#ifdef GPR_POSIX_SOCKET -#include <sys/un.h> -#endif #include <grpc/support/alloc.h> #include <grpc/support/host_port.h> @@ -47,6 +44,7 @@ #include "src/core/client_config/lb_policy_registry.h" #include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/unix_sockets_posix.h" #include "src/core/support/string.h" typedef struct { @@ -168,24 +166,6 @@ static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { gpr_free(r); } -#ifdef GPR_POSIX_SOCKET -static int parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, - size_t *len) { - struct sockaddr_un *un = (struct sockaddr_un *)addr; - - un->sun_family = AF_UNIX; - strcpy(un->sun_path, uri->path); - *len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; - - return 1; -} - -static char *unix_get_default_authority(grpc_resolver_factory *factory, - grpc_uri *uri) { - return gpr_strdup("localhost"); -} -#endif - static char *ip_get_default_authority(grpc_uri *uri) { const char *path = uri->path; if (path[0] == '/') ++path; @@ -371,21 +351,22 @@ static void sockaddr_factory_ref(grpc_resolver_factory *factory) {} static void sockaddr_factory_unref(grpc_resolver_factory *factory) {} -#define DECL_FACTORY(name) \ +#define DECL_FACTORY(name, prefix) \ static grpc_resolver *name##_factory_create_resolver( \ grpc_resolver_factory *factory, grpc_resolver_args *args) { \ - return sockaddr_create(args, "pick_first", parse_##name); \ + return sockaddr_create(args, "pick_first", prefix##parse_##name); \ } \ static const grpc_resolver_factory_vtable name##_factory_vtable = { \ sockaddr_factory_ref, sockaddr_factory_unref, \ - name##_factory_create_resolver, name##_get_default_authority, #name}; \ + name##_factory_create_resolver, prefix##name##_get_default_authority, \ + #name}; \ static grpc_resolver_factory name##_resolver_factory = { \ &name##_factory_vtable}; \ grpc_resolver_factory *grpc_##name##_resolver_factory_create() { \ return &name##_resolver_factory; \ } -#ifdef GPR_POSIX_SOCKET -DECL_FACTORY(unix) +#ifdef GPR_HAVE_UNIX_SOCKET +DECL_FACTORY(unix, grpc_) #endif -DECL_FACTORY(ipv4) DECL_FACTORY(ipv6) +DECL_FACTORY(ipv4, ) DECL_FACTORY(ipv6, ) diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c index 5dea215668..8f150a8d81 100644 --- a/src/core/client_config/subchannel.c +++ b/src/core/client_config/subchannel.c @@ -47,6 +47,7 @@ #include "src/core/profiling/timers.h" #include "src/core/support/backoff.h" #include "src/core/surface/channel.h" +#include "src/core/surface/channel_init.h" #include "src/core/transport/connectivity_state.h" #define INTERNAL_REF_BITS 16 @@ -521,32 +522,15 @@ void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx, static void publish_transport_locked(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { - size_t channel_stack_size; grpc_connected_subchannel *con; grpc_channel_stack *stk; - size_t num_filters; - const grpc_channel_filter **filters; state_watcher *sw_subchannel; - /* build final filter list */ - num_filters = c->num_filters + c->connecting_result.num_filters + 1; - filters = gpr_malloc(sizeof(*filters) * num_filters); - if (c->num_filters > 0) { - memcpy((void *)filters, c->filters, sizeof(*filters) * c->num_filters); - } - memcpy((void *)(filters + c->num_filters), c->connecting_result.filters, - sizeof(*filters) * c->connecting_result.num_filters); - filters[num_filters - 1] = &grpc_connected_channel_filter; - /* construct channel stack */ - channel_stack_size = grpc_channel_stack_size(filters, num_filters); - con = gpr_malloc(channel_stack_size); + con = grpc_channel_init_create_stack( + exec_ctx, GRPC_CLIENT_SUBCHANNEL, 0, c->connecting_result.channel_args, 1, + connection_destroy, NULL, c->connecting_result.transport); stk = CHANNEL_STACK_FROM_CONNECTION(con); - grpc_channel_stack_init(exec_ctx, 1, connection_destroy, con, filters, - num_filters, c->connecting_result.channel_args, - "CONNECTED_SUBCHANNEL", stk); - grpc_connected_channel_bind_transport(stk, c->connecting_result.transport); - gpr_free((void *)c->connecting_result.filters); memset(&c->connecting_result, 0, sizeof(c->connecting_result)); /* initialize state watcher */ @@ -557,9 +541,7 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx, sw_subchannel); if (c->disconnected) { - gpr_mu_unlock(&c->mu); gpr_free(sw_subchannel); - gpr_free((void *)filters); grpc_channel_stack_destroy(exec_ctx, stk); gpr_free(con); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); @@ -587,8 +569,6 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx, /* signal completion */ grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY, "connected"); - - gpr_free((void *)filters); } static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) { diff --git a/src/core/httpcli/format_request.c b/src/core/http/format_request.c index 04f2a2d99a..60179297bf 100644 --- a/src/core/httpcli/format_request.c +++ b/src/core/http/format_request.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,7 @@ * */ -#include "src/core/httpcli/format_request.h" +#include "src/core/http/format_request.h" #include <stdarg.h> #include <stdio.h> @@ -46,7 +46,7 @@ static void fill_common_header(const grpc_httpcli_request *request, gpr_strvec *buf) { size_t i; - gpr_strvec_add(buf, gpr_strdup(request->path)); + gpr_strvec_add(buf, gpr_strdup(request->http.path)); gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n")); /* just in case some crazy server really expects HTTP/1.1 */ gpr_strvec_add(buf, gpr_strdup("Host: ")); @@ -56,10 +56,10 @@ static void fill_common_header(const grpc_httpcli_request *request, gpr_strvec_add(buf, gpr_strdup("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n")); /* user supplied headers */ - for (i = 0; i < request->hdr_count; i++) { - gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].key)); + for (i = 0; i < request->http.hdr_count; i++) { + gpr_strvec_add(buf, gpr_strdup(request->http.hdrs[i].key)); gpr_strvec_add(buf, gpr_strdup(": ")); - gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].value)); + gpr_strvec_add(buf, gpr_strdup(request->http.hdrs[i].value)); gpr_strvec_add(buf, gpr_strdup("\r\n")); } } @@ -94,8 +94,8 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, fill_common_header(request, &out); if (body_bytes) { uint8_t has_content_type = 0; - for (i = 0; i < request->hdr_count; i++) { - if (strcmp(request->hdrs[i].key, "Content-Type") == 0) { + for (i = 0; i < request->http.hdr_count; i++) { + if (strcmp(request->http.hdrs[i].key, "Content-Type") == 0) { has_content_type = 1; break; } diff --git a/src/core/httpcli/format_request.h b/src/core/http/format_request.h index eb47cc90ca..49593b695c 100644 --- a/src/core/httpcli/format_request.h +++ b/src/core/http/format_request.h @@ -31,10 +31,10 @@ * */ -#ifndef GRPC_CORE_HTTPCLI_FORMAT_REQUEST_H -#define GRPC_CORE_HTTPCLI_FORMAT_REQUEST_H +#ifndef GRPC_CORE_HTTP_FORMAT_REQUEST_H +#define GRPC_CORE_HTTP_FORMAT_REQUEST_H -#include "src/core/httpcli/httpcli.h" +#include "src/core/http/httpcli.h" #include <grpc/support/slice.h> gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request); @@ -42,4 +42,4 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, const char *body_bytes, size_t body_size); -#endif /* GRPC_CORE_HTTPCLI_FORMAT_REQUEST_H */ +#endif /* GRPC_CORE_HTTP_FORMAT_REQUEST_H */ diff --git a/src/core/httpcli/httpcli.c b/src/core/http/httpcli.c index 1219c444c7..1c0d3336ea 100644 --- a/src/core/httpcli/httpcli.c +++ b/src/core/http/httpcli.c @@ -31,7 +31,7 @@ * */ -#include "src/core/httpcli/httpcli.h" +#include "src/core/http/httpcli.h" #include "src/core/iomgr/sockaddr.h" #include <string.h> @@ -40,8 +40,8 @@ #include <grpc/support/log.h> #include <grpc/support/string_util.h> -#include "src/core/httpcli/format_request.h" -#include "src/core/httpcli/parser.h" +#include "src/core/http/format_request.h" +#include "src/core/http/parser.h" #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/resolve_address.h" @@ -50,7 +50,7 @@ typedef struct { gpr_slice request_text; - grpc_httpcli_parser parser; + grpc_http_parser parser; grpc_resolved_addresses *addresses; size_t next_address; grpc_endpoint *ep; @@ -99,8 +99,9 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, int success) { grpc_pollset_set_del_pollset(exec_ctx, req->context->pollset_set, req->pollset); - req->on_response(exec_ctx, req->user_data, success ? &req->parser.r : NULL); - grpc_httpcli_parser_destroy(&req->parser); + req->on_response(exec_ctx, req->user_data, + success ? &req->parser.http.response : NULL); + grpc_http_parser_destroy(&req->parser); if (req->addresses != NULL) { grpc_resolved_addresses_destroy(req->addresses); } @@ -129,7 +130,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { for (i = 0; i < req->incoming.count; i++) { if (GPR_SLICE_LENGTH(req->incoming.slices[i])) { req->have_read_byte = 1; - if (!grpc_httpcli_parser_parse(&req->parser, req->incoming.slices[i])) { + if (!grpc_http_parser_parse(&req->parser, req->incoming.slices[i])) { finish(exec_ctx, req, 0); return; } @@ -141,7 +142,11 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { } else if (!req->have_read_byte) { next_address(exec_ctx, req); } else { - finish(exec_ctx, req, grpc_httpcli_parser_eof(&req->parser)); + int parse_success = grpc_http_parser_eof(&req->parser); + if (parse_success && (req->parser.type != GRPC_HTTP_RESPONSE)) { + parse_success = 0; + } + finish(exec_ctx, req, parse_success); } } @@ -223,7 +228,7 @@ static void internal_request_begin( internal_request *req = gpr_malloc(sizeof(internal_request)); memset(req, 0, sizeof(*req)); req->request_text = request_text; - grpc_httpcli_parser_init(&req->parser); + grpc_http_parser_init(&req->parser); req->on_response = on_response; req->user_data = user_data; req->deadline = deadline; @@ -255,7 +260,7 @@ void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, g_get_override(exec_ctx, request, deadline, on_response, user_data)) { return; } - gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path); + gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->http.path); internal_request_begin(exec_ctx, context, pollset, request, deadline, on_response, user_data, name, grpc_httpcli_format_get_request(request)); @@ -274,7 +279,7 @@ void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, on_response, user_data)) { return; } - gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->path); + gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->http.path); internal_request_begin( exec_ctx, context, pollset, request, deadline, on_response, user_data, name, grpc_httpcli_format_post_request(request, body_bytes, body_size)); diff --git a/src/core/httpcli/httpcli.h b/src/core/http/httpcli.h index 1fe5782657..0bf4f2f445 100644 --- a/src/core/httpcli/httpcli.h +++ b/src/core/http/httpcli.h @@ -31,27 +31,20 @@ * */ -#ifndef GRPC_CORE_HTTPCLI_HTTPCLI_H -#define GRPC_CORE_HTTPCLI_HTTPCLI_H +#ifndef GRPC_CORE_HTTP_HTTPCLI_H +#define GRPC_CORE_HTTP_HTTPCLI_H #include <stddef.h> #include <grpc/support/time.h> +#include "src/core/http/parser.h" #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/pollset_set.h" /* User agent this library reports */ #define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0" -/* Maximum length of a header string of the form 'Key: Value\r\n' */ -#define GRPC_HTTPCLI_MAX_HEADER_LENGTH 4096 - -/* A single header to be passed in a request */ -typedef struct grpc_httpcli_header { - char *key; - char *value; -} grpc_httpcli_header; /* Tracks in-progress http requests TODO(ctiller): allow caching and capturing multiple requests for the @@ -77,33 +70,21 @@ typedef struct grpc_httpcli_request { char *host; /* The host to verify in the SSL handshake (or NULL) */ char *ssl_host_override; - /* The path of the resource to fetch */ - char *path; - /* Additional headers: count and key/values; the following are supplied - automatically and MUST NOT be set here: + /* The main part of the request + The following headers are supplied automatically and MUST NOT be set here: Host, Connection, User-Agent */ - size_t hdr_count; - grpc_httpcli_header *hdrs; + grpc_http_request http; /* handshaker to use ssl for the request */ const grpc_httpcli_handshaker *handshaker; } grpc_httpcli_request; -/* A response */ -typedef struct grpc_httpcli_response { - /* HTTP status code */ - int status; - /* Headers: count and key/values */ - size_t hdr_count; - grpc_httpcli_header *hdrs; - /* Body: length and contents; contents are NOT null-terminated */ - size_t body_length; - char *body; -} grpc_httpcli_response; +/* Expose the parser response type as a httpcli response too */ +typedef struct grpc_http_response grpc_httpcli_response; /* Callback for grpc_httpcli_get and grpc_httpcli_post. */ typedef void (*grpc_httpcli_response_cb)(grpc_exec_ctx *exec_ctx, void *user_data, - const grpc_httpcli_response *response); + const grpc_http_response *response); void grpc_httpcli_context_init(grpc_httpcli_context *context); void grpc_httpcli_context_destroy(grpc_httpcli_context *context); @@ -160,4 +141,4 @@ typedef int (*grpc_httpcli_post_override)( void grpc_httpcli_set_override(grpc_httpcli_get_override get, grpc_httpcli_post_override post); -#endif /* GRPC_CORE_HTTPCLI_HTTPCLI_H */ +#endif /* GRPC_CORE_HTTP_HTTPCLI_H */ diff --git a/src/core/httpcli/httpcli_security_connector.c b/src/core/http/httpcli_security_connector.c index 156961a377..ce82701089 100644 --- a/src/core/httpcli/httpcli_security_connector.c +++ b/src/core/http/httpcli_security_connector.c @@ -31,7 +31,7 @@ * */ -#include "src/core/httpcli/httpcli.h" +#include "src/core/http/httpcli.h" #include <string.h> diff --git a/src/core/http/parser.c b/src/core/http/parser.c new file mode 100644 index 0000000000..ebec8a5157 --- /dev/null +++ b/src/core/http/parser.c @@ -0,0 +1,313 @@ +/* + * + * Copyright 2015-2016, 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. + * + */ + +#include "src/core/http/parser.h" + +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/useful.h> + +static char *buf2str(void *buffer, size_t length) { + char *out = gpr_malloc(length + 1); + memcpy(out, buffer, length); + out[length] = 0; + return out; +} + +static int handle_response_line(grpc_http_parser *parser) { + uint8_t *beg = parser->cur_line; + uint8_t *cur = beg; + uint8_t *end = beg + parser->cur_line_length; + + if (cur == end || *cur++ != 'H') goto error; + if (cur == end || *cur++ != 'T') goto error; + if (cur == end || *cur++ != 'T') goto error; + if (cur == end || *cur++ != 'P') goto error; + if (cur == end || *cur++ != '/') goto error; + if (cur == end || *cur++ != '1') goto error; + if (cur == end || *cur++ != '.') goto error; + if (cur == end || *cur < '0' || *cur++ > '1') goto error; + if (cur == end || *cur++ != ' ') goto error; + if (cur == end || *cur < '1' || *cur++ > '9') goto error; + if (cur == end || *cur < '0' || *cur++ > '9') goto error; + if (cur == end || *cur < '0' || *cur++ > '9') goto error; + parser->http.response.status = + (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0'); + if (cur == end || *cur++ != ' ') goto error; + + /* we don't really care about the status code message */ + + return 1; + +error: + gpr_log(GPR_ERROR, "Failed parsing response line"); + return 0; +} + +static int handle_request_line(grpc_http_parser *parser) { + uint8_t *beg = parser->cur_line; + uint8_t *cur = beg; + uint8_t *end = beg + parser->cur_line_length; + uint8_t vers_major = 0; + uint8_t vers_minor = 0; + + while (cur != end && *cur++ != ' ') + ; + if (cur == end) goto error; + parser->http.request.method = buf2str(beg, (size_t)(cur - beg - 1)); + + beg = cur; + while (cur != end && *cur++ != ' ') + ; + if (cur == end) goto error; + parser->http.request.path = buf2str(beg, (size_t)(cur - beg - 1)); + + if (cur == end || *cur++ != 'H') goto error; + if (cur == end || *cur++ != 'T') goto error; + if (cur == end || *cur++ != 'T') goto error; + if (cur == end || *cur++ != 'P') goto error; + if (cur == end || *cur++ != '/') goto error; + vers_major = (uint8_t)(*cur++ - '1' + 1); + ++cur; + if (cur == end) goto error; + vers_minor = (uint8_t)(*cur++ - '1' + 1); + + if (vers_major == 1) { + if (vers_minor == 0) { + parser->http.request.version = GRPC_HTTP_HTTP10; + } else if (vers_minor == 1) { + parser->http.request.version = GRPC_HTTP_HTTP11; + } else { + goto error; + } + } else if (vers_major == 2) { + if (vers_minor == 0) { + parser->http.request.version = GRPC_HTTP_HTTP20; + } else { + goto error; + } + } else { + goto error; + } + + return 1; + +error: + gpr_log(GPR_ERROR, "Failed parsing request line"); + return 0; +} + +static int handle_first_line(grpc_http_parser *parser) { + if (parser->cur_line[0] == 'H') { + parser->type = GRPC_HTTP_RESPONSE; + return handle_response_line(parser); + } else { + parser->type = GRPC_HTTP_REQUEST; + return handle_request_line(parser); + } +} + +static int add_header(grpc_http_parser *parser) { + uint8_t *beg = parser->cur_line; + uint8_t *cur = beg; + uint8_t *end = beg + parser->cur_line_length; + size_t *hdr_count = NULL; + grpc_http_header **hdrs = NULL; + grpc_http_header hdr = {NULL, NULL}; + + GPR_ASSERT(cur != end); + + if (*cur == ' ' || *cur == '\t') { + gpr_log(GPR_ERROR, "Continued header lines not supported yet"); + goto error; + } + + while (cur != end && *cur != ':') { + cur++; + } + if (cur == end) { + gpr_log(GPR_ERROR, "Didn't find ':' in header string"); + goto error; + } + GPR_ASSERT(cur >= beg); + hdr.key = buf2str(beg, (size_t)(cur - beg)); + cur++; /* skip : */ + + while (cur != end && (*cur == ' ' || *cur == '\t')) { + cur++; + } + GPR_ASSERT(end - cur >= 2); + hdr.value = buf2str(cur, (size_t)(end - cur) - 2); + + if (parser->type == GRPC_HTTP_RESPONSE) { + hdr_count = &parser->http.response.hdr_count; + hdrs = &parser->http.response.hdrs; + } else if (parser->type == GRPC_HTTP_REQUEST) { + hdr_count = &parser->http.request.hdr_count; + hdrs = &parser->http.request.hdrs; + } else { + return 0; + } + + if (*hdr_count == parser->hdr_capacity) { + parser->hdr_capacity = + GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2); + *hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs)); + } + (*hdrs)[(*hdr_count)++] = hdr; + return 1; + +error: + gpr_free(hdr.key); + gpr_free(hdr.value); + return 0; +} + +static int finish_line(grpc_http_parser *parser) { + switch (parser->state) { + case GRPC_HTTP_FIRST_LINE: + if (!handle_first_line(parser)) { + return 0; + } + parser->state = GRPC_HTTP_HEADERS; + break; + case GRPC_HTTP_HEADERS: + if (parser->cur_line_length == 2) { + parser->state = GRPC_HTTP_BODY; + break; + } + if (!add_header(parser)) { + return 0; + } + break; + case GRPC_HTTP_BODY: + GPR_UNREACHABLE_CODE(return 0); + } + + parser->cur_line_length = 0; + return 1; +} + +static int addbyte_body(grpc_http_parser *parser, uint8_t byte) { + size_t *body_length = NULL; + char **body = NULL; + + if (parser->type == GRPC_HTTP_RESPONSE) { + body_length = &parser->http.response.body_length; + body = &parser->http.response.body; + } else if (parser->type == GRPC_HTTP_REQUEST) { + body_length = &parser->http.request.body_length; + body = &parser->http.request.body; + } else { + return 0; + } + + if (*body_length == parser->body_capacity) { + parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2); + *body = gpr_realloc((void *)*body, parser->body_capacity); + } + (*body)[*body_length] = (char)byte; + (*body_length)++; + + return 1; +} + +static int addbyte(grpc_http_parser *parser, uint8_t byte) { + switch (parser->state) { + case GRPC_HTTP_FIRST_LINE: + case GRPC_HTTP_HEADERS: + if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) { + gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded", + GRPC_HTTP_PARSER_MAX_HEADER_LENGTH); + return 0; + } + parser->cur_line[parser->cur_line_length] = byte; + parser->cur_line_length++; + if (parser->cur_line_length >= 2 && + parser->cur_line[parser->cur_line_length - 2] == '\r' && + parser->cur_line[parser->cur_line_length - 1] == '\n') { + return finish_line(parser); + } else { + return 1; + } + GPR_UNREACHABLE_CODE(return 0); + case GRPC_HTTP_BODY: + return addbyte_body(parser, byte); + } + GPR_UNREACHABLE_CODE(return 0); +} + +void grpc_http_parser_init(grpc_http_parser *parser) { + memset(parser, 0, sizeof(*parser)); + parser->state = GRPC_HTTP_FIRST_LINE; + parser->type = GRPC_HTTP_UNKNOWN; +} + +void grpc_http_parser_destroy(grpc_http_parser *parser) { + size_t i; + if (parser->type == GRPC_HTTP_RESPONSE) { + gpr_free(parser->http.response.body); + for (i = 0; i < parser->http.response.hdr_count; i++) { + gpr_free(parser->http.response.hdrs[i].key); + gpr_free(parser->http.response.hdrs[i].value); + } + gpr_free(parser->http.response.hdrs); + } else if (parser->type == GRPC_HTTP_REQUEST) { + gpr_free(parser->http.request.body); + for (i = 0; i < parser->http.request.hdr_count; i++) { + gpr_free(parser->http.request.hdrs[i].key); + gpr_free(parser->http.request.hdrs[i].value); + } + gpr_free(parser->http.request.hdrs); + gpr_free(parser->http.request.method); + gpr_free(parser->http.request.path); + } +} + +int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) { + size_t i; + + for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) { + if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) { + return 0; + } + } + + return 1; +} + +int grpc_http_parser_eof(grpc_http_parser *parser) { + return parser->state == GRPC_HTTP_BODY; +} diff --git a/src/core/http/parser.h b/src/core/http/parser.h new file mode 100644 index 0000000000..39517e485a --- /dev/null +++ b/src/core/http/parser.h @@ -0,0 +1,116 @@ +/* + * + * Copyright 2015-2016, 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. + * + */ + +#ifndef GRPC_CORE_HTTP_PARSER_H +#define GRPC_CORE_HTTP_PARSER_H + +#include <grpc/support/port_platform.h> +#include <grpc/support/slice.h> + +/* Maximum length of a header string of the form 'Key: Value\r\n' */ +#define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH 4096 + +/* A single header to be passed in a request */ +typedef struct grpc_http_header { + char *key; + char *value; +} grpc_http_header; + +typedef enum { + GRPC_HTTP_FIRST_LINE, + GRPC_HTTP_HEADERS, + GRPC_HTTP_BODY +} grpc_http_parser_state; + +typedef enum { + GRPC_HTTP_HTTP10, + GRPC_HTTP_HTTP11, + GRPC_HTTP_HTTP20, +} grpc_http_version; + +typedef enum { + GRPC_HTTP_RESPONSE, + GRPC_HTTP_REQUEST, + GRPC_HTTP_UNKNOWN +} grpc_http_type; + +/* A request */ +typedef struct grpc_http_request { + /* Method of the request (e.g. GET, POST) */ + char *method; + /* The path of the resource to fetch */ + char *path; + /* HTTP version to use */ + grpc_http_version version; + /* Headers attached to the request */ + size_t hdr_count; + grpc_http_header *hdrs; + /* Body: length and contents; contents are NOT null-terminated */ + size_t body_length; + char *body; +} grpc_http_request; + +/* A response */ +typedef struct grpc_http_response { + /* HTTP status code */ + int status; + /* Headers: count and key/values */ + size_t hdr_count; + grpc_http_header *hdrs; + /* Body: length and contents; contents are NOT null-terminated */ + size_t body_length; + char *body; +} grpc_http_response; + +typedef struct { + grpc_http_parser_state state; + grpc_http_type type; + + union { + grpc_http_response response; + grpc_http_request request; + } http; + size_t body_capacity; + size_t hdr_capacity; + + uint8_t cur_line[GRPC_HTTP_PARSER_MAX_HEADER_LENGTH]; + size_t cur_line_length; +} grpc_http_parser; + +void grpc_http_parser_init(grpc_http_parser *parser); +void grpc_http_parser_destroy(grpc_http_parser *parser); + +int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice); +int grpc_http_parser_eof(grpc_http_parser *parser); + +#endif /* GRPC_CORE_HTTP_PARSER_H */ diff --git a/src/core/httpcli/parser.c b/src/core/httpcli/parser.c deleted file mode 100644 index c314f025a0..0000000000 --- a/src/core/httpcli/parser.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * - * 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. - * - */ - -#include "src/core/httpcli/parser.h" - -#include <string.h> - -#include <grpc/support/alloc.h> -#include <grpc/support/log.h> -#include <grpc/support/useful.h> - -static int handle_response_line(grpc_httpcli_parser *parser) { - uint8_t *beg = parser->cur_line; - uint8_t *cur = beg; - uint8_t *end = beg + parser->cur_line_length; - - if (cur == end || *cur++ != 'H') goto error; - if (cur == end || *cur++ != 'T') goto error; - if (cur == end || *cur++ != 'T') goto error; - if (cur == end || *cur++ != 'P') goto error; - if (cur == end || *cur++ != '/') goto error; - if (cur == end || *cur++ != '1') goto error; - if (cur == end || *cur++ != '.') goto error; - if (cur == end || *cur < '0' || *cur++ > '1') goto error; - if (cur == end || *cur++ != ' ') goto error; - if (cur == end || *cur < '1' || *cur++ > '9') goto error; - if (cur == end || *cur < '0' || *cur++ > '9') goto error; - if (cur == end || *cur < '0' || *cur++ > '9') goto error; - parser->r.status = - (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0'); - if (cur == end || *cur++ != ' ') goto error; - - /* we don't really care about the status code message */ - - return 1; - -error: - gpr_log(GPR_ERROR, "Failed parsing response line"); - return 0; -} - -static char *buf2str(void *buffer, size_t length) { - char *out = gpr_malloc(length + 1); - memcpy(out, buffer, length); - out[length] = 0; - return out; -} - -static int add_header(grpc_httpcli_parser *parser) { - uint8_t *beg = parser->cur_line; - uint8_t *cur = beg; - uint8_t *end = beg + parser->cur_line_length; - grpc_httpcli_header hdr = {NULL, NULL}; - - GPR_ASSERT(cur != end); - - if (*cur == ' ' || *cur == '\t') { - gpr_log(GPR_ERROR, "Continued header lines not supported yet"); - goto error; - } - - while (cur != end && *cur != ':') { - cur++; - } - if (cur == end) { - gpr_log(GPR_ERROR, "Didn't find ':' in header string"); - goto error; - } - GPR_ASSERT(cur >= beg); - hdr.key = buf2str(beg, (size_t)(cur - beg)); - cur++; /* skip : */ - - while (cur != end && (*cur == ' ' || *cur == '\t')) { - cur++; - } - GPR_ASSERT(end - cur >= 2); - hdr.value = buf2str(cur, (size_t)(end - cur) - 2); - - if (parser->r.hdr_count == parser->hdr_capacity) { - parser->hdr_capacity = - GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2); - parser->r.hdrs = gpr_realloc( - parser->r.hdrs, parser->hdr_capacity * sizeof(*parser->r.hdrs)); - } - parser->r.hdrs[parser->r.hdr_count++] = hdr; - return 1; - -error: - gpr_free(hdr.key); - gpr_free(hdr.value); - return 0; -} - -static int finish_line(grpc_httpcli_parser *parser) { - switch (parser->state) { - case GRPC_HTTPCLI_INITIAL_RESPONSE: - if (!handle_response_line(parser)) { - return 0; - } - parser->state = GRPC_HTTPCLI_HEADERS; - break; - case GRPC_HTTPCLI_HEADERS: - if (parser->cur_line_length == 2) { - parser->state = GRPC_HTTPCLI_BODY; - break; - } - if (!add_header(parser)) { - return 0; - } - break; - case GRPC_HTTPCLI_BODY: - GPR_UNREACHABLE_CODE(return 0); - } - - parser->cur_line_length = 0; - return 1; -} - -static int addbyte(grpc_httpcli_parser *parser, uint8_t byte) { - switch (parser->state) { - case GRPC_HTTPCLI_INITIAL_RESPONSE: - case GRPC_HTTPCLI_HEADERS: - if (parser->cur_line_length >= GRPC_HTTPCLI_MAX_HEADER_LENGTH) { - gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded", - GRPC_HTTPCLI_MAX_HEADER_LENGTH); - return 0; - } - parser->cur_line[parser->cur_line_length] = byte; - parser->cur_line_length++; - if (parser->cur_line_length >= 2 && - parser->cur_line[parser->cur_line_length - 2] == '\r' && - parser->cur_line[parser->cur_line_length - 1] == '\n') { - return finish_line(parser); - } else { - return 1; - } - GPR_UNREACHABLE_CODE(return 0); - case GRPC_HTTPCLI_BODY: - if (parser->r.body_length == parser->body_capacity) { - parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2); - parser->r.body = - gpr_realloc((void *)parser->r.body, parser->body_capacity); - } - parser->r.body[parser->r.body_length] = (char)byte; - parser->r.body_length++; - return 1; - } - GPR_UNREACHABLE_CODE(return 0); -} - -void grpc_httpcli_parser_init(grpc_httpcli_parser *parser) { - memset(parser, 0, sizeof(*parser)); - parser->state = GRPC_HTTPCLI_INITIAL_RESPONSE; - parser->r.status = 500; -} - -void grpc_httpcli_parser_destroy(grpc_httpcli_parser *parser) { - size_t i; - gpr_free(parser->r.body); - for (i = 0; i < parser->r.hdr_count; i++) { - gpr_free(parser->r.hdrs[i].key); - gpr_free(parser->r.hdrs[i].value); - } - gpr_free(parser->r.hdrs); -} - -int grpc_httpcli_parser_parse(grpc_httpcli_parser *parser, gpr_slice slice) { - size_t i; - - for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) { - if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) { - return 0; - } - } - - return 1; -} - -int grpc_httpcli_parser_eof(grpc_httpcli_parser *parser) { - return parser->state == GRPC_HTTPCLI_BODY; -} diff --git a/src/core/iomgr/endpoint_pair_posix.c b/src/core/iomgr/endpoint_pair_posix.c index 56f6f146fd..f84b8441df 100644 --- a/src/core/iomgr/endpoint_pair_posix.c +++ b/src/core/iomgr/endpoint_pair_posix.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,7 @@ #include "src/core/iomgr/endpoint_pair.h" #include "src/core/iomgr/socket_utils_posix.h" +#include "src/core/iomgr/unix_sockets_posix.h" #include <errno.h> #include <fcntl.h> @@ -52,7 +53,7 @@ static void create_sockets(int sv[2]) { int flags; - GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); + grpc_create_socketpair_if_unix(sv); flags = fcntl(sv[0], F_GETFL, 0); GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0); flags = fcntl(sv[1], F_GETFL, 0); diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c index 4ba7c5df94..b4d038a3a1 100644 --- a/src/core/iomgr/fd_posix.c +++ b/src/core/iomgr/fd_posix.c @@ -92,7 +92,7 @@ static grpc_fd *alloc_fd(int fd) { gpr_mu_init(&r->mu); } - gpr_atm_rel_store(&r->refst, 1); + gpr_mu_lock(&r->mu); r->shutdown = 0; r->read_closure = CLOSURE_NOT_READY; r->write_closure = CLOSURE_NOT_READY; @@ -104,6 +104,9 @@ static grpc_fd *alloc_fd(int fd) { r->on_done_closure = NULL; r->closed = 0; r->released = 0; + gpr_atm_rel_store(&r->refst, 1); + gpr_mu_unlock(&r->mu); + return r; } diff --git a/src/core/iomgr/resolve_address_posix.c b/src/core/iomgr/resolve_address_posix.c index a6c9893f23..26b3aa8189 100644 --- a/src/core/iomgr/resolve_address_posix.c +++ b/src/core/iomgr/resolve_address_posix.c @@ -39,7 +39,6 @@ #include <string.h> #include <sys/types.h> -#include <sys/un.h> #include <grpc/support/alloc.h> #include <grpc/support/host_port.h> @@ -51,6 +50,7 @@ #include "src/core/iomgr/executor.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/iomgr/unix_sockets_posix.h" #include "src/core/support/block_annotate.h" #include "src/core/support/string.h" @@ -71,18 +71,10 @@ static grpc_resolved_addresses *blocking_resolve_address_impl( int s; size_t i; grpc_resolved_addresses *addrs = NULL; - struct sockaddr_un *un; if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' && name[4] == ':' && name[5] != 0) { - addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); - addrs->naddrs = 1; - addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address)); - un = (struct sockaddr_un *)addrs->addrs->addr; - un->sun_family = AF_UNIX; - strcpy(un->sun_path, name + 5); - addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; - return addrs; + return grpc_resolve_unix_domain_address(name + 5); } /* parse name, splitting it into host and port parts */ diff --git a/src/core/iomgr/sockaddr_utils.c b/src/core/iomgr/sockaddr_utils.c index 61006d7a7a..a3c3a874c1 100644 --- a/src/core/iomgr/sockaddr_utils.c +++ b/src/core/iomgr/sockaddr_utils.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,16 +36,13 @@ #include <errno.h> #include <string.h> -#ifdef GPR_POSIX_SOCKET -#include <sys/un.h> -#endif - #include <grpc/support/alloc.h> #include <grpc/support/host_port.h> #include <grpc/support/log.h> #include <grpc/support/port_platform.h> #include <grpc/support/string_util.h> +#include "src/core/iomgr/unix_sockets_posix.h" #include "src/core/support/string.h" static const uint8_t kV4MappedPrefix[] = {0, 0, 0, 0, 0, 0, @@ -191,14 +188,9 @@ char *grpc_sockaddr_to_uri(const struct sockaddr *addr) { gpr_asprintf(&result, "ipv6:%s", temp); gpr_free(temp); return result; -#ifdef GPR_POSIX_SOCKET - case AF_UNIX: - gpr_asprintf(&result, "unix:%s", ((struct sockaddr_un *)addr)->sun_path); - return result; -#endif + default: + return grpc_sockaddr_to_uri_unix_if_possible(addr); } - - return NULL; } int grpc_sockaddr_get_port(const struct sockaddr *addr) { @@ -207,9 +199,10 @@ int grpc_sockaddr_get_port(const struct sockaddr *addr) { return ntohs(((struct sockaddr_in *)addr)->sin_port); case AF_INET6: return ntohs(((struct sockaddr_in6 *)addr)->sin6_port); - case AF_UNIX: - return 1; default: + if (grpc_is_unix_socket(addr)) { + return 1; + } gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port", addr->sa_family); return 0; diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c index 15727856ab..1d3f9b6555 100644 --- a/src/core/iomgr/tcp_client_posix.c +++ b/src/core/iomgr/tcp_client_posix.c @@ -54,6 +54,7 @@ #include "src/core/iomgr/socket_utils_posix.h" #include "src/core/iomgr/tcp_posix.h" #include "src/core/iomgr/timer.h" +#include "src/core/iomgr/unix_sockets_posix.h" #include "src/core/support/string.h" extern int grpc_tcp_trace; @@ -77,13 +78,12 @@ static int prepare_socket(const struct sockaddr *addr, int fd) { } if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || - (addr->sa_family != AF_UNIX && !grpc_set_socket_low_latency(fd, 1)) || + (!grpc_is_unix_socket(addr) && !grpc_set_socket_low_latency(fd, 1)) || !grpc_set_socket_no_sigpipe_if_possible(fd)) { gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, strerror(errno)); goto error; } - return 1; error: diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c index 5e07f8261c..11508044dc 100644 --- a/src/core/iomgr/tcp_server_posix.c +++ b/src/core/iomgr/tcp_server_posix.c @@ -52,7 +52,6 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> -#include <sys/un.h> #include <unistd.h> #include "src/core/iomgr/pollset_posix.h" @@ -60,6 +59,7 @@ #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/socket_utils_posix.h" #include "src/core/iomgr/tcp_posix.h" +#include "src/core/iomgr/unix_sockets_posix.h" #include "src/core/support/string.h" #include <grpc/support/alloc.h> #include <grpc/support/log.h> @@ -81,7 +81,6 @@ struct grpc_tcp_listener { union { uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE]; struct sockaddr sockaddr; - struct sockaddr_un un; } addr; size_t addr_len; int port; @@ -98,14 +97,6 @@ struct grpc_tcp_listener { int is_sibling; }; -static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) { - struct stat st; - - if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { - unlink(un->sun_path); - } -} - /* the overall server */ struct grpc_tcp_server { gpr_refcount refs; @@ -203,9 +194,7 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { if (s->head) { grpc_tcp_listener *sp; for (sp = s->head; sp; sp = sp->next) { - if (sp->addr.sockaddr.sa_family == AF_UNIX) { - unlink_if_unix_domain_socket(&sp->addr.un); - } + grpc_unlink_if_unix_domain_socket(&sp->addr.sockaddr); sp->destroyed_closure.cb = destroyed_port; sp->destroyed_closure.cb_arg = s; grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, @@ -281,7 +270,7 @@ static int prepare_socket(int fd, const struct sockaddr *addr, } if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || - (addr->sa_family != AF_UNIX && (!grpc_set_socket_low_latency(fd, 1) || + (!grpc_is_unix_socket(addr) && (!grpc_set_socket_low_latency(fd, 1) || !grpc_set_socket_reuse_addr(fd, 1))) || !grpc_set_socket_no_sigpipe_if_possible(fd)) { gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, @@ -451,9 +440,7 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, if (s->tail != NULL) { port_index = s->tail->port_index + 1; } - if (((struct sockaddr *)addr)->sa_family == AF_UNIX) { - unlink_if_unix_domain_socket(addr); - } + grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr); /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ @@ -499,7 +486,6 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ if (port == 0 && sp != NULL) { grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port); - sp2 = sp; } addr = (struct sockaddr *)&wild4; addr_len = sizeof(wild4); @@ -508,16 +494,18 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); - } - if (dsmode == GRPC_DSMODE_IPV4 && - grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { - addr = (struct sockaddr *)&addr4_copy; - addr_len = sizeof(addr4_copy); - } - sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index); - if (sp2 != NULL && sp != NULL) { - sp2->sibling = sp; - sp->is_sibling = 1; + } else { + if (dsmode == GRPC_DSMODE_IPV4 && + grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { + addr = (struct sockaddr *)&addr4_copy; + addr_len = sizeof(addr4_copy); + } + sp2 = sp; + sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index); + if (sp2 != NULL && sp != NULL) { + sp2->sibling = sp; + sp->is_sibling = 1; + } } done: diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c index ef548cfe4d..e7853af58a 100644 --- a/src/core/iomgr/udp_server.c +++ b/src/core/iomgr/udp_server.c @@ -52,7 +52,6 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> -#include <sys/un.h> #include <unistd.h> #include "src/core/iomgr/fd_posix.h" @@ -60,7 +59,9 @@ #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/socket_utils_posix.h" +#include "src/core/iomgr/unix_sockets_posix.h" #include "src/core/support/string.h" +#include <grpc/grpc.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/sync.h> @@ -77,7 +78,6 @@ typedef struct { union { uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE]; struct sockaddr sockaddr; - struct sockaddr_un un; } addr; size_t addr_len; grpc_closure read_closure; @@ -85,14 +85,6 @@ typedef struct { grpc_udp_server_read_cb read_cb; } server_port; -static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) { - struct stat st; - - if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { - unlink(un->sun_path); - } -} - /* the overall server */ struct grpc_udp_server { gpr_mu mu; @@ -176,9 +168,7 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { if (s->nports) { for (i = 0; i < s->nports; i++) { server_port *sp = &s->ports[i]; - if (sp->addr.sockaddr.sa_family == AF_UNIX) { - unlink_if_unix_domain_socket(&sp->addr.un); - } + grpc_unlink_if_unix_domain_socket(&sp->addr.sockaddr); sp->destroyed_closure.cb = destroyed_port; sp->destroyed_closure.cb_arg = s; grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, @@ -336,9 +326,7 @@ int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, socklen_t sockname_len; int port; - if (((struct sockaddr *)addr)->sa_family == AF_UNIX) { - unlink_if_unix_domain_socket(addr); - } + grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr); /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ diff --git a/src/core/iomgr/udp_server.h b/src/core/iomgr/udp_server.h index 1e59a92392..148c04fa9b 100644 --- a/src/core/iomgr/udp_server.h +++ b/src/core/iomgr/udp_server.h @@ -37,15 +37,16 @@ #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/fd_posix.h" -/* Forward decl of grpc_server */ -typedef struct grpc_server grpc_server; +/* Forward decl of struct grpc_server */ +/* This is not typedef'ed to avoid a typedef-redefinition error */ +struct grpc_server; /* Forward decl of grpc_udp_server */ typedef struct grpc_udp_server grpc_udp_server; /* Called when data is available to read from the socket. */ typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd, - grpc_server *server); + struct grpc_server *server); /* Create a server, initially not bound to any ports */ grpc_udp_server *grpc_udp_server_create(void); @@ -53,7 +54,7 @@ grpc_udp_server *grpc_udp_server_create(void); /* Start listening to bound ports */ void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *udp_server, grpc_pollset **pollsets, size_t pollset_count, - grpc_server *server); + struct grpc_server *server); int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index); diff --git a/src/core/iomgr/unix_sockets_posix.c b/src/core/iomgr/unix_sockets_posix.c new file mode 100644 index 0000000000..480ff613f6 --- /dev/null +++ b/src/core/iomgr/unix_sockets_posix.c @@ -0,0 +1,103 @@ +/* + * + * Copyright 2016, 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. + * + */ + +#include "src/core/iomgr/unix_sockets_posix.h" + +#ifdef GPR_HAVE_UNIX_SOCKET + +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/un.h> + +#include <grpc/support/alloc.h> + +void grpc_create_socketpair_if_unix(int sv[2]) { + GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); +} + +grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) { + struct sockaddr_un *un; + + grpc_resolved_addresses *addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); + addrs->naddrs = 1; + addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address)); + un = (struct sockaddr_un *)addrs->addrs->addr; + un->sun_family = AF_UNIX; + strcpy(un->sun_path, name); + addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; + return addrs; +} + +int grpc_is_unix_socket(const struct sockaddr *addr) { + return addr->sa_family == AF_UNIX; +} + +void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr) { + if (addr->sa_family != AF_UNIX) { + return; + } + struct sockaddr_un *un = (struct sockaddr_un *)addr; + struct stat st; + + if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { + unlink(un->sun_path); + } +} + +int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len) { + struct sockaddr_un *un = (struct sockaddr_un *)addr; + + un->sun_family = AF_UNIX; + strcpy(un->sun_path, uri->path); + *len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; + + return 1; +} + +char *grpc_unix_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri) { + return gpr_strdup("localhost"); +} + +char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr) { + if (addr->sa_family != AF_UNIX) { + return NULL; + } + + char *result; + gpr_asprintf(&result, "unix:%s", ((struct sockaddr_un *)addr)->sun_path); + return result; +} + +#endif diff --git a/src/core/iomgr/unix_sockets_posix.h b/src/core/iomgr/unix_sockets_posix.h new file mode 100644 index 0000000000..e842ba3770 --- /dev/null +++ b/src/core/iomgr/unix_sockets_posix.h @@ -0,0 +1,61 @@ +/* + * + * Copyright 2016, 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. + * + */ + +#ifndef GRPC_CORE_IOMGR_UNIX_SOCKETS_POSIX_H +#define GRPC_CORE_IOMGR_UNIX_SOCKETS_POSIX_H + +#include <grpc/support/port_platform.h> + +#include <grpc/support/string_util.h> + +#include "src/core/client_config/resolver_factory.h" +#include "src/core/client_config/uri_parser.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/sockaddr.h" + +void grpc_create_socketpair_if_unix(int sv[2]); + +grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name); + +int grpc_is_unix_socket(const struct sockaddr *addr); + +void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr); + +int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len); + +char *grpc_unix_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri); + +char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr); + +#endif /* GRPC_CORE_IOMGR_UNIX_SOCKETS_POSIX_H */ diff --git a/src/core/iomgr/unix_sockets_posix_noop.c b/src/core/iomgr/unix_sockets_posix_noop.c new file mode 100644 index 0000000000..045467bea4 --- /dev/null +++ b/src/core/iomgr/unix_sockets_posix_noop.c @@ -0,0 +1,61 @@ +/* + * + * Copyright 2016, 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. + * + */ + +#include "src/core/iomgr/unix_sockets_posix.h" + +#ifndef GPR_HAVE_UNIX_SOCKET + +void grpc_create_socketpair_if_unix(int sv[2]) {} + +grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) { + return NULL; +} + +int grpc_is_unix_socket(const struct sockaddr *addr) { return false; } + +void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr) {} + +int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len) { + return 0; +} + +char *grpc_unix_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri) { + return NULL; +} + +char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr) { + return NULL; +} + +#endif diff --git a/src/core/iomgr/wakeup_fd_pipe.c b/src/core/iomgr/wakeup_fd_pipe.c index 80de181d9d..dd2fd1f057 100644 --- a/src/core/iomgr/wakeup_fd_pipe.c +++ b/src/core/iomgr/wakeup_fd_pipe.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,13 +41,18 @@ #include <string.h> #include <unistd.h> -#include "src/core/iomgr/socket_utils_posix.h" #include <grpc/support/log.h> +#include "src/core/iomgr/socket_utils_posix.h" + static void pipe_init(grpc_wakeup_fd* fd_info) { int pipefd[2]; /* TODO(klempner): Make this nonfatal */ - GPR_ASSERT(0 == pipe(pipefd)); + int r = pipe(pipefd); + if (0 != r) { + gpr_log(GPR_ERROR, "pipe creation failed (%d): %s", errno, strerror(errno)); + abort(); + } GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[0], 1)); GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[1], 1)); fd_info->read_fd = pipefd[0]; diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index b4fa616fa7..0ba6d5dd84 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -38,7 +38,8 @@ #include "src/core/channel/channel_args.h" #include "src/core/channel/http_client_filter.h" -#include "src/core/httpcli/httpcli.h" +#include "src/core/http/parser.h" +#include "src/core/http/httpcli.h" #include "src/core/iomgr/executor.h" #include "src/core/json/json.h" #include "src/core/support/string.h" @@ -539,7 +540,7 @@ static void oauth2_token_fetcher_destruct(grpc_call_credentials *creds) { grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( - const grpc_httpcli_response *response, grpc_credentials_md_store **token_md, + const grpc_http_response *response, grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime) { char *null_terminated_body = NULL; char *new_access_token = NULL; @@ -629,7 +630,7 @@ end: static void on_oauth2_token_fetcher_http_response( grpc_exec_ctx *exec_ctx, void *user_data, - const grpc_httpcli_response *response) { + const grpc_http_response *response) { grpc_credentials_metadata_request *r = (grpc_credentials_metadata_request *)user_data; grpc_oauth2_token_fetcher_credentials *c = @@ -706,13 +707,13 @@ static void compute_engine_fetch_oauth2( grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, grpc_httpcli_context *httpcli_context, grpc_pollset *pollset, grpc_httpcli_response_cb response_cb, gpr_timespec deadline) { - grpc_httpcli_header header = {"Metadata-Flavor", "Google"}; + grpc_http_header header = {"Metadata-Flavor", "Google"}; grpc_httpcli_request request; memset(&request, 0, sizeof(grpc_httpcli_request)); request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST; - request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH; - request.hdr_count = 1; - request.hdrs = &header; + request.http.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH; + request.http.hdr_count = 1; + request.http.hdrs = &header; grpc_httpcli_get(exec_ctx, httpcli_context, pollset, &request, deadline, response_cb, metadata_req); } @@ -747,8 +748,8 @@ static void refresh_token_fetch_oauth2( grpc_httpcli_response_cb response_cb, gpr_timespec deadline) { grpc_google_refresh_token_credentials *c = (grpc_google_refresh_token_credentials *)metadata_req->creds; - grpc_httpcli_header header = {"Content-Type", - "application/x-www-form-urlencoded"}; + grpc_http_header header = {"Content-Type", + "application/x-www-form-urlencoded"}; grpc_httpcli_request request; char *body = NULL; gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING, @@ -756,9 +757,9 @@ static void refresh_token_fetch_oauth2( c->refresh_token.refresh_token); memset(&request, 0, sizeof(grpc_httpcli_request)); request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST; - request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; - request.hdr_count = 1; - request.hdrs = &header; + request.http.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; + request.http.hdr_count = 1; + request.http.hdrs = &header; request.handshaker = &grpc_httpcli_ssl; grpc_httpcli_post(exec_ctx, httpcli_context, pollset, &request, body, strlen(body), deadline, response_cb, metadata_req); diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 133aa9d8d9..afac7a5bf2 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -39,11 +39,12 @@ #include <grpc/grpc_security.h> #include <grpc/support/sync.h> -#include "src/core/httpcli/httpcli.h" +#include "src/core/http/httpcli.h" +#include "src/core/http/parser.h" #include "src/core/security/json_token.h" #include "src/core/security/security_connector.h" -struct grpc_httpcli_response; +struct grpc_http_response; /* --- Constants. --- */ @@ -207,7 +208,7 @@ grpc_call_credentials *grpc_credentials_contains_type( /* Exposed for testing only. */ grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( - const struct grpc_httpcli_response *response, + const struct grpc_http_response *response, grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime); void grpc_flush_cached_google_default_credentials(void); diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index 1f4f3e4aa5..3872e86993 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -39,7 +39,8 @@ #include <grpc/support/log.h> #include <grpc/support/sync.h> -#include "src/core/httpcli/httpcli.h" +#include "src/core/http/httpcli.h" +#include "src/core/http/parser.h" #include "src/core/support/env.h" #include "src/core/support/load_file.h" #include "src/core/surface/api_trace.h" @@ -66,14 +67,14 @@ typedef struct { static void on_compute_engine_detection_http_response( grpc_exec_ctx *exec_ctx, void *user_data, - const grpc_httpcli_response *response) { + const grpc_http_response *response) { compute_engine_detector *detector = (compute_engine_detector *)user_data; if (response != NULL && response->status == 200 && response->hdr_count > 0) { /* Internet providers can return a generic response to all requests, so it is necessary to check that metadata header is present also. */ size_t i; for (i = 0; i < response->hdr_count; i++) { - grpc_httpcli_header *header = &response->hdrs[i]; + grpc_http_header *header = &response->hdrs[i]; if (strcmp(header->key, "Metadata-Flavor") == 0 && strcmp(header->value, "Google") == 0) { detector->success = 1; @@ -109,7 +110,7 @@ static int is_stack_running_on_compute_engine(void) { memset(&request, 0, sizeof(grpc_httpcli_request)); request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST; - request.path = "/"; + request.http.path = "/"; grpc_httpcli_context_init(&context); diff --git a/src/core/security/jwt_verifier.c b/src/core/security/jwt_verifier.c index 928c6c148d..0bb8e05306 100644 --- a/src/core/security/jwt_verifier.c +++ b/src/core/security/jwt_verifier.c @@ -36,7 +36,7 @@ #include <limits.h> #include <string.h> -#include "src/core/httpcli/httpcli.h" +#include "src/core/http/httpcli.h" #include "src/core/security/b64.h" #include "src/core/tsi/ssl_types.h" @@ -635,11 +635,11 @@ static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data, jwks_uri += 8; req.handshaker = &grpc_httpcli_ssl; req.host = gpr_strdup(jwks_uri); - req.path = strchr(jwks_uri, '/'); - if (req.path == NULL) { - req.path = ""; + req.http.path = strchr(jwks_uri, '/'); + if (req.http.path == NULL) { + req.http.path = ""; } else { - *(req.host + (req.path - jwks_uri)) = '\0'; + *(req.host + (req.http.path - jwks_uri)) = '\0'; } grpc_httpcli_get( exec_ctx, &ctx->verifier->http_ctx, ctx->pollset, &req, @@ -725,20 +725,20 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx, req.host = gpr_strdup(mapping->key_url_prefix); path_prefix = strchr(req.host, '/'); if (path_prefix == NULL) { - gpr_asprintf(&req.path, "/%s", iss); + gpr_asprintf(&req.http.path, "/%s", iss); } else { *(path_prefix++) = '\0'; - gpr_asprintf(&req.path, "/%s/%s", path_prefix, iss); + gpr_asprintf(&req.http.path, "/%s/%s", path_prefix, iss); } http_cb = on_keys_retrieved; } else { req.host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss); path_prefix = strchr(req.host, '/'); if (path_prefix == NULL) { - req.path = gpr_strdup(GRPC_OPENID_CONFIG_URL_SUFFIX); + req.http.path = gpr_strdup(GRPC_OPENID_CONFIG_URL_SUFFIX); } else { *(path_prefix++) = 0; - gpr_asprintf(&req.path, "/%s%s", path_prefix, + gpr_asprintf(&req.http.path, "/%s%s", path_prefix, GRPC_OPENID_CONFIG_URL_SUFFIX); } http_cb = on_openid_config_retrieved; @@ -749,7 +749,7 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay), http_cb, ctx); gpr_free(req.host); - gpr_free(req.path); + gpr_free(req.http.path); return; error: diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index 91547eb26e..009ec95682 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -83,8 +83,6 @@ static void state_unref(grpc_server_secure_state *state) { static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep, grpc_transport *transport, grpc_auth_context *auth_context) { - static grpc_channel_filter const *extra_filters[] = { - &grpc_server_auth_filter, &grpc_http_server_filter}; grpc_server_secure_state *state = statep; grpc_channel_args *args_copy; grpc_arg args_to_add[2]; @@ -93,8 +91,7 @@ static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep, args_copy = grpc_channel_args_copy_and_add( grpc_server_get_channel_args(state->server), args_to_add, GPR_ARRAY_SIZE(args_to_add)); - grpc_server_setup_transport(exec_ctx, state->server, transport, extra_filters, - GPR_ARRAY_SIZE(extra_filters), args_copy); + grpc_server_setup_transport(exec_ctx, state->server, transport, args_copy); grpc_channel_args_destroy(args_copy); } diff --git a/src/core/support/backoff.c b/src/core/support/backoff.c index 7458219645..4ccfb774ed 100644 --- a/src/core/support/backoff.c +++ b/src/core/support/backoff.c @@ -69,3 +69,8 @@ gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now) { return gpr_time_add( now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN)); } + +void gpr_backoff_reset(gpr_backoff *backoff) { + // forces step() to return a timeout of min_timeout_millis + backoff->current_timeout_millis = 0; +} diff --git a/src/core/support/backoff.h b/src/core/support/backoff.h index f7730fde2a..0f933c3149 100644 --- a/src/core/support/backoff.h +++ b/src/core/support/backoff.h @@ -61,5 +61,8 @@ void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter, gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now); /// Step a retry loop: returns a timespec for the NEXT retry gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now); +/// Reset the backoff, so the next gpr_backoff_step will be a gpr_backoff_begin +/// instead +void gpr_backoff_reset(gpr_backoff *backoff); #endif /* GRPC_CORE_SUPPORT_BACKOFF_H */ diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c index 12d8ebceb9..964ab34431 100644 --- a/src/core/surface/channel.c +++ b/src/core/surface/channel.c @@ -40,6 +40,7 @@ #include <grpc/support/log.h> #include <grpc/support/string_util.h> +#include "src/core/surface/channel_init.h" #include "src/core/client_config/resolver_registry.h" #include "src/core/iomgr/iomgr.h" #include "src/core/support/string.h" @@ -82,24 +83,25 @@ struct grpc_channel { static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success); -grpc_channel *grpc_channel_create_from_filters( - grpc_exec_ctx *exec_ctx, const char *target, - const grpc_channel_filter **filters, size_t num_filters, - const grpc_channel_args *args, int is_client) { - size_t i; - size_t size = - sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters); - grpc_channel *channel = gpr_malloc(size); +grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, + const grpc_channel_args *args, + grpc_channel_stack_type channel_stack_type, + grpc_transport *optional_transport) { + bool is_client = grpc_channel_stack_type_is_client(channel_stack_type); + + grpc_channel *channel = grpc_channel_init_create_stack( + exec_ctx, channel_stack_type, sizeof(grpc_channel), args, 1, + destroy_channel, NULL, optional_transport); + memset(channel, 0, sizeof(*channel)); channel->target = gpr_strdup(target); - GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); channel->is_client = is_client; gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = NULL; channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH; if (args) { - for (i = 0; i < args->num_args; i++) { + for (size_t i = 0; i < args->num_args; i++) { if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) { if (args->args[i].type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s ignored: it must be an integer", @@ -152,11 +154,6 @@ grpc_channel *grpc_channel_create_from_filters( gpr_free(default_authority); } - grpc_channel_stack_init(exec_ctx, 1, destroy_channel, channel, filters, - num_filters, args, - is_client ? "CLIENT_CHANNEL" : "SERVER_CHANNEL", - CHANNEL_STACK_FROM_CHANNEL(channel)); - return channel; } diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h index d5bc691d9a..c08988d9e7 100644 --- a/src/core/surface/channel.h +++ b/src/core/surface/channel.h @@ -35,12 +35,13 @@ #define GRPC_CORE_SURFACE_CHANNEL_H #include "src/core/channel/channel_stack.h" +#include "src/core/surface/channel_stack_type.h" #include "src/core/client_config/subchannel_factory.h" -grpc_channel *grpc_channel_create_from_filters( - grpc_exec_ctx *exec_ctx, const char *target, - const grpc_channel_filter **filters, size_t count, - const grpc_channel_args *args, int is_client); +grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, + const grpc_channel_args *args, + grpc_channel_stack_type channel_stack_type, + grpc_transport *optional_transport); /** 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/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c index 2dd4fce26b..18267939ed 100644 --- a/src/core/surface/channel_connectivity.c +++ b/src/core/surface/channel_connectivity.c @@ -37,7 +37,6 @@ #include <grpc/support/log.h> #include "src/core/channel/client_channel.h" -#include "src/core/channel/client_uchannel.h" #include "src/core/iomgr/timer.h" #include "src/core/surface/api_trace.h" #include "src/core/surface/completion_queue.h" @@ -58,12 +57,6 @@ grpc_connectivity_state grpc_channel_check_connectivity_state( grpc_exec_ctx_finish(&exec_ctx); return state; } - if (client_channel_elem->filter == &grpc_client_uchannel_filter) { - state = grpc_client_uchannel_check_connectivity_state( - &exec_ctx, client_channel_elem, try_to_connect); - grpc_exec_ctx_finish(&exec_ctx); - return state; - } gpr_log(GPR_ERROR, "grpc_channel_check_connectivity_state called on something that is " "not a (u)client channel, but '%s'", @@ -98,9 +91,6 @@ static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) { if (client_channel_elem->filter == &grpc_client_channel_filter) { GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel, "watch_channel_connectivity"); - } else if (client_channel_elem->filter == &grpc_client_uchannel_filter) { - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel, - "watch_uchannel_connectivity"); } else { abort(); } @@ -209,11 +199,8 @@ void grpc_channel_watch_connectivity_state( grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state, &w->on_complete); - } else if (client_channel_elem->filter == &grpc_client_uchannel_filter) { - GRPC_CHANNEL_INTERNAL_REF(channel, "watch_uchannel_connectivity"); - grpc_client_uchannel_watch_connectivity_state( - &exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state, - &w->on_complete); + } else { + abort(); } grpc_exec_ctx_finish(&exec_ctx); diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c index fd7e20e9cc..123447c8ed 100644 --- a/src/core/surface/channel_create.c +++ b/src/core/surface/channel_create.c @@ -105,9 +105,6 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { 0); GPR_ASSERT(c->result->transport); c->result->channel_args = c->args.channel_args; - c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *)); - c->result->filters[0] = &grpc_http_client_filter; - c->result->num_filters = 1; } else { memset(c->result, 0, sizeof(*c->result)); } @@ -190,25 +187,16 @@ grpc_channel *grpc_insecure_channel_create(const char *target, const grpc_channel_args *args, void *reserved) { grpc_channel *channel = NULL; -#define MAX_FILTERS 3 - const grpc_channel_filter *filters[MAX_FILTERS]; grpc_resolver *resolver; subchannel_factory *f; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - size_t n = 0; GRPC_API_TRACE( "grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3, (target, args, reserved)); GPR_ASSERT(!reserved); - if (grpc_channel_args_is_census_enabled(args)) { - filters[n++] = &grpc_client_census_filter; - } - filters[n++] = &grpc_compress_filter; - filters[n++] = &grpc_client_channel_filter; - GPR_ASSERT(n <= MAX_FILTERS); channel = - grpc_channel_create_from_filters(&exec_ctx, target, filters, n, args, 1); + grpc_channel_create(&exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL); f = gpr_malloc(sizeof(*f)); f->base.vtable = &subchannel_factory_vtable; diff --git a/src/core/surface/channel_init.c b/src/core/surface/channel_init.c new file mode 100644 index 0000000000..ac962f3972 --- /dev/null +++ b/src/core/surface/channel_init.c @@ -0,0 +1,146 @@ +/* + * + * Copyright 2016, 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. + * + */ + +#include "src/core/surface/channel_init.h" + +#include <grpc/support/alloc.h> +#include <grpc/support/useful.h> + +typedef struct stage_slot { + grpc_channel_init_stage fn; + void *arg; + int priority; + size_t insertion_order; +} stage_slot; + +typedef struct stage_slots { + stage_slot *slots; + size_t num_slots; + size_t cap_slots; +} stage_slots; + +static stage_slots g_slots[GRPC_NUM_CHANNEL_STACK_TYPES]; +static bool g_finalized; + +void grpc_channel_init_init(void) { + for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { + g_slots[i].slots = NULL; + g_slots[i].num_slots = 0; + g_slots[i].cap_slots = 0; + } + g_finalized = false; +} + +void grpc_channel_init_register_stage(grpc_channel_stack_type type, + int priority, + grpc_channel_init_stage stage, + void *stage_arg) { + GPR_ASSERT(!g_finalized); + if (g_slots[type].cap_slots == g_slots[type].num_slots) { + g_slots[type].cap_slots = GPR_MAX(8, 3 * g_slots[type].cap_slots / 2); + g_slots[type].slots = + gpr_realloc(g_slots[type].slots, + g_slots[type].cap_slots * sizeof(*g_slots[type].slots)); + } + stage_slot *s = &g_slots[type].slots[g_slots[type].num_slots++]; + s->insertion_order = g_slots[type].num_slots; + s->priority = priority; + s->fn = stage; + s->arg = stage_arg; +} + +static int compare_slots(const void *a, const void *b) { + const stage_slot *sa = a; + const stage_slot *sb = b; + + int c = GPR_ICMP(sa->priority, sb->priority); + if (c != 0) return c; + return GPR_ICMP(sa->insertion_order, sb->insertion_order); +} + +void grpc_channel_init_finalize(void) { + GPR_ASSERT(!g_finalized); + for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { + qsort(g_slots[i].slots, g_slots[i].num_slots, sizeof(*g_slots[i].slots), + compare_slots); + } + g_finalized = true; +} + +void grpc_channel_init_shutdown(void) { + for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { + gpr_free(g_slots[i].slots); + g_slots[i].slots = (void *)(uintptr_t)0xdeadbeef; + } +} + +static const char *name_for_type(grpc_channel_stack_type type) { + switch (type) { + case GRPC_CLIENT_CHANNEL: + return "CLIENT_CHANNEL"; + case GRPC_CLIENT_SUBCHANNEL: + return "CLIENT_SUBCHANNEL"; + case GRPC_SERVER_CHANNEL: + return "SERVER_CHANNEL"; + case GRPC_CLIENT_LAME_CHANNEL: + return "CLIENT_LAME_CHANNEL"; + case GRPC_CLIENT_DIRECT_CHANNEL: + return "CLIENT_DIRECT_CHANNEL"; + case GRPC_NUM_CHANNEL_STACK_TYPES: + break; + } + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} + +void *grpc_channel_init_create_stack( + grpc_exec_ctx *exec_ctx, grpc_channel_stack_type type, size_t prefix_bytes, + const grpc_channel_args *args, int initial_refs, grpc_iomgr_cb_func destroy, + void *destroy_arg, grpc_transport *transport) { + GPR_ASSERT(g_finalized); + + grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create(); + grpc_channel_stack_builder_set_name(builder, name_for_type(type)); + grpc_channel_stack_builder_set_channel_arguments(builder, args); + grpc_channel_stack_builder_set_transport(builder, transport); + + for (size_t i = 0; i < g_slots[type].num_slots; i++) { + const stage_slot *slot = &g_slots[type].slots[i]; + if (!slot->fn(builder, slot->arg)) { + grpc_channel_stack_builder_destroy(builder); + return NULL; + } + } + + return grpc_channel_stack_builder_finish(exec_ctx, builder, prefix_bytes, + initial_refs, destroy, destroy_arg); +} diff --git a/src/core/surface/channel_init.h b/src/core/surface/channel_init.h new file mode 100644 index 0000000000..06faef6ddb --- /dev/null +++ b/src/core/surface/channel_init.h @@ -0,0 +1,86 @@ +/* + * + * Copyright 2016, 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. + * + */ + +#ifndef GRPC_CORE_SURFACE_CHANNEL_INIT_H +#define GRPC_CORE_SURFACE_CHANNEL_INIT_H + +#include "src/core/channel/channel_stack_builder.h" +#include "src/core/surface/channel_stack_type.h" +#include "src/core/transport/transport.h" + +/// This module provides a way for plugins (and the grpc core library itself) +/// to register mutators for channel stacks. +/// It also provides a universal entry path to run those mutators to build +/// a channel stack for various subsystems. + +/// One stage of mutation: call functions against \a builder to influence the +/// finally constructed channel stack +typedef bool (*grpc_channel_init_stage)(grpc_channel_stack_builder *builder, + void *arg); + +/// Global initialization of the system +void grpc_channel_init_init(void); + +/// Register one stage of mutators. +/// Stages are run in priority order (lowest to highest), and then in +/// registration order (in the case of a tie). +/// Stages are registered against one of the pre-determined channel stack +/// types. +void grpc_channel_init_register_stage(grpc_channel_stack_type type, + int priority, + grpc_channel_init_stage stage_fn, + void *stage_arg); + +/// Finalize registration. No more calls to grpc_channel_init_register_stage are +/// allowed. +void grpc_channel_init_finalize(void); +/// Shutdown the channel init system +void grpc_channel_init_shutdown(void); + +/// Construct a channel stack of some sort: see channel_stack.h for details +/// \a type is the type of channel stack to create +/// \a prefix_bytes is the number of bytes before the channel stack to allocate +/// \a args are configuration arguments for the channel stack +/// \a initial_refs is the initial refcount to give the channel stack +/// \a destroy and \a destroy_arg specify how to destroy the channel stack +/// if destroy_arg is NULL, the returned value from this function will be +/// substituted +/// \a optional_transport is either NULL or a constructed transport object +/// Returns a pointer to the base of the memory allocated (the actual channel +/// stack object will be prefix_bytes past that pointer) +void *grpc_channel_init_create_stack( + grpc_exec_ctx *exec_ctx, grpc_channel_stack_type type, size_t prefix_bytes, + const grpc_channel_args *args, int initial_refs, grpc_iomgr_cb_func destroy, + void *destroy_arg, grpc_transport *optional_transport); + +#endif /* GRPC_CORE_SURFACE_CHANNEL_INIT_H */ diff --git a/src/core/surface/channel_stack_type.c b/src/core/surface/channel_stack_type.c new file mode 100644 index 0000000000..29bb7704f8 --- /dev/null +++ b/src/core/surface/channel_stack_type.c @@ -0,0 +1,54 @@ +/* + * + * Copyright 2016, 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. + * + */ + +#include <grpc/support/port_platform.h> +#include "src/core/surface/channel_stack_type.h" +#include <grpc/support/log.h> + +bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type) { + switch (type) { + case GRPC_CLIENT_CHANNEL: + return true; + case GRPC_CLIENT_SUBCHANNEL: + return true; + case GRPC_CLIENT_LAME_CHANNEL: + return true; + case GRPC_CLIENT_DIRECT_CHANNEL: + return true; + case GRPC_SERVER_CHANNEL: + return false; + case GRPC_NUM_CHANNEL_STACK_TYPES: + break; + } + GPR_UNREACHABLE_CODE(return true;); +} diff --git a/src/core/httpcli/parser.h b/src/core/surface/channel_stack_type.h index cd4a737245..75a1b9c072 100644 --- a/src/core/httpcli/parser.h +++ b/src/core/surface/channel_stack_type.h @@ -31,34 +31,28 @@ * */ -#ifndef GRPC_CORE_HTTPCLI_PARSER_H -#define GRPC_CORE_HTTPCLI_PARSER_H +#ifndef GRPC_CORE_SURFACE_CHANNEL_STACK_TYPE_H +#define GRPC_CORE_SURFACE_CHANNEL_STACK_TYPE_H -#include "src/core/httpcli/httpcli.h" -#include <grpc/support/port_platform.h> -#include <grpc/support/slice.h> +#include <stdbool.h> typedef enum { - GRPC_HTTPCLI_INITIAL_RESPONSE, - GRPC_HTTPCLI_HEADERS, - GRPC_HTTPCLI_BODY -} grpc_httpcli_parser_state; - -typedef struct { - grpc_httpcli_parser_state state; - - grpc_httpcli_response r; - size_t body_capacity; - size_t hdr_capacity; - - uint8_t cur_line[GRPC_HTTPCLI_MAX_HEADER_LENGTH]; - size_t cur_line_length; -} grpc_httpcli_parser; - -void grpc_httpcli_parser_init(grpc_httpcli_parser* parser); -void grpc_httpcli_parser_destroy(grpc_httpcli_parser* parser); - -int grpc_httpcli_parser_parse(grpc_httpcli_parser* parser, gpr_slice slice); -int grpc_httpcli_parser_eof(grpc_httpcli_parser* parser); - -#endif /* GRPC_CORE_HTTPCLI_PARSER_H */ + // normal top-half client channel with load-balancing, connection management + GRPC_CLIENT_CHANNEL, + // bottom-half of a client channel: everything that happens post-load + // balancing (bound to a specific transport) + GRPC_CLIENT_SUBCHANNEL, + // a permanently broken client channel + GRPC_CLIENT_LAME_CHANNEL, + // a directly connected client channel (without load-balancing, directly talks + // to a transport) + GRPC_CLIENT_DIRECT_CHANNEL, + // server side channel + GRPC_SERVER_CHANNEL, + // must be last + GRPC_NUM_CHANNEL_STACK_TYPES +} grpc_channel_stack_type; + +bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type); + +#endif /* GRPC_CORE_SURFACE_CHANNEL_STACK_TYPE_H */ diff --git a/src/core/surface/init.c b/src/core/surface/init.c index a4a53d3ec1..233572a9f3 100644 --- a/src/core/surface/init.c +++ b/src/core/surface/init.c @@ -33,13 +33,20 @@ #include <grpc/support/port_platform.h> +#include <limits.h> #include <memory.h> -#include <grpc/census.h> #include <grpc/grpc.h> #include <grpc/support/alloc.h> #include <grpc/support/time.h> +/* TODO(ctiller): find another way? - better not to include census here */ +#include "src/core/census/grpc_plugin.h" #include "src/core/channel/channel_stack.h" +#include "src/core/channel/compress_filter.h" +#include "src/core/channel/connected_channel.h" +#include "src/core/channel/client_channel.h" +#include "src/core/channel/http_client_filter.h" +#include "src/core/channel/http_server_filter.h" #include "src/core/client_config/lb_policy_registry.h" #include "src/core/client_config/lb_policies/pick_first.h" #include "src/core/client_config/lb_policies/round_robin.h" @@ -54,11 +61,15 @@ #include "src/core/profiling/timers.h" #include "src/core/surface/api_trace.h" #include "src/core/surface/call.h" +#include "src/core/surface/channel_init.h" #include "src/core/surface/completion_queue.h" #include "src/core/surface/init.h" +#include "src/core/surface/lame_client.h" +#include "src/core/surface/server.h" #include "src/core/surface/surface_trace.h" #include "src/core/transport/chttp2_transport.h" #include "src/core/transport/connectivity_state.h" +#include "src/core/transport/transport_impl.h" #ifndef GRPC_DEFAULT_NAME_PREFIX #define GRPC_DEFAULT_NAME_PREFIX "dns:///" @@ -72,9 +83,62 @@ static int g_initializations; static void do_basic_init(void) { gpr_mu_init(&g_init_mu); + /* TODO(ctiller): ideally remove this strict linkage */ + grpc_register_plugin(census_grpc_plugin_init, census_grpc_plugin_destroy); g_initializations = 0; } +static bool append_filter(grpc_channel_stack_builder *builder, void *arg) { + return grpc_channel_stack_builder_append_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL); +} + +static bool prepend_filter(grpc_channel_stack_builder *builder, void *arg) { + return grpc_channel_stack_builder_prepend_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL); +} + +static bool maybe_add_http_filter(grpc_channel_stack_builder *builder, + void *arg) { + grpc_transport *t = grpc_channel_stack_builder_get_transport(builder); + if (t && strstr(t->vtable->name, "http")) { + return grpc_channel_stack_builder_prepend_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL); + } + return true; +} + +static void register_builtin_channel_init() { + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, prepend_filter, + (void *)&grpc_compress_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + prepend_filter, + (void *)&grpc_compress_filter); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter, + (void *)&grpc_compress_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, + maybe_add_http_filter, + (void *)&grpc_http_client_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, + grpc_add_connected_filter, NULL); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + maybe_add_http_filter, + (void *)&grpc_http_client_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + grpc_add_connected_filter, NULL); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + maybe_add_http_filter, + (void *)&grpc_http_server_filter); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + grpc_add_connected_filter, NULL); + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, append_filter, + (void *)&grpc_client_channel_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_LAME_CHANNEL, INT_MAX, + 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 { void (*init)(); void (*destroy)(); @@ -85,7 +149,7 @@ static int g_number_of_plugins = 0; void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) { GRPC_API_TRACE("grpc_register_plugin(init=%p, destroy=%p)", 2, - ((void*)(intptr_t)init, (void*)(intptr_t)destroy)); + ((void *)(intptr_t)init, (void *)(intptr_t)destroy)); GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS); g_all_of_the_plugins[g_number_of_plugins].init = init; g_all_of_the_plugins[g_number_of_plugins].destroy = destroy; @@ -100,6 +164,7 @@ void grpc_init(void) { if (++g_initializations == 1) { gpr_time_init(); grpc_mdctx_global_init(); + grpc_channel_init_init(); grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create()); grpc_register_lb_policy(grpc_pick_first_lb_factory_create()); grpc_register_lb_policy(grpc_round_robin_lb_factory_create()); @@ -115,18 +180,12 @@ void grpc_init(void) { grpc_register_tracer("http", &grpc_http_trace); grpc_register_tracer("flowctl", &grpc_flowctl_trace); grpc_register_tracer("connectivity_state", &grpc_connectivity_state_trace); + grpc_register_tracer("channel_stack_builder", + &grpc_trace_channel_stack_builder); grpc_security_pre_init(); grpc_iomgr_init(); grpc_executor_init(); grpc_tracer_init("GRPC_TRACE"); - /* Only initialize census if no one else has and some features are - * available. */ - if (census_enabled() == CENSUS_FEATURE_NONE && - census_supported() != CENSUS_FEATURE_NONE) { - if (census_initialize(census_supported())) { /* enable all features. */ - gpr_log(GPR_ERROR, "Could not initialize census."); - } - } gpr_timers_global_init(); grpc_cq_global_init(); grpc_subchannel_index_init(); @@ -135,6 +194,12 @@ void grpc_init(void) { g_all_of_the_plugins[i].init(); } } + /* register channel finalization AFTER all plugins, to ensure that it's run + * at the appropriate time */ + grpc_register_security_filters(); + register_builtin_channel_init(); + /* no more changes to channel init pipelines */ + grpc_channel_init_finalize(); } gpr_mu_unlock(&g_init_mu); GRPC_API_TRACE("grpc_init(void)", 0, ()); @@ -149,7 +214,6 @@ void grpc_shutdown(void) { grpc_cq_global_shutdown(); grpc_iomgr_shutdown(); grpc_subchannel_index_shutdown(); - census_shutdown(); gpr_timers_global_destroy(); grpc_tracer_shutdown(); grpc_resolver_registry_shutdown(); @@ -159,6 +223,7 @@ void grpc_shutdown(void) { g_all_of_the_plugins[i].destroy(); } } + grpc_channel_init_shutdown(); grpc_mdctx_global_shutdown(); } gpr_mu_unlock(&g_init_mu); diff --git a/src/core/surface/init.h b/src/core/surface/init.h index dddabbc8ce..5e358c7022 100644 --- a/src/core/surface/init.h +++ b/src/core/surface/init.h @@ -34,6 +34,7 @@ #ifndef GRPC_CORE_SURFACE_INIT_H #define GRPC_CORE_SURFACE_INIT_H +void grpc_register_security_filters(void); void grpc_security_pre_init(void); int grpc_is_initialized(void); diff --git a/src/core/surface/init_secure.c b/src/core/surface/init_secure.c index fa20e91583..311dda9864 100644 --- a/src/core/surface/init_secure.c +++ b/src/core/surface/init_secure.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,11 +32,58 @@ */ #include "src/core/surface/init.h" + +#include <limits.h> +#include <string.h> + +#include "src/core/surface/channel_init.h" #include "src/core/debug/trace.h" +#include "src/core/security/auth_filters.h" +#include "src/core/security/credentials.h" #include "src/core/security/secure_endpoint.h" +#include "src/core/security/security_connector.h" #include "src/core/tsi/transport_security_interface.h" void grpc_security_pre_init(void) { grpc_register_tracer("secure_endpoint", &grpc_trace_secure_endpoint); grpc_register_tracer("transport_security", &tsi_tracing_enabled); } + +static bool maybe_prepend_client_auth_filter( + grpc_channel_stack_builder *builder, void *arg) { + const grpc_channel_args *args = + grpc_channel_stack_builder_get_channel_arguments(builder); + if (args) { + for (size_t i = 0; i < args->num_args; i++) { + if (0 == strcmp(GRPC_SECURITY_CONNECTOR_ARG, args->args[i].key)) { + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_client_auth_filter, NULL, NULL); + } + } + } + return true; +} + +static bool maybe_prepend_server_auth_filter( + grpc_channel_stack_builder *builder, void *arg) { + const grpc_channel_args *args = + grpc_channel_stack_builder_get_channel_arguments(builder); + if (args) { + for (size_t i = 0; i < args->num_args; i++) { + if (0 == strcmp(GRPC_SERVER_CREDENTIALS_ARG, args->args[i].key)) { + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_server_auth_filter, NULL, NULL); + } + } + } + return true; +} + +void grpc_register_security_filters(void) { + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, + maybe_prepend_client_auth_filter, NULL); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + maybe_prepend_client_auth_filter, NULL); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + maybe_prepend_server_auth_filter, NULL); +} diff --git a/src/core/surface/init_unsecure.c b/src/core/surface/init_unsecure.c index 630d564a7d..278fcc83ac 100644 --- a/src/core/surface/init_unsecure.c +++ b/src/core/surface/init_unsecure.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,3 +34,5 @@ #include "src/core/surface/init.h" void grpc_security_pre_init(void) {} + +void grpc_register_security_filters(void) {} diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c index 537069e984..58f89946d2 100644 --- a/src/core/surface/lame_client.c +++ b/src/core/surface/lame_client.c @@ -31,6 +31,8 @@ * */ +#include "src/core/surface/lame_client.h" + #include <grpc/grpc.h> #include <string.h> @@ -115,7 +117,7 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx, static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem) {} -static const grpc_channel_filter lame_filter = { +const grpc_channel_filter grpc_lame_filter = { lame_start_transport_stream_op, lame_start_transport_op, sizeof(call_data), init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, @@ -127,19 +129,17 @@ static const grpc_channel_filter lame_filter = { grpc_channel *grpc_lame_client_channel_create(const char *target, grpc_status_code error_code, const char *error_message) { - grpc_channel *channel; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_channel_element *elem; channel_data *chand; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - static const grpc_channel_filter *filters[] = {&lame_filter}; - channel = - grpc_channel_create_from_filters(&exec_ctx, target, filters, 1, NULL, 1); + grpc_channel *channel = grpc_channel_create(&exec_ctx, target, NULL, + GRPC_CLIENT_LAME_CHANNEL, NULL); elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); GRPC_API_TRACE( "grpc_lame_client_channel_create(target=%s, error_code=%d, " "error_message=%s)", 3, (target, (int)error_code, error_message)); - GPR_ASSERT(elem->filter == &lame_filter); + GPR_ASSERT(elem->filter == &grpc_lame_filter); chand = (channel_data *)elem->channel_data; chand->error_code = error_code; chand->error_message = error_message; diff --git a/src/core/channel/client_uchannel.h b/src/core/surface/lame_client.h index 8bb288e7d4..3f3abd2ffe 100644 --- a/src/core/channel/client_uchannel.h +++ b/src/core/surface/lame_client.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015-2016, Google Inc. + * Copyright 2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,30 +31,11 @@ * */ -#ifndef GRPC_CORE_CHANNEL_CLIENT_UCHANNEL_H -#define GRPC_CORE_CHANNEL_CLIENT_UCHANNEL_H +#ifndef GRPC_CORE_SURFACE_LAME_CLIENT_H +#define GRPC_CORE_SURFACE_LAME_CLIENT_H #include "src/core/channel/channel_stack.h" -#include "src/core/client_config/resolver.h" -#define GRPC_MICROCHANNEL_SUBCHANNEL_ARG "grpc.microchannel_subchannel_key" +extern const grpc_channel_filter grpc_lame_filter; -/* A client microchannel (aka uchannel) is a channel wrapping a subchannel, for - * the purposes of lightweight RPC communications from within the core.*/ - -extern const grpc_channel_filter grpc_client_uchannel_filter; - -grpc_connectivity_state grpc_client_uchannel_check_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); - -void grpc_client_uchannel_watch_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete); - -grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel, - grpc_channel_args *args); - -void grpc_client_uchannel_set_connected_subchannel( - grpc_channel *uchannel, grpc_connected_subchannel *connected_subchannel); - -#endif /* GRPC_CORE_CHANNEL_CLIENT_UCHANNEL_H */ +#endif /* GRPC_CORE_SURFACE_LAME_CLIENT_H */ diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index aadfac4c91..cc752227ee 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -40,11 +40,8 @@ #include <grpc/support/slice.h> #include <grpc/support/slice_buffer.h> -#include "src/core/census/grpc_filter.h" #include "src/core/channel/channel_args.h" #include "src/core/channel/client_channel.h" -#include "src/core/channel/compress_filter.h" -#include "src/core/channel/http_client_filter.h" #include "src/core/client_config/resolver_registry.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/security/auth_filters.h" @@ -115,10 +112,6 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, args_copy = grpc_channel_args_copy_and_add(c->args.channel_args, &auth_context_arg, 1); c->result->channel_args = args_copy; - c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *) * 2); - c->result->filters[0] = &grpc_http_client_filter; - c->result->filters[1] = &grpc_client_auth_filter; - c->result->num_filters = 2; } notify = c->notify; c->notify = NULL; @@ -262,10 +255,7 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds, grpc_channel_security_connector *security_connector; grpc_resolver *resolver; subchannel_factory *f; -#define MAX_FILTERS 3 - const grpc_channel_filter *filters[MAX_FILTERS]; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - size_t n = 0; GRPC_API_TRACE( "grpc_secure_channel_create(creds=%p, target=%s, args=%p, " @@ -294,15 +284,9 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds, args_copy = grpc_channel_args_copy_and_add( new_args_from_connector != NULL ? new_args_from_connector : args, &connector_arg, 1); - if (grpc_channel_args_is_census_enabled(args)) { - filters[n++] = &grpc_client_census_filter; - } - filters[n++] = &grpc_compress_filter; - filters[n++] = &grpc_client_channel_filter; - GPR_ASSERT(n <= MAX_FILTERS); - channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n, - args_copy, 1); + channel = grpc_channel_create(&exec_ctx, target, args_copy, + GRPC_CLIENT_CHANNEL, NULL); f = gpr_malloc(sizeof(*f)); f->base.vtable = &subchannel_factory_vtable; diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 5b13d4ba52..da93474b26 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -42,7 +42,6 @@ #include <grpc/support/string_util.h> #include <grpc/support/useful.h> -#include "src/core/census/grpc_filter.h" #include "src/core/channel/channel_args.h" #include "src/core/channel/connected_channel.h" #include "src/core/iomgr/iomgr.h" @@ -182,8 +181,6 @@ typedef struct { } channel_broadcaster; struct grpc_server { - size_t channel_filter_count; - grpc_channel_filter const **channel_filters; grpc_channel_args *channel_args; grpc_completion_queue **cqs; @@ -355,7 +352,6 @@ static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) { grpc_channel_args_destroy(server->channel_args); gpr_mu_destroy(&server->mu_global); gpr_mu_destroy(&server->mu_call); - gpr_free((void *)server->channel_filters); while ((rm = server->registered_methods) != NULL) { server->registered_methods = rm->next; request_matcher_destroy(&rm->request_matcher); @@ -757,7 +753,7 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, } } -static const grpc_channel_filter server_surface_filter = { +const grpc_channel_filter grpc_server_top_filter = { server_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data), init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, @@ -783,11 +779,10 @@ void grpc_server_register_completion_queue(grpc_server *server, server->cqs[n] = cq; } -grpc_server *grpc_server_create_from_filters( - const grpc_channel_filter **filters, size_t filter_count, - const grpc_channel_args *args) { +grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { size_t i; - int census_enabled = grpc_channel_args_is_census_enabled(args); + + GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved)); grpc_server *server = gpr_malloc(sizeof(grpc_server)); @@ -815,23 +810,6 @@ grpc_server *grpc_server_create_from_filters( server->requested_calls = gpr_malloc(server->max_requested_calls * sizeof(*server->requested_calls)); - /* Server filter stack is: - - server_surface_filter - for making surface API calls - grpc_server_census_filter (optional) - for stats collection and tracing - {passed in filter stack} - grpc_connected_channel_filter - for interfacing with transports */ - server->channel_filter_count = filter_count + 1u + (census_enabled ? 1u : 0u); - server->channel_filters = - gpr_malloc(server->channel_filter_count * sizeof(grpc_channel_filter *)); - server->channel_filters[0] = &server_surface_filter; - if (census_enabled) { - server->channel_filters[1] = &grpc_server_census_filter; - } - for (i = 0; i < filter_count; i++) { - server->channel_filters[i + 1u + (census_enabled ? 1u : 0u)] = filters[i]; - } - server->channel_args = grpc_channel_args_copy(args); return server; @@ -892,12 +870,7 @@ void grpc_server_start(grpc_server *server) { void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, grpc_transport *transport, - grpc_channel_filter const **extra_filters, - size_t num_extra_filters, const grpc_channel_args *args) { - size_t num_filters = s->channel_filter_count + num_extra_filters + 1; - grpc_channel_filter const **filters = - gpr_malloc(sizeof(grpc_channel_filter *) * num_filters); size_t i; size_t num_registered_methods; size_t alloc; @@ -913,22 +886,14 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, uint32_t max_probes = 0; grpc_transport_op op; - for (i = 0; i < s->channel_filter_count; i++) { - filters[i] = s->channel_filters[i]; - } - for (; i < s->channel_filter_count + num_extra_filters; i++) { - filters[i] = extra_filters[i - s->channel_filter_count]; - } - filters[i] = &grpc_connected_channel_filter; - for (i = 0; i < s->cq_count; i++) { memset(&op, 0, sizeof(op)); op.bind_pollset = grpc_cq_pollset(s->cqs[i]); grpc_transport_perform_op(exec_ctx, transport, &op); } - channel = grpc_channel_create_from_filters(exec_ctx, NULL, filters, - num_filters, args, 0); + channel = + grpc_channel_create(exec_ctx, NULL, args, GRPC_SERVER_CHANNEL, transport); chand = (channel_data *)grpc_channel_stack_element( grpc_channel_get_channel_stack(channel), 0)->channel_data; chand->server = s; @@ -965,17 +930,12 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, chand->registered_method_max_probes = max_probes; } - grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel), - transport); - gpr_mu_lock(&s->mu_global); chand->next = &s->root_channel_data; chand->prev = chand->next->prev; chand->next->prev = chand->prev->next = chand; gpr_mu_unlock(&s->mu_global); - gpr_free((void *)filters); - GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity"); memset(&op, 0, sizeof(op)); op.set_accept_stream = true; diff --git a/src/core/surface/server.h b/src/core/surface/server.h index 9ddcb01ae9..cd62eadd7f 100644 --- a/src/core/surface/server.h +++ b/src/core/surface/server.h @@ -34,14 +34,11 @@ #ifndef GRPC_CORE_SURFACE_SERVER_H #define GRPC_CORE_SURFACE_SERVER_H -#include "src/core/channel/channel_stack.h" #include <grpc/grpc.h> +#include "src/core/channel/channel_stack.h" #include "src/core/transport/transport.h" -/* Create a server */ -grpc_server *grpc_server_create_from_filters( - const grpc_channel_filter **filters, size_t filter_count, - const grpc_channel_args *args); +extern const grpc_channel_filter grpc_server_top_filter; /* Add a listener to the server: when the server starts, it will call start, and when it shuts down, it will call destroy */ @@ -56,8 +53,6 @@ void grpc_server_add_listener( server */ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *server, grpc_transport *transport, - grpc_channel_filter const **extra_filters, - size_t num_extra_filters, const grpc_channel_args *args); const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server); diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c index ce970dfe73..ff2840f655 100644 --- a/src/core/surface/server_chttp2.c +++ b/src/core/surface/server_chttp2.c @@ -45,10 +45,7 @@ static void setup_transport(grpc_exec_ctx *exec_ctx, void *server, grpc_transport *transport) { - static grpc_channel_filter const *extra_filters[] = { - &grpc_http_server_filter}; - grpc_server_setup_transport(exec_ctx, server, transport, extra_filters, - GPR_ARRAY_SIZE(extra_filters), + grpc_server_setup_transport(exec_ctx, server, transport, grpc_server_get_channel_args(server)); } diff --git a/src/core/transport/chttp2/timeout_encoding.c b/src/core/transport/chttp2/timeout_encoding.c index a6f7081d21..c4802e050e 100644 --- a/src/core/transport/chttp2/timeout_encoding.c +++ b/src/core/transport/chttp2/timeout_encoding.c @@ -150,7 +150,7 @@ int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) { /* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */ if (x >= (100 * 1000 * 1000)) { if (x != (100 * 1000 * 1000) || digit != 0) { - *timeout = gpr_inf_future(GPR_CLOCK_REALTIME); + *timeout = gpr_inf_future(GPR_TIMESPAN); return 1; } } diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 03444fd4c2..b16768d06e 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -1757,8 +1757,9 @@ static char *chttp2_get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *t) { } static const grpc_transport_vtable vtable = { - sizeof(grpc_chttp2_stream), init_stream, set_pollset, perform_stream_op, - perform_transport_op, destroy_stream, destroy_transport, chttp2_get_peer}; + sizeof(grpc_chttp2_stream), "chttp2", init_stream, set_pollset, + perform_stream_op, perform_transport_op, destroy_stream, destroy_transport, + chttp2_get_peer}; grpc_transport *grpc_create_chttp2_transport( grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args, diff --git a/src/core/transport/static_metadata.c b/src/core/transport/static_metadata.c index eeedae0619..84abb59e99 100644 --- a/src/core/transport/static_metadata.c +++ b/src/core/transport/static_metadata.c @@ -50,7 +50,7 @@ grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = { 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, 3, 7, 5, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 8, 6, 2, 4, 8, 6, 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, 0, 0, 0, 0}; diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h index fe9a653f7f..d9ecc4d2ba 100644 --- a/src/core/transport/transport_impl.h +++ b/src/core/transport/transport_impl.h @@ -41,6 +41,9 @@ typedef struct grpc_transport_vtable { layers and initialized by the transport */ size_t sizeof_stream; /* = sizeof(transport stream) */ + /* name of this transport implementation */ + const char *name; + /* implementation of grpc_transport_init_stream */ int (*init_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self, grpc_stream *stream, grpc_stream_refcount *refcount, diff --git a/src/node/README.md b/src/node/README.md index 3501b54a66..15d4c6d02f 100644 --- a/src/node/README.md +++ b/src/node/README.md @@ -7,6 +7,8 @@ Beta ## PREREQUISITES - `node`: This requires `node` to be installed, version `0.12` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package. +- **Note:** If you installed `node` via a package manager and the version is still less than `0.12`, try directly installing it from [nodejs.org](https://nodejs.org). + ## INSTALLATION Install the gRPC NPM package @@ -17,7 +19,21 @@ npm install grpc ## BUILD FROM SOURCE 1. Clone [the grpc Git Repository](https://github.com/grpc/grpc). - 3. Run `npm install`. + 2. Run `npm install` from the repository root. + + - **Note:** On Windows, this might fail due to [nodejs issue #4932](https://github.com/nodejs/node/issues/4932) in which case, you will see something like the following in `npm install`'s output (towards the very beginning): + + ``` + .. + Building the projects in this solution one at a time. To enable parallel build, please add the "/m" switch. + WINDOWS_BUILD_WARNING + "..\IMPORTANT: Due to https:\github.com\nodejs\node\issues\4932, to build this library on Windows, you must first remove C:\Users\jenkins\.node-gyp\4.4.0\include\node\openssl" + ... + .. + ``` + + To fix this, you will have to delete the folder `C:\Users\<username>\.node-gyp\<node_version>\include\node\openssl` and retry `npm install` + ## TESTING To run the test suite, simply run `npm test` in the install location. diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc index 98696db232..bd2d146bbc 100644 --- a/src/node/ext/call_credentials.cc +++ b/src/node/ext/call_credentials.cc @@ -35,6 +35,8 @@ #include <nan.h> #include <uv.h> +#include <list> + #include "grpc/grpc.h" #include "grpc/grpc_security.h" #include "grpc/support/log.h" @@ -161,6 +163,15 @@ NAN_METHOD(CallCredentials::CreateFromPlugin) { grpc_metadata_credentials_plugin plugin; plugin_state *state = new plugin_state; state->callback = new Nan::Callback(info[0].As<Function>()); + state->pending_callbacks = new std::list<plugin_callback_data*>(); + uv_mutex_init(&state->plugin_mutex); + uv_async_init(uv_default_loop(), + &state->plugin_async, + SendPluginCallback); + uv_unref((uv_handle_t*)&state->plugin_async); + + state->plugin_async.data = state; + plugin.get_metadata = plugin_get_metadata; plugin.destroy = plugin_destroy_state; plugin.state = reinterpret_cast<void*>(state); @@ -208,48 +219,60 @@ NAN_METHOD(PluginCallback) { NAUV_WORK_CB(SendPluginCallback) { Nan::HandleScope scope; - plugin_callback_data *data = reinterpret_cast<plugin_callback_data*>( - async->data); - // Attach cb and user_data to plugin_callback so that it can access them later - v8::Local<v8::Function> plugin_callback = Nan::GetFunction( - Nan::New<v8::FunctionTemplate>(PluginCallback)).ToLocalChecked(); - Nan::Set(plugin_callback, Nan::New("cb").ToLocalChecked(), - Nan::New<v8::External>(reinterpret_cast<void*>(data->cb))); - Nan::Set(plugin_callback, Nan::New("user_data").ToLocalChecked(), - Nan::New<v8::External>(data->user_data)); - const int argc = 2; - v8::Local<v8::Value> argv[argc] = { - Nan::New(data->service_url).ToLocalChecked(), - plugin_callback - }; - Nan::Callback *callback = data->state->callback; - callback->Call(argc, argv); - delete data; - uv_unref((uv_handle_t *)async); - uv_close((uv_handle_t *)async, (uv_close_cb)free); + plugin_state *state = reinterpret_cast<plugin_state*>(async->data); + std::list<plugin_callback_data*> callbacks; + uv_mutex_lock(&state->plugin_mutex); + callbacks.splice(callbacks.begin(), *state->pending_callbacks); + uv_mutex_unlock(&state->plugin_mutex); + while (!callbacks.empty()) { + plugin_callback_data *data = callbacks.front(); + callbacks.pop_front(); + // Attach cb and user_data to plugin_callback so that it can access them later + v8::Local<v8::Function> plugin_callback = Nan::GetFunction( + Nan::New<v8::FunctionTemplate>(PluginCallback)).ToLocalChecked(); + Nan::Set(plugin_callback, Nan::New("cb").ToLocalChecked(), + Nan::New<v8::External>(reinterpret_cast<void*>(data->cb))); + Nan::Set(plugin_callback, Nan::New("user_data").ToLocalChecked(), + Nan::New<v8::External>(data->user_data)); + const int argc = 2; + v8::Local<v8::Value> argv[argc] = { + Nan::New(data->service_url).ToLocalChecked(), + plugin_callback + }; + Nan::Callback *callback = state->callback; + callback->Call(argc, argv); + delete data; + } } void plugin_get_metadata(void *state, grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb, void *user_data) { - uv_async_t *async = static_cast<uv_async_t*>(malloc(sizeof(uv_async_t))); - uv_async_init(uv_default_loop(), - async, - SendPluginCallback); + plugin_state *p_state = reinterpret_cast<plugin_state*>(state); plugin_callback_data *data = new plugin_callback_data; - data->state = reinterpret_cast<plugin_state*>(state); data->service_url = context.service_url; data->cb = cb; data->user_data = user_data; - async->data = data; - /* libuv says that it will coalesce calls to uv_async_send. If there is ever a - * problem with a callback not getting called, that is probably the reason */ - uv_async_send(async); + + uv_mutex_lock(&p_state->plugin_mutex); + p_state->pending_callbacks->push_back(data); + uv_mutex_unlock(&p_state->plugin_mutex); + + uv_async_send(&p_state->plugin_async); +} + +void plugin_uv_close_cb(uv_handle_t *handle) { + uv_async_t *async = reinterpret_cast<uv_async_t*>(handle); + plugin_state *state = reinterpret_cast<plugin_state *>(async->data); + uv_mutex_destroy(&state->plugin_mutex); + delete state->pending_callbacks; + delete state->callback; + delete state; } void plugin_destroy_state(void *ptr) { plugin_state *state = reinterpret_cast<plugin_state *>(ptr); - delete state->callback; + uv_close((uv_handle_t*)&state->plugin_async, plugin_uv_close_cb); } } // namespace node diff --git a/src/node/ext/call_credentials.h b/src/node/ext/call_credentials.h index a9bfe30f94..1f35595f3d 100644 --- a/src/node/ext/call_credentials.h +++ b/src/node/ext/call_credentials.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,8 +34,11 @@ #ifndef GRPC_NODE_CALL_CREDENTIALS_H_ #define GRPC_NODE_CALL_CREDENTIALS_H_ +#include <list> + #include <node.h> #include <nan.h> +#include <uv.h> #include "grpc/grpc_security.h" namespace grpc { @@ -73,17 +76,20 @@ class CallCredentials : public Nan::ObjectWrap { /* Auth metadata plugin functionality */ -typedef struct plugin_state { - Nan::Callback *callback; -} plugin_state; - typedef struct plugin_callback_data { - plugin_state *state; const char *service_url; grpc_credentials_plugin_metadata_cb cb; void *user_data; } plugin_callback_data; +typedef struct plugin_state { + Nan::Callback *callback; + std::list<plugin_callback_data*> *pending_callbacks; + uv_mutex_t plugin_mutex; + // async.data == this + uv_async_t plugin_async; +} plugin_state; + void plugin_get_metadata(void *state, grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb, void *user_data); diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js index 1d73723cc0..97c4bd73ac 100644 --- a/src/node/src/credentials.js +++ b/src/node/src/credentials.js @@ -118,7 +118,6 @@ exports.createFromMetadataGenerator = function(metadata_generator) { exports.createFromGoogleCredential = function(google_credential) { return exports.createFromMetadataGenerator(function(auth_context, callback) { var service_url = auth_context.service_url; - console.log('Service URL:', service_url); google_credential.getRequestMetadata(service_url, function(err, header) { if (err) { console.log('Auth error:', err); @@ -127,7 +126,6 @@ exports.createFromGoogleCredential = function(google_credential) { } var metadata = new Metadata(); metadata.add('authorization', header.Authorization); - console.log(header.Authorization); callback(null, metadata); }); }); diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 2d45818b6e..51263b073c 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -308,37 +308,30 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey"; } - (void)invokeCall { - __weak GRPCCall *weakSelf = self; [self invokeCallWithHeadersHandler:^(NSDictionary *headers) { // Response headers received. - GRPCCall *strongSelf = weakSelf; - if (strongSelf) { - strongSelf.responseHeaders = headers; - [strongSelf startNextRead]; - } + self.responseHeaders = headers; + [self startNextRead]; } completionHandler:^(NSError *error, NSDictionary *trailers) { - GRPCCall *strongSelf = weakSelf; - if (strongSelf) { - strongSelf.responseTrailers = trailers; - - if (error) { - NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; - if (error.userInfo) { - [userInfo addEntriesFromDictionary:error.userInfo]; - } - userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers; - // TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be - // called before this one, so an error might end up with trailers but no headers. We - // shouldn't call finishWithError until ater both blocks are called. It is also when this is - // done that we can provide a merged view of response headers and trailers in a thread-safe - // way. - if (strongSelf.responseHeaders) { - userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders; - } - error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo]; + self.responseTrailers = trailers; + + if (error) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (error.userInfo) { + [userInfo addEntriesFromDictionary:error.userInfo]; + } + userInfo[kGRPCTrailersKey] = self.responseTrailers; + // TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be + // called before this one, so an error might end up with trailers but no headers. We + // shouldn't call finishWithError until ater both blocks are called. It is also when this is + // done that we can provide a merged view of response headers and trailers in a thread-safe + // way. + if (self.responseHeaders) { + userInfo[kGRPCHeadersKey] = self.responseHeaders; } - [strongSelf finishWithError:error]; + error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo]; } + [self finishWithError:error]; }]; // Now that the RPC has been initiated, request writes can start. @synchronized(_requestWriter) { @@ -377,7 +370,6 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey"; [strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Connectivity lost."}]]; - [[GRPCHost hostWithAddress:strongSelf->_host] disconnect]; } }]; } diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index fe3d51da53..f6527e283c 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,7 +54,9 @@ - (void)finish { if (_handler) { - _handler(); + void(^handler)() = _handler; + _handler = nil; + handler(); } } @end diff --git a/src/proto/grpc/testing/metrics.proto b/src/proto/grpc/testing/metrics.proto index 4485d3a53b..df719afd99 100644 --- a/src/proto/grpc/testing/metrics.proto +++ b/src/proto/grpc/testing/metrics.proto @@ -1,5 +1,4 @@ - -// Copyright 2015, Google Inc. +// Copyright 2015-2016, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -28,12 +27,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// An integration test service that covers all the method signature permutations -// of unary/streaming requests/responses. +// Contains the definitions for a metrics service and the type of metrics +// exposed by the service. +// +// Currently, 'Gauge' (i.e a metric that represents the measured value of +// something at an instant of time) is the only metric type supported by the +// service. syntax = "proto3"; package grpc.testing; +// Reponse message containing the gauge name and value message GaugeResponse { string name = 1; oneof value { @@ -43,11 +47,18 @@ message GaugeResponse { } } -message GaugeRequest { string name = 1; } +// Request message containing the gauge name +message GaugeRequest { + string name = 1; +} message EmptyMessage {} service MetricsService { + // Returns the values of all the gauges that are currently being maintained by + // the service rpc GetAllGauges(EmptyMessage) returns (stream GaugeResponse); + + // Returns the value of one gauge rpc GetGauge(GaugeRequest) returns (GaugeResponse); } diff --git a/src/python/grpcio/grpc/_adapter/_types.py b/src/python/grpcio/grpc/_adapter/_types.py index 3d5ab33d00..f9e18f0bb3 100644 --- a/src/python/grpcio/grpc/_adapter/_types.py +++ b/src/python/grpcio/grpc/_adapter/_types.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,6 +31,8 @@ import abc import collections import enum +import six + from grpc._cython import cygrpc @@ -247,8 +249,7 @@ class Event(collections.namedtuple( """ -class CompletionQueue: - __metaclass__ = abc.ABCMeta +class CompletionQueue(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def __init__(self): @@ -262,6 +263,9 @@ class CompletionQueue: """ return self + def __next__(self): + return self.next() + @abc.abstractmethod def next(self, deadline=float('+inf')): """Get the next event on this completion queue. @@ -285,8 +289,7 @@ class CompletionQueue: return None -class Call: - __metaclass__ = abc.ABCMeta +class Call(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def start_batch(self, ops, tag): @@ -334,8 +337,7 @@ class Call: return None -class Channel: - __metaclass__ = abc.ABCMeta +class Channel(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def __init__(self, target, args, credentials=None): @@ -399,8 +401,7 @@ class Channel: return None -class Server: - __metaclass__ = abc.ABCMeta +class Server(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def __init__(self, completion_queue, args): diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi index 851389a261..6ecdcf7222 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi @@ -254,7 +254,7 @@ cdef class ByteBuffer: if self.c_byte_buffer != NULL: with nogil: grpc_byte_buffer_reader_init(&reader, self.c_byte_buffer) - result = b"" + result = bytearray() with nogil: while grpc_byte_buffer_reader_next(&reader, &data_slice): data_slice_pointer = gpr_slice_start_ptr(data_slice) @@ -263,7 +263,7 @@ cdef class ByteBuffer: result += (<char *>data_slice_pointer)[:data_slice_length] with nogil: grpc_byte_buffer_reader_destroy(&reader) - return result + return bytes(result) else: return None diff --git a/src/python/grpcio/grpc/_links/invocation.py b/src/python/grpcio/grpc/_links/invocation.py index 5ca0a0ee60..672e3e4cc8 100644 --- a/src/python/grpcio/grpc/_links/invocation.py +++ b/src/python/grpcio/grpc/_links/invocation.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -35,6 +35,8 @@ import logging import threading import time +import six + from grpc._adapter import _intermediary_low from grpc._links import _constants from grpc.beta import interfaces as beta_interfaces @@ -372,12 +374,11 @@ class _Kernel(object): pool.shutdown(wait=True) -class InvocationLink(links.Link, activated.Activated): +class InvocationLink(six.with_metaclass(abc.ABCMeta, links.Link, activated.Activated)): """A links.Link for use on the invocation-side of a gRPC connection. Implementations of this interface are only valid for use when activated. """ - __metaclass__ = abc.ABCMeta class _InvocationLink(InvocationLink): diff --git a/src/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py index 01edee6896..e0f26a5b0f 100644 --- a/src/python/grpcio/grpc/_links/service.py +++ b/src/python/grpcio/grpc/_links/service.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -177,7 +177,7 @@ class _Kernel(object): call = service_acceptance.call call.accept(self._completion_queue, call) try: - group, method = service_acceptance.method.split('/')[1:3] + group, method = service_acceptance.method.split(b'/')[1:3] except ValueError: logging.info('Illegal path "%s"!', service_acceptance.method) return diff --git a/src/python/grpcio/grpc/beta/_server.py b/src/python/grpcio/grpc/beta/_server.py index 2b520cc7e5..12d16e6c18 100644 --- a/src/python/grpcio/grpc/beta/_server.py +++ b/src/python/grpcio/grpc/beta/_server.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -62,7 +62,7 @@ class _GRPCServicer(base.Servicer): if e.code is None and e.details is None: raise base.NoSuchMethodError( interfaces.StatusCode.UNIMPLEMENTED, - b'Method "%s" of service "%s" not implemented!' % (method, group)) + 'Method "%s" of service "%s" not implemented!' % (method, group)) else: raise diff --git a/src/python/grpcio/grpc/beta/interfaces.py b/src/python/grpcio/grpc/beta/interfaces.py index 0663119163..e29a5b3379 100644 --- a/src/python/grpcio/grpc/beta/interfaces.py +++ b/src/python/grpcio/grpc/beta/interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import abc import enum +import six + from grpc._adapter import _types @@ -105,19 +107,17 @@ def grpc_call_options(disable_compression=False, credentials=None): return GRPCCallOptions(disable_compression, None, credentials) -class GRPCAuthMetadataContext(object): +class GRPCAuthMetadataContext(six.with_metaclass(abc.ABCMeta)): """Provides information to call credentials metadata plugins. Attributes: service_url: A string URL of the service being called into. method_name: A string of the fully qualified method name being called. """ - __metaclass__ = abc.ABCMeta -class GRPCAuthMetadataPluginCallback(object): +class GRPCAuthMetadataPluginCallback(six.with_metaclass(abc.ABCMeta)): """Callback object received by a metadata plugin.""" - __metaclass__ = abc.ABCMeta def __call__(self, metadata, error): """Inform the gRPC runtime of the metadata to construct a CallCredentials. @@ -130,10 +130,9 @@ class GRPCAuthMetadataPluginCallback(object): raise NotImplementedError() -class GRPCAuthMetadataPlugin(object): +class GRPCAuthMetadataPlugin(six.with_metaclass(abc.ABCMeta)): """ """ - __metaclass__ = abc.ABCMeta def __call__(self, context, callback): """Invoke the plugin. @@ -149,9 +148,8 @@ class GRPCAuthMetadataPlugin(object): raise NotImplementedError() -class GRPCServicerContext(object): +class GRPCServicerContext(six.with_metaclass(abc.ABCMeta)): """Exposes gRPC-specific options and behaviors to code servicing RPCs.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def peer(self): @@ -168,9 +166,8 @@ class GRPCServicerContext(object): raise NotImplementedError() -class GRPCInvocationContext(object): +class GRPCInvocationContext(six.with_metaclass(abc.ABCMeta)): """Exposes gRPC-specific options and behaviors to code invoking RPCs.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def disable_next_request_compression(self): @@ -178,9 +175,8 @@ class GRPCInvocationContext(object): raise NotImplementedError() -class Server(object): +class Server(six.with_metaclass(abc.ABCMeta)): """Services RPCs.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def add_insecure_port(self, address): diff --git a/src/python/grpcio/grpc/framework/alpha/_face_utilities.py b/src/python/grpcio/grpc/framework/alpha/_face_utilities.py index fb0cfe426d..b5e4133cad 100644 --- a/src/python/grpcio/grpc/framework/alpha/_face_utilities.py +++ b/src/python/grpcio/grpc/framework/alpha/_face_utilities.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -30,6 +30,8 @@ import abc import collections +import six + # face_interfaces is referenced from specification in this module. from grpc.framework.common import cardinality from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import @@ -45,7 +47,7 @@ def _qualified_name(service_name, method_name): # TODO(nathaniel): This structure is getting bloated; it could be shrunk if # implementations._Stub used a generic rather than a dynamic underlying # face-layer stub. -class InvocationBreakdown(object): +class InvocationBreakdown(six.with_metaclass(abc.ABCMeta)): """An intermediate representation of invocation-side views of RPC methods. Attributes: @@ -61,7 +63,6 @@ class InvocationBreakdown(object): to callable behavior to be used deserializing response values for the RPC. """ - __metaclass__ = abc.ABCMeta class _EasyInvocationBreakdown( @@ -73,7 +74,7 @@ class _EasyInvocationBreakdown( pass -class ServiceBreakdown(object): +class ServiceBreakdown(six.with_metaclass(abc.ABCMeta)): """An intermediate representation of service-side views of RPC methods. Attributes: @@ -84,7 +85,6 @@ class ServiceBreakdown(object): response_serializers: A dictionary from service-qualified RPC method name to callable behavior to be used serializing response values for the RPC. """ - __metaclass__ = abc.ABCMeta class _EasyServiceBreakdown( @@ -111,7 +111,7 @@ def break_down_invocation(service_name, method_descriptions): face_cardinalities = {} request_serializers = {} response_deserializers = {} - for name, method_description in method_descriptions.iteritems(): + for name, method_description in six.iteritems(method_descriptions): qualified_name = _qualified_name(service_name, name) method_cardinality = method_description.cardinality() cardinalities[name] = method_description.cardinality() @@ -139,7 +139,7 @@ def break_down_service(service_name, method_descriptions): implementations = {} request_deserializers = {} response_serializers = {} - for name, method_description in method_descriptions.iteritems(): + for name, method_description in six.iteritems(method_descriptions): qualified_name = _qualified_name(service_name, name) method_cardinality = method_description.cardinality() if method_cardinality is interfaces.Cardinality.UNARY_UNARY: diff --git a/src/python/grpcio/grpc/framework/alpha/_reexport.py b/src/python/grpcio/grpc/framework/alpha/_reexport.py index 198cb95ad5..4ea0e94d80 100644 --- a/src/python/grpcio/grpc/framework/alpha/_reexport.py +++ b/src/python/grpcio/grpc/framework/alpha/_reexport.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,6 +27,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import six + from grpc.framework.common import cardinality from grpc.framework.face import exceptions as face_exceptions from grpc.framework.face import interfaces as face_interfaces @@ -181,7 +183,7 @@ def common_cardinality(early_adopter_cardinality): def common_cardinalities(early_adopter_cardinalities): common_cardinalities = {} - for name, early_adopter_cardinality in early_adopter_cardinalities.iteritems(): + for name, early_adopter_cardinality in six.iteritems(early_adopter_cardinalities): common_cardinalities[name] = _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[ early_adopter_cardinality] return common_cardinalities diff --git a/src/python/grpcio/grpc/framework/alpha/exceptions.py b/src/python/grpcio/grpc/framework/alpha/exceptions.py index 5234d3b91c..8ec260488e 100644 --- a/src/python/grpcio/grpc/framework/alpha/exceptions.py +++ b/src/python/grpcio/grpc/framework/alpha/exceptions.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,13 +31,12 @@ Only GRPC should instantiate and raise these exceptions. """ - import abc +import six -class RpcError(Exception): +class RpcError(six.with_metaclass(abc.ABCMeta, Exception)): """Common super type for all exceptions raised by GRPC.""" - __metaclass__ = abc.ABCMeta class CancellationError(RpcError): diff --git a/src/python/grpcio/grpc/framework/alpha/interfaces.py b/src/python/grpcio/grpc/framework/alpha/interfaces.py index 8380567c97..cb6d58bb2e 100644 --- a/src/python/grpcio/grpc/framework/alpha/interfaces.py +++ b/src/python/grpcio/grpc/framework/alpha/interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import abc import enum +import six + # exceptions is referenced from specification in this module. from grpc.framework.alpha import exceptions # pylint: disable=unused-import from grpc.framework.foundation import activated @@ -59,15 +61,17 @@ class Abortion(enum.Enum): SERVICER_FAILURE = 'servicer failure' -class CancellableIterator(object): +class CancellableIterator(six.with_metaclass(abc.ABCMeta)): """Implements the Iterator protocol and affords a cancel method.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __iter__(self): """Returns the self object in accordance with the Iterator protocol.""" raise NotImplementedError() + def __next__(self): + return self.next() + @abc.abstractmethod def next(self): """Returns a value or raises StopIteration per the Iterator protocol.""" @@ -79,9 +83,8 @@ class CancellableIterator(object): raise NotImplementedError() -class RpcContext(object): +class RpcContext(six.with_metaclass(abc.ABCMeta)): """Provides RPC-related information and action.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def is_active(self): @@ -108,7 +111,7 @@ class RpcContext(object): raise NotImplementedError() -class UnaryUnarySyncAsync(object): +class UnaryUnarySyncAsync(six.with_metaclass(abc.ABCMeta)): """Affords invoking a unary-unary RPC synchronously or asynchronously. Values implementing this interface are directly callable and present an "async" method. Both calls take a request value and a numeric timeout. @@ -117,7 +120,6 @@ class UnaryUnarySyncAsync(object): of a value of this type invokes its associated RPC and immediately returns a future.Future bound to the asynchronous execution of the RPC. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request, timeout): @@ -147,7 +149,7 @@ class UnaryUnarySyncAsync(object): raise NotImplementedError() -class StreamUnarySyncAsync(object): +class StreamUnarySyncAsync(six.with_metaclass(abc.ABCMeta)): """Affords invoking a stream-unary RPC synchronously or asynchronously. Values implementing this interface are directly callable and present an "async" method. Both calls take an iterator of request values and a numeric @@ -156,7 +158,6 @@ class StreamUnarySyncAsync(object): of a value of this type invokes its associated RPC and immediately returns a future.Future bound to the asynchronous execution of the RPC. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request_iterator, timeout): @@ -191,9 +192,8 @@ class StreamUnarySyncAsync(object): raise NotImplementedError() -class RpcMethodDescription(object): +class RpcMethodDescription(six.with_metaclass(abc.ABCMeta)): """A type for the common aspects of RPC method descriptions.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def cardinality(self): @@ -207,9 +207,8 @@ class RpcMethodDescription(object): raise NotImplementedError() -class RpcMethodInvocationDescription(RpcMethodDescription): +class RpcMethodInvocationDescription(six.with_metaclass(abc.ABCMeta, RpcMethodDescription)): """Invocation-side description of an RPC method.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def serialize_request(self, request): @@ -240,9 +239,8 @@ class RpcMethodInvocationDescription(RpcMethodDescription): raise NotImplementedError() -class RpcMethodServiceDescription(RpcMethodDescription): +class RpcMethodServiceDescription(six.with_metaclass(abc.ABCMeta, RpcMethodDescription)): """Service-side description of an RPC method.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def deserialize_request(self, serialized_request): @@ -345,7 +343,7 @@ class RpcMethodServiceDescription(RpcMethodDescription): raise NotImplementedError() -class Stub(object): +class Stub(six.with_metaclass(abc.ABCMeta)): """A stub with callable RPC method names for attributes. Instances of this type are context managers and only afford RPC invocation @@ -369,12 +367,10 @@ class Stub(object): exceptions.RpcError, exceptions.CancellationError, and exceptions.ExpirationError. """ - __metaclass__ = abc.ABCMeta -class Server(activated.Activated): +class Server(six.with_metaclass(abc.ABCMeta, activated.Activated)): """A GRPC Server.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def port(self): diff --git a/src/python/grpcio/grpc/framework/base/_ingestion.py b/src/python/grpcio/grpc/framework/base/_ingestion.py index 06d5b92f0b..090cb158c9 100644 --- a/src/python/grpcio/grpc/framework/base/_ingestion.py +++ b/src/python/grpcio/grpc/framework/base/_ingestion.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import abc import collections +import six + from grpc.framework.base import _constants from grpc.framework.base import _interfaces from grpc.framework.base import exceptions @@ -72,9 +74,8 @@ class _EmptyConsumer(stream.Consumer): """See stream.Consumer.consume_and_terminate for specification.""" -class _ConsumerCreator(object): +class _ConsumerCreator(six.with_metaclass(abc.ABCMeta)): """Common specification of different consumer-creating behavior.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def create_consumer(self, requirement): diff --git a/src/python/grpcio/grpc/framework/base/_interfaces.py b/src/python/grpcio/grpc/framework/base/_interfaces.py index d88cf76590..c0cc866cad 100644 --- a/src/python/grpcio/grpc/framework/base/_interfaces.py +++ b/src/python/grpcio/grpc/framework/base/_interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,14 +31,15 @@ import abc +import six + # interfaces is referenced from specification in this module. from grpc.framework.base import interfaces # pylint: disable=unused-import from grpc.framework.foundation import stream -class TerminationManager(object): +class TerminationManager(six.with_metaclass(abc.ABCMeta)): """An object responsible for handling the termination of an operation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_expiration_manager(self, expiration_manager): @@ -91,9 +92,8 @@ class TerminationManager(object): raise NotImplementedError() -class TransmissionManager(object): +class TransmissionManager(six.with_metaclass(abc.ABCMeta)): """A manager responsible for transmitting to the other end of an operation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def inmit(self, emission, complete): @@ -117,9 +117,8 @@ class TransmissionManager(object): raise NotImplementedError() -class EmissionManager(stream.Consumer): +class EmissionManager(six.with_metaclass(abc.ABCMeta, stream.Consumer)): """A manager of values emitted by customer code.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_ingestion_manager_and_expiration_manager( @@ -166,9 +165,8 @@ class EmissionManager(stream.Consumer): raise NotImplementedError() -class IngestionManager(stream.Consumer): +class IngestionManager(six.with_metaclass(abc.ABCMeta, stream.Consumer)): """A manager responsible for executing customer code.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_expiration_manager(self, expiration_manager): @@ -214,9 +212,8 @@ class IngestionManager(stream.Consumer): raise NotImplementedError() -class ExpirationManager(object): +class ExpirationManager(six.with_metaclass(abc.ABCMeta)): """A manager responsible for aborting the operation if it runs out of time.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def change_timeout(self, timeout): @@ -246,9 +243,8 @@ class ExpirationManager(object): raise NotImplementedError() -class ReceptionManager(object): +class ReceptionManager(six.with_metaclass(abc.ABCMeta)): """A manager responsible for receiving tickets from the other end.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def receive_ticket(self, ticket): @@ -261,9 +257,8 @@ class ReceptionManager(object): raise NotImplementedError() -class CancellationManager(object): +class CancellationManager(six.with_metaclass(abc.ABCMeta)): """A manager of operation cancellation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def cancel(self): diff --git a/src/python/grpcio/grpc/framework/base/_reception.py b/src/python/grpcio/grpc/framework/base/_reception.py index dd428964f1..2bee3947f0 100644 --- a/src/python/grpcio/grpc/framework/base/_reception.py +++ b/src/python/grpcio/grpc/framework/base/_reception.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,6 +31,8 @@ import abc +import six + from grpc.framework.base import interfaces from grpc.framework.base import _interfaces @@ -40,9 +42,8 @@ _INITIAL_FRONT_TO_BACK_TICKET_KINDS = ( ) -class _Receiver(object): +class _Receiver(six.with_metaclass(abc.ABCMeta)): """Common specification of different ticket-handling behavior.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def abort_if_abortive(self, ticket): diff --git a/src/python/grpcio/grpc/framework/base/_transmission.py b/src/python/grpcio/grpc/framework/base/_transmission.py index 6845129234..398faaf314 100644 --- a/src/python/grpcio/grpc/framework/base/_transmission.py +++ b/src/python/grpcio/grpc/framework/base/_transmission.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,6 +31,8 @@ import abc +import six + from grpc.framework.base import _constants from grpc.framework.base import _interfaces from grpc.framework.base import interfaces @@ -77,9 +79,8 @@ _ABORTION_OUTCOME_TO_BACK_TO_FRONT_TICKET_KIND = { } -class _Ticketizer(object): +class _Ticketizer(six.with_metaclass(abc.ABCMeta)): """Common specification of different ticket-creating behavior.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def ticketize(self, operation_id, sequence_number, payload, complete): @@ -187,9 +188,8 @@ class _BackTicketizer(_Ticketizer): operation_id, sequence_number, kind, None) -class TransmissionManager(_interfaces.TransmissionManager): +class TransmissionManager(six.with_metaclass(abc.ABCMeta, _interfaces.TransmissionManager)): """A _interfaces.TransmissionManager on which other managers may be set.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_ingestion_and_expiration_managers( diff --git a/src/python/grpcio/grpc/framework/base/interfaces.py b/src/python/grpcio/grpc/framework/base/interfaces.py index e22c10d975..7c58a23ce0 100644 --- a/src/python/grpcio/grpc/framework/base/interfaces.py +++ b/src/python/grpcio/grpc/framework/base/interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,6 +33,8 @@ import abc import collections import enum +import six + # stream is referenced from specification in this module. from grpc.framework.foundation import stream # pylint: disable=unused-import @@ -50,13 +52,12 @@ class Outcome(enum.Enum): SERVICED_FAILURE = 'serviced failure' -class OperationContext(object): +class OperationContext(six.with_metaclass(abc.ABCMeta)): """Provides operation-related information and action. Attributes: trace_id: A uuid.UUID identifying a particular set of related operations. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def is_active(self): @@ -93,9 +94,8 @@ class OperationContext(object): raise NotImplementedError() -class Servicer(object): +class Servicer(six.with_metaclass(abc.ABCMeta)): """Interface for service implementations.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, name, context, output_consumer): @@ -120,7 +120,7 @@ class Servicer(object): raise NotImplementedError() -class Operation(object): +class Operation(six.with_metaclass(abc.ABCMeta)): """Representation of an in-progress operation. Attributes: @@ -129,7 +129,6 @@ class Operation(object): context: An OperationContext affording information and action about the operation. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def cancel(self): @@ -137,9 +136,8 @@ class Operation(object): raise NotImplementedError() -class ServicedIngestor(object): +class ServicedIngestor(six.with_metaclass(abc.ABCMeta)): """Responsible for accepting the result of an operation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def consumer(self, operation_context): @@ -159,7 +157,7 @@ class ServicedIngestor(object): raise NotImplementedError() -class ServicedSubscription(object): +class ServicedSubscription(six.with_metaclass(abc.ABCMeta)): """A sum type representing a serviced's interest in an operation. Attributes: @@ -167,7 +165,6 @@ class ServicedSubscription(object): ingestor: A ServicedIngestor. Must be present if kind is Kind.FULL. Must be None if kind is Kind.TERMINATION_ONLY or Kind.NONE. """ - __metaclass__ = abc.ABCMeta @enum.unique class Kind(enum.Enum): @@ -178,9 +175,8 @@ class ServicedSubscription(object): NONE = 'none' -class End(object): +class End(six.with_metaclass(abc.ABCMeta)): """Common type for entry-point objects on both sides of an operation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def operation_stats(self): @@ -202,9 +198,8 @@ class End(object): raise NotImplementedError() -class Front(End): +class Front(six.with_metaclass(abc.ABCMeta, End)): """Clientish objects that afford the invocation of operations.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def operate( @@ -228,9 +223,8 @@ class Front(End): raise NotImplementedError() -class Back(End): +class Back(six.with_metaclass(abc.ABCMeta, End)): """Serverish objects that perform the work of operations.""" - __metaclass__ = abc.ABCMeta class FrontToBackTicket( @@ -315,9 +309,8 @@ class BackToFrontTicket( TRANSMISSION_FAILURE = 'transmission failure' -class ForeLink(object): +class ForeLink(six.with_metaclass(abc.ABCMeta)): """Accepts back-to-front tickets and emits front-to-back tickets.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def accept_back_to_front_ticket(self, ticket): @@ -334,9 +327,8 @@ class ForeLink(object): raise NotImplementedError() -class RearLink(object): +class RearLink(six.with_metaclass(abc.ABCMeta)): """Accepts front-to-back tickets and emits back-to-front tickets.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def accept_front_to_back_ticket(self, ticket): @@ -353,11 +345,9 @@ class RearLink(object): raise NotImplementedError() -class FrontLink(Front, ForeLink): +class FrontLink(six.with_metaclass(abc.ABCMeta, Front, ForeLink)): """Clientish objects that operate by sending and receiving tickets.""" - __metaclass__ = abc.ABCMeta -class BackLink(Back, RearLink): +class BackLink(six.with_metaclass(abc.ABCMeta, Back, RearLink)): """Serverish objects that operate by sending and receiving tickets.""" - __metaclass__ = abc.ABCMeta diff --git a/src/python/grpcio/grpc/framework/core/_end.py b/src/python/grpcio/grpc/framework/core/_end.py index 9c615672aa..dc2f48589a 100644 --- a/src/python/grpcio/grpc/framework/core/_end.py +++ b/src/python/grpcio/grpc/framework/core/_end.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,6 +33,8 @@ import abc import threading import uuid +import six + from grpc.framework.core import _operation from grpc.framework.core import _utilities from grpc.framework.foundation import callable_util @@ -45,7 +47,7 @@ from grpc.framework.interfaces.links import utilities _IDLE_ACTION_EXCEPTION_LOG_MESSAGE = 'Exception calling idle action!' -class End(base.End, links.Link): +class End(six.with_metaclass(abc.ABCMeta, base.End, links.Link)): """A bridge between base.End and links.Link. Implementations of this interface translate arriving tickets into @@ -53,7 +55,6 @@ class End(base.End, links.Link): translate calls from application objects implementing base interfaces into tickets sent to a joined link. """ - __metaclass__ = abc.ABCMeta class _Cycle(object): diff --git a/src/python/grpcio/grpc/framework/core/_ingestion.py b/src/python/grpcio/grpc/framework/core/_ingestion.py index 4129a8ce43..1e1fd73ce4 100644 --- a/src/python/grpcio/grpc/framework/core/_ingestion.py +++ b/src/python/grpcio/grpc/framework/core/_ingestion.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,6 +33,8 @@ import abc import collections import enum +import six + from grpc.framework.core import _constants from grpc.framework.core import _interfaces from grpc.framework.core import _utilities @@ -70,9 +72,8 @@ class _SubscriptionCreation( ABANDONED = 'abandoned' -class _SubscriptionCreator(object): +class _SubscriptionCreator(six.with_metaclass(abc.ABCMeta)): """Common specification of subscription-creating behavior.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def create(self, group, method): diff --git a/src/python/grpcio/grpc/framework/core/_interfaces.py b/src/python/grpcio/grpc/framework/core/_interfaces.py index ffa686b2b7..985e5e8550 100644 --- a/src/python/grpcio/grpc/framework/core/_interfaces.py +++ b/src/python/grpcio/grpc/framework/core/_interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,17 +31,18 @@ import abc +import six + from grpc.framework.interfaces.base import base -class TerminationManager(object): +class TerminationManager(six.with_metaclass(abc.ABCMeta)): """An object responsible for handling the termination of an operation. Attributes: outcome: None if the operation is active or a base.Outcome value if it has terminated. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def add_callback(self, callback): @@ -105,9 +106,8 @@ class TerminationManager(object): raise NotImplementedError() -class TransmissionManager(object): +class TransmissionManager(six.with_metaclass(abc.ABCMeta)): """A manager responsible for transmitting to the other end of an operation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def kick_off( @@ -171,9 +171,8 @@ class TransmissionManager(object): raise NotImplementedError() -class ExpirationManager(object): +class ExpirationManager(six.with_metaclass(abc.ABCMeta)): """A manager responsible for aborting the operation if it runs out of time.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def change_timeout(self, timeout): @@ -203,9 +202,8 @@ class ExpirationManager(object): raise NotImplementedError() -class ProtocolManager(object): +class ProtocolManager(six.with_metaclass(abc.ABCMeta)): """A manager of protocol-specific values passing through an operation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_protocol_receiver(self, protocol_receiver): @@ -228,9 +226,8 @@ class ProtocolManager(object): raise NotImplementedError() -class EmissionManager(base.Operator): +class EmissionManager(six.with_metaclass(abc.ABCMeta, base.Operator)): """A manager of values emitted by customer code.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def advance( @@ -254,14 +251,13 @@ class EmissionManager(base.Operator): raise NotImplementedError() -class IngestionManager(object): +class IngestionManager(six.with_metaclass(abc.ABCMeta)): """A manager responsible for executing customer code. This name of this manager comes from its responsibility to pass successive values from the other side of the operation into the code of the local customer. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_group_and_method(self, group, method): @@ -294,9 +290,8 @@ class IngestionManager(object): raise NotImplementedError() -class ReceptionManager(object): +class ReceptionManager(six.with_metaclass(abc.ABCMeta)): """A manager responsible for receiving tickets from the other end.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def receive_ticket(self, ticket): @@ -308,7 +303,7 @@ class ReceptionManager(object): raise NotImplementedError() -class Operation(object): +class Operation(six.with_metaclass(abc.ABCMeta)): """An ongoing operation. Attributes: @@ -316,7 +311,6 @@ class Operation(object): operator: A base.Operator object for the operation for use by the customer of the operation. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def handle_ticket(self, ticket): diff --git a/src/python/grpcio/grpc/framework/core/_termination.py b/src/python/grpcio/grpc/framework/core/_termination.py index 364158b2b8..e8c4ec60a3 100644 --- a/src/python/grpcio/grpc/framework/core/_termination.py +++ b/src/python/grpcio/grpc/framework/core/_termination.py @@ -31,6 +31,8 @@ import abc +import six + from grpc.framework.core import _constants from grpc.framework.core import _interfaces from grpc.framework.core import _utilities @@ -50,9 +52,8 @@ def _service_completion_predicate( return transmission_complete and ingestion_complete -class TerminationManager(_interfaces.TerminationManager): +class TerminationManager(six.with_metaclass(abc.ABCMeta, _interfaces.TerminationManager)): """A _interfaces.TransmissionManager on which another manager may be set.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_expiration_manager(self, expiration_manager): diff --git a/src/python/grpcio/grpc/framework/crust/_control.py b/src/python/grpcio/grpc/framework/crust/_control.py index 5e9efdf732..c27fc9106d 100644 --- a/src/python/grpcio/grpc/framework/crust/_control.py +++ b/src/python/grpcio/grpc/framework/crust/_control.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -405,6 +405,9 @@ class Rendezvous(base.Operator, future.Future, stream.Consumer, face.Call): def __iter__(self): return self + def __next__(self): + return self.next() + def next(self): with self._condition: while True: diff --git a/src/python/grpcio/grpc/framework/crust/implementations.py b/src/python/grpcio/grpc/framework/crust/implementations.py index 4ebc4e9ae8..d0ecafcaf6 100644 --- a/src/python/grpcio/grpc/framework/crust/implementations.py +++ b/src/python/grpcio/grpc/framework/crust/implementations.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -29,6 +29,8 @@ """Entry points into the Crust layer of RPC Framework.""" +import six + from grpc.framework.common import cardinality from grpc.framework.common import style from grpc.framework.crust import _calls @@ -271,7 +273,7 @@ class _DynamicStub(face.DynamicStub): def _adapt_method_implementations(method_implementations, pool): adapted_implementations = {} - for name, method_implementation in method_implementations.iteritems(): + for name, method_implementation in six.iteritems(method_implementations): if method_implementation.style is style.Service.INLINE: if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY: adapted_implementations[name] = _service.adapt_inline_unary_unary( diff --git a/src/python/grpcio/grpc/framework/face/_control.py b/src/python/grpcio/grpc/framework/face/_control.py index e918907b74..ec43203a25 100644 --- a/src/python/grpcio/grpc/framework/face/_control.py +++ b/src/python/grpcio/grpc/framework/face/_control.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -120,6 +120,9 @@ class Rendezvous(stream.Consumer): def __iter__(self): return self + def __next__(self): + return self.next() + def next(self): with self._condition: while ((self._abortion is None) and diff --git a/src/python/grpcio/grpc/framework/face/exceptions.py b/src/python/grpcio/grpc/framework/face/exceptions.py index f112df70bc..c272ac75ab 100644 --- a/src/python/grpcio/grpc/framework/face/exceptions.py +++ b/src/python/grpcio/grpc/framework/face/exceptions.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,6 +31,8 @@ import abc +import six + class NoSuchMethodError(Exception): """Raised by customer code to indicate an unrecognized RPC method name. @@ -49,12 +51,11 @@ class NoSuchMethodError(Exception): self.name = name -class RpcError(Exception): +class RpcError(six.with_metaclass(abc.ABCMeta, Exception)): """Common super type for all exceptions raised by the Face layer. Only RPC Framework should instantiate and raise these exceptions. """ - __metaclass__ = abc.ABCMeta class CancellationError(RpcError): diff --git a/src/python/grpcio/grpc/framework/face/implementations.py b/src/python/grpcio/grpc/framework/face/implementations.py index 4a6de52974..9c75a5faf4 100644 --- a/src/python/grpcio/grpc/framework/face/implementations.py +++ b/src/python/grpcio/grpc/framework/face/implementations.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -29,6 +29,8 @@ """Entry points into the Face layer of RPC Framework.""" +import six + from grpc.framework.common import cardinality from grpc.framework.common import style from grpc.framework.base import exceptions as _base_exceptions @@ -228,7 +230,7 @@ class _DynamicStub(interfaces.DynamicStub): def _adapt_method_implementations(method_implementations, pool): adapted_implementations = {} - for name, method_implementation in method_implementations.iteritems(): + for name, method_implementation in six.iteritems(method_implementations): if method_implementation.style is style.Service.INLINE: if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY: adapted_implementations[name] = _service.adapt_inline_value_in_value_out( diff --git a/src/python/grpcio/grpc/framework/face/interfaces.py b/src/python/grpcio/grpc/framework/face/interfaces.py index b7cc4c1169..9fc18d73bc 100644 --- a/src/python/grpcio/grpc/framework/face/interfaces.py +++ b/src/python/grpcio/grpc/framework/face/interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import abc import enum +import six + # cardinality, style, exceptions, abandonment, future, and stream are # referenced from specification in this module. from grpc.framework.common import cardinality # pylint: disable=unused-import @@ -52,15 +54,17 @@ class Abortion(enum.Enum): SERVICER_FAILURE = 'servicer failure' -class CancellableIterator(object): +class CancellableIterator(six.with_metaclass(abc.ABCMeta)): """Implements the Iterator protocol and affords a cancel method.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __iter__(self): """Returns the self object in accordance with the Iterator protocol.""" raise NotImplementedError() + def __next__(self): + return self.next() + @abc.abstractmethod def next(self): """Returns a value or raises StopIteration per the Iterator protocol.""" @@ -72,9 +76,8 @@ class CancellableIterator(object): raise NotImplementedError() -class RpcContext(object): +class RpcContext(six.with_metaclass(abc.ABCMeta)): """Provides RPC-related information and action.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def is_active(self): @@ -103,13 +106,12 @@ class RpcContext(object): raise NotImplementedError() -class Call(object): +class Call(six.with_metaclass(abc.ABCMeta)): """Invocation-side representation of an RPC. Attributes: context: An RpcContext affording information about the RPC. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def cancel(self): @@ -117,9 +119,8 @@ class Call(object): raise NotImplementedError() -class UnaryUnaryMultiCallable(object): +class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)): """Affords invoking a unary-unary RPC in any call style.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request, timeout): @@ -171,9 +172,8 @@ class UnaryUnaryMultiCallable(object): raise NotImplementedError() -class UnaryStreamMultiCallable(object): +class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)): """Affords invoking a unary-stream RPC in any call style.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request, timeout): @@ -209,9 +209,8 @@ class UnaryStreamMultiCallable(object): raise NotImplementedError() -class StreamUnaryMultiCallable(object): +class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)): """Affords invoking a stream-unary RPC in any call style.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request_iterator, timeout): @@ -264,9 +263,8 @@ class StreamUnaryMultiCallable(object): raise NotImplementedError() -class StreamStreamMultiCallable(object): +class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)): """Affords invoking a stream-stream RPC in any call style.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request_iterator, timeout): @@ -302,7 +300,7 @@ l Args: raise NotImplementedError() -class MethodImplementation(object): +class MethodImplementation(six.with_metaclass(abc.ABCMeta)): """A sum type that describes an RPC method implementation. Attributes: @@ -347,12 +345,10 @@ class MethodImplementation(object): is cardinality.Cardinality.STREAM_STREAM and style is style.Service.EVENT. """ - __metaclass__ = abc.ABCMeta -class MultiMethodImplementation(object): +class MultiMethodImplementation(six.with_metaclass(abc.ABCMeta)): """A general type able to service many RPC methods.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, name, response_consumer, context): @@ -381,9 +377,8 @@ class MultiMethodImplementation(object): raise NotImplementedError() -class GenericStub(object): +class GenericStub(six.with_metaclass(abc.ABCMeta)): """Affords RPC methods to callers.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def blocking_value_in_value_out(self, name, request, timeout): @@ -622,7 +617,7 @@ class GenericStub(object): raise NotImplementedError() -class DynamicStub(object): +class DynamicStub(six.with_metaclass(abc.ABCMeta)): """A stub with RPC-method-bound multi-callable attributes. Instances of this type responsd to attribute access as follows: if the @@ -637,4 +632,3 @@ class DynamicStub(object): the attribute will be a StreamStreamMultiCallable with which to invoke the RPC method. """ - __metaclass__ = abc.ABCMeta diff --git a/src/python/grpcio/grpc/framework/foundation/activated.py b/src/python/grpcio/grpc/framework/foundation/activated.py index 426a71c705..9b49b6363c 100644 --- a/src/python/grpcio/grpc/framework/foundation/activated.py +++ b/src/python/grpcio/grpc/framework/foundation/activated.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,14 +31,14 @@ import abc +import six -class Activated(object): +class Activated(six.with_metaclass(abc.ABCMeta)): """Interface for objects that may be started and stopped. Values implementing this type must also implement the context manager protocol. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __enter__(self): diff --git a/src/python/grpcio/grpc/framework/foundation/callable_util.py b/src/python/grpcio/grpc/framework/foundation/callable_util.py index 32b0751a01..e0a4cab738 100644 --- a/src/python/grpcio/grpc/framework/foundation/callable_util.py +++ b/src/python/grpcio/grpc/framework/foundation/callable_util.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -35,8 +35,10 @@ import enum import functools import logging +import six -class Outcome(object): + +class Outcome(six.with_metaclass(abc.ABCMeta)): """A sum type describing the outcome of some call. Attributes: @@ -47,7 +49,6 @@ class Outcome(object): exception: The exception raised by the call. Must be present if kind is Kind.RAISED. """ - __metaclass__ = abc.ABCMeta @enum.unique class Kind(enum.Enum): diff --git a/src/python/grpcio/grpc/framework/foundation/future.py b/src/python/grpcio/grpc/framework/foundation/future.py index bfc16fc1ea..bb8ee3ad87 100644 --- a/src/python/grpcio/grpc/framework/foundation/future.py +++ b/src/python/grpcio/grpc/framework/foundation/future.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -49,6 +49,8 @@ built-in-but-only-in-3.3-and-later TimeoutError. import abc +import six + class TimeoutError(Exception): """Indicates that a particular call timed out.""" @@ -58,13 +60,12 @@ class CancelledError(Exception): """Indicates that the computation underlying a Future was cancelled.""" -class Future(object): +class Future(six.with_metaclass(abc.ABCMeta)): """A representation of a computation in another control flow. Computations represented by a Future may be yet to be begun, may be ongoing, or may have already completed. """ - __metaclass__ = abc.ABCMeta # NOTE(nathaniel): This isn't the return type that I would want to have if it # were up to me. Were this interface being written from scratch, the return diff --git a/src/python/grpcio/grpc/framework/foundation/relay.py b/src/python/grpcio/grpc/framework/foundation/relay.py index 9c23946552..ff4e2275ae 100644 --- a/src/python/grpcio/grpc/framework/foundation/relay.py +++ b/src/python/grpcio/grpc/framework/foundation/relay.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -46,7 +46,6 @@ class Relay(object): would be no reason to use an implementation of this interface instead of a thread pool. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def add_value(self, value): diff --git a/src/python/grpcio/grpc/framework/foundation/stream.py b/src/python/grpcio/grpc/framework/foundation/stream.py index 75c0cf145b..32a2e52aed 100644 --- a/src/python/grpcio/grpc/framework/foundation/stream.py +++ b/src/python/grpcio/grpc/framework/foundation/stream.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,10 +31,10 @@ import abc +import six -class Consumer(object): +class Consumer(six.with_metaclass(abc.ABCMeta)): """Interface for consumers of finite streams of values or objects.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def consume(self, value): diff --git a/src/python/grpcio/grpc/framework/foundation/stream_util.py b/src/python/grpcio/grpc/framework/foundation/stream_util.py index 2210e4efcf..7d5977fbbd 100644 --- a/src/python/grpcio/grpc/framework/foundation/stream_util.py +++ b/src/python/grpcio/grpc/framework/foundation/stream_util.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -83,6 +83,9 @@ class IterableConsumer(stream.Consumer): def __iter__(self): return self + def __next__(self): + return self.next() + def next(self): with self._condition: while self._active and not self._values: diff --git a/src/python/grpcio/grpc/framework/interfaces/base/base.py b/src/python/grpcio/grpc/framework/interfaces/base/base.py index a1e70be5e8..69be37e7ab 100644 --- a/src/python/grpcio/grpc/framework/interfaces/base/base.py +++ b/src/python/grpcio/grpc/framework/interfaces/base/base.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -42,6 +42,8 @@ import abc import enum import threading # pylint: disable=unused-import +import six + # abandonment is referenced from specification in this module. from grpc.framework.foundation import abandonment # pylint: disable=unused-import @@ -95,7 +97,7 @@ class Outcome(object): REMOTE_FAILURE = 'remote failure' -class Completion(object): +class Completion(six.with_metaclass(abc.ABCMeta)): """An aggregate of the values exchanged upon operation completion. Attributes: @@ -103,12 +105,10 @@ class Completion(object): code: A code value for the operation. message: A message value for the operation. """ - __metaclass__ = abc.ABCMeta -class OperationContext(object): +class OperationContext(six.with_metaclass(abc.ABCMeta)): """Provides operation-related information and action.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def outcome(self): @@ -162,9 +162,8 @@ class OperationContext(object): raise NotImplementedError() -class Operator(object): +class Operator(six.with_metaclass(abc.ABCMeta)): """An interface through which to participate in an operation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def advance( @@ -184,9 +183,8 @@ class Operator(object): """ raise NotImplementedError() -class ProtocolReceiver(object): +class ProtocolReceiver(six.with_metaclass(abc.ABCMeta)): """A means of receiving protocol values during an operation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def context(self, protocol_context): @@ -198,7 +196,7 @@ class ProtocolReceiver(object): raise NotImplementedError() -class Subscription(object): +class Subscription(six.with_metaclass(abc.ABCMeta)): """Describes customer code's interest in values from the other side. Attributes: @@ -216,7 +214,6 @@ class Subscription(object): become available during the operation. Must be non-None if kind is Kind.FULL. """ - __metaclass__ = abc.ABCMeta @enum.unique class Kind(enum.Enum): @@ -226,9 +223,8 @@ class Subscription(object): FULL = 'full' -class Servicer(object): +class Servicer(six.with_metaclass(abc.ABCMeta)): """Interface for service implementations.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, group, method, context, output_operator): @@ -255,9 +251,8 @@ class Servicer(object): raise NotImplementedError() -class End(object): +class End(six.with_metaclass(abc.ABCMeta)): """Common type for entry-point objects on both sides of an operation.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def start(self): diff --git a/src/python/grpcio/grpc/framework/interfaces/face/face.py b/src/python/grpcio/grpc/framework/interfaces/face/face.py index 404c3a7937..b994acecac 100644 --- a/src/python/grpcio/grpc/framework/interfaces/face/face.py +++ b/src/python/grpcio/grpc/framework/interfaces/face/face.py @@ -33,6 +33,8 @@ import abc import collections import enum +import six + # cardinality, style, abandonment, future, and stream are # referenced from specification in this module. from grpc.framework.common import cardinality # pylint: disable=unused-import @@ -96,7 +98,7 @@ class Abortion( REMOTE_FAILURE = 'remote failure' -class AbortionError(Exception): +class AbortionError(six.with_metaclass(abc.ABCMeta, Exception)): """Common super type for exceptions indicating RPC abortion. initial_metadata: The initial metadata from the other side of the RPC or @@ -108,7 +110,6 @@ class AbortionError(Exception): details: The details value from the other side of the RPC or None if no details value was received. """ - __metaclass__ = abc.ABCMeta def __init__(self, initial_metadata, terminal_metadata, code, details): super(AbortionError, self).__init__() @@ -150,9 +151,8 @@ class RemoteError(AbortionError): """Indicates that an RPC has terminated due to a remote defect.""" -class RpcContext(object): +class RpcContext(six.with_metaclass(abc.ABCMeta)): """Provides RPC-related information and action.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def is_active(self): @@ -199,9 +199,8 @@ class RpcContext(object): raise NotImplementedError() -class Call(RpcContext): +class Call(six.with_metaclass(abc.ABCMeta, RpcContext)): """Invocation-side utility object for an RPC.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def initial_metadata(self): @@ -256,9 +255,8 @@ class Call(RpcContext): raise NotImplementedError() -class ServicerContext(RpcContext): +class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)): """A context object passed to method implementations.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def invocation_metadata(self): @@ -326,9 +324,8 @@ class ServicerContext(RpcContext): raise NotImplementedError() -class ResponseReceiver(object): +class ResponseReceiver(six.with_metaclass(abc.ABCMeta)): """Invocation-side object used to accept the output of an RPC.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def initial_metadata(self, initial_metadata): @@ -362,9 +359,8 @@ class ResponseReceiver(object): raise NotImplementedError() -class UnaryUnaryMultiCallable(object): +class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)): """Affords invoking a unary-unary RPC in any call style.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__( @@ -434,9 +430,8 @@ class UnaryUnaryMultiCallable(object): raise NotImplementedError() -class UnaryStreamMultiCallable(object): +class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)): """Affords invoking a unary-stream RPC in any call style.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request, timeout, metadata=None, protocol_options=None): @@ -480,9 +475,8 @@ class UnaryStreamMultiCallable(object): raise NotImplementedError() -class StreamUnaryMultiCallable(object): +class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)): """Affords invoking a stream-unary RPC in any call style.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__( @@ -553,9 +547,8 @@ class StreamUnaryMultiCallable(object): raise NotImplementedError() -class StreamStreamMultiCallable(object): +class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)): """Affords invoking a stream-stream RPC in any call style.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__( @@ -600,7 +593,7 @@ class StreamStreamMultiCallable(object): raise NotImplementedError() -class MethodImplementation(object): +class MethodImplementation(six.with_metaclass(abc.ABCMeta)): """A sum type that describes a method implementation. Attributes: @@ -643,12 +636,10 @@ class MethodImplementation(object): is cardinality.Cardinality.STREAM_STREAM and style is style.Service.EVENT. """ - __metaclass__ = abc.ABCMeta -class MultiMethodImplementation(object): +class MultiMethodImplementation(six.with_metaclass(abc.ABCMeta)): """A general type able to service many methods.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, group, method, response_consumer, context): @@ -678,9 +669,8 @@ class MultiMethodImplementation(object): raise NotImplementedError() -class GenericStub(object): +class GenericStub(six.with_metaclass(abc.ABCMeta)): """Affords RPC invocation via generic methods.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def blocking_unary_unary( @@ -977,7 +967,7 @@ class GenericStub(object): raise NotImplementedError() -class DynamicStub(object): +class DynamicStub(six.with_metaclass(abc.ABCMeta)): """Affords RPC invocation via attributes corresponding to afforded methods. Instances of this type may be scoped to a single group so that attribute @@ -993,4 +983,3 @@ class DynamicStub(object): if the requested attribute is the name of a stream-stream method, the value of the attribute will be a StreamStreamMultiCallable with which to invoke an RPC. """ - __metaclass__ = abc.ABCMeta diff --git a/src/python/grpcio/grpc/framework/interfaces/links/links.py b/src/python/grpcio/grpc/framework/interfaces/links/links.py index 24f0e3b354..808167935f 100644 --- a/src/python/grpcio/grpc/framework/interfaces/links/links.py +++ b/src/python/grpcio/grpc/framework/interfaces/links/links.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,6 +33,8 @@ import abc import collections import enum +import six + class Protocol(collections.namedtuple('Protocol', ('kind', 'value',))): """A sum type for handles to a system that transmits tickets. @@ -123,9 +125,8 @@ class Ticket( REMOTE_FAILURE = 'remote failure' -class Link(object): +class Link(six.with_metaclass(abc.ABCMeta)): """Accepts and emits tickets.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def accept_ticket(self, ticket): diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 31e16e0491..27cd8d60bc 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -76,10 +76,11 @@ CORE_SOURCE_FILES = [ 'src/core/support/wrap_memcpy.c', 'src/core/census/grpc_context.c', 'src/core/census/grpc_filter.c', + 'src/core/census/grpc_plugin.c', 'src/core/channel/channel_args.c', 'src/core/channel/channel_stack.c', + 'src/core/channel/channel_stack_builder.c', 'src/core/channel/client_channel.c', - 'src/core/channel/client_uchannel.c', 'src/core/channel/compress_filter.c', 'src/core/channel/connected_channel.c', 'src/core/channel/http_client_filter.c', @@ -107,9 +108,9 @@ CORE_SOURCE_FILES = [ 'src/core/compression/compression_algorithm.c', 'src/core/compression/message_compress.c', 'src/core/debug/trace.c', - 'src/core/httpcli/format_request.c', - 'src/core/httpcli/httpcli.c', - 'src/core/httpcli/parser.c', + 'src/core/http/format_request.c', + 'src/core/http/httpcli.c', + 'src/core/http/parser.c', 'src/core/iomgr/closure.c', 'src/core/iomgr/endpoint.c', 'src/core/iomgr/endpoint_pair_posix.c', @@ -144,6 +145,8 @@ CORE_SOURCE_FILES = [ 'src/core/iomgr/timer.c', 'src/core/iomgr/timer_heap.c', 'src/core/iomgr/udp_server.c', + 'src/core/iomgr/unix_sockets_posix.c', + 'src/core/iomgr/unix_sockets_posix_noop.c', 'src/core/iomgr/wakeup_fd_eventfd.c', 'src/core/iomgr/wakeup_fd_nospecial.c', 'src/core/iomgr/wakeup_fd_pipe.c', @@ -165,7 +168,9 @@ CORE_SOURCE_FILES = [ 'src/core/surface/channel.c', 'src/core/surface/channel_connectivity.c', 'src/core/surface/channel_create.c', + 'src/core/surface/channel_init.c', 'src/core/surface/channel_ping.c', + 'src/core/surface/channel_stack_type.c', 'src/core/surface/completion_queue.c', 'src/core/surface/event_string.c', 'src/core/surface/init.c', @@ -173,7 +178,6 @@ CORE_SOURCE_FILES = [ 'src/core/surface/metadata_array.c', 'src/core/surface/server.c', 'src/core/surface/server_chttp2.c', - 'src/core/surface/server_create.c', 'src/core/surface/validate_metadata.c', 'src/core/surface/version.c', 'src/core/transport/byte_stream.c', @@ -204,7 +208,7 @@ CORE_SOURCE_FILES = [ 'src/core/transport/static_metadata.c', 'src/core/transport/transport.c', 'src/core/transport/transport_op_string.c', - 'src/core/httpcli/httpcli_security_connector.c', + 'src/core/http/httpcli_security_connector.c', 'src/core/security/b64.c', 'src/core/security/client_auth_filter.c', 'src/core/security/credentials.c', diff --git a/src/python/grpcio/tests/__init__.py b/src/python/grpcio/tests/__init__.py index b76b3985a1..c3b80d766d 100644 --- a/src/python/grpcio/tests/__init__.py +++ b/src/python/grpcio/tests/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,6 +27,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from __future__ import absolute_import + from tests import _loader from tests import _runner diff --git a/src/python/grpcio/tests/_loader.py b/src/python/grpcio/tests/_loader.py index 6992029b5e..2f9e5c660e 100644 --- a/src/python/grpcio/tests/_loader.py +++ b/src/python/grpcio/tests/_loader.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,6 +27,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from __future__ import absolute_import + import importlib import pkgutil import re diff --git a/src/python/grpcio/tests/_result.py b/src/python/grpcio/tests/_result.py index 0670be921f..065153f0c3 100644 --- a/src/python/grpcio/tests/_result.py +++ b/src/python/grpcio/tests/_result.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,7 +27,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import cStringIO as StringIO +from __future__ import absolute_import + import collections import itertools import traceback @@ -35,6 +36,7 @@ import unittest from xml.etree import ElementTree import coverage +from six import moves from tests import _loader @@ -356,7 +358,7 @@ def _traceback_string(type, value, trace): Returns: str: Formatted exception descriptive string. """ - buffer = StringIO.StringIO() + buffer = moves.cStringIO() traceback.print_exception(type, value, trace, file=buffer) return buffer.getvalue() diff --git a/src/python/grpcio/tests/_runner.py b/src/python/grpcio/tests/_runner.py index 3b5ca03dd9..e899154b0b 100644 --- a/src/python/grpcio/tests/_runner.py +++ b/src/python/grpcio/tests/_runner.py @@ -27,7 +27,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import cStringIO as StringIO +from __future__ import absolute_import + import collections import fcntl import multiprocessing @@ -41,6 +42,8 @@ import time import unittest import uuid +from six import moves + from tests import _loader from tests import _result @@ -143,7 +146,7 @@ class Runner(object): for case in filtered_cases] case_id_by_case = dict((augmented_case.case, augmented_case.id) for augmented_case in augmented_cases) - result_out = StringIO.StringIO() + result_out = moves.cStringIO() result = _result.TerminalResult( result_out, id_map=lambda case: case_id_by_case[case]) stdout_pipe = CaptureFile(sys.stdout.fileno()) diff --git a/src/python/grpcio/tests/interop/methods.py b/src/python/grpcio/tests/interop/methods.py index b3591aef7b..1f5561c1f0 100644 --- a/src/python/grpcio/tests/interop/methods.py +++ b/src/python/grpcio/tests/interop/methods.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -173,6 +173,9 @@ class _Pipe(object): def __iter__(self): return self + def __next__(self): + return self.next() + def next(self): with self._condition: while not self._values and self._open: diff --git a/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py index f55a7a23ea..c9f36636b5 100644 --- a/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py +++ b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,12 +32,13 @@ import abc import threading +import six + from tests.unit._junkdrawer import math_pb2 -class ProtoScenario(object): +class ProtoScenario(six.with_metaclass(abc.ABCMeta)): """An RPC test scenario using protocol buffers.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def method(self): diff --git a/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py index efc990421a..881633754c 100644 --- a/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py +++ b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -35,6 +35,8 @@ import random import time import unittest +import six + from grpc._adapter import _intermediary_low from grpc._links import invocation from grpc._links import service @@ -68,7 +70,7 @@ def _serialization_behaviors_from_serializations(serializations): request_deserializers = {} response_serializers = {} response_deserializers = {} - for (group, method), serialization in serializations.iteritems(): + for (group, method), serialization in six.iteritems(serializations): request_serializers[group, method] = serialization.serialize_request request_deserializers[group, method] = serialization.deserialize_request response_serializers[group, method] = serialization.serialize_response diff --git a/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py index 4faaaadc2b..3be3b051fb 100644 --- a/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py +++ b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import collections import unittest +import six + from grpc._adapter import _intermediary_low from grpc._links import invocation from grpc._links import service @@ -59,7 +61,7 @@ def _serialization_behaviors_from_test_methods(test_methods): request_deserializers = {} response_serializers = {} response_deserializers = {} - for (group, method), test_method in test_methods.iteritems(): + for (group, method), test_method in six.iteritems(test_methods): request_serializers[group, method] = test_method.serialize_request request_deserializers[group, method] = test_method.deserialize_request response_serializers[group, method] = test_method.serialize_response @@ -108,7 +110,7 @@ class _Implementation(test_interfaces.Implementation): # _digest.TestServiceDigest. cardinalities = { method: method_object.cardinality() - for (group, method), method_object in methods.iteritems()} + for (group, method), method_object in six.iteritems(methods)} dynamic_stub = crust_implementations.dynamic_stub( invocation_end_link, group, cardinalities, pool) diff --git a/src/python/grpcio/tests/unit/_links/_proto_scenarios.py b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py index f69ff51b16..acd4891390 100644 --- a/src/python/grpcio/tests/unit/_links/_proto_scenarios.py +++ b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,13 +32,14 @@ import abc import threading +import six + from tests.unit._junkdrawer import math_pb2 from tests.unit.framework.common import test_constants -class ProtoScenario(object): +class ProtoScenario(six.with_metaclass(abc.ABCMeta)): """An RPC test scenario using protocol buffers.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def group_and_method(self): diff --git a/src/python/grpcio/tests/unit/beta/_beta_features_test.py b/src/python/grpcio/tests/unit/beta/_beta_features_test.py index ea44177b49..ebdedcc11e 100644 --- a/src/python/grpcio/tests/unit/beta/_beta_features_test.py +++ b/src/python/grpcio/tests/unit/beta/_beta_features_test.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -125,6 +125,9 @@ class _BlockingIterator(object): def __iter__(self): return self + def __next__(self): + return self.next() + def next(self): with self._condition: while True: diff --git a/src/python/grpcio/tests/unit/beta/_face_interface_test.py b/src/python/grpcio/tests/unit/beta/_face_interface_test.py index 1c21dfd03d..cb302bbf68 100644 --- a/src/python/grpcio/tests/unit/beta/_face_interface_test.py +++ b/src/python/grpcio/tests/unit/beta/_face_interface_test.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import collections import unittest +import six + from grpc.beta import implementations from grpc.beta import interfaces from tests.unit import resources @@ -57,7 +59,7 @@ def _serialization_behaviors_from_test_methods(test_methods): request_deserializers = {} response_serializers = {} response_deserializers = {} - for (group, method), test_method in test_methods.iteritems(): + for (group, method), test_method in six.iteritems(test_methods): request_serializers[group, method] = test_method.serialize_request request_deserializers[group, method] = test_method.deserialize_request response_serializers[group, method] = test_method.serialize_response @@ -79,7 +81,7 @@ class _Implementation(test_interfaces.Implementation): # _digest.TestServiceDigest. cardinalities = { method: method_object.cardinality() - for (group, method), method_object in methods.iteritems()} + for (group, method), method_object in six.iteritems(methods)} server_options = implementations.server_options( request_deserializers=serialization_behaviors.request_deserializers, diff --git a/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py index 360ecc95d5..fd2d4298f9 100644 --- a/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py +++ b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import collections import unittest +import six + from grpc.framework.core import implementations as core_implementations from grpc.framework.crust import implementations as crust_implementations from grpc.framework.foundation import logging_pool @@ -66,7 +68,7 @@ class _Implementation(test_interfaces.Implementation): # _digest.TestServiceDigest. cardinalities = { method: method_object.cardinality() - for (group, method), method_object in methods.iteritems()} + for (group, method), method_object in six.iteritems(methods)} dynamic_stub = crust_implementations.dynamic_stub( invocation_end_link, group, cardinalities, pool) diff --git a/src/python/grpcio/tests/unit/framework/common/test_control.py b/src/python/grpcio/tests/unit/framework/common/test_control.py index 8d6eba5c2c..0387668b11 100644 --- a/src/python/grpcio/tests/unit/framework/common/test_control.py +++ b/src/python/grpcio/tests/unit/framework/common/test_control.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,6 +33,8 @@ import abc import contextlib import threading +import six + class Defect(Exception): """Simulates a programming defect raised into in a system under test. @@ -42,7 +44,7 @@ class Defect(Exception): """ -class Control(object): +class Control(six.with_metaclass(abc.ABCMeta)): """An object that accepts program control from a system under test. Systems under test passed a Control should call its control() method @@ -51,8 +53,6 @@ class Control(object): the system under test to simulate hanging, failing, or functioning. """ - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def control(self): """Potentially does anything.""" diff --git a/src/python/grpcio/tests/unit/framework/common/test_coverage.py b/src/python/grpcio/tests/unit/framework/common/test_coverage.py index a7ed3582c4..184621fb5c 100644 --- a/src/python/grpcio/tests/unit/framework/common/test_coverage.py +++ b/src/python/grpcio/tests/unit/framework/common/test_coverage.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,13 +31,14 @@ import abc +import six + # This code is designed for use with the unittest module. # pylint: disable=invalid-name -class Coverage(object): +class Coverage(six.with_metaclass(abc.ABCMeta)): """Specification of test coverage.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def testSuccessfulUnaryRequestUnaryResponse(self): diff --git a/src/python/grpcio/tests/unit/framework/face/testing/base_util.py b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py index 1df1529b27..60ab5bc0fe 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/base_util.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,6 +31,8 @@ import abc +import six + # interfaces is referenced from specification in this module. from grpc.framework.base import util as _base_util from grpc.framework.base import implementations @@ -43,7 +45,7 @@ _POOL_SIZE_LIMIT = 5 _MAXIMUM_TIMEOUT = 90 -class LinkedPair(object): +class LinkedPair(six.with_metaclass(abc.ABCMeta)): """A Front and Back that are linked to one another. Attributes: @@ -51,8 +53,6 @@ class LinkedPair(object): back: An interfaces.Back. """ - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def shut_down(self): """Shuts down this object and releases its resources.""" diff --git a/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py index 0613516421..b0b00bfa81 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,6 +33,8 @@ import abc import unittest # pylint: disable=unused-import +import six + from grpc.framework.face import exceptions from tests.unit.framework.common import test_constants from tests.unit.framework.face.testing import control @@ -43,12 +45,12 @@ from tests.unit.framework.face.testing import test_case class BlockingInvocationInlineServiceTestCase( - test_case.FaceTestCase, coverage.BlockingCoverage): + six.with_metaclass(abc.ABCMeta, + test_case.FaceTestCase, coverage.BlockingCoverage)): """A test of the Face layer of RPC Framework. Concrete subclasses must also extend unittest.TestCase. """ - __metaclass__ = abc.ABCMeta def setUp(self): """See unittest.TestCase.setUp for full specification. @@ -72,7 +74,7 @@ class BlockingInvocationInlineServiceTestCase( def testSuccessfulUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -83,7 +85,7 @@ class BlockingInvocationInlineServiceTestCase( def testSuccessfulUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -95,7 +97,7 @@ class BlockingInvocationInlineServiceTestCase( def testSuccessfulStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -106,7 +108,7 @@ class BlockingInvocationInlineServiceTestCase( def testSuccessfulStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -118,7 +120,7 @@ class BlockingInvocationInlineServiceTestCase( def testSequentialInvocations(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() @@ -135,7 +137,7 @@ class BlockingInvocationInlineServiceTestCase( def testExpiredUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -146,7 +148,7 @@ class BlockingInvocationInlineServiceTestCase( def testExpiredUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -158,7 +160,7 @@ class BlockingInvocationInlineServiceTestCase( def testExpiredStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -169,7 +171,7 @@ class BlockingInvocationInlineServiceTestCase( def testExpiredStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -181,7 +183,7 @@ class BlockingInvocationInlineServiceTestCase( def testFailedUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -191,7 +193,7 @@ class BlockingInvocationInlineServiceTestCase( def testFailedUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -202,7 +204,7 @@ class BlockingInvocationInlineServiceTestCase( def testFailedStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -212,7 +214,7 @@ class BlockingInvocationInlineServiceTestCase( def testFailedStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() diff --git a/src/python/grpcio/tests/unit/framework/face/testing/control.py b/src/python/grpcio/tests/unit/framework/face/testing/control.py index 3960c4e649..0d40331e19 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/control.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/control.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,8 +33,10 @@ import abc import contextlib import threading +import six -class Control(object): + +class Control(six.with_metaclass(abc.ABCMeta)): """An object that accepts program control from a system under test. Systems under test passed a Control should call its control() method @@ -43,8 +45,6 @@ class Control(object): the system under test to simulate hanging, failing, or functioning. """ - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def control(self): """Potentially does anything.""" diff --git a/src/python/grpcio/tests/unit/framework/face/testing/coverage.py b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py index f3aca113fe..9f5381069d 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/coverage.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,15 +31,15 @@ import abc +import six + # These classes are only valid when inherited by unittest.TestCases. # pylint: disable=invalid-name -class BlockingCoverage(object): +class BlockingCoverage(six.with_metaclass(abc.ABCMeta)): """Specification of test coverage for blocking behaviors.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def testSuccessfulUnaryRequestUnaryResponse(self): raise NotImplementedError() @@ -93,11 +93,9 @@ class BlockingCoverage(object): raise NotImplementedError() -class FullCoverage(BlockingCoverage): +class FullCoverage(six.with_metaclass(abc.ABCMeta, BlockingCoverage)): """Specification of test coverage for non-blocking behaviors.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def testParallelInvocations(self): raise NotImplementedError() diff --git a/src/python/grpcio/tests/unit/framework/face/testing/digest.py b/src/python/grpcio/tests/unit/framework/face/testing/digest.py index 39f28b9657..100067cc83 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/digest.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/digest.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import collections import threading +import six + # testing_control, interfaces, and testing_service are referenced from # specification in this module. from grpc.framework.common import cardinality @@ -368,7 +370,7 @@ def _assemble( events = {} adaptations = {} messages = {} - for name, scenario in scenarios.iteritems(): + for name, scenario in six.iteritems(scenarios): if name in names: raise ValueError('Repeated name "%s"!' % name) diff --git a/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py index 179f3a2f67..db901cfe4e 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import abc import unittest +import six + from grpc.framework.face import interfaces from tests.unit.framework.common import test_constants from tests.unit.framework.face.testing import callback as testing_callback @@ -43,12 +45,12 @@ from tests.unit.framework.face.testing import test_case class EventInvocationSynchronousEventServiceTestCase( - test_case.FaceTestCase, coverage.FullCoverage): + six.with_metaclass(abc.ABCMeta, + test_case.FaceTestCase, coverage.FullCoverage)): """A test of the Face layer of RPC Framework. Concrete subclasses must also extend unittest.TestCase. """ - __metaclass__ = abc.ABCMeta def setUp(self): """See unittest.TestCase.setUp for full specification. @@ -72,7 +74,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testSuccessfulUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() @@ -87,7 +89,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testSuccessfulUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() @@ -102,7 +104,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testSuccessfulStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() @@ -120,7 +122,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testSuccessfulStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() @@ -138,7 +140,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testSequentialInvocations(self): # pylint: disable=cell-var-from-loop for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() @@ -163,7 +165,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testExpiredUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() @@ -178,7 +180,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testExpiredUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() @@ -193,7 +195,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testExpiredStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for unused_test_messages in test_messages_sequence: callback = testing_callback.Callback() @@ -206,7 +208,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testExpiredStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() @@ -221,7 +223,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testFailedUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() @@ -237,7 +239,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testFailedUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() @@ -253,7 +255,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testFailedStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() @@ -272,7 +274,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testFailedStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() @@ -289,7 +291,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testParallelInvocations(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: first_request = test_messages.request() first_callback = testing_callback.Callback() @@ -316,7 +318,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testCancelledUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() @@ -332,7 +334,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testCancelledUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() @@ -347,7 +349,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testCancelledStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() @@ -364,7 +366,7 @@ class EventInvocationSynchronousEventServiceTestCase( def testCancelledStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for unused_test_messages in test_messages_sequence: callback = testing_callback.Callback() diff --git a/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py index 485524a356..d8706aa39e 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -34,6 +34,8 @@ import contextlib import threading import unittest +import six + from grpc.framework.face import exceptions from grpc.framework.foundation import future from grpc.framework.foundation import logging_pool @@ -66,6 +68,9 @@ class _PauseableIterator(object): def __iter__(self): return self + def __next__(self): + return self.next() + def next(self): with self._condition: while self._paused: @@ -74,12 +79,12 @@ class _PauseableIterator(object): class FutureInvocationAsynchronousEventServiceTestCase( - test_case.FaceTestCase, coverage.FullCoverage): + six.with_metaclass(abc.ABCMeta, + test_case.FaceTestCase, coverage.FullCoverage)): """A test of the Face layer of RPC Framework. Concrete subclasses must also extend unittest.TestCase. """ - __metaclass__ = abc.ABCMeta def setUp(self): """See unittest.TestCase.setUp for full specification. @@ -105,7 +110,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testSuccessfulUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -117,7 +122,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testSuccessfulUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -129,7 +134,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testSuccessfulStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() request_iterator = _PauseableIterator(iter(requests)) @@ -145,7 +150,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testSuccessfulStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() request_iterator = _PauseableIterator(iter(requests)) @@ -161,7 +166,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testSequentialInvocations(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() @@ -180,7 +185,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testExpiredUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -195,7 +200,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testExpiredUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -207,7 +212,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testExpiredStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -222,7 +227,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testExpiredStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -234,7 +239,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testFailedUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -253,7 +258,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testFailedUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -268,7 +273,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testFailedStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -287,7 +292,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testFailedStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -302,7 +307,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testParallelInvocations(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() @@ -324,7 +329,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testCancelledUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -338,7 +343,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testCancelledUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -352,7 +357,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testCancelledStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( - self.digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -366,7 +371,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( def testCancelledStreamRequestStreamResponse(self): for name, test_messages_sequence in ( - self.digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self.digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() diff --git a/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py index 5932dabf1e..87be836e2d 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,13 +31,14 @@ import abc +import six + # cardinality is referenced from specification in this module. from grpc.framework.common import cardinality # pylint: disable=unused-import -class Method(object): +class Method(six.with_metaclass(abc.ABCMeta)): """An RPC method to be used in tests of RPC implementations.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def name(self): diff --git a/src/python/grpcio/tests/unit/framework/face/testing/service.py b/src/python/grpcio/tests/unit/framework/face/testing/service.py index ac0b89b6ee..dc0f204c04 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/service.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/service.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,16 +31,16 @@ import abc +import six + # interfaces is referenced from specification in this module. from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import from tests.unit.framework.face.testing import interfaces -class UnaryUnaryTestMethodImplementation(interfaces.Method): +class UnaryUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)): """A controllable implementation of a unary-unary RPC method.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def service(self, request, response_callback, context, control): """Services an RPC that accepts one message and produces one message. @@ -59,11 +59,9 @@ class UnaryUnaryTestMethodImplementation(interfaces.Method): raise NotImplementedError() -class UnaryUnaryTestMessages(object): +class UnaryUnaryTestMessages(six.with_metaclass(abc.ABCMeta)): """A type for unary-request-unary-response message pairings.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def request(self): """Affords a request message. @@ -93,11 +91,9 @@ class UnaryUnaryTestMessages(object): raise NotImplementedError() -class UnaryStreamTestMethodImplementation(interfaces.Method): +class UnaryStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)): """A controllable implementation of a unary-stream RPC method.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def service(self, request, response_consumer, context, control): """Services an RPC that takes one message and produces a stream of messages. @@ -116,11 +112,9 @@ class UnaryStreamTestMethodImplementation(interfaces.Method): raise NotImplementedError() -class UnaryStreamTestMessages(object): +class UnaryStreamTestMessages(six.with_metaclass(abc.ABCMeta)): """A type for unary-request-stream-response message pairings.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def request(self): """Affords a request message. @@ -150,11 +144,9 @@ class UnaryStreamTestMessages(object): raise NotImplementedError() -class StreamUnaryTestMethodImplementation(interfaces.Method): +class StreamUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)): """A controllable implementation of a stream-unary RPC method.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def service(self, response_callback, context, control): """Services an RPC that takes a stream of messages and produces one message. @@ -180,11 +172,9 @@ class StreamUnaryTestMethodImplementation(interfaces.Method): raise NotImplementedError() -class StreamUnaryTestMessages(object): +class StreamUnaryTestMessages(six.with_metaclass(abc.ABCMeta)): """A type for stream-request-unary-response message pairings.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def requests(self): """Affords a sequence of request messages. @@ -214,11 +204,9 @@ class StreamUnaryTestMessages(object): raise NotImplementedError() -class StreamStreamTestMethodImplementation(interfaces.Method): +class StreamStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)): """A controllable implementation of a stream-stream RPC method.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def service(self, response_consumer, context, control): """Services an RPC that accepts and produces streams of messages. @@ -244,11 +232,9 @@ class StreamStreamTestMethodImplementation(interfaces.Method): raise NotImplementedError() -class StreamStreamTestMessages(object): +class StreamStreamTestMessages(six.with_metaclass(abc.ABCMeta)): """A type for stream-request-stream-response message pairings.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def requests(self): """Affords a sequence of request messages. @@ -278,11 +264,9 @@ class StreamStreamTestMessages(object): raise NotImplementedError() -class TestService(object): +class TestService(six.with_metaclass(abc.ABCMeta)): """A specification of implemented RPC methods to use in tests.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def name(self): """Identifies the RPC service name used during the test. diff --git a/src/python/grpcio/tests/unit/framework/face/testing/test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py index 23d4d919c2..5be9330a77 100644 --- a/src/python/grpcio/tests/unit/framework/face/testing/test_case.py +++ b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,18 +31,19 @@ import abc +import six + # face_interfaces and interfaces are referenced in specification in this module. from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import from tests.unit.framework.face.testing import interfaces # pylint: disable=unused-import -class FaceTestCase(object): +class FaceTestCase(six.with_metaclass(abc.ABCMeta)): """Describes a test of the Face Layer of RPC Framework. Concrete subclasses must also inherit from unittest.TestCase and from at least one class that defines test methods. """ - __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_up_implementation( diff --git a/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py index 38102b198a..fe69e63995 100644 --- a/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -36,6 +36,8 @@ import random # pylint: disable=unused-import import threading import time +import six + from grpc.framework.interfaces.base import base from tests.unit.framework.common import test_constants from tests.unit.framework.interfaces.base import _sequence @@ -247,8 +249,7 @@ class Instruction( CONCLUDE = 'CONCLUDE' -class Controller(object): - __metaclass__ = abc.ABCMeta +class Controller(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def failed(self, message): @@ -308,8 +309,7 @@ class Controller(object): raise NotImplementedError() -class ControllerCreator(object): - __metaclass__ = abc.ABCMeta +class ControllerCreator(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def name(self): diff --git a/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py index 84afd24d47..0594cfeb31 100644 --- a/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,12 +31,13 @@ import abc +import six + from grpc.framework.interfaces.base import base # pylint: disable=unused-import -class Serialization(object): +class Serialization(six.with_metaclass(abc.ABCMeta)): """Specifies serialization and deserialization of test payloads.""" - __metaclass__ = abc.ABCMeta def serialize_request(self, request): """Serializes a request value used in a test. @@ -85,9 +86,8 @@ class Serialization(object): raise NotImplementedError() -class Implementation(object): +class Implementation(six.with_metaclass(abc.ABCMeta)): """Specifies an implementation of the Base layer.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def instantiate(self, serializations, servicer): diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py index c8a3a1bc74..530ba4ff0f 100644 --- a/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py @@ -34,6 +34,8 @@ import itertools import unittest from concurrent import futures +import six + # test_interfaces is referenced from specification in this module. from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.face import face @@ -46,14 +48,13 @@ from tests.unit.framework.interfaces.face import _stock_service from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import -class TestCase(test_coverage.Coverage, unittest.TestCase): +class TestCase(six.with_metaclass(abc.ABCMeta, test_coverage.Coverage, unittest.TestCase)): """A test of the Face layer of RPC Framework. Concrete subclasses must have an "implementation" attribute of type test_interfaces.Implementation and an "invoker_constructor" attribute of type _invocation.InvokerConstructor. """ - __metaclass__ = abc.ABCMeta NAME = 'BlockingInvocationInlineServiceTest' @@ -81,7 +82,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSuccessfulUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -92,7 +93,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSuccessfulUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -104,7 +105,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSuccessfulStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -115,7 +116,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSuccessfulStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -127,7 +128,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSequentialInvocations(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() @@ -145,7 +146,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testParallelInvocations(self): pool = logging_pool.pool(test_constants.PARALLELISM) for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = [] response_futures = [] @@ -167,7 +168,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testWaitingForSomeButNotAllParallelInvocations(self): pool = logging_pool.pool(test_constants.PARALLELISM) for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = [] response_futures_to_indices = {} @@ -205,7 +206,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testExpiredUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -216,7 +217,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testExpiredUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -228,7 +229,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testExpiredStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -239,7 +240,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testExpiredStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -251,7 +252,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testFailedUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -261,7 +262,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testFailedUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -272,7 +273,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testFailedStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -282,7 +283,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testFailedStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py index 9304b6b1db..40c03f9e71 100644 --- a/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ import collections import threading +import six + # test_control, _service, and test_interfaces are referenced from specification # in this module. from grpc.framework.common import cardinality @@ -363,7 +365,7 @@ def _assemble( events = {} adaptations = {} messages = {} - for identifier, scenario in scenarios.iteritems(): + for identifier, scenario in six.iteritems(scenarios): if identifier in identifiers: raise ValueError('Repeated identifier "(%s, %s)"!' % identifier) diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py index 1d36a931e8..89f344c289 100644 --- a/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py @@ -36,6 +36,8 @@ import threading import unittest from concurrent import futures +import six + # test_interfaces is referenced from specification in this module. from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.face import face @@ -67,6 +69,9 @@ class _PauseableIterator(object): def __iter__(self): return self + def __next__(self): + return self.next() + def next(self): with self._condition: while self._paused: @@ -104,14 +109,13 @@ class _Callback(object): self._condition.wait() -class TestCase(test_coverage.Coverage, unittest.TestCase): +class TestCase(six.with_metaclass(abc.ABCMeta, test_coverage.Coverage, unittest.TestCase)): """A test of the Face layer of RPC Framework. Concrete subclasses must have an "implementation" attribute of type test_interfaces.Implementation and an "invoker_constructor" attribute of type _invocation.InvokerConstructor. """ - __metaclass__ = abc.ABCMeta NAME = 'FutureInvocationAsynchronousEventServiceTest' @@ -141,7 +145,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSuccessfulUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = _Callback() @@ -156,7 +160,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSuccessfulUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -168,7 +172,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSuccessfulStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() request_iterator = _PauseableIterator(iter(requests)) @@ -188,7 +192,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSuccessfulStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() request_iterator = _PauseableIterator(iter(requests)) @@ -204,7 +208,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testSequentialInvocations(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() @@ -223,7 +227,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testParallelInvocations(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() @@ -239,7 +243,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): test_messages.verify(second_request, second_response, self) for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = [] response_futures = [] @@ -259,7 +263,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testWaitingForSomeButNotAllParallelInvocations(self): pool = logging_pool.pool(test_constants.PARALLELISM) for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = [] response_futures_to_indices = {} @@ -281,7 +285,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testCancelledUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = _Callback() @@ -298,7 +302,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testCancelledUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -312,7 +316,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testCancelledStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = _Callback() @@ -329,7 +333,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testCancelledStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -343,7 +347,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testExpiredUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = _Callback() @@ -360,7 +364,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testExpiredUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -372,7 +376,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testExpiredStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = _Callback() @@ -389,7 +393,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testExpiredStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() @@ -401,7 +405,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testFailedUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_unary_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() callback = _Callback() @@ -423,7 +427,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testFailedUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.unary_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.unary_stream_messages_sequences)): for test_messages in test_messages_sequence: request = test_messages.request() @@ -438,7 +442,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testFailedStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_unary_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_unary_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = _Callback() @@ -460,7 +464,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): def testFailedStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( - self._digest.stream_stream_messages_sequences.iteritems()): + six.iteritems(self._digest.stream_stream_messages_sequences)): for test_messages in test_messages_sequence: requests = test_messages.requests() diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py index 448e845a08..ff38dc2ece 100644 --- a/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,6 +31,8 @@ import abc +import six + from grpc.framework.common import cardinality _CARDINALITY_TO_GENERIC_BLOCKING_BEHAVIOR = { @@ -62,9 +64,8 @@ _CARDINALITY_TO_MULTI_CALLABLE_ATTRIBUTE = { } -class Invoker(object): +class Invoker(six.with_metaclass(abc.ABCMeta)): """A type used to invoke test RPCs.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def blocking(self, group, name): @@ -82,9 +83,8 @@ class Invoker(object): raise NotImplementedError() -class InvokerConstructor(object): +class InvokerConstructor(six.with_metaclass(abc.ABCMeta)): """A type used to create Invokers.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def name(self): diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py index 28941e2ad0..bec8d5113c 100644 --- a/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,16 +31,16 @@ import abc +import six + # face is referenced from specification in this module. from grpc.framework.interfaces.face import face # pylint: disable=unused-import from tests.unit.framework.interfaces.face import test_interfaces -class UnaryUnaryTestMethodImplementation(test_interfaces.Method): +class UnaryUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, test_interfaces.Method)): """A controllable implementation of a unary-unary method.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def service(self, request, response_callback, context, control): """Services an RPC that accepts one message and produces one message. @@ -59,11 +59,9 @@ class UnaryUnaryTestMethodImplementation(test_interfaces.Method): raise NotImplementedError() -class UnaryUnaryTestMessages(object): +class UnaryUnaryTestMessages(six.with_metaclass(abc.ABCMeta)): """A type for unary-request-unary-response message pairings.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def request(self): """Affords a request message. @@ -93,11 +91,9 @@ class UnaryUnaryTestMessages(object): raise NotImplementedError() -class UnaryStreamTestMethodImplementation(test_interfaces.Method): +class UnaryStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, test_interfaces.Method)): """A controllable implementation of a unary-stream method.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def service(self, request, response_consumer, context, control): """Services an RPC that takes one message and produces a stream of messages. @@ -116,11 +112,9 @@ class UnaryStreamTestMethodImplementation(test_interfaces.Method): raise NotImplementedError() -class UnaryStreamTestMessages(object): +class UnaryStreamTestMessages(six.with_metaclass(abc.ABCMeta)): """A type for unary-request-stream-response message pairings.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def request(self): """Affords a request message. @@ -150,11 +144,9 @@ class UnaryStreamTestMessages(object): raise NotImplementedError() -class StreamUnaryTestMethodImplementation(test_interfaces.Method): +class StreamUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, test_interfaces.Method)): """A controllable implementation of a stream-unary method.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def service(self, response_callback, context, control): """Services an RPC that takes a stream of messages and produces one message. @@ -180,11 +172,9 @@ class StreamUnaryTestMethodImplementation(test_interfaces.Method): raise NotImplementedError() -class StreamUnaryTestMessages(object): +class StreamUnaryTestMessages(six.with_metaclass(abc.ABCMeta)): """A type for stream-request-unary-response message pairings.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def requests(self): """Affords a sequence of request messages. @@ -214,11 +204,9 @@ class StreamUnaryTestMessages(object): raise NotImplementedError() -class StreamStreamTestMethodImplementation(test_interfaces.Method): +class StreamStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, test_interfaces.Method)): """A controllable implementation of a stream-stream method.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def service(self, response_consumer, context, control): """Services an RPC that accepts and produces streams of messages. @@ -244,11 +232,9 @@ class StreamStreamTestMethodImplementation(test_interfaces.Method): raise NotImplementedError() -class StreamStreamTestMessages(object): +class StreamStreamTestMessages(six.with_metaclass(abc.ABCMeta)): """A type for stream-request-stream-response message pairings.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def requests(self): """Affords a sequence of request messages. @@ -278,11 +264,9 @@ class StreamStreamTestMessages(object): raise NotImplementedError() -class TestService(object): +class TestService(six.with_metaclass(abc.ABCMeta)): """A specification of implemented methods to use in tests.""" - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def unary_unary_scenarios(self): """Affords unary-request-unary-response test methods and their messages. diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py index b2b5c10fa6..a5e28b7942 100644 --- a/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,13 +31,14 @@ import abc +import six + from grpc.framework.common import cardinality # pylint: disable=unused-import from grpc.framework.interfaces.face import face # pylint: disable=unused-import -class Method(object): +class Method(six.with_metaclass(abc.ABCMeta)): """Specifies a method to be used in tests.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def group(self): @@ -126,9 +127,8 @@ class Method(object): raise NotImplementedError() -class Implementation(object): +class Implementation(six.with_metaclass(abc.ABCMeta)): """Specifies an implementation of the Face layer.""" - __metaclass__ = abc.ABCMeta @abc.abstractmethod def instantiate( diff --git a/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py index dace6c23f3..2283e79f0a 100644 --- a/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py +++ b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,6 +33,8 @@ import abc import unittest # pylint: disable=unused-import +import six + from grpc.framework.interfaces.links import links from tests.unit.framework.common import test_constants from tests.unit.framework.interfaces.links import test_utilities @@ -58,13 +60,12 @@ _TRANSMISSION_GROUP = 'test.Group' _TRANSMISSION_METHOD = 'TestMethod' -class TransmissionTest(object): +class TransmissionTest(six.with_metaclass(abc.ABCMeta)): """Tests ticket transmission between two connected links. This class must be mixed into a unittest.TestCase that implements the abstract methods it provides. """ - __metaclass__ = abc.ABCMeta # This is a unittest.TestCase mix-in. # pylint: disable=invalid-name diff --git a/src/python/grpcio/tests/unit/test_common.py b/src/python/grpcio/tests/unit/test_common.py index 29431bfb9d..824f1cbd16 100644 --- a/src/python/grpcio/tests/unit/test_common.py +++ b/src/python/grpcio/tests/unit/test_common.py @@ -1,4 +1,4 @@ -# Copyright 2015, Google Inc. +# Copyright 2015-2016, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,6 +31,8 @@ import collections +import six + INVOCATION_INITIAL_METADATA = ((b'0', b'abc'), (b'1', b'def'), (b'2', b'ghi'),) SERVICE_INITIAL_METADATA = ((b'3', b'jkl'), (b'4', b'mno'), (b'5', b'pqr'),) SERVICE_TERMINAL_METADATA = ((b'6', b'stu'), (b'7', b'vwx'), (b'8', b'yza'),) @@ -65,7 +67,7 @@ def metadata_transmitted(original_metadata, transmitted_metadata): key, value = tuple(key_value_pair) transmitted[key].append(value) - for key, values in original.iteritems(): + for key, values in six.iteritems(original): transmitted_values = transmitted[key] transmitted_iterator = iter(transmitted_values) try: diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index af05ddf6e7..cd0aa6aaf2 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -72,6 +72,10 @@ static ID id_cq; * the flags used to create metadata from a Hash */ static ID id_flags; +/* id_credentials is the name of the hidden ivar that preserves the value + * of the credentials added to the call */ +static ID id_credentials; + /* id_input_md is the name of the hidden ivar that preserves the hash used to * create metadata, so that references to the strings it contains last as long * as the call the metadata is added to. */ @@ -299,6 +303,7 @@ static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) { "grpc_call_set_credentials failed with %s (code=%d)", grpc_call_error_detail_of(err), err); } + rb_ivar_set(self, id_credentials, credentials); return Qnil; } @@ -859,6 +864,7 @@ void Init_grpc_call() { id_cq = rb_intern("__cq"); id_flags = rb_intern("__flags"); id_input_md = rb_intern("__input_md"); + id_credentials = rb_intern("__credentials"); /* Ids used in constructing the batch result. */ sym_send_message = ID2SYM(rb_intern("send_message")); diff --git a/src/ruby/ext/grpc/rb_call_credentials.c b/src/ruby/ext/grpc/rb_call_credentials.c index 2426f106a9..2b978fcdd0 100644 --- a/src/ruby/ext/grpc/rb_call_credentials.c +++ b/src/ruby/ext/grpc/rb_call_credentials.c @@ -41,6 +41,7 @@ #include <grpc/grpc.h> #include <grpc/grpc_security.h> #include <grpc/support/alloc.h> +#include <grpc/support/log.h> #include "rb_call.h" #include "rb_event_thread.h" @@ -50,9 +51,9 @@ * grpc_call_credentials */ static VALUE grpc_rb_cCallCredentials = Qnil; -/* grpc_rb_call_credentials wraps a grpc_call_credentials. It provides a peer - * ruby object, 'mark' to minimize copying when a credential is created from - * ruby. */ +/* grpc_rb_call_credentials wraps a grpc_call_credentials. It provides a mark + * object that is used to hold references to any objects used to create the + * credentials. */ typedef struct grpc_rb_call_credentials { /* Holder of ruby objects involved in contructing the credentials */ VALUE mark; @@ -81,14 +82,23 @@ static VALUE grpc_rb_call_credentials_callback(VALUE callback_args) { static VALUE grpc_rb_call_credentials_callback_rescue(VALUE args, VALUE exception_object) { VALUE result = rb_hash_new(); + VALUE backtrace = rb_funcall( + rb_funcall(exception_object, rb_intern("backtrace"), 0), + rb_intern("join"), + 1, rb_str_new2("\n\tfrom ")); + VALUE exception_info = rb_funcall(exception_object, rb_intern("to_s"), 0); + const char *exception_classname = rb_obj_classname(exception_object); (void)args; + gpr_log(GPR_INFO, "Call credentials callback failed: %s: %s\n%s", + exception_classname, StringValueCStr(exception_info), + StringValueCStr(backtrace)); rb_hash_aset(result, rb_str_new2("metadata"), Qnil); /* Currently only gives the exception class name. It should be possible get more details */ rb_hash_aset(result, rb_str_new2("status"), INT2NUM(GRPC_STATUS_PERMISSION_DENIED)); rb_hash_aset(result, rb_str_new2("details"), - rb_str_new2(rb_obj_classname(exception_object))); + rb_str_new2(exception_classname)); return result; } @@ -146,13 +156,8 @@ static void grpc_rb_call_credentials_free(void *p) { return; } wrapper = (grpc_rb_call_credentials *)p; - - /* Delete the wrapped object if the mark object is Qnil, which indicates that - * no other object is the actual owner. */ - if (wrapper->wrapped != NULL && wrapper->mark == Qnil) { - grpc_call_credentials_release(wrapper->wrapped); - wrapper->wrapped = NULL; - } + grpc_call_credentials_release(wrapper->wrapped); + wrapper->wrapped = NULL; xfree(p); } @@ -164,8 +169,6 @@ static void grpc_rb_call_credentials_mark(void *p) { return; } wrapper = (grpc_rb_call_credentials *)p; - - /* If it's not already cleaned up, mark the mark object */ if (wrapper->mark != Qnil) { rb_gc_mark(wrapper->mark); } @@ -194,7 +197,7 @@ static VALUE grpc_rb_call_credentials_alloc(VALUE cls) { /* Creates a wrapping object for a given call credentials. This should only be * called with grpc_call_credentials objects that are not already associated * with any Ruby object */ -VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c) { +VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c, VALUE mark) { VALUE rb_wrapper; grpc_rb_call_credentials *wrapper; if (c == NULL) { @@ -204,6 +207,7 @@ VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c) { TypedData_Get_Struct(rb_wrapper, grpc_rb_call_credentials, &grpc_rb_call_credentials_data_type, wrapper); wrapper->wrapped = c; + wrapper->mark = mark; return rb_wrapper; } @@ -267,6 +271,7 @@ static VALUE grpc_rb_call_credentials_init(VALUE self, VALUE proc) { return Qnil; } + wrapper->mark = proc; wrapper->wrapped = creds; rb_ivar_set(self, id_callback, proc); @@ -277,15 +282,18 @@ static VALUE grpc_rb_call_credentials_compose(int argc, VALUE *argv, VALUE self) { grpc_call_credentials *creds; grpc_call_credentials *other; + VALUE mark; if (argc == 0) { return self; } + mark = rb_ary_new(); creds = grpc_rb_get_wrapped_call_credentials(self); for (int i = 0; i < argc; i++) { + rb_ary_push(mark, argv[i]); other = grpc_rb_get_wrapped_call_credentials(argv[i]); creds = grpc_composite_call_credentials_create(creds, other, NULL); } - return grpc_rb_wrap_call_credentials(creds); + return grpc_rb_wrap_call_credentials(creds, mark); } void Init_grpc_call_credentials() { diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 0e6badbdaf..e1aaa539db 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -70,11 +70,10 @@ static VALUE grpc_rb_cChannel = Qnil; /* Used during the conversion of a hash to channel args during channel setup */ static VALUE grpc_rb_cChannelArgs; -/* grpc_rb_channel wraps a grpc_channel. It provides a peer ruby object, - * 'mark' to minimize copying when a channel is created from ruby. */ +/* grpc_rb_channel wraps a grpc_channel. */ typedef struct grpc_rb_channel { - /* Holder of ruby objects involved in constructing the channel */ - VALUE mark; + VALUE credentials; + /* The actual channel */ grpc_channel *wrapped; } grpc_rb_channel; @@ -87,13 +86,8 @@ static void grpc_rb_channel_free(void *p) { }; ch = (grpc_rb_channel *)p; - /* Deletes the wrapped object if the mark object is Qnil, which indicates - * that no other object is the actual owner. */ - if (ch->wrapped != NULL && ch->mark == Qnil) { + if (ch->wrapped != NULL) { grpc_channel_destroy(ch->wrapped); - rb_warning("channel gc: destroyed the c channel"); - } else { - rb_warning("channel gc: did not destroy the c channel"); } xfree(p); @@ -106,8 +100,8 @@ static void grpc_rb_channel_mark(void *p) { return; } channel = (grpc_rb_channel *)p; - if (channel->mark != Qnil) { - rb_gc_mark(channel->mark); + if (channel->credentials != Qnil) { + rb_gc_mark(channel->credentials); } } @@ -125,7 +119,7 @@ static rb_data_type_t grpc_channel_data_type = { static VALUE grpc_rb_channel_alloc(VALUE cls) { grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel); wrapper->wrapped = NULL; - wrapper->mark = Qnil; + wrapper->credentials = Qnil; return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper); } @@ -162,6 +156,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { } ch = grpc_insecure_channel_create(target_chars, &args, NULL); } else { + wrapper->credentials = credentials; creds = grpc_rb_get_wrapped_channel_credentials(credentials); ch = grpc_secure_channel_create(creds, target_chars, &args, NULL); } @@ -330,7 +325,6 @@ static VALUE grpc_rb_channel_destroy(VALUE self) { if (ch != NULL) { grpc_channel_destroy(ch); wrapper->wrapped = NULL; - wrapper->mark = Qnil; } return Qnil; diff --git a/src/ruby/ext/grpc/rb_channel_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c index 8c6fc3b7eb..f649084311 100644 --- a/src/ruby/ext/grpc/rb_channel_credentials.c +++ b/src/ruby/ext/grpc/rb_channel_credentials.c @@ -49,8 +49,8 @@ static VALUE grpc_rb_cChannelCredentials = Qnil; /* grpc_rb_channel_credentials wraps a grpc_channel_credentials. It provides a - * peer ruby object, 'mark' to minimize copying when a credential is - * created from ruby. */ + * mark object that is used to hold references to any objects used to create + * the credentials. */ typedef struct grpc_rb_channel_credentials { /* Holder of ruby objects involved in constructing the credentials */ VALUE mark; @@ -66,13 +66,8 @@ static void grpc_rb_channel_credentials_free(void *p) { return; }; wrapper = (grpc_rb_channel_credentials *)p; - - /* Delete the wrapped object if the mark object is Qnil, which indicates that - * no other object is the actual owner. */ - if (wrapper->wrapped != NULL && wrapper->mark == Qnil) { - grpc_channel_credentials_release(wrapper->wrapped); - wrapper->wrapped = NULL; - } + grpc_channel_credentials_release(wrapper->wrapped); + wrapper->wrapped = NULL; xfree(p); } @@ -85,7 +80,6 @@ static void grpc_rb_channel_credentials_mark(void *p) { } wrapper = (grpc_rb_channel_credentials *)p; - /* If it's not already cleaned up, mark the mark object */ if (wrapper->mark != Qnil) { rb_gc_mark(wrapper->mark); } @@ -114,7 +108,7 @@ static VALUE grpc_rb_channel_credentials_alloc(VALUE cls) { /* Creates a wrapping object for a given channel credentials. This should only * be called with grpc_channel_credentials objects that are not already * associated with any Ruby object. */ -VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c) { +VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c, VALUE mark) { VALUE rb_wrapper; grpc_rb_channel_credentials *wrapper; if (c == NULL) { @@ -124,6 +118,7 @@ VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c) { TypedData_Get_Struct(rb_wrapper, grpc_rb_channel_credentials, &grpc_rb_channel_credentials_data_type, wrapper); wrapper->wrapped = c; + wrapper->mark = mark; return rb_wrapper; } @@ -222,11 +217,15 @@ static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv, VALUE self) { grpc_channel_credentials *creds; grpc_call_credentials *other; + VALUE mark; if (argc == 0) { return self; } + mark = rb_ary_new(); + rb_ary_push(mark, self); creds = grpc_rb_get_wrapped_channel_credentials(self); for (int i = 0; i < argc; i++) { + rb_ary_push(mark, argv[i]); other = grpc_rb_get_wrapped_call_credentials(argv[i]); creds = grpc_composite_channel_credentials_create(creds, other, NULL); if (creds == NULL) { @@ -234,7 +233,7 @@ static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv, "Failed to compose channel and call credentials"); } } - return grpc_rb_wrap_channel_credentials(creds); + return grpc_rb_wrap_channel_credentials(creds, mark); } void Init_grpc_channel_credentials() { |