LCOV - code coverage report
Current view: top level - core/security - server_secure_chttp2.c (source / functions) Hit Total Coverage
Test: tmp.CaZ6RjdVn2 Lines: 100 118 84.7 %
Date: 2015-12-10 22:15:08 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  * Copyright 2015, Google Inc.
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions are
       8             :  * met:
       9             :  *
      10             :  *     * Redistributions of source code must retain the above copyright
      11             :  * notice, this list of conditions and the following disclaimer.
      12             :  *     * Redistributions in binary form must reproduce the above
      13             :  * copyright notice, this list of conditions and the following disclaimer
      14             :  * in the documentation and/or other materials provided with the
      15             :  * distribution.
      16             :  *     * Neither the name of Google Inc. nor the names of its
      17             :  * contributors may be used to endorse or promote products derived from
      18             :  * this software without specific prior written permission.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      21             :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      22             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      23             :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      24             :  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      25             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      26             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      27             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      28             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      29             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      30             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      31             :  *
      32             :  */
      33             : 
      34             : #include <grpc/grpc.h>
      35             : 
      36             : #include <string.h>
      37             : 
      38             : #include "src/core/channel/channel_args.h"
      39             : #include "src/core/channel/http_server_filter.h"
      40             : #include "src/core/iomgr/endpoint.h"
      41             : #include "src/core/iomgr/resolve_address.h"
      42             : #include "src/core/iomgr/tcp_server.h"
      43             : #include "src/core/security/auth_filters.h"
      44             : #include "src/core/security/credentials.h"
      45             : #include "src/core/security/security_connector.h"
      46             : #include "src/core/security/security_context.h"
      47             : #include "src/core/surface/api_trace.h"
      48             : #include "src/core/surface/server.h"
      49             : #include "src/core/transport/chttp2_transport.h"
      50             : #include <grpc/support/alloc.h>
      51             : #include <grpc/support/log.h>
      52             : #include <grpc/support/sync.h>
      53             : #include <grpc/support/useful.h>
      54             : 
      55             : typedef struct grpc_server_secure_state {
      56             :   grpc_server *server;
      57             :   grpc_tcp_server *tcp;
      58             :   grpc_security_connector *sc;
      59             :   grpc_server_credentials *creds;
      60             :   int is_shutdown;
      61             :   gpr_mu mu;
      62             :   gpr_refcount refcount;
      63             :   grpc_closure destroy_closure;
      64             :   grpc_closure *destroy_callback;
      65             : } grpc_server_secure_state;
      66             : 
      67         578 : static void state_ref(grpc_server_secure_state *state) {
      68         595 :   gpr_ref(&state->refcount);
      69         578 : }
      70             : 
      71        1299 : static void state_unref(grpc_server_secure_state *state) {
      72        1299 :   if (gpr_unref(&state->refcount)) {
      73             :     /* ensure all threads have unlocked */
      74         704 :     gpr_mu_lock(&state->mu);
      75         704 :     gpr_mu_unlock(&state->mu);
      76             :     /* clean up */
      77         704 :     GRPC_SECURITY_CONNECTOR_UNREF(state->sc, "server");
      78         704 :     grpc_server_credentials_unref(state->creds);
      79         704 :     gpr_free(state);
      80             :   }
      81        1299 : }
      82             : 
      83         590 : static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
      84             :                             grpc_transport *transport) {
      85             :   static grpc_channel_filter const *extra_filters[] = {
      86             :       &grpc_server_auth_filter, &grpc_http_server_filter};
      87         573 :   grpc_server_secure_state *state = statep;
      88             :   grpc_channel_args *args_copy;
      89             :   grpc_arg args_to_add[2];
      90         590 :   args_to_add[0] = grpc_server_credentials_to_arg(state->creds);
      91         590 :   args_to_add[1] = grpc_auth_context_to_arg(state->sc->auth_context);
      92         590 :   args_copy = grpc_channel_args_copy_and_add(
      93             :       grpc_server_get_channel_args(state->server), args_to_add,
      94             :       GPR_ARRAY_SIZE(args_to_add));
      95         590 :   grpc_server_setup_transport(exec_ctx, state->server, transport, extra_filters,
      96             :                               GPR_ARRAY_SIZE(extra_filters), args_copy);
      97         590 :   grpc_channel_args_destroy(args_copy);
      98         590 : }
      99             : 
     100         595 : static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
     101             :                                      grpc_security_status status,
     102             :                                      grpc_endpoint *secure_endpoint) {
     103         578 :   grpc_server_secure_state *state = statep;
     104             :   grpc_transport *transport;
     105         595 :   if (status == GRPC_SECURITY_OK) {
     106         590 :     if (secure_endpoint) {
     107         590 :       gpr_mu_lock(&state->mu);
     108         590 :       if (!state->is_shutdown) {
     109         590 :         transport = grpc_create_chttp2_transport(
     110             :             exec_ctx, grpc_server_get_channel_args(state->server),
     111             :             secure_endpoint, 0);
     112         590 :         setup_transport(exec_ctx, state, transport);
     113         590 :         grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
     114             :       } else {
     115             :         /* We need to consume this here, because the server may already have
     116             :          * gone away. */
     117           0 :         grpc_endpoint_destroy(exec_ctx, secure_endpoint);
     118             :       }
     119         590 :       gpr_mu_unlock(&state->mu);
     120             :     }
     121             :   } else {
     122           5 :     gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
     123             :   }
     124         595 :   state_unref(state);
     125         595 : }
     126             : 
     127         595 : static void on_accept(grpc_exec_ctx *exec_ctx, void *statep,
     128             :                       grpc_endpoint *tcp) {
     129         578 :   grpc_server_secure_state *state = statep;
     130         578 :   state_ref(state);
     131         595 :   grpc_security_connector_do_handshake(exec_ctx, state->sc, tcp,
     132             :                                        on_secure_handshake_done, state);
     133         595 : }
     134             : 
     135             : /* Server callback: start listening on our ports */
     136         704 : static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
     137             :                   grpc_pollset **pollsets, size_t pollset_count) {
     138         702 :   grpc_server_secure_state *state = statep;
     139         704 :   grpc_tcp_server_start(exec_ctx, state->tcp, pollsets, pollset_count,
     140             :                         on_accept, state);
     141         704 : }
     142             : 
     143         704 : static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, int success) {
     144         702 :   grpc_server_secure_state *state = statep;
     145         704 :   state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
     146             :                               success);
     147         704 :   grpc_security_connector_shutdown(exec_ctx, state->sc);
     148         704 :   state_unref(state);
     149         704 : }
     150             : 
     151             : /* Server callback: destroy the tcp listener (so we don't generate further
     152             :    callbacks) */
     153         704 : static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
     154             :                     grpc_closure *callback) {
     155         702 :   grpc_server_secure_state *state = statep;
     156             :   grpc_tcp_server *tcp;
     157         704 :   gpr_mu_lock(&state->mu);
     158         704 :   state->is_shutdown = 1;
     159         704 :   state->destroy_callback = callback;
     160         704 :   tcp = state->tcp;
     161         704 :   gpr_mu_unlock(&state->mu);
     162         704 :   grpc_closure_init(&state->destroy_closure, destroy_done, state);
     163         704 :   grpc_tcp_server_destroy(exec_ctx, tcp, &state->destroy_closure);
     164         704 : }
     165             : 
     166         705 : int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
     167             :                                       grpc_server_credentials *creds) {
     168         702 :   grpc_resolved_addresses *resolved = NULL;
     169         702 :   grpc_tcp_server *tcp = NULL;
     170         702 :   grpc_server_secure_state *state = NULL;
     171             :   size_t i;
     172         702 :   unsigned count = 0;
     173         702 :   int port_num = -1;
     174             :   int port_temp;
     175         702 :   grpc_security_status status = GRPC_SECURITY_ERROR;
     176         705 :   grpc_security_connector *sc = NULL;
     177         705 :   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     178             : 
     179         705 :   GRPC_API_TRACE(
     180             :       "grpc_server_add_secure_http2_port("
     181             :       "server=%p, addr=%s, creds=%p)",
     182             :       3, (server, addr, creds));
     183             : 
     184             :   /* create security context */
     185         705 :   if (creds == NULL) goto error;
     186         705 :   status = grpc_server_credentials_create_security_connector(creds, &sc);
     187         705 :   if (status != GRPC_SECURITY_OK) {
     188           0 :     gpr_log(GPR_ERROR,
     189             :             "Unable to create secure server with credentials of type %s.",
     190             :             creds->type);
     191           0 :     goto error;
     192             :   }
     193         705 :   sc->channel_args = grpc_server_get_channel_args(server);
     194             : 
     195             :   /* resolve address */
     196         705 :   resolved = grpc_blocking_resolve_address(addr, "https");
     197         705 :   if (!resolved) {
     198           0 :     goto error;
     199             :   }
     200             : 
     201         705 :   tcp = grpc_tcp_server_create();
     202         705 :   if (!tcp) {
     203           0 :     goto error;
     204             :   }
     205             : 
     206        2061 :   for (i = 0; i < resolved->naddrs; i++) {
     207             :     grpc_tcp_listener *listener;
     208        2718 :     listener = grpc_tcp_server_add_port(
     209        1359 :         tcp, (struct sockaddr *)&resolved->addrs[i].addr,
     210        1359 :         resolved->addrs[i].len);
     211        1359 :     port_temp = grpc_tcp_listener_get_port(listener);
     212        1359 :     if (port_temp >= 0) {
     213        1359 :       if (port_num == -1) {
     214         702 :         port_num = port_temp;
     215             :       } else {
     216         654 :         GPR_ASSERT(port_num == port_temp);
     217             :       }
     218        1359 :       count++;
     219             :     }
     220             :   }
     221         705 :   if (count == 0) {
     222           0 :     gpr_log(GPR_ERROR, "No address added out of total %d resolved",
     223             :             resolved->naddrs);
     224           0 :     goto error;
     225             :   }
     226         705 :   if (count != resolved->naddrs) {
     227           0 :     gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
     228             :             count, resolved->naddrs);
     229             :     /* if it's an error, don't we want to goto error; here ? */
     230             :   }
     231         705 :   grpc_resolved_addresses_destroy(resolved);
     232             : 
     233         705 :   state = gpr_malloc(sizeof(*state));
     234         705 :   memset(state, 0, sizeof(*state));
     235         705 :   state->server = server;
     236         705 :   state->tcp = tcp;
     237         705 :   state->sc = sc;
     238         705 :   state->creds = grpc_server_credentials_ref(creds);
     239             : 
     240         705 :   state->is_shutdown = 0;
     241         705 :   gpr_mu_init(&state->mu);
     242         705 :   gpr_ref_init(&state->refcount, 1);
     243             : 
     244             :   /* Register with the server only upon success */
     245         705 :   grpc_server_add_listener(&exec_ctx, server, state, start, destroy);
     246             : 
     247         705 :   grpc_exec_ctx_finish(&exec_ctx);
     248         705 :   return port_num;
     249             : 
     250             : /* Error path: cleanup and return */
     251             : error:
     252           0 :   if (sc) {
     253           0 :     GRPC_SECURITY_CONNECTOR_UNREF(sc, "server");
     254             :   }
     255           0 :   if (resolved) {
     256           0 :     grpc_resolved_addresses_destroy(resolved);
     257             :   }
     258           0 :   if (tcp) {
     259           0 :     grpc_tcp_server_destroy(&exec_ctx, tcp, NULL);
     260             :   }
     261           0 :   if (state) {
     262           0 :     gpr_free(state);
     263             :   }
     264           0 :   grpc_exec_ctx_finish(&exec_ctx);
     265           0 :   return 0;
     266             : }

Generated by: LCOV version 1.11