|  | @@ -102,13 +102,18 @@ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
 | 
	
		
			
				|  |  |    return NULL;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +void grpc_security_connector_shutdown(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                      grpc_security_connector *connector) {
 | 
	
		
			
				|  |  | +  connector->vtable->shutdown(exec_ctx, connector);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  void grpc_security_connector_do_handshake(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                            grpc_security_connector *sc,
 | 
	
		
			
				|  |  |                                            grpc_endpoint *nonsecure_endpoint,
 | 
	
		
			
				|  |  |                                            grpc_security_handshake_done_cb cb,
 | 
	
		
			
				|  |  |                                            void *user_data) {
 | 
	
		
			
				|  |  |    if (sc == NULL || nonsecure_endpoint == NULL) {
 | 
	
		
			
				|  |  | -    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, nonsecure_endpoint, NULL);
 | 
	
		
			
				|  |  | +    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL);
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      sc->vtable->do_handshake(exec_ctx, sc, nonsecure_endpoint, cb, user_data);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -210,6 +215,17 @@ typedef struct {
 | 
	
		
			
				|  |  |    int call_host_check_is_async;
 | 
	
		
			
				|  |  |  } grpc_fake_channel_security_connector;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +typedef struct tcp_endpoint_list {
 | 
	
		
			
				|  |  | +  grpc_endpoint *tcp_endpoint;
 | 
	
		
			
				|  |  | +  struct tcp_endpoint_list *next;
 | 
	
		
			
				|  |  | +} tcp_endpoint_list;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +typedef struct {
 | 
	
		
			
				|  |  | +  grpc_security_connector base;
 | 
	
		
			
				|  |  | +  gpr_mu mu;
 | 
	
		
			
				|  |  | +  tcp_endpoint_list *handshaking_tcp_endpoints;
 | 
	
		
			
				|  |  | +} grpc_fake_server_security_connector;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void fake_channel_destroy(grpc_security_connector *sc) {
 | 
	
		
			
				|  |  |    grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
 | 
	
		
			
				|  |  |    grpc_call_credentials_unref(c->request_metadata_creds);
 | 
	
	
		
			
				|  | @@ -280,20 +296,99 @@ static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                               nonsecure_endpoint, cb, user_data);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +typedef struct callback_data {
 | 
	
		
			
				|  |  | +  grpc_security_connector *sc;
 | 
	
		
			
				|  |  | +  grpc_endpoint *tcp;
 | 
	
		
			
				|  |  | +  grpc_security_handshake_done_cb cb;
 | 
	
		
			
				|  |  | +  void *user_data;
 | 
	
		
			
				|  |  | +} callback_data;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static tcp_endpoint_list *remove_tcp_from_list(tcp_endpoint_list *head,
 | 
	
		
			
				|  |  | +                                               grpc_endpoint *tcp) {
 | 
	
		
			
				|  |  | +  tcp_endpoint_list *node = head;
 | 
	
		
			
				|  |  | +  tcp_endpoint_list *tmp = NULL;
 | 
	
		
			
				|  |  | +  if (head && head->tcp_endpoint == tcp) {
 | 
	
		
			
				|  |  | +    head = head->next;
 | 
	
		
			
				|  |  | +    gpr_free(node);
 | 
	
		
			
				|  |  | +    return head;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  while (node) {
 | 
	
		
			
				|  |  | +    if (node->next->tcp_endpoint == tcp) {
 | 
	
		
			
				|  |  | +      tmp = node->next;
 | 
	
		
			
				|  |  | +      node->next = node->next->next;
 | 
	
		
			
				|  |  | +      gpr_free(tmp);
 | 
	
		
			
				|  |  | +      return head;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    node = node->next;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return head;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void fake_remove_tcp_and_call_user_cb(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                             void *user_data,
 | 
	
		
			
				|  |  | +                                             grpc_security_status status,
 | 
	
		
			
				|  |  | +                                             grpc_endpoint *secure_endpoint) {
 | 
	
		
			
				|  |  | +  callback_data *d = (callback_data *)user_data;
 | 
	
		
			
				|  |  | +  grpc_fake_server_security_connector *sc =
 | 
	
		
			
				|  |  | +      (grpc_fake_server_security_connector *)d->sc;
 | 
	
		
			
				|  |  | +  grpc_security_handshake_done_cb cb = d->cb;
 | 
	
		
			
				|  |  | +  void *data = d->user_data;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&sc->mu);
 | 
	
		
			
				|  |  | +  sc->handshaking_tcp_endpoints =
 | 
	
		
			
				|  |  | +      remove_tcp_from_list(sc->handshaking_tcp_endpoints, d->tcp);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&sc->mu);
 | 
	
		
			
				|  |  | +  gpr_free(d);
 | 
	
		
			
				|  |  | +  cb(exec_ctx, data, status, secure_endpoint);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void fake_server_do_handshake(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                       grpc_security_connector *sc,
 | 
	
		
			
				|  |  |                                       grpc_endpoint *nonsecure_endpoint,
 | 
	
		
			
				|  |  |                                       grpc_security_handshake_done_cb cb,
 | 
	
		
			
				|  |  |                                       void *user_data) {
 | 
	
		
			
				|  |  | +  grpc_fake_server_security_connector *c =
 | 
	
		
			
				|  |  | +      (grpc_fake_server_security_connector *)sc;
 | 
	
		
			
				|  |  | +  tcp_endpoint_list *node = gpr_malloc(sizeof(tcp_endpoint_list));
 | 
	
		
			
				|  |  | +  callback_data *wrapped_data;
 | 
	
		
			
				|  |  | +  node->tcp_endpoint = nonsecure_endpoint;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&c->mu);
 | 
	
		
			
				|  |  | +  node->next = c->handshaking_tcp_endpoints;
 | 
	
		
			
				|  |  | +  c->handshaking_tcp_endpoints = node;
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  | +  wrapped_data = gpr_malloc(sizeof(callback_data));
 | 
	
		
			
				|  |  | +  wrapped_data->sc = &c->base;
 | 
	
		
			
				|  |  | +  wrapped_data->tcp = nonsecure_endpoint;
 | 
	
		
			
				|  |  | +  wrapped_data->cb = cb;
 | 
	
		
			
				|  |  | +  wrapped_data->user_data = user_data;
 | 
	
		
			
				|  |  |    grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), sc,
 | 
	
		
			
				|  |  | -                             nonsecure_endpoint, cb, user_data);
 | 
	
		
			
				|  |  | +                             nonsecure_endpoint,
 | 
	
		
			
				|  |  | +                             fake_remove_tcp_and_call_user_cb, wrapped_data);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void fake_channel_shutdown(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                  grpc_security_connector *sc) {}
 | 
	
		
			
				|  |  | +static void fake_server_shutdown(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                 grpc_security_connector *sc) {
 | 
	
		
			
				|  |  | +  grpc_fake_server_security_connector *c =
 | 
	
		
			
				|  |  | +      (grpc_fake_server_security_connector *)sc;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&c->mu);
 | 
	
		
			
				|  |  | +  while (c->handshaking_tcp_endpoints != NULL) {
 | 
	
		
			
				|  |  | +    grpc_endpoint_shutdown(exec_ctx,
 | 
	
		
			
				|  |  | +                           c->handshaking_tcp_endpoints->tcp_endpoint);
 | 
	
		
			
				|  |  | +    c->handshaking_tcp_endpoints =
 | 
	
		
			
				|  |  | +        remove_tcp_from_list(c->handshaking_tcp_endpoints,
 | 
	
		
			
				|  |  | +                             c->handshaking_tcp_endpoints->tcp_endpoint);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_security_connector_vtable fake_channel_vtable = {
 | 
	
		
			
				|  |  | -    fake_channel_destroy, fake_channel_do_handshake, fake_check_peer};
 | 
	
		
			
				|  |  | +    fake_channel_destroy, fake_channel_do_handshake, fake_check_peer,
 | 
	
		
			
				|  |  | +    fake_channel_shutdown};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_security_connector_vtable fake_server_vtable = {
 | 
	
		
			
				|  |  | -    fake_server_destroy, fake_server_do_handshake, fake_check_peer};
 | 
	
		
			
				|  |  | +    fake_server_destroy, fake_server_do_handshake, fake_check_peer,
 | 
	
		
			
				|  |  | +    fake_server_shutdown};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
 | 
	
		
			
				|  |  |      grpc_call_credentials *request_metadata_creds,
 | 
	
	
		
			
				|  | @@ -313,13 +408,15 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_security_connector *grpc_fake_server_security_connector_create(void) {
 | 
	
		
			
				|  |  | -  grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector));
 | 
	
		
			
				|  |  | -  memset(c, 0, sizeof(grpc_security_connector));
 | 
	
		
			
				|  |  | -  gpr_ref_init(&c->refcount, 1);
 | 
	
		
			
				|  |  | -  c->is_client_side = 0;
 | 
	
		
			
				|  |  | -  c->vtable = &fake_server_vtable;
 | 
	
		
			
				|  |  | -  c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
 | 
	
		
			
				|  |  | -  return c;
 | 
	
		
			
				|  |  | +  grpc_fake_server_security_connector *c =
 | 
	
		
			
				|  |  | +      gpr_malloc(sizeof(grpc_fake_server_security_connector));
 | 
	
		
			
				|  |  | +  memset(c, 0, sizeof(grpc_fake_server_security_connector));
 | 
	
		
			
				|  |  | +  gpr_ref_init(&c->base.refcount, 1);
 | 
	
		
			
				|  |  | +  c->base.is_client_side = 0;
 | 
	
		
			
				|  |  | +  c->base.vtable = &fake_server_vtable;
 | 
	
		
			
				|  |  | +  c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
 | 
	
		
			
				|  |  | +  gpr_mu_init(&c->mu);
 | 
	
		
			
				|  |  | +  return &c->base;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* --- Ssl implementation. --- */
 | 
	
	
		
			
				|  | @@ -334,6 +431,8 @@ typedef struct {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef struct {
 | 
	
		
			
				|  |  |    grpc_security_connector base;
 | 
	
		
			
				|  |  | +  gpr_mu mu;
 | 
	
		
			
				|  |  | +  tcp_endpoint_list *handshaking_tcp_endpoints;
 | 
	
		
			
				|  |  |    tsi_ssl_handshaker_factory *handshaker_factory;
 | 
	
		
			
				|  |  |  } grpc_ssl_server_security_connector;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -354,6 +453,7 @@ static void ssl_channel_destroy(grpc_security_connector *sc) {
 | 
	
		
			
				|  |  |  static void ssl_server_destroy(grpc_security_connector *sc) {
 | 
	
		
			
				|  |  |    grpc_ssl_server_security_connector *c =
 | 
	
		
			
				|  |  |        (grpc_ssl_server_security_connector *)sc;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    if (c->handshaker_factory != NULL) {
 | 
	
		
			
				|  |  |      tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -390,13 +490,30 @@ static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                          : c->target_name,
 | 
	
		
			
				|  |  |        &handshaker);
 | 
	
		
			
				|  |  |    if (status != GRPC_SECURITY_OK) {
 | 
	
		
			
				|  |  | -    cb(exec_ctx, user_data, status, nonsecure_endpoint, NULL);
 | 
	
		
			
				|  |  | +    cb(exec_ctx, user_data, status, NULL);
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint, cb,
 | 
	
		
			
				|  |  |                                 user_data);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void ssl_remove_tcp_and_call_user_cb(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                            void *user_data,
 | 
	
		
			
				|  |  | +                                            grpc_security_status status,
 | 
	
		
			
				|  |  | +                                            grpc_endpoint *secure_endpoint) {
 | 
	
		
			
				|  |  | +  callback_data *d = (callback_data *)user_data;
 | 
	
		
			
				|  |  | +  grpc_ssl_server_security_connector *sc =
 | 
	
		
			
				|  |  | +      (grpc_ssl_server_security_connector *)d->sc;
 | 
	
		
			
				|  |  | +  grpc_security_handshake_done_cb cb = d->cb;
 | 
	
		
			
				|  |  | +  void *data = d->user_data;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&sc->mu);
 | 
	
		
			
				|  |  | +  sc->handshaking_tcp_endpoints =
 | 
	
		
			
				|  |  | +      remove_tcp_from_list(sc->handshaking_tcp_endpoints, d->tcp);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&sc->mu);
 | 
	
		
			
				|  |  | +  gpr_free(d);
 | 
	
		
			
				|  |  | +  cb(exec_ctx, data, status, secure_endpoint);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                      grpc_security_connector *sc,
 | 
	
		
			
				|  |  |                                      grpc_endpoint *nonsecure_endpoint,
 | 
	
	
		
			
				|  | @@ -405,13 +522,26 @@ static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    grpc_ssl_server_security_connector *c =
 | 
	
		
			
				|  |  |        (grpc_ssl_server_security_connector *)sc;
 | 
	
		
			
				|  |  |    tsi_handshaker *handshaker;
 | 
	
		
			
				|  |  | +  callback_data *wrapped_data;
 | 
	
		
			
				|  |  | +  tcp_endpoint_list *node;
 | 
	
		
			
				|  |  |    grpc_security_status status =
 | 
	
		
			
				|  |  |        ssl_create_handshaker(c->handshaker_factory, 0, NULL, &handshaker);
 | 
	
		
			
				|  |  |    if (status != GRPC_SECURITY_OK) {
 | 
	
		
			
				|  |  | -    cb(exec_ctx, user_data, status, nonsecure_endpoint, NULL);
 | 
	
		
			
				|  |  | +    cb(exec_ctx, user_data, status, NULL);
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  | -    grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint, cb,
 | 
	
		
			
				|  |  | -                               user_data);
 | 
	
		
			
				|  |  | +    node = gpr_malloc(sizeof(tcp_endpoint_list));
 | 
	
		
			
				|  |  | +    node->tcp_endpoint = nonsecure_endpoint;
 | 
	
		
			
				|  |  | +    gpr_mu_lock(&c->mu);
 | 
	
		
			
				|  |  | +    node->next = c->handshaking_tcp_endpoints;
 | 
	
		
			
				|  |  | +    c->handshaking_tcp_endpoints = node;
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  | +    wrapped_data = gpr_malloc(sizeof(callback_data));
 | 
	
		
			
				|  |  | +    wrapped_data->sc = &c->base;
 | 
	
		
			
				|  |  | +    wrapped_data->tcp = nonsecure_endpoint;
 | 
	
		
			
				|  |  | +    wrapped_data->cb = cb;
 | 
	
		
			
				|  |  | +    wrapped_data->user_data = user_data;
 | 
	
		
			
				|  |  | +    grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint,
 | 
	
		
			
				|  |  | +                               ssl_remove_tcp_and_call_user_cb, wrapped_data);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -536,11 +666,29 @@ static grpc_security_status ssl_channel_check_call_host(
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void ssl_channel_shutdown(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                 grpc_security_connector *sc) {}
 | 
	
		
			
				|  |  | +static void ssl_server_shutdown(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                grpc_security_connector *sc) {
 | 
	
		
			
				|  |  | +  grpc_ssl_server_security_connector *c =
 | 
	
		
			
				|  |  | +      (grpc_ssl_server_security_connector *)sc;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&c->mu);
 | 
	
		
			
				|  |  | +  while (c->handshaking_tcp_endpoints != NULL) {
 | 
	
		
			
				|  |  | +    grpc_endpoint_shutdown(exec_ctx,
 | 
	
		
			
				|  |  | +                           c->handshaking_tcp_endpoints->tcp_endpoint);
 | 
	
		
			
				|  |  | +    c->handshaking_tcp_endpoints =
 | 
	
		
			
				|  |  | +        remove_tcp_from_list(c->handshaking_tcp_endpoints,
 | 
	
		
			
				|  |  | +                             c->handshaking_tcp_endpoints->tcp_endpoint);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  static grpc_security_connector_vtable ssl_channel_vtable = {
 | 
	
		
			
				|  |  | -    ssl_channel_destroy, ssl_channel_do_handshake, ssl_channel_check_peer};
 | 
	
		
			
				|  |  | +    ssl_channel_destroy, ssl_channel_do_handshake, ssl_channel_check_peer,
 | 
	
		
			
				|  |  | +    ssl_channel_shutdown};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_security_connector_vtable ssl_server_vtable = {
 | 
	
		
			
				|  |  | -    ssl_server_destroy, ssl_server_do_handshake, ssl_server_check_peer};
 | 
	
		
			
				|  |  | +    ssl_server_destroy, ssl_server_do_handshake, ssl_server_check_peer,
 | 
	
		
			
				|  |  | +    ssl_server_shutdown};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static gpr_slice default_pem_root_certs;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -691,6 +839,7 @@ grpc_security_status grpc_ssl_server_security_connector_create(
 | 
	
		
			
				|  |  |      *sc = NULL;
 | 
	
		
			
				|  |  |      goto error;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  gpr_mu_init(&c->mu);
 | 
	
		
			
				|  |  |    *sc = &c->base;
 | 
	
		
			
				|  |  |    gpr_free((void *)alpn_protocol_strings);
 | 
	
		
			
				|  |  |    gpr_free(alpn_protocol_string_lengths);
 |