|  | @@ -39,7 +39,9 @@
 | 
	
		
			
				|  |  |  #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/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"
 | 
	
	
		
			
				|  | @@ -47,24 +49,22 @@
 | 
	
		
			
				|  |  |  #define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef struct {
 | 
	
		
			
				|  |  | +  grpc_handshaker base;
 | 
	
		
			
				|  |  | +  grpc_handshaker_args* args;
 | 
	
		
			
				|  |  | +  grpc_closure* on_handshake_done;
 | 
	
		
			
				|  |  |    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;
 | 
	
		
			
				|  |  | +} security_handshaker;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                                   void *setup,
 | 
	
	
		
			
				|  | @@ -73,40 +73,12 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  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) {
 | 
	
		
			
				|  |  | +static void unref_handshake(security_handshaker *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);
 | 
	
	
		
			
				|  | @@ -114,36 +86,38 @@ static void unref_handshake(grpc_security_handshake *h) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void security_handshake_done(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | -                                    grpc_security_handshake *h,
 | 
	
		
			
				|  |  | +                                    security_handshaker *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);
 | 
	
		
			
				|  |  | +    h->args->endpoint = h->secure_endpoint;
 | 
	
		
			
				|  |  | +    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);
 | 
	
		
			
				|  |  |    } 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);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  // Clear out the read buffer before it gets passed to the transport,
 | 
	
		
			
				|  |  | +  // since any excess bytes were already moved to h->left_overs.
 | 
	
		
			
				|  |  | +  grpc_slice_buffer_reset_and_unref(h->args->read_buffer);
 | 
	
		
			
				|  |  | +  h->args = NULL;
 | 
	
		
			
				|  |  | +  grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, error, 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;
 | 
	
		
			
				|  |  | +  security_handshaker *h = user_data;
 | 
	
		
			
				|  |  |    tsi_frame_protector *protector;
 | 
	
		
			
				|  |  |    tsi_result result;
 | 
	
		
			
				|  |  |    if (status != GRPC_SECURITY_OK) {
 | 
	
	
		
			
				|  | @@ -172,7 +146,7 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
 | 
	
		
			
				|  |  |    return;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) {
 | 
	
		
			
				|  |  | +static void check_peer(grpc_exec_ctx *exec_ctx, security_handshaker *h) {
 | 
	
		
			
				|  |  |    tsi_peer peer;
 | 
	
		
			
				|  |  |    tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -187,7 +161,7 @@ static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | -                                         grpc_security_handshake *h) {
 | 
	
		
			
				|  |  | +                                         security_handshaker *h) {
 | 
	
		
			
				|  |  |    size_t offset = 0;
 | 
	
		
			
				|  |  |    tsi_result result = TSI_OK;
 | 
	
		
			
				|  |  |    grpc_slice to_send;
 | 
	
	
		
			
				|  | @@ -215,8 +189,6 @@ static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |        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);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -224,7 +196,7 @@ static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                                   void *handshake,
 | 
	
		
			
				|  |  |                                                   grpc_error *error) {
 | 
	
		
			
				|  |  | -  grpc_security_handshake *h = handshake;
 | 
	
		
			
				|  |  | +  security_handshaker *h = handshake;
 | 
	
		
			
				|  |  |    size_t consumed_slice_size = 0;
 | 
	
		
			
				|  |  |    tsi_result result = TSI_OK;
 | 
	
		
			
				|  |  |    size_t i;
 | 
	
	
		
			
				|  | @@ -238,10 +210,10 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  for (i = 0; i < h->incoming.count; i++) {
 | 
	
		
			
				|  |  | -    consumed_slice_size = GRPC_SLICE_LENGTH(h->incoming.slices[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->incoming.slices[i]),
 | 
	
		
			
				|  |  | +        h->handshaker, GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]),
 | 
	
		
			
				|  |  |          &consumed_slice_size);
 | 
	
		
			
				|  |  |      if (!tsi_handshaker_is_in_progress(h->handshaker)) break;
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -249,7 +221,7 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    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,
 | 
	
		
			
				|  |  | +      grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, h->args->read_buffer,
 | 
	
		
			
				|  |  |                           &h->on_handshake_data_received_from_peer);
 | 
	
		
			
				|  |  |        return;
 | 
	
		
			
				|  |  |      } else {
 | 
	
	
		
			
				|  | @@ -267,32 +239,33 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Handshake is done and successful this point. */
 | 
	
		
			
				|  |  |    has_left_overs_in_current_slice =
 | 
	
		
			
				|  |  | -      (consumed_slice_size < GRPC_SLICE_LENGTH(h->incoming.slices[i]));
 | 
	
		
			
				|  |  | +      (consumed_slice_size <
 | 
	
		
			
				|  |  | +       GRPC_SLICE_LENGTH(h->args->read_buffer->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;
 | 
	
		
			
				|  |  | +      (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);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* 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;
 | 
	
		
			
				|  |  | +  security_handshaker *h = handshake;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Make sure that write is OK. */
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
	
		
			
				|  | @@ -305,70 +278,110 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* 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,
 | 
	
		
			
				|  |  | +    grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, h->args->read_buffer,
 | 
	
		
			
				|  |  |                         &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);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +// public handshaker API
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void security_handshaker_destroy(grpc_exec_ctx* exec_ctx,
 | 
	
		
			
				|  |  | +                                            grpc_handshaker* handshaker) {
 | 
	
		
			
				|  |  | +  security_handshaker* h = (security_handshaker*)handshaker;
 | 
	
		
			
				|  |  |    unref_handshake(h);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void grpc_do_security_handshake(
 | 
	
		
			
				|  |  | +static void security_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
 | 
	
		
			
				|  |  | +                                             grpc_handshaker* handshaker) {
 | 
	
		
			
				|  |  | +  security_handshaker *h = (security_handshaker*)handshaker;
 | 
	
		
			
				|  |  | +  grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +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;
 | 
	
		
			
				|  |  | +  h->args = args;
 | 
	
		
			
				|  |  | +  h->on_handshake_done = on_handshake_done;
 | 
	
		
			
				|  |  | +  h->wrapped_endpoint = args->endpoint;  // FIXME: remove?
 | 
	
		
			
				|  |  | +  gpr_ref(&h->refs);
 | 
	
		
			
				|  |  | +  send_handshake_bytes_to_peer(exec_ctx, h);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +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, 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));
 | 
	
		
			
				|  |  | +    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");
 | 
	
		
			
				|  |  | -  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 */
 | 
	
		
			
				|  |  | +  gpr_ref_init(&h->refs, 1);
 | 
	
		
			
				|  |  |    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));
 | 
	
		
			
				|  |  | +  return &h->base;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -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);
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +// 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));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  }
 |