From 714038204a897c4eb7064686181b447f3dfa9da5 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" <roth@google.com> Date: Fri, 2 Dec 2016 10:51:39 -0800 Subject: [PATCH] Use the same server code for both secure and insecure servers. --- BUILD | 8 + CMakeLists.txt | 3 + Makefile | 3 + binding.gyp | 1 + build.yaml | 10 + config.m4 | 2 + gRPC-Core.podspec | 3 + grpc.gemspec | 2 + package.xml | 2 + .../transport/chttp2/server/chttp2_server.c | 355 ++++++++++++++++++ .../transport/chttp2/server/chttp2_server.h | 79 ++++ .../chttp2/server/insecure/server_chttp2.c | 283 +------------- .../server/secure/server_secure_chttp2.c | 346 +++-------------- src/python/grpcio/grpc_core_dependencies.py | 1 + tools/doxygen/Doxyfile.core.internal | 2 + tools/run_tests/sources_and_headers.json | 23 +- vsprojects/vcxproj/grpc/grpc.vcxproj | 3 + vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 6 + .../grpc_unsecure/grpc_unsecure.vcxproj | 3 + .../grpc_unsecure.vcxproj.filters | 6 + 20 files changed, 572 insertions(+), 569 deletions(-) create mode 100644 src/core/ext/transport/chttp2/server/chttp2_server.c create mode 100644 src/core/ext/transport/chttp2/server/chttp2_server.h diff --git a/BUILD b/BUILD index 1ee5fd3dacf..ab0fc237b78 100644 --- a/BUILD +++ b/BUILD @@ -298,6 +298,7 @@ cc_library( "src/core/lib/tsi/ssl_types.h", "src/core/lib/tsi/transport_security.h", "src/core/lib/tsi/transport_security_interface.h", + "src/core/ext/transport/chttp2/server/chttp2_server.h", "src/core/ext/client_channel/client_channel.h", "src/core/ext/client_channel/client_channel_factory.h", "src/core/ext/client_channel/connector.h", @@ -493,6 +494,7 @@ cc_library( "src/core/lib/tsi/fake_transport_security.c", "src/core/lib/tsi/ssl_transport_security.c", "src/core/lib/tsi/transport_security.c", + "src/core/ext/transport/chttp2/server/chttp2_server.c", "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c", "src/core/ext/client_channel/channel_connectivity.c", "src/core/ext/client_channel/client_channel.c", @@ -1101,6 +1103,7 @@ cc_library( "src/core/ext/transport/chttp2/transport/stream_map.h", "src/core/ext/transport/chttp2/transport/varint.h", "src/core/ext/transport/chttp2/alpn/alpn.h", + "src/core/ext/transport/chttp2/server/chttp2_server.h", "src/core/ext/transport/chttp2/client/chttp2_connector.h", "src/core/ext/client_channel/client_channel.h", "src/core/ext/client_channel/client_channel_factory.h", @@ -1271,6 +1274,7 @@ cc_library( "src/core/ext/transport/chttp2/transport/varint.c", "src/core/ext/transport/chttp2/transport/writing.c", "src/core/ext/transport/chttp2/alpn/alpn.c", + "src/core/ext/transport/chttp2/server/chttp2_server.c", "src/core/ext/transport/chttp2/client/insecure/channel_create.c", "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c", "src/core/ext/transport/chttp2/client/chttp2_connector.c", @@ -1655,6 +1659,7 @@ cc_library( "src/core/ext/client_channel/subchannel.h", "src/core/ext/client_channel/subchannel_index.h", "src/core/ext/client_channel/uri_parser.h", + "src/core/ext/transport/chttp2/server/chttp2_server.h", "src/core/ext/census/aggregation.h", "src/core/ext/census/base_resources.h", "src/core/ext/census/census_interface.h", @@ -1856,6 +1861,7 @@ cc_library( "src/core/ext/client_channel/uri_parser.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c", + "src/core/ext/transport/chttp2/server/chttp2_server.c", "src/core/ext/census/base_resources.c", "src/core/ext/census/context.c", "src/core/ext/census/gen/census.pb.c", @@ -2486,6 +2492,7 @@ objc_library( "src/core/lib/tsi/fake_transport_security.c", "src/core/lib/tsi/ssl_transport_security.c", "src/core/lib/tsi/transport_security.c", + "src/core/ext/transport/chttp2/server/chttp2_server.c", "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c", "src/core/ext/client_channel/channel_connectivity.c", "src/core/ext/client_channel/client_channel.c", @@ -2706,6 +2713,7 @@ objc_library( "src/core/lib/tsi/ssl_types.h", "src/core/lib/tsi/transport_security.h", "src/core/lib/tsi/transport_security_interface.h", + "src/core/ext/transport/chttp2/server/chttp2_server.h", "src/core/ext/client_channel/client_channel.h", "src/core/ext/client_channel/client_channel_factory.h", "src/core/ext/client_channel/connector.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 66f740fe288..ff0927504aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -447,6 +447,7 @@ add_library(grpc src/core/lib/tsi/fake_transport_security.c src/core/lib/tsi/ssl_transport_security.c src/core/lib/tsi/transport_security.c + src/core/ext/transport/chttp2/server/chttp2_server.c src/core/ext/transport/chttp2/client/secure/secure_channel_create.c src/core/ext/client_channel/channel_connectivity.c src/core/ext/client_channel/client_channel.c @@ -953,6 +954,7 @@ add_library(grpc_unsecure src/core/ext/transport/chttp2/transport/varint.c src/core/ext/transport/chttp2/transport/writing.c src/core/ext/transport/chttp2/alpn/alpn.c + src/core/ext/transport/chttp2/server/chttp2_server.c src/core/ext/transport/chttp2/client/insecure/channel_create.c src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c src/core/ext/transport/chttp2/client/chttp2_connector.c @@ -1416,6 +1418,7 @@ add_library(grpc++_cronet src/core/ext/client_channel/uri_parser.c src/core/ext/transport/chttp2/server/insecure/server_chttp2.c src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c + src/core/ext/transport/chttp2/server/chttp2_server.c src/core/ext/census/base_resources.c src/core/ext/census/context.c src/core/ext/census/gen/census.pb.c diff --git a/Makefile b/Makefile index e80a10e4439..db30c215862 100644 --- a/Makefile +++ b/Makefile @@ -2786,6 +2786,7 @@ LIBGRPC_SRC = \ src/core/lib/tsi/fake_transport_security.c \ src/core/lib/tsi/ssl_transport_security.c \ src/core/lib/tsi/transport_security.c \ + src/core/ext/transport/chttp2/server/chttp2_server.c \ src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \ src/core/ext/client_channel/channel_connectivity.c \ src/core/ext/client_channel/client_channel.c \ @@ -3564,6 +3565,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/transport/chttp2/transport/varint.c \ src/core/ext/transport/chttp2/transport/writing.c \ src/core/ext/transport/chttp2/alpn/alpn.c \ + src/core/ext/transport/chttp2/server/chttp2_server.c \ src/core/ext/transport/chttp2/client/insecure/channel_create.c \ src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \ src/core/ext/transport/chttp2/client/chttp2_connector.c \ @@ -4139,6 +4141,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/client_channel/uri_parser.c \ src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \ src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \ + src/core/ext/transport/chttp2/server/chttp2_server.c \ src/core/ext/census/base_resources.c \ src/core/ext/census/context.c \ src/core/ext/census/gen/census.pb.c \ diff --git a/binding.gyp b/binding.gyp index 8b1f5131fca..516cbdce5dc 100644 --- a/binding.gyp +++ b/binding.gyp @@ -727,6 +727,7 @@ 'src/core/lib/tsi/fake_transport_security.c', 'src/core/lib/tsi/ssl_transport_security.c', 'src/core/lib/tsi/transport_security.c', + 'src/core/ext/transport/chttp2/server/chttp2_server.c', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c', 'src/core/ext/client_channel/channel_connectivity.c', 'src/core/ext/client_channel/client_channel.c', diff --git a/build.yaml b/build.yaml index 1b95b2098e1..68d19a6b44f 100644 --- a/build.yaml +++ b/build.yaml @@ -647,6 +647,14 @@ filegroups: - grpc_client_channel - grpc_secure - grpc_transport_chttp2_client_connector +- name: grpc_transport_chttp2_server + headers: + - src/core/ext/transport/chttp2/server/chttp2_server.h + src: + - src/core/ext/transport/chttp2/server/chttp2_server.c + uses: + - grpc_transport_chttp2 + - grpc_base - name: grpc_transport_chttp2_server_insecure src: - src/core/ext/transport/chttp2/server/insecure/server_chttp2.c @@ -654,6 +662,7 @@ filegroups: uses: - grpc_transport_chttp2 - grpc_base + - grpc_transport_chttp2_server - name: grpc_transport_chttp2_server_secure src: - src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c @@ -661,6 +670,7 @@ filegroups: - grpc_transport_chttp2 - grpc_base - grpc_secure + - grpc_transport_chttp2_server - name: grpc_transport_cronet_client_secure public_headers: - include/grpc/grpc_cronet.h diff --git a/config.m4 b/config.m4 index 5f48cf04a05..4b86e25581d 100644 --- a/config.m4 +++ b/config.m4 @@ -243,6 +243,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/tsi/fake_transport_security.c \ src/core/lib/tsi/ssl_transport_security.c \ src/core/lib/tsi/transport_security.c \ + src/core/ext/transport/chttp2/server/chttp2_server.c \ src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \ src/core/ext/client_channel/channel_connectivity.c \ src/core/ext/client_channel/client_channel.c \ @@ -613,6 +614,7 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/insecure) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/secure) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/insecure) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport) diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 8ea6eca6a5b..04f7211d210 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -387,6 +387,7 @@ Pod::Spec.new do |s| 'src/core/lib/tsi/ssl_types.h', 'src/core/lib/tsi/transport_security.h', 'src/core/lib/tsi/transport_security_interface.h', + 'src/core/ext/transport/chttp2/server/chttp2_server.h', 'src/core/ext/client_channel/client_channel.h', 'src/core/ext/client_channel/client_channel_factory.h', 'src/core/ext/client_channel/connector.h', @@ -586,6 +587,7 @@ Pod::Spec.new do |s| 'src/core/lib/tsi/fake_transport_security.c', 'src/core/lib/tsi/ssl_transport_security.c', 'src/core/lib/tsi/transport_security.c', + 'src/core/ext/transport/chttp2/server/chttp2_server.c', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c', 'src/core/ext/client_channel/channel_connectivity.c', 'src/core/ext/client_channel/client_channel.c', @@ -792,6 +794,7 @@ Pod::Spec.new do |s| 'src/core/lib/tsi/ssl_types.h', 'src/core/lib/tsi/transport_security.h', 'src/core/lib/tsi/transport_security_interface.h', + 'src/core/ext/transport/chttp2/server/chttp2_server.h', 'src/core/ext/client_channel/client_channel.h', 'src/core/ext/client_channel/client_channel_factory.h', 'src/core/ext/client_channel/connector.h', diff --git a/grpc.gemspec b/grpc.gemspec index 9fe6512673c..6019b97f672 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -306,6 +306,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/tsi/ssl_types.h ) s.files += %w( src/core/lib/tsi/transport_security.h ) s.files += %w( src/core/lib/tsi/transport_security_interface.h ) + s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h ) s.files += %w( src/core/ext/client_channel/client_channel.h ) s.files += %w( src/core/ext/client_channel/client_channel_factory.h ) s.files += %w( src/core/ext/client_channel/connector.h ) @@ -505,6 +506,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/tsi/fake_transport_security.c ) s.files += %w( src/core/lib/tsi/ssl_transport_security.c ) s.files += %w( src/core/lib/tsi/transport_security.c ) + s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.c ) s.files += %w( src/core/ext/transport/chttp2/client/secure/secure_channel_create.c ) s.files += %w( src/core/ext/client_channel/channel_connectivity.c ) s.files += %w( src/core/ext/client_channel/client_channel.c ) diff --git a/package.xml b/package.xml index 7f2c6130ff3..61668815a68 100644 --- a/package.xml +++ b/package.xml @@ -314,6 +314,7 @@ <file baseinstalldir="/" name="src/core/lib/tsi/ssl_types.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/tsi/transport_security.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/tsi/transport_security_interface.h" role="src" /> + <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_factory.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/connector.h" role="src" /> @@ -513,6 +514,7 @@ <file baseinstalldir="/" name="src/core/lib/tsi/fake_transport_security.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/tsi/ssl_transport_security.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/tsi/transport_security.c" role="src" /> + <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/secure/secure_channel_create.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/channel_connectivity.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel.c" role="src" /> diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.c b/src/core/ext/transport/chttp2/server/chttp2_server.c new file mode 100644 index 00000000000..9282d7ef898 --- /dev/null +++ b/src/core/ext/transport/chttp2/server/chttp2_server.c @@ -0,0 +1,355 @@ +/* + * + * 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/ext/transport/chttp2/server/chttp2_server.h" + +#include <grpc/grpc.h> + +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> +#include <grpc/support/sync.h> +#include <grpc/support/useful.h> + +#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/handshaker.h" +#include "src/core/lib/channel/http_server_filter.h" +#include "src/core/lib/iomgr/endpoint.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/iomgr/tcp_server.h" +#include "src/core/lib/surface/api_trace.h" +#include "src/core/lib/surface/server.h" + +void grpc_chttp2_server_handshaker_factory_create_handshakers( + grpc_exec_ctx *exec_ctx, + grpc_chttp2_server_handshaker_factory *handshaker_factory, + grpc_handshake_manager *handshake_mgr) { + if (handshaker_factory != NULL) { + handshaker_factory->vtable->create_handshakers( + exec_ctx, handshaker_factory, handshake_mgr); + } +} + +void grpc_chttp2_server_handshaker_factory_destroy( + grpc_exec_ctx *exec_ctx, + grpc_chttp2_server_handshaker_factory *handshaker_factory) { + if (handshaker_factory != NULL) { + handshaker_factory->vtable->destroy(exec_ctx, handshaker_factory); + } +} + + +typedef struct pending_handshake_manager_node { + grpc_handshake_manager *handshake_mgr; + struct pending_handshake_manager_node *next; +} pending_handshake_manager_node; + +typedef struct { + grpc_server *server; + grpc_tcp_server *tcp_server; + grpc_channel_args *args; + grpc_chttp2_server_handshaker_factory *handshaker_factory; + gpr_mu mu; + bool shutdown; + grpc_closure tcp_server_shutdown_complete; + grpc_closure *server_destroy_listener_done; + pending_handshake_manager_node *pending_handshake_mgrs; +} server_state; + +typedef struct { + server_state *server_state; + grpc_pollset *accepting_pollset; + grpc_tcp_server_acceptor *acceptor; + grpc_handshake_manager *handshake_mgr; +} server_connection_state; + +static void pending_handshake_manager_add_locked( + server_state *state, grpc_handshake_manager *handshake_mgr) { + pending_handshake_manager_node *node = gpr_malloc(sizeof(*node)); + node->handshake_mgr = handshake_mgr; + node->next = state->pending_handshake_mgrs; + state->pending_handshake_mgrs = node; +} + +static void pending_handshake_manager_remove_locked( + server_state *state, grpc_handshake_manager *handshake_mgr) { + pending_handshake_manager_node **prev_node = &state->pending_handshake_mgrs; + for (pending_handshake_manager_node *node = state->pending_handshake_mgrs; + node != NULL; node = node->next) { + if (node->handshake_mgr == handshake_mgr) { + *prev_node = node->next; + gpr_free(node); + break; + } + prev_node = &node->next; + } +} + +static void pending_handshake_manager_shutdown_locked(grpc_exec_ctx *exec_ctx, + server_state *state) { + pending_handshake_manager_node *prev_node = NULL; + for (pending_handshake_manager_node *node = state->pending_handshake_mgrs; + node != NULL; node = node->next) { + grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr); + gpr_free(prev_node); + prev_node = node; + } + gpr_free(prev_node); + state->pending_handshake_mgrs = NULL; +} + +static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_handshaker_args *args = arg; + server_connection_state *connection_state = args->user_data; + gpr_mu_lock(&connection_state->server_state->mu); + if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) { + const char *error_str = grpc_error_string(error); + gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str); + grpc_error_free_string(error_str); + if (error == GRPC_ERROR_NONE) { + // We were shut down after handshaking completed successfully, so + // destroy the endpoint here. + // TODO(ctiller): It is currently necessary to shutdown endpoints + // before destroying them, even if we know that there are no + // pending read/write callbacks. This should be fixed, at which + // point this can be removed. + grpc_endpoint_shutdown(exec_ctx, args->endpoint); + grpc_endpoint_destroy(exec_ctx, args->endpoint); + grpc_channel_args_destroy(args->args); + grpc_slice_buffer_destroy(args->read_buffer); + gpr_free(args->read_buffer); + } + } else { + grpc_transport *transport = + grpc_create_chttp2_transport(exec_ctx, args->args, args->endpoint, 0); + grpc_server_setup_transport( + exec_ctx, connection_state->server_state->server, transport, + connection_state->accepting_pollset, args->args); + grpc_chttp2_transport_start_reading(exec_ctx, transport, args->read_buffer); + grpc_channel_args_destroy(args->args); + } + pending_handshake_manager_remove_locked(connection_state->server_state, + connection_state->handshake_mgr); + gpr_mu_unlock(&connection_state->server_state->mu); + grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr); + grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp_server); + gpr_free(connection_state); +} + +static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, + grpc_pollset *accepting_pollset, + grpc_tcp_server_acceptor *acceptor) { + server_state *state = arg; + gpr_mu_lock(&state->mu); + if (state->shutdown) { + gpr_mu_unlock(&state->mu); + grpc_endpoint_destroy(exec_ctx, tcp); + return; + } + grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create(); + pending_handshake_manager_add_locked(state, handshake_mgr); + gpr_mu_unlock(&state->mu); + grpc_tcp_server_ref(state->tcp_server); + server_connection_state *connection_state = + gpr_malloc(sizeof(*connection_state)); + connection_state->server_state = state; + connection_state->accepting_pollset = accepting_pollset; + connection_state->acceptor = acceptor; + connection_state->handshake_mgr = handshake_mgr; + grpc_chttp2_server_handshaker_factory_create_handshakers( + exec_ctx, state->handshaker_factory, connection_state->handshake_mgr); + // TODO(roth): We should really get this timeout value from channel + // args instead of hard-coding it. + const gpr_timespec deadline = gpr_time_add( + gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN)); + grpc_handshake_manager_do_handshake( + exec_ctx, connection_state->handshake_mgr, tcp, state->args, deadline, + acceptor, on_handshake_done, connection_state); +} + +/* Server callback: start listening on our ports */ +static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server, + void *arg, grpc_pollset **pollsets, + size_t pollset_count) { + server_state *state = arg; + gpr_mu_lock(&state->mu); + state->shutdown = false; + gpr_mu_unlock(&state->mu); + grpc_tcp_server_start(exec_ctx, state->tcp_server, pollsets, pollset_count, + on_accept, state); +} + +static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + server_state *state = arg; + /* ensure all threads have unlocked */ + gpr_mu_lock(&state->mu); + grpc_closure *destroy_done = state->server_destroy_listener_done; + GPR_ASSERT(state->shutdown); + pending_handshake_manager_shutdown_locked(exec_ctx, state); + gpr_mu_unlock(&state->mu); + // Flush queued work before destroying handshaker factory, since that + // may do a synchronous unref. + grpc_exec_ctx_flush(exec_ctx); + grpc_chttp2_server_handshaker_factory_destroy(exec_ctx, + state->handshaker_factory); + if (destroy_done != NULL) { + destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error)); + grpc_exec_ctx_flush(exec_ctx); + } + grpc_channel_args_destroy(state->args); + gpr_mu_destroy(&state->mu); + gpr_free(state); +} + +/* Server callback: destroy the tcp listener (so we don't generate further + callbacks) */ +static void server_destroy_listener(grpc_exec_ctx *exec_ctx, + grpc_server *server, void *arg, + grpc_closure *destroy_done) { + server_state *state = arg; + gpr_mu_lock(&state->mu); + state->shutdown = true; + state->server_destroy_listener_done = destroy_done; + grpc_tcp_server *tcp_server = state->tcp_server; + gpr_mu_unlock(&state->mu); + grpc_tcp_server_shutdown_listeners(exec_ctx, tcp_server); + grpc_tcp_server_unref(exec_ctx, tcp_server); +} + +grpc_error *grpc_chttp2_server_add_port( + grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr, + grpc_channel_args *args, + grpc_chttp2_server_handshaker_factory *handshaker_factory, int *port_num) { + grpc_resolved_addresses *resolved = NULL; + grpc_tcp_server *tcp_server = NULL; + size_t i; + size_t count = 0; + int port_temp; + grpc_error *err = GRPC_ERROR_NONE; + server_state *state = NULL; + + *port_num = -1; + + /* resolve address */ + err = grpc_blocking_resolve_address(addr, "https", &resolved); + if (err != GRPC_ERROR_NONE) { + goto error; + } + state = gpr_malloc(sizeof(*state)); + memset(state, 0, sizeof(*state)); + grpc_closure_init(&state->tcp_server_shutdown_complete, + tcp_server_shutdown_complete, state); + err = + grpc_tcp_server_create(exec_ctx, &state->tcp_server_shutdown_complete, + args, &tcp_server); + if (err != GRPC_ERROR_NONE) { + goto error; + } + + state->server = server; + state->tcp_server = tcp_server; + state->args = args; + state->handshaker_factory = handshaker_factory; + state->shutdown = true; + gpr_mu_init(&state->mu); + + const size_t naddrs = resolved->naddrs; + grpc_error **errors = gpr_malloc(sizeof(*errors) * naddrs); + for (i = 0; i < naddrs; i++) { + errors[i] = + grpc_tcp_server_add_port(tcp_server, &resolved->addrs[i], &port_temp); + if (errors[i] == GRPC_ERROR_NONE) { + if (*port_num == -1) { + *port_num = port_temp; + } else { + GPR_ASSERT(*port_num == port_temp); + } + count++; + } + } + if (count == 0) { + char *msg; + gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved", + naddrs); + err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); + gpr_free(msg); + goto error; + } else if (count != naddrs) { + char *msg; + gpr_asprintf(&msg, "Only %" PRIuPTR + " addresses added out of total %" PRIuPTR " resolved", + count, naddrs); + err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); + gpr_free(msg); + + const char *warning_message = grpc_error_string(err); + gpr_log(GPR_INFO, "WARNING: %s", warning_message); + grpc_error_free_string(warning_message); + /* we managed to bind some addresses: continue */ + } + grpc_resolved_addresses_destroy(resolved); + + /* Register with the server only upon success */ + grpc_server_add_listener(exec_ctx, server, state, server_start_listener, + server_destroy_listener); + goto done; + +/* Error path: cleanup and return */ +error: + GPR_ASSERT(err != GRPC_ERROR_NONE); + if (resolved) { + grpc_resolved_addresses_destroy(resolved); + } + if (tcp_server) { + grpc_tcp_server_unref(exec_ctx, tcp_server); + } + grpc_channel_args_destroy(state->args); + grpc_chttp2_server_handshaker_factory_destroy(exec_ctx, + state->handshaker_factory); + gpr_free(state); + *port_num = 0; + +done: + if (errors != NULL) { + for (i = 0; i < naddrs; i++) { + GRPC_ERROR_UNREF(errors[i]); + } + gpr_free(errors); + } + return err; +} diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.h b/src/core/ext/transport/chttp2/server/chttp2_server.h new file mode 100644 index 00000000000..b1ff04bcbb8 --- /dev/null +++ b/src/core/ext/transport/chttp2/server/chttp2_server.h @@ -0,0 +1,79 @@ +/* + * + * 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_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H +#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H + +#include <grpc/impl/codegen/grpc_types.h> + +#include "src/core/lib/channel/handshaker.h" +#include "src/core/lib/iomgr/exec_ctx.h" + +/// A server handshaker factory is used to create handshakers for server +/// connections. +typedef struct grpc_chttp2_server_handshaker_factory + grpc_chttp2_server_handshaker_factory; + +typedef struct { + void (*create_handshakers)( + grpc_exec_ctx *exec_ctx, + grpc_chttp2_server_handshaker_factory *handshaker_factory, + grpc_handshake_manager *handshake_mgr); + void (*destroy)(grpc_exec_ctx *exec_ctx, + grpc_chttp2_server_handshaker_factory *handshaker_factory); +} grpc_chttp2_server_handshaker_factory_vtable; + +struct grpc_chttp2_server_handshaker_factory { + const grpc_chttp2_server_handshaker_factory_vtable *vtable; +}; + +void grpc_chttp2_server_handshaker_factory_create_handshakers( + grpc_exec_ctx *exec_ctx, + grpc_chttp2_server_handshaker_factory *handshaker_factory, + grpc_handshake_manager *handshake_mgr); + +void grpc_chttp2_server_handshaker_factory_destroy( + grpc_exec_ctx *exec_ctx, + grpc_chttp2_server_handshaker_factory *handshaker_factory); + +/// Adds a port to \a server. Sets \a port_num to the port number. +/// If \a handshaker_factory is not NULL, it will be used to create +/// handshakers for the port. +/// Takes ownership of \a args and \a handshaker_factory. +grpc_error *grpc_chttp2_server_add_port( + grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr, + grpc_channel_args *args, + grpc_chttp2_server_handshaker_factory *handshaker_factory, + int *port_num); + +#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H */ diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c index a4d7fc5f70b..366312bd728 100644 --- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c +++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c @@ -33,291 +33,28 @@ #include <grpc/grpc.h> -#include <string.h> - -#include <grpc/support/alloc.h> #include <grpc/support/log.h> -#include <grpc/support/string_util.h> -#include <grpc/support/useful.h> -#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" +#include "src/core/ext/transport/chttp2/server/chttp2_server.h" #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/channel/handshaker.h" -#include "src/core/lib/channel/http_server_filter.h" -#include "src/core/lib/iomgr/resolve_address.h" -#include "src/core/lib/iomgr/tcp_server.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/server.h" -typedef struct pending_handshake_manager_node { - grpc_handshake_manager *handshake_mgr; - struct pending_handshake_manager_node *next; -} pending_handshake_manager_node; - -typedef struct { - grpc_server *server; - grpc_tcp_server *tcp_server; - gpr_mu mu; - bool shutdown; - grpc_closure tcp_server_shutdown_complete; - grpc_closure *server_destroy_listener_done; - pending_handshake_manager_node *pending_handshake_mgrs; -} server_state; - -typedef struct { - server_state *server_state; - grpc_pollset *accepting_pollset; - grpc_tcp_server_acceptor *acceptor; - grpc_handshake_manager *handshake_mgr; -} server_connection_state; - -static void pending_handshake_manager_add_locked( - server_state *state, grpc_handshake_manager *handshake_mgr) { - pending_handshake_manager_node *node = gpr_malloc(sizeof(*node)); - node->handshake_mgr = handshake_mgr; - node->next = state->pending_handshake_mgrs; - state->pending_handshake_mgrs = node; -} - -static void pending_handshake_manager_remove_locked( - server_state *state, grpc_handshake_manager *handshake_mgr) { - pending_handshake_manager_node **prev_node = &state->pending_handshake_mgrs; - for (pending_handshake_manager_node *node = state->pending_handshake_mgrs; - node != NULL; node = node->next) { - if (node->handshake_mgr == handshake_mgr) { - *prev_node = node->next; - gpr_free(node); - break; - } - prev_node = &node->next; - } -} - -static void pending_handshake_manager_shutdown_locked(grpc_exec_ctx *exec_ctx, - server_state *state) { - pending_handshake_manager_node *prev_node = NULL; - for (pending_handshake_manager_node *node = state->pending_handshake_mgrs; - node != NULL; node = node->next) { - grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr); - gpr_free(prev_node); - prev_node = node; - } - gpr_free(prev_node); - state->pending_handshake_mgrs = NULL; -} - -static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - grpc_handshaker_args *args = arg; - server_connection_state *connection_state = args->user_data; - gpr_mu_lock(&connection_state->server_state->mu); - if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) { - const char *error_str = grpc_error_string(error); - gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str); - grpc_error_free_string(error_str); - if (error == GRPC_ERROR_NONE) { - // We were shut down after handshaking completed successfully, so - // destroy the endpoint here. - // TODO(ctiller): It is currently necessary to shutdown endpoints - // before destroying them, even if we know that there are no - // pending read/write callbacks. This should be fixed, at which - // point this can be removed. - grpc_endpoint_shutdown(exec_ctx, args->endpoint); - grpc_endpoint_destroy(exec_ctx, args->endpoint); - grpc_channel_args_destroy(args->args); - grpc_slice_buffer_destroy(args->read_buffer); - gpr_free(args->read_buffer); - } - } else { - grpc_transport *transport = - grpc_create_chttp2_transport(exec_ctx, args->args, args->endpoint, 0); - grpc_server_setup_transport( - exec_ctx, connection_state->server_state->server, transport, - connection_state->accepting_pollset, - grpc_server_get_channel_args(connection_state->server_state->server)); - grpc_chttp2_transport_start_reading(exec_ctx, transport, args->read_buffer); - grpc_channel_args_destroy(args->args); - } - pending_handshake_manager_remove_locked(connection_state->server_state, - connection_state->handshake_mgr); - gpr_mu_unlock(&connection_state->server_state->mu); - grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr); - grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp_server); - gpr_free(connection_state); -} - -static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, - grpc_pollset *accepting_pollset, - grpc_tcp_server_acceptor *acceptor) { - server_state *state = arg; - gpr_mu_lock(&state->mu); - if (state->shutdown) { - gpr_mu_unlock(&state->mu); - grpc_endpoint_destroy(exec_ctx, tcp); - return; - } - grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create(); - pending_handshake_manager_add_locked(state, handshake_mgr); - gpr_mu_unlock(&state->mu); - grpc_tcp_server_ref(state->tcp_server); - server_connection_state *connection_state = - gpr_malloc(sizeof(*connection_state)); - connection_state->server_state = state; - connection_state->accepting_pollset = accepting_pollset; - connection_state->acceptor = acceptor; - connection_state->handshake_mgr = handshake_mgr; - // TODO(roth): We should really get this timeout value from channel - // args instead of hard-coding it. - const gpr_timespec deadline = gpr_time_add( - gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN)); - grpc_handshake_manager_do_handshake( - exec_ctx, connection_state->handshake_mgr, tcp, - grpc_server_get_channel_args(state->server), deadline, acceptor, - on_handshake_done, connection_state); -} - -/* Server callback: start listening on our ports */ -static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server, - void *arg, grpc_pollset **pollsets, - size_t pollset_count) { - server_state *state = arg; - gpr_mu_lock(&state->mu); - state->shutdown = false; - gpr_mu_unlock(&state->mu); - grpc_tcp_server_start(exec_ctx, state->tcp_server, pollsets, pollset_count, - on_accept, state); -} - -static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - server_state *state = arg; - /* ensure all threads have unlocked */ - gpr_mu_lock(&state->mu); - grpc_closure *destroy_done = state->server_destroy_listener_done; - GPR_ASSERT(state->shutdown); - pending_handshake_manager_shutdown_locked(exec_ctx, state); - gpr_mu_unlock(&state->mu); - // Invoke callback. - if (destroy_done != NULL) { - grpc_exec_ctx_sched(exec_ctx, destroy_done, GRPC_ERROR_REF(error), NULL); - } - gpr_mu_destroy(&state->mu); - gpr_free(state); -} - -/* Server callback: destroy the tcp listener (so we don't generate further - callbacks) */ -static void server_destroy_listener(grpc_exec_ctx *exec_ctx, - grpc_server *server, void *arg, - grpc_closure *destroy_done) { - server_state *state = arg; - gpr_mu_lock(&state->mu); - state->shutdown = true; - state->server_destroy_listener_done = destroy_done; - grpc_tcp_server *tcp_server = state->tcp_server; - gpr_mu_unlock(&state->mu); - grpc_tcp_server_shutdown_listeners(exec_ctx, tcp_server); - grpc_tcp_server_unref(exec_ctx, tcp_server); -} - int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) { - grpc_resolved_addresses *resolved = NULL; - grpc_tcp_server *tcp_server = NULL; - size_t i; - size_t count = 0; - int port_num = -1; - int port_temp; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_error *err = GRPC_ERROR_NONE; - + int port_num = 0; GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2, (server, addr)); - - grpc_error **errors = NULL; - err = grpc_blocking_resolve_address(addr, "https", &resolved); - if (err != GRPC_ERROR_NONE) { - goto error; - } - server_state *state = gpr_malloc(sizeof(*state)); - memset(state, 0, sizeof(*state)); - grpc_closure_init(&state->tcp_server_shutdown_complete, - tcp_server_shutdown_complete, state); - err = - grpc_tcp_server_create(&exec_ctx, &state->tcp_server_shutdown_complete, - grpc_server_get_channel_args(server), &tcp_server); + grpc_error* err = grpc_chttp2_server_add_port( + &exec_ctx, server, addr, + grpc_channel_args_copy(grpc_server_get_channel_args(server)), + NULL /* handshaker_factory */, &port_num); if (err != GRPC_ERROR_NONE) { - goto error; - } - - state->server = server; - state->tcp_server = tcp_server; - state->shutdown = true; - gpr_mu_init(&state->mu); - - const size_t naddrs = resolved->naddrs; - errors = gpr_malloc(sizeof(*errors) * naddrs); - for (i = 0; i < naddrs; i++) { - errors[i] = - grpc_tcp_server_add_port(tcp_server, &resolved->addrs[i], &port_temp); - if (errors[i] == GRPC_ERROR_NONE) { - if (port_num == -1) { - port_num = port_temp; - } else { - GPR_ASSERT(port_num == port_temp); - } - count++; - } - } - if (count == 0) { - char *msg; - gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved", - naddrs); - err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); - gpr_free(msg); - goto error; - } else if (count != naddrs) { - char *msg; - gpr_asprintf(&msg, "Only %" PRIuPTR - " addresses added out of total %" PRIuPTR " resolved", - count, naddrs); - err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); - gpr_free(msg); - - const char *warning_message = grpc_error_string(err); - gpr_log(GPR_INFO, "WARNING: %s", warning_message); - grpc_error_free_string(warning_message); - /* we managed to bind some addresses: continue */ - } - grpc_resolved_addresses_destroy(resolved); - - /* Register with the server only upon success */ - grpc_server_add_listener(&exec_ctx, server, state, server_start_listener, - server_destroy_listener); - goto done; - -/* Error path: cleanup and return */ -error: - GPR_ASSERT(err != GRPC_ERROR_NONE); - if (resolved) { - grpc_resolved_addresses_destroy(resolved); - } - if (tcp_server) { - grpc_tcp_server_unref(&exec_ctx, tcp_server); + const char *msg = grpc_error_string(err); + gpr_log(GPR_ERROR, "%s", msg); + grpc_error_free_string(msg); + GRPC_ERROR_UNREF(err); } - port_num = 0; - - const char *msg = grpc_error_string(err); - gpr_log(GPR_ERROR, "%s", msg); - grpc_error_free_string(msg); - GRPC_ERROR_UNREF(err); - -done: grpc_exec_ctx_finish(&exec_ctx); - if (errors != NULL) { - for (i = 0; i < naddrs; i++) { - GRPC_ERROR_UNREF(errors[i]); - } - } - gpr_free(errors); return port_num; } diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c index 8d2371c917e..b9a833803bc 100644 --- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c +++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c @@ -38,230 +38,62 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/string_util.h> -#include <grpc/support/sync.h> -#include <grpc/support/useful.h> + +#include "src/core/ext/transport/chttp2/server/chttp2_server.h" + #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker.h" -#include "src/core/lib/channel/http_server_filter.h" -#include "src/core/lib/iomgr/endpoint.h" -#include "src/core/lib/iomgr/resolve_address.h" -#include "src/core/lib/iomgr/tcp_server.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" -#include "src/core/lib/security/transport/auth_filters.h" -#include "src/core/lib/security/transport/security_connector.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/server.h" -typedef struct pending_handshake_manager_node { - grpc_handshake_manager *handshake_mgr; - struct pending_handshake_manager_node *next; -} pending_handshake_manager_node; - -typedef struct server_secure_state { - grpc_server *server; - grpc_tcp_server *tcp_server; - grpc_server_security_connector *sc; - grpc_server_credentials *creds; - gpr_mu mu; - bool shutdown; - grpc_closure tcp_server_shutdown_complete; - grpc_closure *server_destroy_listener_done; - pending_handshake_manager_node *pending_handshake_mgrs; -} server_secure_state; - -typedef struct server_secure_connection_state { - server_secure_state *server_state; - grpc_pollset *accepting_pollset; - grpc_tcp_server_acceptor *acceptor; - grpc_handshake_manager *handshake_mgr; -} server_secure_connection_state; - -static void pending_handshake_manager_add_locked( - server_secure_state *state, grpc_handshake_manager *handshake_mgr) { - pending_handshake_manager_node *node = gpr_malloc(sizeof(*node)); - node->handshake_mgr = handshake_mgr; - node->next = state->pending_handshake_mgrs; - state->pending_handshake_mgrs = node; -} - -static void pending_handshake_manager_remove_locked( - server_secure_state *state, grpc_handshake_manager *handshake_mgr) { - pending_handshake_manager_node **prev_node = &state->pending_handshake_mgrs; - for (pending_handshake_manager_node *node = state->pending_handshake_mgrs; - node != NULL; node = node->next) { - if (node->handshake_mgr == handshake_mgr) { - *prev_node = node->next; - gpr_free(node); - break; - } - prev_node = &node->next; - } -} +typedef struct { + grpc_chttp2_server_handshaker_factory base; + grpc_server_security_connector *security_connector; +} server_security_handshaker_factory; -static void pending_handshake_manager_shutdown_locked( - grpc_exec_ctx *exec_ctx, server_secure_state *state) { - pending_handshake_manager_node *prev_node = NULL; - for (pending_handshake_manager_node *node = state->pending_handshake_mgrs; - node != NULL; node = node->next) { - grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr); - gpr_free(prev_node); - prev_node = node; - } - gpr_free(prev_node); - state->pending_handshake_mgrs = NULL; -} - -static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - grpc_handshaker_args *args = arg; - server_secure_connection_state *connection_state = args->user_data; - gpr_mu_lock(&connection_state->server_state->mu); - if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) { - const char *error_str = grpc_error_string(error); - gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str); - grpc_error_free_string(error_str); - if (error == GRPC_ERROR_NONE) { - // We were shut down after handshaking completed successfully, so - // destroy the endpoint here. - // TODO(ctiller): It is currently necessary to shutdown endpoints - // before destroying them, even if we know that there are no - // pending read/write callbacks. This should be fixed, at which - // point this can be removed. - grpc_endpoint_shutdown(exec_ctx, args->endpoint); - grpc_endpoint_destroy(exec_ctx, args->endpoint); - grpc_channel_args_destroy(args->args); - grpc_slice_buffer_destroy(args->read_buffer); - gpr_free(args->read_buffer); - } - } else { - grpc_arg channel_arg = - grpc_server_credentials_to_arg(connection_state->server_state->creds); - grpc_channel_args *args_copy = - grpc_channel_args_copy_and_add(args->args, &channel_arg, 1); - grpc_channel_args_destroy(args->args); - grpc_transport *transport = - grpc_create_chttp2_transport(exec_ctx, args_copy, args->endpoint, 0); - grpc_server_setup_transport( - exec_ctx, connection_state->server_state->server, transport, - connection_state->accepting_pollset, args_copy); - grpc_channel_args_destroy(args_copy); - grpc_chttp2_transport_start_reading(exec_ctx, transport, args->read_buffer); - } - pending_handshake_manager_remove_locked(connection_state->server_state, - connection_state->handshake_mgr); - gpr_mu_unlock(&connection_state->server_state->mu); - grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr); - grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp_server); - gpr_free(connection_state); -} - -static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, - grpc_pollset *accepting_pollset, - grpc_tcp_server_acceptor *acceptor) { - server_secure_state *state = arg; - gpr_mu_lock(&state->mu); - if (state->shutdown) { - gpr_mu_unlock(&state->mu); - grpc_endpoint_destroy(exec_ctx, tcp); - return; - } - grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create(); - pending_handshake_manager_add_locked(state, handshake_mgr); - gpr_mu_unlock(&state->mu); - grpc_tcp_server_ref(state->tcp_server); - server_secure_connection_state *connection_state = - gpr_malloc(sizeof(*connection_state)); - connection_state->server_state = state; - connection_state->accepting_pollset = accepting_pollset; - connection_state->acceptor = acceptor; - connection_state->handshake_mgr = handshake_mgr; +static void server_security_handshaker_factory_create_handshakers( + grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf, + grpc_handshake_manager *handshake_mgr) { + server_security_handshaker_factory *handshaker_factory = + (server_security_handshaker_factory *)hf; grpc_server_security_connector_create_handshakers( - exec_ctx, state->sc, connection_state->handshake_mgr); - // TODO(roth): We should really get this timeout value from channel - // args instead of hard-coding it. - const gpr_timespec deadline = gpr_time_add( - gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN)); - grpc_handshake_manager_do_handshake( - exec_ctx, connection_state->handshake_mgr, tcp, - grpc_server_get_channel_args(state->server), deadline, acceptor, - on_handshake_done, connection_state); + exec_ctx, handshaker_factory->security_connector, handshake_mgr); } -/* Server callback: start listening on our ports */ -static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server, - void *arg, grpc_pollset **pollsets, - size_t pollset_count) { - server_secure_state *state = arg; - gpr_mu_lock(&state->mu); - state->shutdown = false; - gpr_mu_unlock(&state->mu); - grpc_tcp_server_start(exec_ctx, state->tcp_server, pollsets, pollset_count, - on_accept, state); +static void server_security_handshaker_factory_destroy( + grpc_exec_ctx* exec_ctx, grpc_chttp2_server_handshaker_factory *hf) { + server_security_handshaker_factory *handshaker_factory = + (server_security_handshaker_factory *)hf; + GRPC_SECURITY_CONNECTOR_UNREF(&handshaker_factory->security_connector->base, + "server"); } -static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - server_secure_state *state = arg; - /* ensure all threads have unlocked */ - gpr_mu_lock(&state->mu); - grpc_closure *destroy_done = state->server_destroy_listener_done; - GPR_ASSERT(state->shutdown); - pending_handshake_manager_shutdown_locked(exec_ctx, state); - gpr_mu_unlock(&state->mu); - /* Flush queued work before a synchronous unref. */ - grpc_exec_ctx_flush(exec_ctx); - GRPC_SECURITY_CONNECTOR_UNREF(&state->sc->base, "server"); - grpc_server_credentials_unref(state->creds); - if (destroy_done != NULL) { - destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error)); - grpc_exec_ctx_flush(exec_ctx); - } - gpr_mu_destroy(&state->mu); - gpr_free(state); -} - -static void server_destroy_listener(grpc_exec_ctx *exec_ctx, - grpc_server *server, void *arg, - grpc_closure *destroy_done) { - server_secure_state *state = arg; - gpr_mu_lock(&state->mu); - state->shutdown = true; - state->server_destroy_listener_done = destroy_done; - grpc_tcp_server *tcp_server = state->tcp_server; - gpr_mu_unlock(&state->mu); - grpc_tcp_server_shutdown_listeners(exec_ctx, tcp_server); - grpc_tcp_server_unref(exec_ctx, tcp_server); -} +static const grpc_chttp2_server_handshaker_factory_vtable + server_security_handshaker_factory_vtable = { + server_security_handshaker_factory_create_handshakers, + server_security_handshaker_factory_destroy}; int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) { - grpc_resolved_addresses *resolved = NULL; - grpc_tcp_server *tcp_server = NULL; - server_secure_state *state = NULL; - size_t i; - size_t count = 0; - int port_num = -1; - int port_temp; - grpc_security_status status = GRPC_SECURITY_ERROR; - grpc_server_security_connector *sc = NULL; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_error *err = GRPC_ERROR_NONE; - grpc_error **errors = NULL; - + grpc_server_security_connector *sc = NULL; + int port_num = 0; GRPC_API_TRACE( "grpc_server_add_secure_http2_port(" "server=%p, addr=%s, creds=%p)", 3, (server, addr, creds)); - - /* create security context */ + // Create security context. if (creds == NULL) { err = GRPC_ERROR_CREATE( "No credentials specified for secure server port (creds==NULL)"); - goto error; + goto done; } - status = grpc_server_credentials_create_security_connector(creds, &sc); + grpc_security_status status = + grpc_server_credentials_create_security_connector(creds, &sc); if (status != GRPC_SECURITY_OK) { char *msg; gpr_asprintf(&msg, @@ -270,107 +102,31 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, err = grpc_error_set_int(GRPC_ERROR_CREATE(msg), GRPC_ERROR_INT_SECURITY_STATUS, status); gpr_free(msg); - goto error; + goto done; } - - /* resolve address */ - err = grpc_blocking_resolve_address(addr, "https", &resolved); - if (err != GRPC_ERROR_NONE) { - goto error; - } - state = gpr_malloc(sizeof(*state)); - memset(state, 0, sizeof(*state)); - grpc_closure_init(&state->tcp_server_shutdown_complete, - tcp_server_shutdown_complete, state); - err = - grpc_tcp_server_create(&exec_ctx, &state->tcp_server_shutdown_complete, - grpc_server_get_channel_args(server), &tcp_server); - if (err != GRPC_ERROR_NONE) { - goto error; - } - - state->server = server; - state->tcp_server = tcp_server; - state->sc = sc; - state->creds = grpc_server_credentials_ref(creds); - state->shutdown = true; - gpr_mu_init(&state->mu); - - errors = gpr_malloc(sizeof(*errors) * resolved->naddrs); - for (i = 0; i < resolved->naddrs; i++) { - errors[i] = - grpc_tcp_server_add_port(tcp_server, &resolved->addrs[i], &port_temp); - if (errors[i] == GRPC_ERROR_NONE) { - if (port_num == -1) { - port_num = port_temp; - } else { - GPR_ASSERT(port_num == port_temp); - } - count++; - } - } - if (count == 0) { - char *msg; - gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved", - resolved->naddrs); - err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs); - gpr_free(msg); - goto error; - } else if (count != resolved->naddrs) { - char *msg; - gpr_asprintf(&msg, "Only %" PRIuPTR - " addresses added out of total %" PRIuPTR " resolved", - count, resolved->naddrs); - err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs); - gpr_free(msg); - - const char *warning_message = grpc_error_string(err); - gpr_log(GPR_INFO, "WARNING: %s", warning_message); - grpc_error_free_string(warning_message); - /* we managed to bind some addresses: continue */ - } else { - for (i = 0; i < resolved->naddrs; i++) { - GRPC_ERROR_UNREF(errors[i]); - } - } - gpr_free(errors); - errors = NULL; - grpc_resolved_addresses_destroy(resolved); - - /* Register with the server only upon success */ - grpc_server_add_listener(&exec_ctx, server, state, server_start_listener, - server_destroy_listener); - + // Create handshaker factory. + server_security_handshaker_factory* handshaker_factory = + gpr_malloc(sizeof(*handshaker_factory)); + memset(handshaker_factory, 0, sizeof(*handshaker_factory)); + handshaker_factory->base.vtable = &server_security_handshaker_factory_vtable; + handshaker_factory->security_connector = sc; + // Create channel args. + grpc_arg channel_arg = grpc_server_credentials_to_arg(creds); + grpc_channel_args *args = grpc_channel_args_copy_and_add( + grpc_server_get_channel_args(server), &channel_arg, 1); + // Add server port. + err = grpc_chttp2_server_add_port(&exec_ctx, server, addr, args, + &handshaker_factory->base, &port_num); +done: grpc_exec_ctx_finish(&exec_ctx); - return port_num; - -/* Error path: cleanup and return */ -error: - GPR_ASSERT(err != GRPC_ERROR_NONE); - if (errors != NULL) { - for (i = 0; i < resolved->naddrs; i++) { - GRPC_ERROR_UNREF(errors[i]); - } - gpr_free(errors); - } - if (resolved) { - grpc_resolved_addresses_destroy(resolved); - } - if (tcp_server) { - grpc_tcp_server_unref(&exec_ctx, tcp_server); - } else { - if (sc) { - grpc_exec_ctx_flush(&exec_ctx); + if (err != GRPC_ERROR_NONE) { + const char *msg = grpc_error_string(err); + gpr_log(GPR_ERROR, "%s", msg); + grpc_error_free_string(msg); + GRPC_ERROR_UNREF(err); + if (sc != NULL) { GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server"); } - if (state) { - gpr_free(state); - } } - grpc_exec_ctx_finish(&exec_ctx); - const char *msg = grpc_error_string(err); - GRPC_ERROR_UNREF(err); - gpr_log(GPR_ERROR, "%s", msg); - grpc_error_free_string(msg); - return 0; + return port_num; } diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 3e5aa1416fa..d43f93b94fe 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -237,6 +237,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/tsi/fake_transport_security.c', 'src/core/lib/tsi/ssl_transport_security.c', 'src/core/lib/tsi/transport_security.c', + 'src/core/ext/transport/chttp2/server/chttp2_server.c', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c', 'src/core/ext/client_channel/channel_connectivity.c', 'src/core/ext/client_channel/client_channel.c', diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index ce29f8e43ca..6572bd4ddf9 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -930,6 +930,7 @@ src/core/lib/tsi/ssl_transport_security.h \ src/core/lib/tsi/ssl_types.h \ src/core/lib/tsi/transport_security.h \ src/core/lib/tsi/transport_security_interface.h \ +src/core/ext/transport/chttp2/server/chttp2_server.h \ src/core/ext/client_channel/client_channel.h \ src/core/ext/client_channel/client_channel_factory.h \ src/core/ext/client_channel/connector.h \ @@ -1129,6 +1130,7 @@ src/core/lib/surface/init_secure.c \ src/core/lib/tsi/fake_transport_security.c \ src/core/lib/tsi/ssl_transport_security.c \ src/core/lib/tsi/transport_security.c \ +src/core/ext/transport/chttp2/server/chttp2_server.c \ src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \ src/core/ext/client_channel/channel_connectivity.c \ src/core/ext/client_channel/client_channel.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 19b8a8be2a4..2e6877ccac5 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -7491,6 +7491,26 @@ "grpc_base", "grpc_transport_chttp2" ], + "headers": [ + "src/core/ext/transport/chttp2/server/chttp2_server.h" + ], + "is_filegroup": true, + "language": "c", + "name": "grpc_transport_chttp2_server", + "src": [ + "src/core/ext/transport/chttp2/server/chttp2_server.c", + "src/core/ext/transport/chttp2/server/chttp2_server.h" + ], + "third_party": false, + "type": "filegroup" + }, + { + "deps": [ + "gpr", + "grpc_base", + "grpc_transport_chttp2", + "grpc_transport_chttp2_server" + ], "headers": [], "is_filegroup": true, "language": "c", @@ -7507,7 +7527,8 @@ "gpr", "grpc_base", "grpc_secure", - "grpc_transport_chttp2" + "grpc_transport_chttp2", + "grpc_transport_chttp2_server" ], "headers": [], "is_filegroup": true, diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index fe7e06aa773..558b5b0c66a 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -439,6 +439,7 @@ <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\ssl_types.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security_interface.h" /> + <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.h" /> @@ -803,6 +804,8 @@ </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.c"> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c"> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c"> </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\channel_connectivity.c"> diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index 8fce4ceb419..a40a1b5f1c8 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -490,6 +490,9 @@ <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.c"> <Filter>src\core\lib\tsi</Filter> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c"> + <Filter>src\core\ext\transport\chttp2\server</Filter> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c"> <Filter>src\core\ext\transport\chttp2\client\secure</Filter> </ClCompile> @@ -1157,6 +1160,9 @@ <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security_interface.h"> <Filter>src\core\lib\tsi</Filter> </ClInclude> + <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h"> + <Filter>src\core\ext\transport\chttp2\server</Filter> + </ClInclude> <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h"> <Filter>src\core\ext\client_channel</Filter> </ClInclude> diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 5e5b7246093..661192101c8 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -405,6 +405,7 @@ <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" /> + <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h" /> @@ -719,6 +720,8 @@ </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c"> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c"> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c"> </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c"> diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index 4363f8a8681..466116e6043 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -415,6 +415,9 @@ <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c"> <Filter>src\core\ext\transport\chttp2\alpn</Filter> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c"> + <Filter>src\core\ext\transport\chttp2\server</Filter> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c"> <Filter>src\core\ext\transport\chttp2\client\insecure</Filter> </ClCompile> @@ -998,6 +1001,9 @@ <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h"> <Filter>src\core\ext\transport\chttp2\alpn</Filter> </ClInclude> + <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h"> + <Filter>src\core\ext\transport\chttp2\server</Filter> + </ClInclude> <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h"> <Filter>src\core\ext\transport\chttp2\client</Filter> </ClInclude>