|  | @@ -136,6 +136,39 @@ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +int grpc_security_connector_cmp(grpc_security_connector *sc,
 | 
	
		
			
				|  |  | +                                grpc_security_connector *other) {
 | 
	
		
			
				|  |  | +  if (sc == NULL || other == NULL) return GPR_ICMP(sc, other);
 | 
	
		
			
				|  |  | +  int c = GPR_ICMP(sc->vtable, other->vtable);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  return sc->vtable->cmp(sc, other);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int grpc_channel_security_connector_cmp(grpc_channel_security_connector *sc1,
 | 
	
		
			
				|  |  | +                                        grpc_channel_security_connector *sc2) {
 | 
	
		
			
				|  |  | +  GPR_ASSERT(sc1->channel_creds != NULL);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(sc2->channel_creds != NULL);
 | 
	
		
			
				|  |  | +  int c = GPR_ICMP(sc1->channel_creds, sc2->channel_creds);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  c = GPR_ICMP(sc1->request_metadata_creds, sc2->request_metadata_creds);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  c = GPR_ICMP((void *)sc1->check_call_host, (void *)sc2->check_call_host);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  c = GPR_ICMP((void *)sc1->cancel_check_call_host,
 | 
	
		
			
				|  |  | +               (void *)sc2->cancel_check_call_host);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  return GPR_ICMP((void *)sc1->add_handshakers, (void *)sc2->add_handshakers);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int grpc_server_security_connector_cmp(grpc_server_security_connector *sc1,
 | 
	
		
			
				|  |  | +                                       grpc_server_security_connector *sc2) {
 | 
	
		
			
				|  |  | +  GPR_ASSERT(sc1->server_creds != NULL);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(sc2->server_creds != NULL);
 | 
	
		
			
				|  |  | +  int c = GPR_ICMP(sc1->server_creds, sc2->server_creds);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  return GPR_ICMP((void *)sc1->add_handshakers, (void *)sc2->add_handshakers);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  bool grpc_channel_security_connector_check_call_host(
 | 
	
		
			
				|  |  |      grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
 | 
	
		
			
				|  |  |      const char *host, grpc_auth_context *auth_context,
 | 
	
	
		
			
				|  | @@ -199,25 +232,27 @@ void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    if (gpr_unref(&sc->refcount)) sc->vtable->destroy(exec_ctx, sc);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void connector_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) {
 | 
	
		
			
				|  |  | +static void connector_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) {
 | 
	
		
			
				|  |  |    GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, (grpc_security_connector *)p,
 | 
	
		
			
				|  |  | -                                "connector_pointer_arg_destroy");
 | 
	
		
			
				|  |  | +                                "connector_arg_destroy");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void *connector_pointer_arg_copy(void *p) {
 | 
	
		
			
				|  |  | +static void *connector_arg_copy(void *p) {
 | 
	
		
			
				|  |  |    return GRPC_SECURITY_CONNECTOR_REF((grpc_security_connector *)p,
 | 
	
		
			
				|  |  | -                                     "connector_pointer_arg_copy");
 | 
	
		
			
				|  |  | +                                     "connector_arg_copy");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static int connector_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
 | 
	
		
			
				|  |  | +static int connector_cmp(void *a, void *b) {
 | 
	
		
			
				|  |  | +  return grpc_security_connector_cmp((grpc_security_connector *)a,
 | 
	
		
			
				|  |  | +                                     (grpc_security_connector *)b);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static const grpc_arg_pointer_vtable connector_pointer_vtable = {
 | 
	
		
			
				|  |  | -    connector_pointer_arg_copy, connector_pointer_arg_destroy,
 | 
	
		
			
				|  |  | -    connector_pointer_cmp};
 | 
	
		
			
				|  |  | +static const grpc_arg_pointer_vtable connector_arg_vtable = {
 | 
	
		
			
				|  |  | +    connector_arg_copy, connector_arg_destroy, connector_cmp};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
 | 
	
		
			
				|  |  |    return grpc_channel_arg_pointer_create((char *)GRPC_ARG_SECURITY_CONNECTOR,
 | 
	
		
			
				|  |  | -                                         sc, &connector_pointer_vtable);
 | 
	
		
			
				|  |  | +                                         sc, &connector_arg_vtable);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) {
 | 
	
	
		
			
				|  | @@ -382,6 +417,32 @@ static void fake_server_check_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    fake_check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static int fake_channel_cmp(grpc_security_connector *sc1,
 | 
	
		
			
				|  |  | +                            grpc_security_connector *sc2) {
 | 
	
		
			
				|  |  | +  grpc_fake_channel_security_connector *c1 =
 | 
	
		
			
				|  |  | +      (grpc_fake_channel_security_connector *)sc1;
 | 
	
		
			
				|  |  | +  grpc_fake_channel_security_connector *c2 =
 | 
	
		
			
				|  |  | +      (grpc_fake_channel_security_connector *)sc2;
 | 
	
		
			
				|  |  | +  int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  c = strcmp(c1->target, c2->target);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  if (c1->expected_targets == NULL || c2->expected_targets == NULL) {
 | 
	
		
			
				|  |  | +    c = GPR_ICMP(c1->expected_targets, c2->expected_targets);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    c = strcmp(c1->expected_targets, c2->expected_targets);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  return GPR_ICMP(c1->is_lb_channel, c2->is_lb_channel);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int fake_server_cmp(grpc_security_connector *sc1,
 | 
	
		
			
				|  |  | +                           grpc_security_connector *sc2) {
 | 
	
		
			
				|  |  | +  return grpc_server_security_connector_cmp(
 | 
	
		
			
				|  |  | +      (grpc_server_security_connector *)sc1,
 | 
	
		
			
				|  |  | +      (grpc_server_security_connector *)sc2);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static bool fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                           grpc_channel_security_connector *sc,
 | 
	
		
			
				|  |  |                                           const char *host,
 | 
	
	
		
			
				|  | @@ -418,12 +479,13 @@ static void fake_server_add_handshakers(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_security_connector_vtable fake_channel_vtable = {
 | 
	
		
			
				|  |  | -    fake_channel_destroy, fake_channel_check_peer};
 | 
	
		
			
				|  |  | +    fake_channel_destroy, fake_channel_check_peer, fake_channel_cmp};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_security_connector_vtable fake_server_vtable = {
 | 
	
		
			
				|  |  | -    fake_server_destroy, fake_server_check_peer};
 | 
	
		
			
				|  |  | +    fake_server_destroy, fake_server_check_peer, fake_server_cmp};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
 | 
	
		
			
				|  |  | +    grpc_channel_credentials *channel_creds,
 | 
	
		
			
				|  |  |      grpc_call_credentials *request_metadata_creds, const char *target,
 | 
	
		
			
				|  |  |      const grpc_channel_args *args) {
 | 
	
		
			
				|  |  |    grpc_fake_channel_security_connector *c =
 | 
	
	
		
			
				|  | @@ -431,6 +493,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
 | 
	
		
			
				|  |  |    gpr_ref_init(&c->base.base.refcount, 1);
 | 
	
		
			
				|  |  |    c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
 | 
	
		
			
				|  |  |    c->base.base.vtable = &fake_channel_vtable;
 | 
	
		
			
				|  |  | +  c->base.channel_creds = channel_creds;
 | 
	
		
			
				|  |  |    c->base.request_metadata_creds =
 | 
	
		
			
				|  |  |        grpc_call_credentials_ref(request_metadata_creds);
 | 
	
		
			
				|  |  |    c->base.check_call_host = fake_channel_check_call_host;
 | 
	
	
		
			
				|  | @@ -444,13 +507,14 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_server_security_connector *grpc_fake_server_security_connector_create(
 | 
	
		
			
				|  |  | -    void) {
 | 
	
		
			
				|  |  | +    grpc_server_credentials *server_creds) {
 | 
	
		
			
				|  |  |    grpc_server_security_connector *c =
 | 
	
		
			
				|  |  |        (grpc_server_security_connector *)gpr_zalloc(
 | 
	
		
			
				|  |  |            sizeof(grpc_server_security_connector));
 | 
	
		
			
				|  |  |    gpr_ref_init(&c->base.refcount, 1);
 | 
	
		
			
				|  |  |    c->base.vtable = &fake_server_vtable;
 | 
	
		
			
				|  |  |    c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
 | 
	
		
			
				|  |  | +  c->server_creds = server_creds;
 | 
	
		
			
				|  |  |    c->add_handshakers = fake_server_add_handshakers;
 | 
	
		
			
				|  |  |    return c;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -473,6 +537,7 @@ static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                  grpc_security_connector *sc) {
 | 
	
		
			
				|  |  |    grpc_ssl_channel_security_connector *c =
 | 
	
		
			
				|  |  |        (grpc_ssl_channel_security_connector *)sc;
 | 
	
		
			
				|  |  | +  grpc_channel_credentials_unref(exec_ctx, c->base.channel_creds);
 | 
	
		
			
				|  |  |    grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds);
 | 
	
		
			
				|  |  |    tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory);
 | 
	
		
			
				|  |  |    c->client_handshaker_factory = NULL;
 | 
	
	
		
			
				|  | @@ -485,6 +550,7 @@ static void ssl_server_destroy(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                 grpc_security_connector *sc) {
 | 
	
		
			
				|  |  |    grpc_ssl_server_security_connector *c =
 | 
	
		
			
				|  |  |        (grpc_ssl_server_security_connector *)sc;
 | 
	
		
			
				|  |  | +  grpc_server_credentials_unref(exec_ctx, c->base.server_creds);
 | 
	
		
			
				|  |  |    tsi_ssl_server_handshaker_factory_unref(c->server_handshaker_factory);
 | 
	
		
			
				|  |  |    c->server_handshaker_factory = NULL;
 | 
	
		
			
				|  |  |    gpr_free(sc);
 | 
	
	
		
			
				|  | @@ -641,6 +707,29 @@ static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    GRPC_CLOSURE_SCHED(exec_ctx, on_peer_checked, error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static int ssl_channel_cmp(grpc_security_connector *sc1,
 | 
	
		
			
				|  |  | +                           grpc_security_connector *sc2) {
 | 
	
		
			
				|  |  | +  grpc_ssl_channel_security_connector *c1 =
 | 
	
		
			
				|  |  | +      (grpc_ssl_channel_security_connector *)sc1;
 | 
	
		
			
				|  |  | +  grpc_ssl_channel_security_connector *c2 =
 | 
	
		
			
				|  |  | +      (grpc_ssl_channel_security_connector *)sc2;
 | 
	
		
			
				|  |  | +  int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  c = strcmp(c1->target_name, c2->target_name);
 | 
	
		
			
				|  |  | +  if (c != 0) return c;
 | 
	
		
			
				|  |  | +  return (c1->overridden_target_name == NULL ||
 | 
	
		
			
				|  |  | +          c2->overridden_target_name == NULL)
 | 
	
		
			
				|  |  | +             ? GPR_ICMP(c1->overridden_target_name, c2->overridden_target_name)
 | 
	
		
			
				|  |  | +             : strcmp(c1->overridden_target_name, c2->overridden_target_name);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int ssl_server_cmp(grpc_security_connector *sc1,
 | 
	
		
			
				|  |  | +                          grpc_security_connector *sc2) {
 | 
	
		
			
				|  |  | +  return grpc_server_security_connector_cmp(
 | 
	
		
			
				|  |  | +      (grpc_server_security_connector *)sc1,
 | 
	
		
			
				|  |  | +      (grpc_server_security_connector *)sc2);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void add_shallow_auth_property_to_peer(tsi_peer *peer,
 | 
	
		
			
				|  |  |                                                const grpc_auth_property *prop,
 | 
	
		
			
				|  |  |                                                const char *tsi_prop_name) {
 | 
	
	
		
			
				|  | @@ -717,10 +806,10 @@ static void ssl_channel_cancel_check_call_host(
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_security_connector_vtable ssl_channel_vtable = {
 | 
	
		
			
				|  |  | -    ssl_channel_destroy, ssl_channel_check_peer};
 | 
	
		
			
				|  |  | +    ssl_channel_destroy, ssl_channel_check_peer, ssl_channel_cmp};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_security_connector_vtable ssl_server_vtable = {
 | 
	
		
			
				|  |  | -    ssl_server_destroy, ssl_server_check_peer};
 | 
	
		
			
				|  |  | +    ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* returns a NULL terminated slice. */
 | 
	
		
			
				|  |  |  static grpc_slice compute_default_pem_root_certs_once(void) {
 | 
	
	
		
			
				|  | @@ -804,7 +893,8 @@ const char *grpc_get_default_ssl_roots(void) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_security_status grpc_ssl_channel_security_connector_create(
 | 
	
		
			
				|  |  | -    grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds,
 | 
	
		
			
				|  |  | +    grpc_exec_ctx *exec_ctx, grpc_channel_credentials *channel_creds,
 | 
	
		
			
				|  |  | +    grpc_call_credentials *request_metadata_creds,
 | 
	
		
			
				|  |  |      const grpc_ssl_config *config, const char *target_name,
 | 
	
		
			
				|  |  |      const char *overridden_target_name, grpc_channel_security_connector **sc) {
 | 
	
		
			
				|  |  |    size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
 | 
	
	
		
			
				|  | @@ -840,6 +930,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
 | 
	
		
			
				|  |  |    gpr_ref_init(&c->base.base.refcount, 1);
 | 
	
		
			
				|  |  |    c->base.base.vtable = &ssl_channel_vtable;
 | 
	
		
			
				|  |  |    c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
 | 
	
		
			
				|  |  | +  c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
 | 
	
		
			
				|  |  |    c->base.request_metadata_creds =
 | 
	
		
			
				|  |  |        grpc_call_credentials_ref(request_metadata_creds);
 | 
	
		
			
				|  |  |    c->base.check_call_host = ssl_channel_check_call_host;
 | 
	
	
		
			
				|  | @@ -874,8 +965,8 @@ error:
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_security_status grpc_ssl_server_security_connector_create(
 | 
	
		
			
				|  |  | -    grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config,
 | 
	
		
			
				|  |  | -    grpc_server_security_connector **sc) {
 | 
	
		
			
				|  |  | +    grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds,
 | 
	
		
			
				|  |  | +    const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
 | 
	
		
			
				|  |  |    size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
 | 
	
		
			
				|  |  |    const char **alpn_protocol_strings =
 | 
	
		
			
				|  |  |        (const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols);
 | 
	
	
		
			
				|  | @@ -897,6 +988,7 @@ grpc_security_status grpc_ssl_server_security_connector_create(
 | 
	
		
			
				|  |  |    gpr_ref_init(&c->base.base.refcount, 1);
 | 
	
		
			
				|  |  |    c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
 | 
	
		
			
				|  |  |    c->base.base.vtable = &ssl_server_vtable;
 | 
	
		
			
				|  |  | +  c->base.server_creds = grpc_server_credentials_ref(server_creds);
 | 
	
		
			
				|  |  |    result = tsi_create_ssl_server_handshaker_factory_ex(
 | 
	
		
			
				|  |  |        config->pem_key_cert_pairs, config->num_key_cert_pairs,
 | 
	
		
			
				|  |  |        config->pem_root_certs, get_tsi_client_certificate_request_type(
 |