|  | @@ -57,15 +57,28 @@ zend_class_entry *grpc_ce_channel_credentials;
 | 
	
		
			
				|  |  |  #if PHP_MAJOR_VERSION >= 7
 | 
	
		
			
				|  |  |  static zend_object_handlers channel_credentials_ce_handlers;
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  | -static char *default_pem_root_certs = NULL;
 | 
	
		
			
				|  |  | +static gpr_mu cc_persistent_list_mu;
 | 
	
		
			
				|  |  | +int le_cc_plink;
 | 
	
		
			
				|  |  | +const char *persistent_list_key = "default_root_certs";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_ssl_roots_override_result get_ssl_roots_override(
 | 
	
		
			
				|  |  |      char **pem_root_certs) {
 | 
	
		
			
				|  |  | -  *pem_root_certs = default_pem_root_certs;
 | 
	
		
			
				|  |  | -  if (default_pem_root_certs == NULL) {
 | 
	
		
			
				|  |  | +  TSRMLS_FETCH();
 | 
	
		
			
				|  |  | +  php_grpc_zend_resource *rsrc;
 | 
	
		
			
				|  |  | +  php_grpc_int key_len = strlen(persistent_list_key);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&cc_persistent_list_mu);
 | 
	
		
			
				|  |  | +  if (PHP_GRPC_PERSISTENT_LIST_FIND(&EG(persistent_list), persistent_list_key,
 | 
	
		
			
				|  |  | +                                    key_len, rsrc)) {
 | 
	
		
			
				|  |  | +    channel_credentials_persistent_le_t *le =
 | 
	
		
			
				|  |  | +      (channel_credentials_persistent_le_t *)rsrc->ptr;
 | 
	
		
			
				|  |  | +    *pem_root_certs = le->default_root_certs;
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&cc_persistent_list_mu);
 | 
	
		
			
				|  |  | +    return GRPC_SSL_ROOTS_OVERRIDE_OK;
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&cc_persistent_list_mu);
 | 
	
		
			
				|  |  |      return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  return GRPC_SSL_ROOTS_OVERRIDE_OK;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Frees and destroys an instance of wrapped_grpc_channel_credentials */
 | 
	
	
		
			
				|  | @@ -100,6 +113,27 @@ zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped,
 | 
	
		
			
				|  |  |    return credentials_object;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +void update_root_certs_persistent_list(char *pem_roots,
 | 
	
		
			
				|  |  | +                                       php_grpc_int pem_roots_length
 | 
	
		
			
				|  |  | +                                       TSRMLS_DC) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  php_grpc_zend_resource new_rsrc;
 | 
	
		
			
				|  |  | +  channel_credentials_persistent_le_t *le;
 | 
	
		
			
				|  |  | +  php_grpc_int key_len = strlen(persistent_list_key);
 | 
	
		
			
				|  |  | +  new_rsrc.type = le_cc_plink;
 | 
	
		
			
				|  |  | +  le = malloc(sizeof(channel_credentials_persistent_le_t));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  char *tmp = malloc(pem_roots_length+1);
 | 
	
		
			
				|  |  | +  memcpy(tmp, pem_roots, pem_roots_length+1);
 | 
	
		
			
				|  |  | +  le->default_root_certs = tmp;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  new_rsrc.ptr = le;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&cc_persistent_list_mu);
 | 
	
		
			
				|  |  | +  PHP_GRPC_PERSISTENT_LIST_UPDATE(&EG(persistent_list), persistent_list_key,
 | 
	
		
			
				|  |  | +                                  key_len, (void *)&new_rsrc);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&cc_persistent_list_mu);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * Set default roots pem.
 | 
	
		
			
				|  |  |   * @param string $pem_roots PEM encoding of the server root certificates
 | 
	
	
		
			
				|  | @@ -116,13 +150,21 @@ PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
 | 
	
		
			
				|  |  |                           "setDefaultRootsPem expects 1 string", 1 TSRMLS_CC);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  char *default_certs = php_grpc_get_default_pem_root_certs(TSRMLS_C);
 | 
	
		
			
				|  |  | -  if (default_certs == NULL) {
 | 
	
		
			
				|  |  | -    default_certs = gpr_malloc((pem_roots_length + 1) * sizeof(char));
 | 
	
		
			
				|  |  | -    memcpy(default_certs, pem_roots, pem_roots_length + 1);
 | 
	
		
			
				|  |  | -    php_grpc_update_default_pem_root_certs(default_certs TSRMLS_CC);
 | 
	
		
			
				|  |  | +  php_grpc_zend_resource *rsrc;
 | 
	
		
			
				|  |  | +  php_grpc_int key_len = strlen(persistent_list_key);
 | 
	
		
			
				|  |  | +  if (!(PHP_GRPC_PERSISTENT_LIST_FIND(&EG(persistent_list),
 | 
	
		
			
				|  |  | +                                      persistent_list_key,
 | 
	
		
			
				|  |  | +                                      key_len, rsrc))) {
 | 
	
		
			
				|  |  | +    update_root_certs_persistent_list(pem_roots,
 | 
	
		
			
				|  |  | +                                      pem_roots_length TSRMLS_CC);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    channel_credentials_persistent_le_t *le =
 | 
	
		
			
				|  |  | +      (channel_credentials_persistent_le_t *)rsrc->ptr;
 | 
	
		
			
				|  |  | +    if (strcmp(pem_roots, le->default_root_certs) != 0) {
 | 
	
		
			
				|  |  | +      update_root_certs_persistent_list(pem_roots, pem_roots_length
 | 
	
		
			
				|  |  | +                                        TSRMLS_CC);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  default_pem_root_certs = default_certs;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
	
		
			
				|  | @@ -231,6 +273,14 @@ PHP_METHOD(ChannelCredentials, createInsecure) {
 | 
	
		
			
				|  |  |    RETURN_NULL();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void php_grpc_channel_credentials_plink_dtor(
 | 
	
		
			
				|  |  | +    php_grpc_zend_resource *rsrc TSRMLS_DC) {
 | 
	
		
			
				|  |  | +  channel_credentials_persistent_le_t *le =
 | 
	
		
			
				|  |  | +    (channel_credentials_persistent_le_t *)rsrc->ptr;
 | 
	
		
			
				|  |  | +  free(le->default_root_certs);
 | 
	
		
			
				|  |  | +  free(le);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  ZEND_BEGIN_ARG_INFO_EX(arginfo_setDefaultRootsPem, 0, 0, 1)
 | 
	
		
			
				|  |  |    ZEND_ARG_INFO(0, pem_roots)
 | 
	
		
			
				|  |  |  ZEND_END_ARG_INFO()
 | 
	
	
		
			
				|  | @@ -266,12 +316,17 @@ static zend_function_entry channel_credentials_methods[] = {
 | 
	
		
			
				|  |  |    PHP_FE_END
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void grpc_init_channel_credentials(TSRMLS_D) {
 | 
	
		
			
				|  |  | +GRPC_STARTUP_FUNCTION(channel_credentials) {
 | 
	
		
			
				|  |  |    zend_class_entry ce;
 | 
	
		
			
				|  |  |    INIT_CLASS_ENTRY(ce, "Grpc\\ChannelCredentials",
 | 
	
		
			
				|  |  |                     channel_credentials_methods);
 | 
	
		
			
				|  |  |    ce.create_object = create_wrapped_grpc_channel_credentials;
 | 
	
		
			
				|  |  |    grpc_ce_channel_credentials = zend_register_internal_class(&ce TSRMLS_CC);
 | 
	
		
			
				|  |  | +  gpr_mu_init(&cc_persistent_list_mu);
 | 
	
		
			
				|  |  | +  le_cc_plink = zend_register_list_destructors_ex(
 | 
	
		
			
				|  |  | +      NULL, php_grpc_channel_credentials_plink_dtor,
 | 
	
		
			
				|  |  | +      "Channel Credentials persistent default certs", module_number);
 | 
	
		
			
				|  |  |    PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel_credentials,
 | 
	
		
			
				|  |  |                          channel_credentials_ce_handlers);
 | 
	
		
			
				|  |  | +  return SUCCESS;
 | 
	
		
			
				|  |  |  }
 |