mirror of https://github.com/grpc/grpc.git
commit
ba801e6465
36 changed files with 1958 additions and 1659 deletions
@ -0,0 +1,261 @@ |
||||
/*
|
||||
* |
||||
* 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/client/chttp2_connector.h" |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/slice_buffer.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/ext/client_channel/connector.h" |
||||
#include "src/core/ext/client_channel/http_connect_handshaker.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/iomgr/tcp_client.h" |
||||
#include "src/core/lib/security/transport/security_connector.h" |
||||
|
||||
typedef struct { |
||||
grpc_connector base; |
||||
|
||||
gpr_mu mu; |
||||
gpr_refcount refs; |
||||
|
||||
bool shutdown; |
||||
|
||||
char *server_name; |
||||
grpc_chttp2_create_handshakers_func create_handshakers; |
||||
void *create_handshakers_user_data; |
||||
|
||||
grpc_closure *notify; |
||||
grpc_connect_in_args args; |
||||
grpc_connect_out_args *result; |
||||
grpc_closure initial_string_sent; |
||||
grpc_slice_buffer initial_string_buffer; |
||||
|
||||
grpc_endpoint *endpoint; // Non-NULL until handshaking starts.
|
||||
|
||||
grpc_closure connected; |
||||
|
||||
grpc_handshake_manager *handshake_mgr; |
||||
} chttp2_connector; |
||||
|
||||
static void chttp2_connector_ref(grpc_connector *con) { |
||||
chttp2_connector *c = (chttp2_connector *)con; |
||||
gpr_ref(&c->refs); |
||||
} |
||||
|
||||
static void chttp2_connector_unref(grpc_exec_ctx *exec_ctx, |
||||
grpc_connector *con) { |
||||
chttp2_connector *c = (chttp2_connector *)con; |
||||
if (gpr_unref(&c->refs)) { |
||||
/* c->initial_string_buffer does not need to be destroyed */ |
||||
gpr_mu_destroy(&c->mu); |
||||
// If handshaking is not yet in progress, destroy the endpoint.
|
||||
// Otherwise, the handshaker will do this for us.
|
||||
if (c->endpoint != NULL) grpc_endpoint_destroy(exec_ctx, c->endpoint); |
||||
gpr_free(c->server_name); |
||||
gpr_free(c); |
||||
} |
||||
} |
||||
|
||||
static void chttp2_connector_shutdown(grpc_exec_ctx *exec_ctx, |
||||
grpc_connector *con) { |
||||
chttp2_connector *c = (chttp2_connector *)con; |
||||
gpr_mu_lock(&c->mu); |
||||
c->shutdown = true; |
||||
if (c->handshake_mgr != NULL) { |
||||
grpc_handshake_manager_shutdown(exec_ctx, c->handshake_mgr); |
||||
} |
||||
// If handshaking is not yet in progress, shutdown the endpoint.
|
||||
// Otherwise, the handshaker will do this for us.
|
||||
if (c->endpoint != NULL) grpc_endpoint_shutdown(exec_ctx, c->endpoint); |
||||
gpr_mu_unlock(&c->mu); |
||||
} |
||||
|
||||
static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, |
||||
grpc_error *error) { |
||||
grpc_handshaker_args *args = arg; |
||||
chttp2_connector *c = args->user_data; |
||||
gpr_mu_lock(&c->mu); |
||||
if (error != GRPC_ERROR_NONE || c->shutdown) { |
||||
if (error == GRPC_ERROR_NONE) { |
||||
error = GRPC_ERROR_CREATE("connector shutdown"); |
||||
// 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 { |
||||
error = GRPC_ERROR_REF(error); |
||||
} |
||||
memset(c->result, 0, sizeof(*c->result)); |
||||
} else { |
||||
c->result->transport = |
||||
grpc_create_chttp2_transport(exec_ctx, args->args, args->endpoint, 1); |
||||
GPR_ASSERT(c->result->transport); |
||||
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, |
||||
args->read_buffer); |
||||
c->result->channel_args = args->args; |
||||
} |
||||
grpc_closure *notify = c->notify; |
||||
c->notify = NULL; |
||||
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL); |
||||
grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr); |
||||
c->handshake_mgr = NULL; |
||||
gpr_mu_unlock(&c->mu); |
||||
chttp2_connector_unref(exec_ctx, (grpc_connector *)c); |
||||
} |
||||
|
||||
static void start_handshake_locked(grpc_exec_ctx *exec_ctx, |
||||
chttp2_connector *c) { |
||||
c->handshake_mgr = grpc_handshake_manager_create(); |
||||
char *proxy_name = grpc_get_http_proxy_server(); |
||||
if (proxy_name != NULL) { |
||||
grpc_handshake_manager_add( |
||||
c->handshake_mgr, |
||||
grpc_http_connect_handshaker_create(proxy_name, c->server_name)); |
||||
gpr_free(proxy_name); |
||||
} |
||||
if (c->create_handshakers != NULL) { |
||||
c->create_handshakers(exec_ctx, c->create_handshakers_user_data, |
||||
c->handshake_mgr); |
||||
} |
||||
grpc_handshake_manager_do_handshake( |
||||
exec_ctx, c->handshake_mgr, c->endpoint, c->args.channel_args, |
||||
c->args.deadline, NULL /* acceptor */, on_handshake_done, c); |
||||
c->endpoint = NULL; // Endpoint handed off to handshake manager.
|
||||
} |
||||
|
||||
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, |
||||
grpc_error *error) { |
||||
chttp2_connector *c = arg; |
||||
gpr_mu_lock(&c->mu); |
||||
if (error != GRPC_ERROR_NONE || c->shutdown) { |
||||
if (error == GRPC_ERROR_NONE) { |
||||
error = GRPC_ERROR_CREATE("connector shutdown"); |
||||
} else { |
||||
error = GRPC_ERROR_REF(error); |
||||
} |
||||
memset(c->result, 0, sizeof(*c->result)); |
||||
grpc_closure *notify = c->notify; |
||||
c->notify = NULL; |
||||
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL); |
||||
gpr_mu_unlock(&c->mu); |
||||
chttp2_connector_unref(exec_ctx, arg); |
||||
} else { |
||||
start_handshake_locked(exec_ctx, c); |
||||
gpr_mu_unlock(&c->mu); |
||||
} |
||||
} |
||||
|
||||
static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { |
||||
chttp2_connector *c = arg; |
||||
gpr_mu_lock(&c->mu); |
||||
if (error != GRPC_ERROR_NONE || c->shutdown) { |
||||
if (error == GRPC_ERROR_NONE) { |
||||
error = GRPC_ERROR_CREATE("connector shutdown"); |
||||
} else { |
||||
error = GRPC_ERROR_REF(error); |
||||
} |
||||
memset(c->result, 0, sizeof(*c->result)); |
||||
grpc_closure *notify = c->notify; |
||||
c->notify = NULL; |
||||
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL); |
||||
gpr_mu_unlock(&c->mu); |
||||
chttp2_connector_unref(exec_ctx, arg); |
||||
} else { |
||||
GPR_ASSERT(c->endpoint != NULL); |
||||
if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) { |
||||
grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent, |
||||
c); |
||||
grpc_slice_buffer_init(&c->initial_string_buffer); |
||||
grpc_slice_buffer_add(&c->initial_string_buffer, |
||||
c->args.initial_connect_string); |
||||
grpc_endpoint_write(exec_ctx, c->endpoint, &c->initial_string_buffer, |
||||
&c->initial_string_sent); |
||||
} else { |
||||
start_handshake_locked(exec_ctx, c); |
||||
} |
||||
gpr_mu_unlock(&c->mu); |
||||
} |
||||
} |
||||
|
||||
static void chttp2_connector_connect(grpc_exec_ctx *exec_ctx, |
||||
grpc_connector *con, |
||||
const grpc_connect_in_args *args, |
||||
grpc_connect_out_args *result, |
||||
grpc_closure *notify) { |
||||
chttp2_connector *c = (chttp2_connector *)con; |
||||
gpr_mu_lock(&c->mu); |
||||
GPR_ASSERT(c->notify == NULL); |
||||
c->notify = notify; |
||||
c->args = *args; |
||||
c->result = result; |
||||
GPR_ASSERT(c->endpoint == NULL); |
||||
chttp2_connector_ref(con); // Ref taken for callback.
|
||||
grpc_closure_init(&c->connected, connected, c); |
||||
grpc_tcp_client_connect(exec_ctx, &c->connected, &c->endpoint, |
||||
args->interested_parties, args->channel_args, |
||||
args->addr, args->deadline); |
||||
gpr_mu_unlock(&c->mu); |
||||
} |
||||
|
||||
static const grpc_connector_vtable chttp2_connector_vtable = { |
||||
chttp2_connector_ref, chttp2_connector_unref, chttp2_connector_shutdown, |
||||
chttp2_connector_connect}; |
||||
|
||||
grpc_connector *grpc_chttp2_connector_create( |
||||
grpc_exec_ctx *exec_ctx, const char *server_name, |
||||
grpc_chttp2_create_handshakers_func create_handshakers, |
||||
void *create_handshakers_user_data) { |
||||
chttp2_connector *c = gpr_malloc(sizeof(*c)); |
||||
memset(c, 0, sizeof(*c)); |
||||
c->base.vtable = &chttp2_connector_vtable; |
||||
gpr_mu_init(&c->mu); |
||||
gpr_ref_init(&c->refs, 1); |
||||
c->server_name = gpr_strdup(server_name); |
||||
c->create_handshakers = create_handshakers; |
||||
c->create_handshakers_user_data = create_handshakers_user_data; |
||||
return &c->base; |
||||
} |
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H |
||||
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H |
||||
|
||||
#include "src/core/ext/client_channel/connector.h" |
||||
#include "src/core/lib/channel/handshaker.h" |
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
|
||||
typedef void (*grpc_chttp2_create_handshakers_func)( |
||||
grpc_exec_ctx* exec_ctx, void* user_data, |
||||
grpc_handshake_manager* handshake_mgr); |
||||
|
||||
/// If \a create_handshakers is non-NULL, it will be called with
|
||||
/// \a create_handshakers_user_data to add handshakers.
|
||||
grpc_connector* grpc_chttp2_connector_create( |
||||
grpc_exec_ctx* exec_ctx, const char* server_name, |
||||
grpc_chttp2_create_handshakers_func create_handshakers, |
||||
void* create_handshakers_user_data); |
||||
|
||||
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H */ |
@ -0,0 +1,356 @@ |
||||
/*
|
||||
* |
||||
* 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; |
||||
grpc_error **errors = 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; |
||||
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; |
||||
} |
@ -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 */ |
@ -1,374 +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/lib/security/transport/handshake.h" |
||||
|
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/slice_buffer.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include "src/core/lib/iomgr/timer.h" |
||||
#include "src/core/lib/security/context/security_context.h" |
||||
#include "src/core/lib/security/transport/secure_endpoint.h" |
||||
#include "src/core/lib/security/transport/tsi_error.h" |
||||
|
||||
#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 |
||||
|
||||
typedef struct { |
||||
grpc_security_connector *connector; |
||||
tsi_handshaker *handshaker; |
||||
bool is_client_side; |
||||
unsigned char *handshake_buffer; |
||||
size_t handshake_buffer_size; |
||||
grpc_endpoint *wrapped_endpoint; |
||||
grpc_endpoint *secure_endpoint; |
||||
grpc_slice_buffer left_overs; |
||||
grpc_slice_buffer incoming; |
||||
grpc_slice_buffer outgoing; |
||||
grpc_security_handshake_done_cb cb; |
||||
void *user_data; |
||||
grpc_closure on_handshake_data_sent_to_peer; |
||||
grpc_closure on_handshake_data_received_from_peer; |
||||
grpc_auth_context *auth_context; |
||||
grpc_timer timer; |
||||
gpr_refcount refs; |
||||
} grpc_security_handshake; |
||||
|
||||
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, |
||||
void *setup, |
||||
grpc_error *error); |
||||
|
||||
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup, |
||||
grpc_error *error); |
||||
|
||||
static void security_connector_remove_handshake(grpc_security_handshake *h) { |
||||
GPR_ASSERT(!h->is_client_side); |
||||
grpc_security_connector_handshake_list *node; |
||||
grpc_security_connector_handshake_list *tmp; |
||||
grpc_server_security_connector *sc = |
||||
(grpc_server_security_connector *)h->connector; |
||||
gpr_mu_lock(&sc->mu); |
||||
node = sc->handshaking_handshakes; |
||||
if (node && node->handshake == h) { |
||||
sc->handshaking_handshakes = node->next; |
||||
gpr_free(node); |
||||
gpr_mu_unlock(&sc->mu); |
||||
return; |
||||
} |
||||
while (node) { |
||||
if (node->next->handshake == h) { |
||||
tmp = node->next; |
||||
node->next = node->next->next; |
||||
gpr_free(tmp); |
||||
gpr_mu_unlock(&sc->mu); |
||||
return; |
||||
} |
||||
node = node->next; |
||||
} |
||||
gpr_mu_unlock(&sc->mu); |
||||
} |
||||
|
||||
static void unref_handshake(grpc_security_handshake *h) { |
||||
if (gpr_unref(&h->refs)) { |
||||
if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker); |
||||
if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer); |
||||
grpc_slice_buffer_destroy(&h->left_overs); |
||||
grpc_slice_buffer_destroy(&h->outgoing); |
||||
grpc_slice_buffer_destroy(&h->incoming); |
||||
GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake"); |
||||
GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake"); |
||||
gpr_free(h); |
||||
} |
||||
} |
||||
|
||||
static void security_handshake_done(grpc_exec_ctx *exec_ctx, |
||||
grpc_security_handshake *h, |
||||
grpc_error *error) { |
||||
grpc_timer_cancel(exec_ctx, &h->timer); |
||||
if (!h->is_client_side) { |
||||
security_connector_remove_handshake(h); |
||||
} |
||||
if (error == GRPC_ERROR_NONE) { |
||||
h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint, |
||||
h->auth_context); |
||||
} else { |
||||
const char *msg = grpc_error_string(error); |
||||
gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg); |
||||
grpc_error_free_string(msg); |
||||
|
||||
if (h->secure_endpoint != NULL) { |
||||
grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint); |
||||
grpc_endpoint_destroy(exec_ctx, h->secure_endpoint); |
||||
} else { |
||||
grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint); |
||||
} |
||||
h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL); |
||||
} |
||||
unref_handshake(h); |
||||
GRPC_ERROR_UNREF(error); |
||||
} |
||||
|
||||
static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data, |
||||
grpc_security_status status, |
||||
grpc_auth_context *auth_context) { |
||||
grpc_security_handshake *h = user_data; |
||||
tsi_frame_protector *protector; |
||||
tsi_result result; |
||||
if (status != GRPC_SECURITY_OK) { |
||||
security_handshake_done( |
||||
exec_ctx, h, |
||||
grpc_error_set_int(GRPC_ERROR_CREATE("Error checking peer."), |
||||
GRPC_ERROR_INT_SECURITY_STATUS, status)); |
||||
return; |
||||
} |
||||
h->auth_context = GRPC_AUTH_CONTEXT_REF(auth_context, "handshake"); |
||||
result = |
||||
tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector); |
||||
if (result != TSI_OK) { |
||||
security_handshake_done( |
||||
exec_ctx, h, |
||||
grpc_set_tsi_error_result( |
||||
GRPC_ERROR_CREATE("Frame protector creation failed"), result)); |
||||
return; |
||||
} |
||||
h->secure_endpoint = |
||||
grpc_secure_endpoint_create(protector, h->wrapped_endpoint, |
||||
h->left_overs.slices, h->left_overs.count); |
||||
h->left_overs.count = 0; |
||||
h->left_overs.length = 0; |
||||
security_handshake_done(exec_ctx, h, GRPC_ERROR_NONE); |
||||
return; |
||||
} |
||||
|
||||
static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) { |
||||
tsi_peer peer; |
||||
tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer); |
||||
|
||||
if (result != TSI_OK) { |
||||
security_handshake_done( |
||||
exec_ctx, h, grpc_set_tsi_error_result( |
||||
GRPC_ERROR_CREATE("Peer extraction failed"), result)); |
||||
return; |
||||
} |
||||
grpc_security_connector_check_peer(exec_ctx, h->connector, peer, |
||||
on_peer_checked, h); |
||||
} |
||||
|
||||
static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx, |
||||
grpc_security_handshake *h) { |
||||
size_t offset = 0; |
||||
tsi_result result = TSI_OK; |
||||
grpc_slice to_send; |
||||
|
||||
do { |
||||
size_t to_send_size = h->handshake_buffer_size - offset; |
||||
result = tsi_handshaker_get_bytes_to_send_to_peer( |
||||
h->handshaker, h->handshake_buffer + offset, &to_send_size); |
||||
offset += to_send_size; |
||||
if (result == TSI_INCOMPLETE_DATA) { |
||||
h->handshake_buffer_size *= 2; |
||||
h->handshake_buffer = |
||||
gpr_realloc(h->handshake_buffer, h->handshake_buffer_size); |
||||
} |
||||
} while (result == TSI_INCOMPLETE_DATA); |
||||
|
||||
if (result != TSI_OK) { |
||||
security_handshake_done(exec_ctx, h, |
||||
grpc_set_tsi_error_result( |
||||
GRPC_ERROR_CREATE("Handshake failed"), result)); |
||||
return; |
||||
} |
||||
|
||||
to_send = |
||||
grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset); |
||||
grpc_slice_buffer_reset_and_unref(&h->outgoing); |
||||
grpc_slice_buffer_add(&h->outgoing, to_send); |
||||
/* TODO(klempner,jboeuf): This should probably use the client setup
|
||||
deadline */ |
||||
grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing, |
||||
&h->on_handshake_data_sent_to_peer); |
||||
} |
||||
|
||||
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, |
||||
void *handshake, |
||||
grpc_error *error) { |
||||
grpc_security_handshake *h = handshake; |
||||
size_t consumed_slice_size = 0; |
||||
tsi_result result = TSI_OK; |
||||
size_t i; |
||||
size_t num_left_overs; |
||||
int has_left_overs_in_current_slice = 0; |
||||
|
||||
if (error != GRPC_ERROR_NONE) { |
||||
security_handshake_done( |
||||
exec_ctx, h, |
||||
GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1)); |
||||
return; |
||||
} |
||||
|
||||
for (i = 0; i < h->incoming.count; i++) { |
||||
consumed_slice_size = GRPC_SLICE_LENGTH(h->incoming.slices[i]); |
||||
result = tsi_handshaker_process_bytes_from_peer( |
||||
h->handshaker, GRPC_SLICE_START_PTR(h->incoming.slices[i]), |
||||
&consumed_slice_size); |
||||
if (!tsi_handshaker_is_in_progress(h->handshaker)) break; |
||||
} |
||||
|
||||
if (tsi_handshaker_is_in_progress(h->handshaker)) { |
||||
/* We may need more data. */ |
||||
if (result == TSI_INCOMPLETE_DATA) { |
||||
grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, |
||||
&h->on_handshake_data_received_from_peer); |
||||
return; |
||||
} else { |
||||
send_handshake_bytes_to_peer(exec_ctx, h); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if (result != TSI_OK) { |
||||
security_handshake_done(exec_ctx, h, |
||||
grpc_set_tsi_error_result( |
||||
GRPC_ERROR_CREATE("Handshake failed"), result)); |
||||
return; |
||||
} |
||||
|
||||
/* Handshake is done and successful this point. */ |
||||
has_left_overs_in_current_slice = |
||||
(consumed_slice_size < GRPC_SLICE_LENGTH(h->incoming.slices[i])); |
||||
num_left_overs = |
||||
(has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1; |
||||
if (num_left_overs == 0) { |
||||
check_peer(exec_ctx, h); |
||||
return; |
||||
} |
||||
|
||||
/* Put the leftovers in our buffer (ownership transfered). */ |
||||
if (has_left_overs_in_current_slice) { |
||||
grpc_slice_buffer_add( |
||||
&h->left_overs, |
||||
grpc_slice_split_tail(&h->incoming.slices[i], consumed_slice_size)); |
||||
grpc_slice_unref( |
||||
h->incoming.slices[i]); /* split_tail above increments refcount. */ |
||||
} |
||||
grpc_slice_buffer_addn( |
||||
&h->left_overs, &h->incoming.slices[i + 1], |
||||
num_left_overs - (size_t)has_left_overs_in_current_slice); |
||||
check_peer(exec_ctx, h); |
||||
} |
||||
|
||||
/* If handshake is NULL, the handshake is done. */ |
||||
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, |
||||
void *handshake, grpc_error *error) { |
||||
grpc_security_handshake *h = handshake; |
||||
|
||||
/* Make sure that write is OK. */ |
||||
if (error != GRPC_ERROR_NONE) { |
||||
if (handshake != NULL) |
||||
security_handshake_done( |
||||
exec_ctx, h, |
||||
GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1)); |
||||
return; |
||||
} |
||||
|
||||
/* We may be done. */ |
||||
if (tsi_handshaker_is_in_progress(h->handshaker)) { |
||||
/* TODO(klempner,jboeuf): This should probably use the client setup
|
||||
deadline */ |
||||
grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, |
||||
&h->on_handshake_data_received_from_peer); |
||||
} else { |
||||
check_peer(exec_ctx, h); |
||||
} |
||||
} |
||||
|
||||
static void on_timeout(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { |
||||
grpc_security_handshake *h = arg; |
||||
if (error == GRPC_ERROR_NONE) { |
||||
grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint); |
||||
} |
||||
unref_handshake(h); |
||||
} |
||||
|
||||
void grpc_do_security_handshake( |
||||
grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker, |
||||
grpc_security_connector *connector, bool is_client_side, |
||||
grpc_endpoint *nonsecure_endpoint, grpc_slice_buffer *read_buffer, |
||||
gpr_timespec deadline, grpc_security_handshake_done_cb cb, |
||||
void *user_data) { |
||||
grpc_security_connector_handshake_list *handshake_node; |
||||
grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake)); |
||||
memset(h, 0, sizeof(grpc_security_handshake)); |
||||
h->handshaker = handshaker; |
||||
h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); |
||||
h->is_client_side = is_client_side; |
||||
h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; |
||||
h->handshake_buffer = gpr_malloc(h->handshake_buffer_size); |
||||
h->wrapped_endpoint = nonsecure_endpoint; |
||||
h->user_data = user_data; |
||||
h->cb = cb; |
||||
gpr_ref_init(&h->refs, 2); /* timer and handshake proper each get a ref */ |
||||
grpc_closure_init(&h->on_handshake_data_sent_to_peer, |
||||
on_handshake_data_sent_to_peer, h); |
||||
grpc_closure_init(&h->on_handshake_data_received_from_peer, |
||||
on_handshake_data_received_from_peer, h); |
||||
grpc_slice_buffer_init(&h->left_overs); |
||||
grpc_slice_buffer_init(&h->outgoing); |
||||
grpc_slice_buffer_init(&h->incoming); |
||||
if (read_buffer != NULL) { |
||||
grpc_slice_buffer_move_into(read_buffer, &h->incoming); |
||||
gpr_free(read_buffer); |
||||
} |
||||
if (!is_client_side) { |
||||
grpc_server_security_connector *server_connector = |
||||
(grpc_server_security_connector *)connector; |
||||
handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list)); |
||||
handshake_node->handshake = h; |
||||
gpr_mu_lock(&server_connector->mu); |
||||
handshake_node->next = server_connector->handshaking_handshakes; |
||||
server_connector->handshaking_handshakes = handshake_node; |
||||
gpr_mu_unlock(&server_connector->mu); |
||||
} |
||||
send_handshake_bytes_to_peer(exec_ctx, h); |
||||
grpc_timer_init(exec_ctx, &h->timer, |
||||
gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), |
||||
on_timeout, h, gpr_now(GPR_CLOCK_MONOTONIC)); |
||||
} |
||||
|
||||
void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, |
||||
void *handshake) { |
||||
grpc_security_handshake *h = handshake; |
||||
grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint); |
||||
} |
@ -0,0 +1,450 @@ |
||||
/*
|
||||
* |
||||
* 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/lib/security/transport/security_handshaker.h" |
||||
|
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/slice_buffer.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
#include "src/core/lib/channel/handshaker.h" |
||||
#include "src/core/lib/security/context/security_context.h" |
||||
#include "src/core/lib/security/transport/secure_endpoint.h" |
||||
#include "src/core/lib/security/transport/tsi_error.h" |
||||
|
||||
#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 |
||||
|
||||
typedef struct { |
||||
grpc_handshaker base; |
||||
|
||||
// State set at creation time.
|
||||
tsi_handshaker *handshaker; |
||||
grpc_security_connector *connector; |
||||
|
||||
gpr_mu mu; |
||||
gpr_refcount refs; |
||||
|
||||
bool shutdown; |
||||
// Endpoint and read buffer to destroy after a shutdown.
|
||||
grpc_endpoint *endpoint_to_destroy; |
||||
grpc_slice_buffer *read_buffer_to_destroy; |
||||
|
||||
// State saved while performing the handshake.
|
||||
grpc_handshaker_args *args; |
||||
grpc_closure *on_handshake_done; |
||||
|
||||
unsigned char *handshake_buffer; |
||||
size_t handshake_buffer_size; |
||||
grpc_slice_buffer left_overs; |
||||
grpc_slice_buffer outgoing; |
||||
grpc_closure on_handshake_data_sent_to_peer; |
||||
grpc_closure on_handshake_data_received_from_peer; |
||||
grpc_closure on_peer_checked; |
||||
grpc_auth_context *auth_context; |
||||
} security_handshaker; |
||||
|
||||
static void security_handshaker_unref(grpc_exec_ctx *exec_ctx, |
||||
security_handshaker *h) { |
||||
if (gpr_unref(&h->refs)) { |
||||
gpr_mu_destroy(&h->mu); |
||||
tsi_handshaker_destroy(h->handshaker); |
||||
if (h->endpoint_to_destroy != NULL) { |
||||
grpc_endpoint_destroy(exec_ctx, h->endpoint_to_destroy); |
||||
} |
||||
if (h->read_buffer_to_destroy != NULL) { |
||||
grpc_slice_buffer_destroy(h->read_buffer_to_destroy); |
||||
gpr_free(h->read_buffer_to_destroy); |
||||
} |
||||
gpr_free(h->handshake_buffer); |
||||
grpc_slice_buffer_destroy(&h->left_overs); |
||||
grpc_slice_buffer_destroy(&h->outgoing); |
||||
GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake"); |
||||
GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake"); |
||||
gpr_free(h); |
||||
} |
||||
} |
||||
|
||||
// Set args fields to NULL, saving the endpoint and read buffer for
|
||||
// later destruction.
|
||||
static void cleanup_args_for_failure_locked(security_handshaker *h) { |
||||
h->endpoint_to_destroy = h->args->endpoint; |
||||
h->args->endpoint = NULL; |
||||
h->read_buffer_to_destroy = h->args->read_buffer; |
||||
h->args->read_buffer = NULL; |
||||
grpc_channel_args_destroy(h->args->args); |
||||
h->args->args = NULL; |
||||
} |
||||
|
||||
// If the handshake failed or we're shutting down, clean up and invoke the
|
||||
// callback with the error.
|
||||
static void security_handshake_failed_locked(grpc_exec_ctx *exec_ctx, |
||||
security_handshaker *h, |
||||
grpc_error *error) { |
||||
if (error == GRPC_ERROR_NONE) { |
||||
// If we were shut down after the handshake succeeded but before an
|
||||
// endpoint callback was invoked, we need to generate our own error.
|
||||
error = GRPC_ERROR_CREATE("Handshaker shutdown"); |
||||
} |
||||
const char *msg = grpc_error_string(error); |
||||
gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg); |
||||
grpc_error_free_string(msg); |
||||
if (!h->shutdown) { |
||||
// 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, h->args->endpoint); |
||||
// Not shutting down, so the write failed. Clean up before
|
||||
// invoking the callback.
|
||||
cleanup_args_for_failure_locked(h); |
||||
} |
||||
// Invoke callback.
|
||||
grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, error, NULL); |
||||
} |
||||
|
||||
static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, |
||||
grpc_error *error) { |
||||
security_handshaker *h = arg; |
||||
gpr_mu_lock(&h->mu); |
||||
if (error != GRPC_ERROR_NONE || h->shutdown) { |
||||
security_handshake_failed_locked(exec_ctx, h, GRPC_ERROR_REF(error)); |
||||
goto done; |
||||
} |
||||
// Get frame protector.
|
||||
tsi_frame_protector *protector; |
||||
tsi_result result = |
||||
tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector); |
||||
if (result != TSI_OK) { |
||||
error = grpc_set_tsi_error_result( |
||||
GRPC_ERROR_CREATE("Frame protector creation failed"), result); |
||||
security_handshake_failed_locked(exec_ctx, h, error); |
||||
goto done; |
||||
} |
||||
// Success.
|
||||
// Create secure endpoint.
|
||||
h->args->endpoint = grpc_secure_endpoint_create( |
||||
protector, h->args->endpoint, h->left_overs.slices, h->left_overs.count); |
||||
h->left_overs.count = 0; |
||||
h->left_overs.length = 0; |
||||
// Clear out the read buffer before it gets passed to the transport,
|
||||
// since any excess bytes were already copied to h->left_overs.
|
||||
grpc_slice_buffer_reset_and_unref(h->args->read_buffer); |
||||
// Add auth context to channel args.
|
||||
grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context); |
||||
grpc_channel_args *tmp_args = h->args->args; |
||||
h->args->args = |
||||
grpc_channel_args_copy_and_add(tmp_args, &auth_context_arg, 1); |
||||
grpc_channel_args_destroy(tmp_args); |
||||
// Invoke callback.
|
||||
grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, GRPC_ERROR_NONE, NULL); |
||||
// Set shutdown to true so that subsequent calls to
|
||||
// security_handshaker_shutdown() do nothing.
|
||||
h->shutdown = true; |
||||
done: |
||||
gpr_mu_unlock(&h->mu); |
||||
security_handshaker_unref(exec_ctx, h); |
||||
} |
||||
|
||||
static grpc_error *check_peer_locked(grpc_exec_ctx *exec_ctx, |
||||
security_handshaker *h) { |
||||
tsi_peer peer; |
||||
tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer); |
||||
if (result != TSI_OK) { |
||||
return grpc_set_tsi_error_result( |
||||
GRPC_ERROR_CREATE("Peer extraction failed"), result); |
||||
} |
||||
grpc_security_connector_check_peer(exec_ctx, h->connector, peer, |
||||
&h->auth_context, &h->on_peer_checked); |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static grpc_error *send_handshake_bytes_to_peer_locked(grpc_exec_ctx *exec_ctx, |
||||
security_handshaker *h) { |
||||
// Get data to send.
|
||||
tsi_result result = TSI_OK; |
||||
size_t offset = 0; |
||||
do { |
||||
size_t to_send_size = h->handshake_buffer_size - offset; |
||||
result = tsi_handshaker_get_bytes_to_send_to_peer( |
||||
h->handshaker, h->handshake_buffer + offset, &to_send_size); |
||||
offset += to_send_size; |
||||
if (result == TSI_INCOMPLETE_DATA) { |
||||
h->handshake_buffer_size *= 2; |
||||
h->handshake_buffer = |
||||
gpr_realloc(h->handshake_buffer, h->handshake_buffer_size); |
||||
} |
||||
} while (result == TSI_INCOMPLETE_DATA); |
||||
if (result != TSI_OK) { |
||||
return grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Handshake failed"), |
||||
result); |
||||
} |
||||
// Send data.
|
||||
grpc_slice to_send = |
||||
grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset); |
||||
grpc_slice_buffer_reset_and_unref(&h->outgoing); |
||||
grpc_slice_buffer_add(&h->outgoing, to_send); |
||||
grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, |
||||
&h->on_handshake_data_sent_to_peer); |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, |
||||
void *arg, grpc_error *error) { |
||||
security_handshaker *h = arg; |
||||
gpr_mu_lock(&h->mu); |
||||
if (error != GRPC_ERROR_NONE || h->shutdown) { |
||||
security_handshake_failed_locked( |
||||
exec_ctx, h, |
||||
GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1)); |
||||
gpr_mu_unlock(&h->mu); |
||||
security_handshaker_unref(exec_ctx, h); |
||||
return; |
||||
} |
||||
// Process received data.
|
||||
tsi_result result = TSI_OK; |
||||
size_t consumed_slice_size = 0; |
||||
size_t i; |
||||
for (i = 0; i < h->args->read_buffer->count; i++) { |
||||
consumed_slice_size = GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]); |
||||
result = tsi_handshaker_process_bytes_from_peer( |
||||
h->handshaker, GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]), |
||||
&consumed_slice_size); |
||||
if (!tsi_handshaker_is_in_progress(h->handshaker)) break; |
||||
} |
||||
if (tsi_handshaker_is_in_progress(h->handshaker)) { |
||||
/* We may need more data. */ |
||||
if (result == TSI_INCOMPLETE_DATA) { |
||||
grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, |
||||
&h->on_handshake_data_received_from_peer); |
||||
goto done; |
||||
} else { |
||||
error = send_handshake_bytes_to_peer_locked(exec_ctx, h); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
security_handshake_failed_locked(exec_ctx, h, error); |
||||
gpr_mu_unlock(&h->mu); |
||||
security_handshaker_unref(exec_ctx, h); |
||||
return; |
||||
} |
||||
goto done; |
||||
} |
||||
} |
||||
if (result != TSI_OK) { |
||||
security_handshake_failed_locked( |
||||
exec_ctx, h, grpc_set_tsi_error_result( |
||||
GRPC_ERROR_CREATE("Handshake failed"), result)); |
||||
gpr_mu_unlock(&h->mu); |
||||
security_handshaker_unref(exec_ctx, h); |
||||
return; |
||||
} |
||||
/* Handshake is done and successful this point. */ |
||||
bool has_left_overs_in_current_slice = |
||||
(consumed_slice_size < |
||||
GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i])); |
||||
size_t num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + |
||||
h->args->read_buffer->count - i - 1; |
||||
if (num_left_overs > 0) { |
||||
/* Put the leftovers in our buffer (ownership transfered). */ |
||||
if (has_left_overs_in_current_slice) { |
||||
grpc_slice_buffer_add( |
||||
&h->left_overs, |
||||
grpc_slice_split_tail(&h->args->read_buffer->slices[i], |
||||
consumed_slice_size)); |
||||
/* split_tail above increments refcount. */ |
||||
grpc_slice_unref(h->args->read_buffer->slices[i]); |
||||
} |
||||
grpc_slice_buffer_addn( |
||||
&h->left_overs, &h->args->read_buffer->slices[i + 1], |
||||
num_left_overs - (size_t)has_left_overs_in_current_slice); |
||||
} |
||||
// Check peer.
|
||||
error = check_peer_locked(exec_ctx, h); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
security_handshake_failed_locked(exec_ctx, h, error); |
||||
gpr_mu_unlock(&h->mu); |
||||
security_handshaker_unref(exec_ctx, h); |
||||
return; |
||||
} |
||||
done: |
||||
gpr_mu_unlock(&h->mu); |
||||
} |
||||
|
||||
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, |
||||
grpc_error *error) { |
||||
security_handshaker *h = arg; |
||||
gpr_mu_lock(&h->mu); |
||||
if (error != GRPC_ERROR_NONE || h->shutdown) { |
||||
security_handshake_failed_locked( |
||||
exec_ctx, h, |
||||
GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1)); |
||||
gpr_mu_unlock(&h->mu); |
||||
security_handshaker_unref(exec_ctx, h); |
||||
return; |
||||
} |
||||
/* We may be done. */ |
||||
if (tsi_handshaker_is_in_progress(h->handshaker)) { |
||||
grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, |
||||
&h->on_handshake_data_received_from_peer); |
||||
} else { |
||||
error = check_peer_locked(exec_ctx, h); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
security_handshake_failed_locked(exec_ctx, h, error); |
||||
gpr_mu_unlock(&h->mu); |
||||
security_handshaker_unref(exec_ctx, h); |
||||
return; |
||||
} |
||||
} |
||||
gpr_mu_unlock(&h->mu); |
||||
} |
||||
|
||||
//
|
||||
// public handshaker API
|
||||
//
|
||||
|
||||
static void security_handshaker_destroy(grpc_exec_ctx *exec_ctx, |
||||
grpc_handshaker *handshaker) { |
||||
security_handshaker *h = (security_handshaker *)handshaker; |
||||
security_handshaker_unref(exec_ctx, h); |
||||
} |
||||
|
||||
static void security_handshaker_shutdown(grpc_exec_ctx *exec_ctx, |
||||
grpc_handshaker *handshaker) { |
||||
security_handshaker *h = (security_handshaker *)handshaker; |
||||
gpr_mu_lock(&h->mu); |
||||
if (!h->shutdown) { |
||||
h->shutdown = true; |
||||
grpc_endpoint_shutdown(exec_ctx, h->args->endpoint); |
||||
cleanup_args_for_failure_locked(h); |
||||
} |
||||
gpr_mu_unlock(&h->mu); |
||||
} |
||||
|
||||
static void security_handshaker_do_handshake(grpc_exec_ctx *exec_ctx, |
||||
grpc_handshaker *handshaker, |
||||
grpc_tcp_server_acceptor *acceptor, |
||||
grpc_closure *on_handshake_done, |
||||
grpc_handshaker_args *args) { |
||||
security_handshaker *h = (security_handshaker *)handshaker; |
||||
gpr_mu_lock(&h->mu); |
||||
h->args = args; |
||||
h->on_handshake_done = on_handshake_done; |
||||
gpr_ref(&h->refs); |
||||
grpc_error *error = send_handshake_bytes_to_peer_locked(exec_ctx, h); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
security_handshake_failed_locked(exec_ctx, h, error); |
||||
gpr_mu_unlock(&h->mu); |
||||
security_handshaker_unref(exec_ctx, h); |
||||
return; |
||||
} |
||||
gpr_mu_unlock(&h->mu); |
||||
} |
||||
|
||||
static const grpc_handshaker_vtable security_handshaker_vtable = { |
||||
security_handshaker_destroy, security_handshaker_shutdown, |
||||
security_handshaker_do_handshake}; |
||||
|
||||
static grpc_handshaker *security_handshaker_create( |
||||
grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker, |
||||
grpc_security_connector *connector) { |
||||
security_handshaker *h = gpr_malloc(sizeof(security_handshaker)); |
||||
memset(h, 0, sizeof(security_handshaker)); |
||||
grpc_handshaker_init(&security_handshaker_vtable, &h->base); |
||||
h->handshaker = handshaker; |
||||
h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); |
||||
gpr_mu_init(&h->mu); |
||||
gpr_ref_init(&h->refs, 1); |
||||
h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; |
||||
h->handshake_buffer = gpr_malloc(h->handshake_buffer_size); |
||||
grpc_closure_init(&h->on_handshake_data_sent_to_peer, |
||||
on_handshake_data_sent_to_peer, h); |
||||
grpc_closure_init(&h->on_handshake_data_received_from_peer, |
||||
on_handshake_data_received_from_peer, h); |
||||
grpc_closure_init(&h->on_peer_checked, on_peer_checked, h); |
||||
grpc_slice_buffer_init(&h->left_overs); |
||||
grpc_slice_buffer_init(&h->outgoing); |
||||
return &h->base; |
||||
} |
||||
|
||||
//
|
||||
// fail_handshaker
|
||||
//
|
||||
|
||||
static void fail_handshaker_destroy(grpc_exec_ctx *exec_ctx, |
||||
grpc_handshaker *handshaker) { |
||||
gpr_free(handshaker); |
||||
} |
||||
|
||||
static void fail_handshaker_shutdown(grpc_exec_ctx *exec_ctx, |
||||
grpc_handshaker *handshaker) {} |
||||
|
||||
static void fail_handshaker_do_handshake(grpc_exec_ctx *exec_ctx, |
||||
grpc_handshaker *handshaker, |
||||
grpc_tcp_server_acceptor *acceptor, |
||||
grpc_closure *on_handshake_done, |
||||
grpc_handshaker_args *args) { |
||||
grpc_exec_ctx_sched(exec_ctx, on_handshake_done, |
||||
GRPC_ERROR_CREATE("Failed to create security handshaker"), |
||||
NULL); |
||||
} |
||||
|
||||
static const grpc_handshaker_vtable fail_handshaker_vtable = { |
||||
fail_handshaker_destroy, fail_handshaker_shutdown, |
||||
fail_handshaker_do_handshake}; |
||||
|
||||
static grpc_handshaker *fail_handshaker_create() { |
||||
grpc_handshaker *h = gpr_malloc(sizeof(*h)); |
||||
grpc_handshaker_init(&fail_handshaker_vtable, h); |
||||
return h; |
||||
} |
||||
|
||||
//
|
||||
// exported functions
|
||||
//
|
||||
|
||||
void grpc_security_create_handshakers(grpc_exec_ctx *exec_ctx, |
||||
tsi_handshaker *handshaker, |
||||
grpc_security_connector *connector, |
||||
grpc_handshake_manager *handshake_mgr) { |
||||
// If no TSI handshaker was created, add a handshaker that always fails.
|
||||
// Otherwise, add a real security handshaker.
|
||||
if (handshaker == NULL) { |
||||
grpc_handshake_manager_add(handshake_mgr, fail_handshaker_create()); |
||||
} else { |
||||
grpc_handshake_manager_add( |
||||
handshake_mgr, |
||||
security_handshaker_create(exec_ctx, handshaker, connector)); |
||||
} |
||||
} |
Loading…
Reference in new issue