diff options
author | Craig Tiller <ctiller@google.com> | 2015-04-20 09:04:57 -0700 |
---|---|---|
committer | Craig Tiller <ctiller@google.com> | 2015-04-20 09:04:57 -0700 |
commit | c8a2299fe88a2e9325e07e6a8579bdb07b85b349 (patch) | |
tree | 3298194be904f974fcbb64b1f155332c350b3725 /src | |
parent | 9c9d4e0cd9025f3ff7aaf7cacfd2e24dfd6aa58e (diff) | |
parent | b572fcba35fd66cce102b29389a5892d3d45e651 (diff) |
Merge github.com:grpc/grpc into batch-metadata
Diffstat (limited to 'src')
38 files changed, 869 insertions, 752 deletions
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c index d2cf09a8df..fe7ea6a86b 100644 --- a/src/core/httpcli/httpcli.c +++ b/src/core/httpcli/httpcli.c @@ -40,9 +40,8 @@ #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/httpcli/format_request.h" -#include "src/core/httpcli/httpcli_security_context.h" +#include "src/core/httpcli/httpcli_security_connector.h" #include "src/core/httpcli/parser.h" -#include "src/core/security/security_context.h" #include "src/core/security/secure_transport_setup.h" #include "src/core/support/string.h" #include <grpc/support/alloc.h> @@ -180,7 +179,7 @@ static void on_connected(void *arg, grpc_endpoint *tcp) { } req->ep = tcp; if (req->use_ssl) { - grpc_channel_security_context *ctx = NULL; + grpc_channel_security_connector *sc = NULL; const unsigned char *pem_root_certs = NULL; size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); if (pem_root_certs == NULL || pem_root_certs_size == 0) { @@ -188,12 +187,12 @@ static void on_connected(void *arg, grpc_endpoint *tcp) { finish(req, 0); return; } - GPR_ASSERT(grpc_httpcli_ssl_channel_security_context_create( - pem_root_certs, pem_root_certs_size, req->host, &ctx) == + GPR_ASSERT(grpc_httpcli_ssl_channel_security_connector_create( + pem_root_certs, pem_root_certs_size, req->host, &sc) == GRPC_SECURITY_OK); - grpc_setup_secure_transport(&ctx->base, tcp, on_secure_transport_setup_done, + grpc_setup_secure_transport(&sc->base, tcp, on_secure_transport_setup_done, req); - grpc_security_context_unref(&ctx->base); + grpc_security_connector_unref(&sc->base); } else { start_write(req); } diff --git a/src/core/httpcli/httpcli_security_context.c b/src/core/httpcli/httpcli_security_connector.c index e97752bbe1..6eed5eaf12 100644 --- a/src/core/httpcli/httpcli_security_context.c +++ b/src/core/httpcli/httpcli_security_connector.c @@ -31,7 +31,7 @@ * */ -#include "src/core/httpcli/httpcli_security_context.h" +#include "src/core/httpcli/httpcli_security_connector.h" #include <string.h> @@ -42,25 +42,25 @@ #include "src/core/tsi/ssl_transport_security.h" typedef struct { - grpc_channel_security_context base; + grpc_channel_security_connector base; tsi_ssl_handshaker_factory *handshaker_factory; char *secure_peer_name; -} grpc_httpcli_ssl_channel_security_context; +} grpc_httpcli_ssl_channel_security_connector; -static void httpcli_ssl_destroy(grpc_security_context *ctx) { - grpc_httpcli_ssl_channel_security_context *c = - (grpc_httpcli_ssl_channel_security_context *)ctx; +static void httpcli_ssl_destroy(grpc_security_connector *sc) { + grpc_httpcli_ssl_channel_security_connector *c = + (grpc_httpcli_ssl_channel_security_connector *)sc; if (c->handshaker_factory != NULL) { tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); } if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name); - gpr_free(ctx); + gpr_free(sc); } static grpc_security_status httpcli_ssl_create_handshaker( - grpc_security_context *ctx, tsi_handshaker **handshaker) { - grpc_httpcli_ssl_channel_security_context *c = - (grpc_httpcli_ssl_channel_security_context *)ctx; + grpc_security_connector *sc, tsi_handshaker **handshaker) { + grpc_httpcli_ssl_channel_security_connector *c = + (grpc_httpcli_ssl_channel_security_connector *)sc; tsi_result result = TSI_OK; if (c->handshaker_factory == NULL) return GRPC_SECURITY_ERROR; result = tsi_ssl_handshaker_factory_create_handshaker( @@ -73,12 +73,12 @@ static grpc_security_status httpcli_ssl_create_handshaker( return GRPC_SECURITY_OK; } -static grpc_security_status httpcli_ssl_check_peer(grpc_security_context *ctx, +static grpc_security_status httpcli_ssl_check_peer(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { - grpc_httpcli_ssl_channel_security_context *c = - (grpc_httpcli_ssl_channel_security_context *)ctx; + grpc_httpcli_ssl_channel_security_connector *c = + (grpc_httpcli_ssl_channel_security_connector *)sc; grpc_security_status status = GRPC_SECURITY_OK; /* Check the peer name. */ @@ -92,14 +92,14 @@ static grpc_security_status httpcli_ssl_check_peer(grpc_security_context *ctx, return status; } -static grpc_security_context_vtable httpcli_ssl_vtable = { +static grpc_security_connector_vtable httpcli_ssl_vtable = { httpcli_ssl_destroy, httpcli_ssl_create_handshaker, httpcli_ssl_check_peer}; -grpc_security_status grpc_httpcli_ssl_channel_security_context_create( +grpc_security_status grpc_httpcli_ssl_channel_security_connector_create( const unsigned char *pem_root_certs, size_t pem_root_certs_size, - const char *secure_peer_name, grpc_channel_security_context **ctx) { + const char *secure_peer_name, grpc_channel_security_connector **sc) { tsi_result result = TSI_OK; - grpc_httpcli_ssl_channel_security_context *c; + grpc_httpcli_ssl_channel_security_connector *c; if (secure_peer_name != NULL && pem_root_certs == NULL) { gpr_log(GPR_ERROR, @@ -107,8 +107,8 @@ grpc_security_status grpc_httpcli_ssl_channel_security_context_create( return GRPC_SECURITY_ERROR; } - c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_context)); - memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_context)); + c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector)); + memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.is_client_side = 1; @@ -123,9 +123,9 @@ grpc_security_status grpc_httpcli_ssl_channel_security_context_create( gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); httpcli_ssl_destroy(&c->base.base); - *ctx = NULL; + *sc = NULL; return GRPC_SECURITY_ERROR; } - *ctx = &c->base; + *sc = &c->base; return GRPC_SECURITY_OK; } diff --git a/src/core/httpcli/httpcli_security_context.h b/src/core/httpcli/httpcli_security_connector.h index a776828a69..c50f25905e 100644 --- a/src/core/httpcli/httpcli_security_context.h +++ b/src/core/httpcli/httpcli_security_connector.h @@ -31,13 +31,13 @@ * */ -#ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H -#define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H +#ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H +#define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H -#include "src/core/security/security_context.h" +#include "src/core/security/security_connector.h" -grpc_security_status grpc_httpcli_ssl_channel_security_context_create( +grpc_security_status grpc_httpcli_ssl_channel_security_connector_create( const unsigned char *pem_root_certs, size_t pem_root_certs_size, - const char *secure_peer_name, grpc_channel_security_context **ctx); + const char *secure_peer_name, grpc_channel_security_connector **sc); -#endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H */ +#endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H */ diff --git a/src/core/security/auth.c b/src/core/security/auth.c index d99e5591ed..fee53a937d 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -40,7 +40,7 @@ #include "src/core/support/string.h" #include "src/core/channel/channel_stack.h" -#include "src/core/security/security_context.h" +#include "src/core/security/security_connector.h" #include "src/core/security/credentials.h" #include "src/core/surface/call.h" @@ -57,7 +57,7 @@ typedef struct { /* We can have a per-channel credentials. */ typedef struct { - grpc_channel_security_context *security_context; + grpc_channel_security_connector *security_connector; grpc_mdctx *md_ctx; grpc_mdstr *authority_string; grpc_mdstr *path_string; @@ -111,7 +111,7 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) { channel_data *channeld = elem->channel_data; grpc_credentials *channel_creds = - channeld->security_context->request_metadata_creds; + channeld->security_connector->request_metadata_creds; /* TODO(jboeuf): Decide on the policy in this case: - populate both channel and call? @@ -123,7 +123,7 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) { if (channel_creds != NULL && grpc_credentials_has_request_metadata(channel_creds)) { char *service_url = - build_service_url(channeld->security_context->base.url_scheme, calld); + build_service_url(channeld->security_connector->base.url_scheme, calld); calld->op = *op; /* Copy op (originates from the caller's stack). */ grpc_credentials_get_request_metadata(channel_creds, service_url, on_credentials_metadata, elem); @@ -180,8 +180,8 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, grpc_security_status status; const char *call_host = grpc_mdstr_as_c_string(calld->host); calld->op = *op; /* Copy op (originates from the caller's stack). */ - status = grpc_channel_security_context_check_call_host( - channeld->security_context, call_host, on_host_checked, elem); + status = grpc_channel_security_connector_check_call_host( + channeld->security_connector, call_host, on_host_checked, elem); if (status != GRPC_SECURITY_OK) { if (status == GRPC_SECURITY_ERROR) { char *error_msg; @@ -242,7 +242,7 @@ static void init_channel_elem(grpc_channel_element *elem, const grpc_channel_args *args, grpc_mdctx *metadata_context, int is_first, int is_last) { - grpc_security_context *ctx = grpc_find_security_context_in_args(args); + grpc_security_connector *ctx = grpc_find_security_connector_in_args(args); /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; @@ -255,8 +255,8 @@ static void init_channel_elem(grpc_channel_element *elem, /* initialize members */ GPR_ASSERT(ctx->is_client_side); - channeld->security_context = - (grpc_channel_security_context *)grpc_security_context_ref(ctx); + channeld->security_connector = + (grpc_channel_security_connector *)grpc_security_connector_ref(ctx); channeld->md_ctx = metadata_context; channeld->authority_string = grpc_mdstr_from_string(channeld->md_ctx, ":authority"); @@ -271,8 +271,8 @@ static void init_channel_elem(grpc_channel_element *elem, static void destroy_channel_elem(grpc_channel_element *elem) { /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; - grpc_channel_security_context *ctx = channeld->security_context; - if (ctx != NULL) grpc_security_context_unref(&ctx->base); + grpc_channel_security_connector *ctx = channeld->security_connector; + if (ctx != NULL) grpc_security_connector_unref(&ctx->base); if (channeld->authority_string != NULL) { grpc_mdstr_unref(channeld->authority_string); } diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index e6d2e9e332..f6366f0750 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -36,11 +36,14 @@ #include <string.h> #include <stdio.h> +#include "src/core/channel/channel_args.h" +#include "src/core/channel/http_client_filter.h" #include "src/core/json/json.h" #include "src/core/httpcli/httpcli.h" #include "src/core/iomgr/iomgr.h" #include "src/core/security/json_token.h" #include "src/core/support/string.h" + #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/sync.h> @@ -111,9 +114,33 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds, creds->vtable->get_request_metadata(creds, service_url, cb, user_data); } -grpc_mdctx *grpc_credentials_get_metadata_context(grpc_credentials *creds) { - if (creds == NULL) return NULL; - return creds->vtable->get_metadata_context(creds); +grpc_mdctx *grpc_credentials_get_or_create_metadata_context( + grpc_credentials *creds) { + grpc_mdctx *mdctx = NULL; + if (creds != NULL && creds->vtable->get_metadata_context != NULL) { + mdctx = creds->vtable->get_metadata_context(creds); + } + if (mdctx == NULL) { + return grpc_mdctx_create(); + } else { + grpc_mdctx_ref(mdctx); + return mdctx; + } +} + +grpc_security_status grpc_credentials_create_security_connector( + grpc_credentials *creds, const char *target, const grpc_channel_args *args, + grpc_credentials *request_metadata_creds, + grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + *new_args = NULL; + if (creds == NULL || creds->vtable->create_security_connector == NULL || + grpc_credentials_has_request_metadata_only(creds)) { + gpr_log(GPR_ERROR, + "Invalid credentials for creating a security connector."); + return GRPC_SECURITY_ERROR; + } + return creds->vtable->create_security_connector( + creds, target, args, request_metadata_creds, sc, new_args); } void grpc_server_credentials_release(grpc_server_credentials *creds) { @@ -121,6 +148,15 @@ void grpc_server_credentials_release(grpc_server_credentials *creds) { creds->vtable->destroy(creds); } +grpc_security_status grpc_server_credentials_create_security_connector( + grpc_server_credentials *creds, grpc_security_connector **sc) { + if (creds == NULL || creds->vtable->create_security_connector == NULL) { + gpr_log(GPR_ERROR, "Server credentials cannot create security context."); + return GRPC_SECURITY_ERROR; + } + return creds->vtable->create_security_connector(creds, sc); +} + /* -- Ssl credentials. -- */ typedef struct { @@ -176,32 +212,49 @@ static grpc_mdctx *ssl_get_metadata_context(grpc_credentials *creds) { return NULL; } -static grpc_credentials_vtable ssl_vtable = { - ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, - ssl_get_metadata_context, NULL}; - -static grpc_server_credentials_vtable ssl_server_vtable = {ssl_server_destroy}; - -const grpc_ssl_config *grpc_ssl_credentials_get_config( - const grpc_credentials *creds) { - if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) { - return NULL; - } else { - grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; - return &c->config; +static grpc_security_status ssl_create_security_connector( + grpc_credentials *creds, const char *target, const grpc_channel_args *args, + grpc_credentials *request_metadata_creds, + grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; + grpc_security_status status = GRPC_SECURITY_OK; + size_t i = 0; + const char *overridden_target_name = NULL; + grpc_arg arg; + + for (i = 0; args && i < args->num_args; i++) { + grpc_arg *arg = &args->args[i]; + if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 && + arg->type == GRPC_ARG_STRING) { + overridden_target_name = arg->value.string; + break; + } + } + status = grpc_ssl_channel_security_connector_create( + request_metadata_creds, &c->config, target, overridden_target_name, sc); + if (status != GRPC_SECURITY_OK) { + return status; } + arg.type = GRPC_ARG_STRING; + arg.key = GRPC_ARG_HTTP2_SCHEME; + arg.value.string = "https"; + *new_args = grpc_channel_args_copy_and_add(args, &arg); + return status; } -const grpc_ssl_server_config *grpc_ssl_server_credentials_get_config( - const grpc_server_credentials *creds) { - if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) { - return NULL; - } else { - grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; - return &c->config; - } +static grpc_security_status ssl_server_create_security_connector( + grpc_server_credentials *creds, grpc_security_connector **sc) { + grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; + return grpc_ssl_server_security_connector_create(&c->config, sc); } +static grpc_credentials_vtable ssl_vtable = { + ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, + ssl_get_metadata_context, NULL, ssl_create_security_connector}; + +static grpc_server_credentials_vtable ssl_server_vtable = { + ssl_server_destroy, ssl_server_create_security_connector}; + static void ssl_copy_key_material(const char *input, unsigned char **output, size_t *output_size) { *output_size = strlen(input); @@ -388,7 +441,7 @@ static grpc_mdctx *jwt_get_metadata_context(grpc_credentials *creds) { static grpc_credentials_vtable jwt_vtable = { jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only, - jwt_get_metadata_context, jwt_get_request_metadata}; + jwt_get_metadata_context, jwt_get_request_metadata, NULL}; grpc_credentials *grpc_jwt_credentials_create(const char *json_key, gpr_timespec token_lifetime) { @@ -613,7 +666,7 @@ static grpc_credentials_vtable compute_engine_vtable = { oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata, oauth2_token_fetcher_has_request_metadata_only, oauth2_token_fetcher_get_metadata_context, - oauth2_token_fetcher_get_request_metadata}; + oauth2_token_fetcher_get_request_metadata, NULL}; static void compute_engine_fetch_oauth2( grpc_credentials_metadata_request *metadata_req, @@ -657,7 +710,7 @@ static grpc_credentials_vtable service_account_vtable = { service_account_destroy, oauth2_token_fetcher_has_request_metadata, oauth2_token_fetcher_has_request_metadata_only, oauth2_token_fetcher_get_metadata_context, - oauth2_token_fetcher_get_request_metadata}; + oauth2_token_fetcher_get_request_metadata, NULL}; static void service_account_fetch_oauth2( grpc_credentials_metadata_request *metadata_req, @@ -731,7 +784,7 @@ static grpc_credentials_vtable refresh_token_vtable = { refresh_token_destroy, oauth2_token_fetcher_has_request_metadata, oauth2_token_fetcher_has_request_metadata_only, oauth2_token_fetcher_get_metadata_context, - oauth2_token_fetcher_get_request_metadata}; + oauth2_token_fetcher_get_request_metadata, NULL}; static void refresh_token_fetch_oauth2( grpc_credentials_metadata_request *metadata_req, @@ -834,7 +887,7 @@ static grpc_mdctx *fake_oauth2_get_metadata_context(grpc_credentials *creds) { static grpc_credentials_vtable fake_oauth2_vtable = { fake_oauth2_destroy, fake_oauth2_has_request_metadata, fake_oauth2_has_request_metadata_only, fake_oauth2_get_metadata_context, - fake_oauth2_get_request_metadata}; + fake_oauth2_get_request_metadata, NULL}; grpc_credentials *grpc_fake_oauth2_credentials_create( const char *token_md_value, int is_async) { @@ -878,15 +931,33 @@ static grpc_mdctx *fake_transport_security_get_metadata_context( return NULL; } +static grpc_security_status +fake_transport_security_create_security_connector( + grpc_credentials *c, const char *target, const grpc_channel_args *args, + grpc_credentials *request_metadata_creds, + grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + *sc = grpc_fake_channel_security_connector_create(request_metadata_creds, 1); + return GRPC_SECURITY_OK; +} + +static grpc_security_status +fake_transport_security_server_create_security_connector( + grpc_server_credentials *c, grpc_security_connector **sc) { + *sc = grpc_fake_server_security_connector_create(); + return GRPC_SECURITY_OK; +} + static grpc_credentials_vtable fake_transport_security_credentials_vtable = { fake_transport_security_credentials_destroy, fake_transport_security_has_request_metadata, fake_transport_security_has_request_metadata_only, - fake_transport_security_get_metadata_context, NULL}; + fake_transport_security_get_metadata_context, NULL, + fake_transport_security_create_security_connector}; static grpc_server_credentials_vtable fake_transport_security_server_credentials_vtable = { - fake_transport_security_server_credentials_destroy}; + fake_transport_security_server_credentials_destroy, + fake_transport_security_server_create_security_connector}; grpc_credentials *grpc_fake_transport_security_credentials_create(void) { grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials)); @@ -911,6 +982,7 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( typedef struct { grpc_credentials base; grpc_credentials_array inner; + grpc_credentials *connector_creds; } grpc_composite_credentials; typedef struct { @@ -1038,7 +1110,10 @@ static grpc_mdctx *composite_get_metadata_context(grpc_credentials *creds) { size_t i; for (i = 0; i < c->inner.num_creds; i++) { grpc_credentials *inner_creds = c->inner.creds_array[i]; - grpc_mdctx *inner_ctx = grpc_credentials_get_metadata_context(inner_creds); + grpc_mdctx *inner_ctx = NULL; + if (inner_creds->vtable->get_metadata_context != NULL) { + inner_ctx = inner_creds->vtable->get_metadata_context(inner_creds); + } if (inner_ctx) { GPR_ASSERT(ctx == NULL && "can only have one metadata context per composite credential"); @@ -1048,10 +1123,24 @@ static grpc_mdctx *composite_get_metadata_context(grpc_credentials *creds) { return ctx; } +static grpc_security_status composite_create_security_connector( + grpc_credentials *creds, const char *target, const grpc_channel_args *args, + grpc_credentials *request_metadata_creds, + grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + grpc_composite_credentials *c = (grpc_composite_credentials *)creds; + if (c->connector_creds == NULL) { + gpr_log(GPR_ERROR, + "Cannot create security connector, missing connector credentials."); + return GRPC_SECURITY_ERROR; + } + return grpc_credentials_create_security_connector(c->connector_creds, target, + args, creds, sc, new_args); +} + static grpc_credentials_vtable composite_credentials_vtable = { composite_destroy, composite_has_request_metadata, composite_has_request_metadata_only, composite_get_metadata_context, - composite_get_request_metadata}; + composite_get_request_metadata, composite_create_security_connector}; static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) { grpc_credentials_array result; @@ -1067,6 +1156,7 @@ static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) { grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, grpc_credentials *creds2) { size_t i; + size_t creds_array_byte_size; grpc_credentials_array creds1_array; grpc_credentials_array creds2_array; grpc_composite_credentials *c; @@ -1080,16 +1170,39 @@ grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, creds1_array = get_creds_array(&creds1); creds2_array = get_creds_array(&creds2); c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds; - c->inner.creds_array = - gpr_malloc(c->inner.num_creds * sizeof(grpc_credentials *)); + creds_array_byte_size = c->inner.num_creds * sizeof(grpc_credentials *); + c->inner.creds_array = gpr_malloc(creds_array_byte_size); + memset(c->inner.creds_array, 0, creds_array_byte_size); for (i = 0; i < creds1_array.num_creds; i++) { - c->inner.creds_array[i] = grpc_credentials_ref(creds1_array.creds_array[i]); + grpc_credentials *cur_creds = creds1_array.creds_array[i]; + if (!grpc_credentials_has_request_metadata_only(cur_creds)) { + if (c->connector_creds == NULL) { + c->connector_creds = cur_creds; + } else { + gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials."); + goto fail; + } + } + c->inner.creds_array[i] = grpc_credentials_ref(cur_creds); } for (i = 0; i < creds2_array.num_creds; i++) { + grpc_credentials *cur_creds = creds2_array.creds_array[i]; + if (!grpc_credentials_has_request_metadata_only(cur_creds)) { + if (c->connector_creds == NULL) { + c->connector_creds = cur_creds; + } else { + gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials."); + goto fail; + } + } c->inner.creds_array[i + creds1_array.num_creds] = - grpc_credentials_ref(creds2_array.creds_array[i]); + grpc_credentials_ref(cur_creds); } return &c->base; + +fail: + grpc_credentials_unref(&c->base); + return NULL; } const grpc_credentials_array *grpc_composite_credentials_get_credentials( @@ -1163,7 +1276,7 @@ static grpc_mdctx *iam_get_metadata_context(grpc_credentials *creds) { static grpc_credentials_vtable iam_vtable = { iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only, - iam_get_metadata_context, iam_get_request_metadata}; + iam_get_metadata_context, iam_get_request_metadata, NULL}; grpc_credentials *grpc_iam_credentials_create(const char *token, const char *authority_selector) { diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 562b3faa33..87c773e49a 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -39,6 +39,8 @@ #include <grpc/grpc_security.h> #include <grpc/support/sync.h> +#include "src/core/security/security_connector.h" + struct grpc_httpcli_response; /* --- Constants. --- */ @@ -99,6 +101,11 @@ typedef struct { const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); + grpc_security_status (*create_security_connector)( + grpc_credentials *c, const char *target, const grpc_channel_args *args, + grpc_credentials *request_metadata_creds, + grpc_channel_security_connector **sc, grpc_channel_args **new_args); + } grpc_credentials_vtable; struct grpc_credentials { @@ -115,19 +122,20 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); -grpc_mdctx *grpc_credentials_get_metadata_context(grpc_credentials *creds); -typedef struct { - unsigned char *pem_private_key; - size_t pem_private_key_size; - unsigned char *pem_cert_chain; - size_t pem_cert_chain_size; - unsigned char *pem_root_certs; - size_t pem_root_certs_size; -} grpc_ssl_config; +/* Gets the mdctx from the credentials and increase the refcount if it exists, + otherwise, create a new one. */ +grpc_mdctx *grpc_credentials_get_or_create_metadata_context( + grpc_credentials *creds); -const grpc_ssl_config *grpc_ssl_credentials_get_config( - const grpc_credentials *ssl_creds); +/* Creates a security connector for the channel. May also create new channel + args for the channel to be used in place of the passed in const args if + returned non NULL. In that case the caller is responsible for destroying + new_args after channel creation. */ +grpc_security_status grpc_credentials_create_security_connector( + grpc_credentials *creds, const char *target, const grpc_channel_args *args, + grpc_credentials *request_metadata_creds, + grpc_channel_security_connector **sc, grpc_channel_args **new_args); typedef struct { grpc_credentials **creds_array; @@ -159,6 +167,8 @@ grpc_credentials *grpc_fake_oauth2_credentials_create( typedef struct { void (*destroy)(grpc_server_credentials *c); + grpc_security_status (*create_security_connector)( + grpc_server_credentials *c, grpc_security_connector **sc); } grpc_server_credentials_vtable; struct grpc_server_credentials { @@ -166,17 +176,7 @@ struct grpc_server_credentials { const char *type; }; -typedef struct { - unsigned char **pem_private_keys; - size_t *pem_private_keys_sizes; - unsigned char **pem_cert_chains; - size_t *pem_cert_chains_sizes; - size_t num_key_cert_pairs; - unsigned char *pem_root_certs; - size_t pem_root_certs_size; -} grpc_ssl_server_config; - -const grpc_ssl_server_config *grpc_ssl_server_credentials_get_config( - const grpc_server_credentials *ssl_creds); +grpc_security_status grpc_server_credentials_create_security_connector( + grpc_server_credentials *creds, grpc_security_connector **sc); #endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */ diff --git a/src/core/security/factories.c b/src/core/security/factories.c deleted file mode 100644 index 3d9216aac4..0000000000 --- a/src/core/security/factories.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <string.h> - -#include <grpc/grpc.h> -#include "src/core/security/credentials.h" -#include "src/core/security/security_context.h" -#include <grpc/support/alloc.h> -#include <grpc/support/log.h> -#include <grpc/support/useful.h> - -grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, - const char *target, - const grpc_channel_args *args) { - grpc_secure_channel_factory factories[] = { - {GRPC_CREDENTIALS_TYPE_SSL, grpc_ssl_channel_create}, - {GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY, - grpc_fake_transport_security_channel_create}}; - return grpc_secure_channel_create_with_factories( - factories, GPR_ARRAY_SIZE(factories), creds, target, args); -} - -grpc_security_status grpc_server_security_context_create( - grpc_server_credentials *creds, grpc_security_context **ctx) { - grpc_security_status status = GRPC_SECURITY_ERROR; - - *ctx = NULL; - if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL) == 0) { - status = grpc_ssl_server_security_context_create( - grpc_ssl_server_credentials_get_config(creds), ctx); - } else if (strcmp(creds->type, - GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) == 0) { - *ctx = grpc_fake_server_security_context_create(); - status = GRPC_SECURITY_OK; - } - return status; -} diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index ebea70dad2..d2f46ddd07 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -127,7 +127,7 @@ static grpc_credentials *create_jwt_creds_from_path(char *creds_path) { gpr_slice creds_data; int file_ok = 0; if (creds_path == NULL) return NULL; - creds_data = gpr_load_file(creds_path, &file_ok); + creds_data = gpr_load_file(creds_path, 1, &file_ok); gpr_free(creds_path); if (file_ok) { result = grpc_jwt_credentials_create( @@ -145,7 +145,7 @@ static grpc_credentials *create_refresh_token_creds_from_path( gpr_slice creds_data; int file_ok = 0; if (creds_path == NULL) return NULL; - creds_data = gpr_load_file(creds_path, &file_ok); + creds_data = gpr_load_file(creds_path, 1, &file_ok); gpr_free(creds_path); if (file_ok) { result = grpc_refresh_token_credentials_create( diff --git a/src/core/security/secure_transport_setup.c b/src/core/security/secure_transport_setup.c index f57d22109c..3e1db9a12d 100644 --- a/src/core/security/secure_transport_setup.c +++ b/src/core/security/secure_transport_setup.c @@ -43,7 +43,7 @@ #define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 typedef struct { - grpc_security_context *ctx; + grpc_security_connector *connector; tsi_handshaker *handshaker; unsigned char *handshake_buffer; size_t handshake_buffer_size; @@ -74,7 +74,7 @@ static void secure_transport_setup_done(grpc_secure_transport_setup *s, if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker); if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer); gpr_slice_buffer_destroy(&s->left_overs); - grpc_security_context_unref(s->ctx); + grpc_security_connector_unref(s->connector); gpr_free(s); } @@ -112,8 +112,8 @@ static void check_peer(grpc_secure_transport_setup *s) { secure_transport_setup_done(s, 0); return; } - peer_status = - grpc_security_context_check_peer(s->ctx, peer, on_peer_checked, s); + peer_status = grpc_security_connector_check_peer(s->connector, peer, + on_peer_checked, s); if (peer_status == GRPC_SECURITY_ERROR) { gpr_log(GPR_ERROR, "Peer check failed."); secure_transport_setup_done(s, 0); @@ -262,7 +262,7 @@ static void on_handshake_data_sent_to_peer(void *setup, } } -void grpc_setup_secure_transport(grpc_security_context *ctx, +void grpc_setup_secure_transport(grpc_security_connector *connector, grpc_endpoint *nonsecure_endpoint, grpc_secure_transport_setup_done_cb cb, void *user_data) { @@ -270,12 +270,12 @@ void grpc_setup_secure_transport(grpc_security_context *ctx, grpc_secure_transport_setup *s = gpr_malloc(sizeof(grpc_secure_transport_setup)); memset(s, 0, sizeof(grpc_secure_transport_setup)); - result = grpc_security_context_create_handshaker(ctx, &s->handshaker); + result = grpc_security_connector_create_handshaker(connector, &s->handshaker); if (result != GRPC_SECURITY_OK) { secure_transport_setup_done(s, 0); return; } - s->ctx = grpc_security_context_ref(ctx); + s->connector = grpc_security_connector_ref(connector); s->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; s->handshake_buffer = gpr_malloc(s->handshake_buffer_size); s->endpoint = nonsecure_endpoint; diff --git a/src/core/security/secure_transport_setup.h b/src/core/security/secure_transport_setup.h index e1f8ed7830..58701c461d 100644 --- a/src/core/security/secure_transport_setup.h +++ b/src/core/security/secure_transport_setup.h @@ -35,7 +35,7 @@ #define GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H #include "src/core/iomgr/endpoint.h" -#include "src/core/security/security_context.h" +#include "src/core/security/security_connector.h" /* --- Secure transport setup --- */ @@ -45,7 +45,7 @@ typedef void (*grpc_secure_transport_setup_done_cb)( grpc_endpoint *secure_endpoint); /* Calls the callback upon completion. */ -void grpc_setup_secure_transport(grpc_security_context *ctx, +void grpc_setup_secure_transport(grpc_security_connector *connector, grpc_endpoint *nonsecure_endpoint, grpc_secure_transport_setup_done_cb cb, void *user_data); diff --git a/src/core/security/security_context.c b/src/core/security/security_connector.c index 08137803a3..dbd79c5b22 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_connector.c @@ -31,12 +31,10 @@ * */ -#include "src/core/security/security_context.h" +#include "src/core/security/security_connector.h" #include <string.h> -#include "src/core/channel/channel_args.h" -#include "src/core/channel/http_client_filter.h" #include "src/core/security/credentials.h" #include "src/core/security/secure_endpoint.h" #include "src/core/support/env.h" @@ -56,7 +54,8 @@ #ifndef INSTALL_PREFIX static const char *installed_roots_path = "/usr/share/grpc/roots.pem"; #else -static const char *installed_roots_path = INSTALL_PREFIX "/share/grpc/roots.pem"; +static const char *installed_roots_path = + INSTALL_PREFIX "/share/grpc/roots.pem"; #endif /* -- Cipher suites. -- */ @@ -82,75 +81,77 @@ static const char *ssl_cipher_suites(void) { /* -- Common methods. -- */ -grpc_security_status grpc_security_context_create_handshaker( - grpc_security_context *ctx, tsi_handshaker **handshaker) { - if (ctx == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR; - return ctx->vtable->create_handshaker(ctx, handshaker); +grpc_security_status grpc_security_connector_create_handshaker( + grpc_security_connector *sc, tsi_handshaker **handshaker) { + if (sc == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR; + return sc->vtable->create_handshaker(sc, handshaker); } -grpc_security_status grpc_security_context_check_peer( - grpc_security_context *ctx, tsi_peer peer, grpc_security_check_cb cb, +grpc_security_status grpc_security_connector_check_peer( + grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { - if (ctx == NULL) { + if (sc == NULL) { tsi_peer_destruct(&peer); return GRPC_SECURITY_ERROR; } - return ctx->vtable->check_peer(ctx, peer, cb, user_data); + return sc->vtable->check_peer(sc, peer, cb, user_data); } -grpc_security_status grpc_channel_security_context_check_call_host( - grpc_channel_security_context *ctx, const char *host, +grpc_security_status grpc_channel_security_connector_check_call_host( + grpc_channel_security_connector *sc, const char *host, grpc_security_check_cb cb, void *user_data) { - if (ctx == NULL || ctx->check_call_host == NULL) return GRPC_SECURITY_ERROR; - return ctx->check_call_host(ctx, host, cb, user_data); + if (sc == NULL || sc->check_call_host == NULL) return GRPC_SECURITY_ERROR; + return sc->check_call_host(sc, host, cb, user_data); } -void grpc_security_context_unref(grpc_security_context *ctx) { - if (ctx == NULL) return; - if (gpr_unref(&ctx->refcount)) ctx->vtable->destroy(ctx); +void grpc_security_connector_unref(grpc_security_connector *sc) { + if (sc == NULL) return; + if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc); } -grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx) { - if (ctx == NULL) return NULL; - gpr_ref(&ctx->refcount); - return ctx; +grpc_security_connector *grpc_security_connector_ref( + grpc_security_connector *sc) { + if (sc == NULL) return NULL; + gpr_ref(&sc->refcount); + return sc; } -static void context_pointer_arg_destroy(void *p) { - grpc_security_context_unref(p); +static void connector_pointer_arg_destroy(void *p) { + grpc_security_connector_unref(p); } -static void *context_pointer_arg_copy(void *p) { - return grpc_security_context_ref(p); +static void *connector_pointer_arg_copy(void *p) { + return grpc_security_connector_ref(p); } -grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx) { +grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) { grpc_arg result; result.type = GRPC_ARG_POINTER; - result.key = GRPC_SECURITY_CONTEXT_ARG; - result.value.pointer.destroy = context_pointer_arg_destroy; - result.value.pointer.copy = context_pointer_arg_copy; - result.value.pointer.p = ctx; + result.key = GRPC_SECURITY_CONNECTOR_ARG; + result.value.pointer.destroy = connector_pointer_arg_destroy; + result.value.pointer.copy = connector_pointer_arg_copy; + result.value.pointer.p = sc; return result; } -grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg) { - if (strcmp(arg->key, GRPC_SECURITY_CONTEXT_ARG)) return NULL; +grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) { + if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL; if (arg->type != GRPC_ARG_POINTER) { gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, - GRPC_SECURITY_CONTEXT_ARG); + GRPC_SECURITY_CONNECTOR_ARG); return NULL; } return arg->value.pointer.p; } -grpc_security_context *grpc_find_security_context_in_args( +grpc_security_connector *grpc_find_security_connector_in_args( const grpc_channel_args *args) { size_t i; if (args == NULL) return NULL; for (i = 0; i < args->num_args; i++) { - grpc_security_context *ctx = grpc_security_context_from_arg(&args->args[i]); - if (ctx != NULL) return ctx; + grpc_security_connector *sc = + grpc_security_connector_from_arg(&args->args[i]); + if (sc != NULL) return sc; } return NULL; } @@ -158,51 +159,41 @@ grpc_security_context *grpc_find_security_context_in_args( static int check_request_metadata_creds(grpc_credentials *creds) { if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) { gpr_log(GPR_ERROR, - "Incompatible credentials for channel security context: needs to " + "Incompatible credentials for channel security connector: needs to " "set request metadata."); return 0; } return 1; } -static grpc_mdctx *get_or_create_mdctx(grpc_credentials *creds) { - grpc_mdctx *mdctx = grpc_credentials_get_metadata_context(creds); - if (mdctx == NULL) { - mdctx = grpc_mdctx_create(); - } else { - grpc_mdctx_ref(mdctx); - } - return mdctx; -} - /* -- Fake implementation. -- */ typedef struct { - grpc_channel_security_context base; + grpc_channel_security_connector base; int call_host_check_is_async; -} grpc_fake_channel_security_context; +} grpc_fake_channel_security_connector; -static void fake_channel_destroy(grpc_security_context *ctx) { - grpc_channel_security_context *c = (grpc_channel_security_context *)ctx; +static void fake_channel_destroy(grpc_security_connector *sc) { + grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc; grpc_credentials_unref(c->request_metadata_creds); - gpr_free(ctx); + gpr_free(sc); } -static void fake_server_destroy(grpc_security_context *ctx) { gpr_free(ctx); } +static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); } static grpc_security_status fake_channel_create_handshaker( - grpc_security_context *ctx, tsi_handshaker **handshaker) { + grpc_security_connector *sc, tsi_handshaker **handshaker) { *handshaker = tsi_create_fake_handshaker(1); return GRPC_SECURITY_OK; } static grpc_security_status fake_server_create_handshaker( - grpc_security_context *ctx, tsi_handshaker **handshaker) { + grpc_security_connector *sc, tsi_handshaker **handshaker) { *handshaker = tsi_create_fake_handshaker(0); return GRPC_SECURITY_OK; } -static grpc_security_status fake_check_peer(grpc_security_context *ctx, +static grpc_security_status fake_check_peer(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { @@ -238,10 +229,10 @@ end: } static grpc_security_status fake_channel_check_call_host( - grpc_channel_security_context *ctx, const char *host, + grpc_channel_security_connector *sc, const char *host, grpc_security_check_cb cb, void *user_data) { - grpc_fake_channel_security_context *c = - (grpc_fake_channel_security_context *)ctx; + grpc_fake_channel_security_connector *c = + (grpc_fake_channel_security_connector *)sc; if (c->call_host_check_is_async) { cb(user_data, GRPC_SECURITY_OK); return GRPC_SECURITY_PENDING; @@ -250,16 +241,16 @@ static grpc_security_status fake_channel_check_call_host( } } -static grpc_security_context_vtable fake_channel_vtable = { +static grpc_security_connector_vtable fake_channel_vtable = { fake_channel_destroy, fake_channel_create_handshaker, fake_check_peer}; -static grpc_security_context_vtable fake_server_vtable = { +static grpc_security_connector_vtable fake_server_vtable = { fake_server_destroy, fake_server_create_handshaker, fake_check_peer}; -grpc_channel_security_context *grpc_fake_channel_security_context_create( +grpc_channel_security_connector *grpc_fake_channel_security_connector_create( grpc_credentials *request_metadata_creds, int call_host_check_is_async) { - grpc_fake_channel_security_context *c = - gpr_malloc(sizeof(grpc_fake_channel_security_context)); + grpc_fake_channel_security_connector *c = + gpr_malloc(sizeof(grpc_fake_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.is_client_side = 1; c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; @@ -271,8 +262,8 @@ grpc_channel_security_context *grpc_fake_channel_security_context_create( return &c->base; } -grpc_security_context *grpc_fake_server_security_context_create(void) { - grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context)); +grpc_security_connector *grpc_fake_server_security_connector_create(void) { + grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector)); gpr_ref_init(&c->refcount, 1); c->vtable = &fake_server_vtable; c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; @@ -282,21 +273,21 @@ grpc_security_context *grpc_fake_server_security_context_create(void) { /* --- Ssl implementation. --- */ typedef struct { - grpc_channel_security_context base; + grpc_channel_security_connector base; tsi_ssl_handshaker_factory *handshaker_factory; char *target_name; char *overridden_target_name; tsi_peer peer; -} grpc_ssl_channel_security_context; +} grpc_ssl_channel_security_connector; typedef struct { - grpc_security_context base; + grpc_security_connector base; tsi_ssl_handshaker_factory *handshaker_factory; -} grpc_ssl_server_security_context; +} grpc_ssl_server_security_connector; -static void ssl_channel_destroy(grpc_security_context *ctx) { - grpc_ssl_channel_security_context *c = - (grpc_ssl_channel_security_context *)ctx; +static void ssl_channel_destroy(grpc_security_connector *sc) { + grpc_ssl_channel_security_connector *c = + (grpc_ssl_channel_security_connector *)sc; grpc_credentials_unref(c->base.request_metadata_creds); if (c->handshaker_factory != NULL) { tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); @@ -304,15 +295,16 @@ static void ssl_channel_destroy(grpc_security_context *ctx) { if (c->target_name != NULL) gpr_free(c->target_name); if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name); tsi_peer_destruct(&c->peer); - gpr_free(ctx); + gpr_free(sc); } -static void ssl_server_destroy(grpc_security_context *ctx) { - grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx; +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); } - gpr_free(ctx); + gpr_free(sc); } static grpc_security_status ssl_create_handshaker( @@ -331,9 +323,9 @@ static grpc_security_status ssl_create_handshaker( } static grpc_security_status ssl_channel_create_handshaker( - grpc_security_context *ctx, tsi_handshaker **handshaker) { - grpc_ssl_channel_security_context *c = - (grpc_ssl_channel_security_context *)ctx; + grpc_security_connector *sc, tsi_handshaker **handshaker) { + grpc_ssl_channel_security_connector *c = + (grpc_ssl_channel_security_connector *)sc; return ssl_create_handshaker(c->handshaker_factory, 1, c->overridden_target_name != NULL ? c->overridden_target_name @@ -342,13 +334,13 @@ static grpc_security_status ssl_channel_create_handshaker( } static grpc_security_status ssl_server_create_handshaker( - grpc_security_context *ctx, tsi_handshaker **handshaker) { - grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx; + grpc_security_connector *sc, tsi_handshaker **handshaker) { + grpc_ssl_server_security_connector *c = + (grpc_ssl_server_security_connector *)sc; return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker); } -static int ssl_host_matches_name(const tsi_peer *peer, - const char *peer_name) { +static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { char *allocated_name = NULL; int r; @@ -359,7 +351,6 @@ static int ssl_host_matches_name(const tsi_peer *peer, peer_name = allocated_name; if (!peer_name) return 0; } - r = tsi_ssl_peer_matches_name(peer, peer_name); gpr_free(allocated_name); return r; @@ -385,8 +376,7 @@ static grpc_security_status ssl_check_peer(const char *peer_name, } /* Check the peer name if specified. */ - if (peer_name != NULL && - !ssl_host_matches_name(peer, peer_name)) { + if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) { gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name); return GRPC_SECURITY_ERROR; } @@ -394,12 +384,12 @@ static grpc_security_status ssl_check_peer(const char *peer_name, return GRPC_SECURITY_OK; } -static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx, +static grpc_security_status ssl_channel_check_peer(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { - grpc_ssl_channel_security_context *c = - (grpc_ssl_channel_security_context *)ctx; + grpc_ssl_channel_security_connector *c = + (grpc_ssl_channel_security_connector *)sc; grpc_security_status status; tsi_peer_destruct(&c->peer); c->peer = peer; @@ -410,7 +400,7 @@ static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx, return status; } -static grpc_security_status ssl_server_check_peer(grpc_security_context *ctx, +static grpc_security_status ssl_server_check_peer(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { @@ -421,10 +411,10 @@ static grpc_security_status ssl_server_check_peer(grpc_security_context *ctx, } static grpc_security_status ssl_channel_check_call_host( - grpc_channel_security_context *ctx, const char *host, + grpc_channel_security_connector *sc, const char *host, grpc_security_check_cb cb, void *user_data) { - grpc_ssl_channel_security_context *c = - (grpc_ssl_channel_security_context *)ctx; + grpc_ssl_channel_security_connector *c = + (grpc_ssl_channel_security_connector *)sc; if (ssl_host_matches_name(&c->peer, host)) return GRPC_SECURITY_OK; @@ -438,10 +428,10 @@ static grpc_security_status ssl_channel_check_call_host( } } -static grpc_security_context_vtable ssl_channel_vtable = { +static grpc_security_connector_vtable ssl_channel_vtable = { ssl_channel_destroy, ssl_channel_create_handshaker, ssl_channel_check_peer}; -static grpc_security_context_vtable ssl_server_vtable = { +static grpc_security_connector_vtable ssl_server_vtable = { ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer}; static gpr_slice default_pem_root_certs; @@ -453,13 +443,13 @@ static void init_default_pem_root_certs(void) { if (default_root_certs_path == NULL) { default_pem_root_certs = gpr_empty_slice(); } else { - default_pem_root_certs = gpr_load_file(default_root_certs_path, NULL); + default_pem_root_certs = gpr_load_file(default_root_certs_path, 0, NULL); gpr_free(default_root_certs_path); } /* Fall back to installed certs if needed. */ if (GPR_SLICE_IS_EMPTY(default_pem_root_certs)) { - default_pem_root_certs = gpr_load_file(installed_roots_path, NULL); + default_pem_root_certs = gpr_load_file(installed_roots_path, 0, NULL); } } @@ -472,17 +462,17 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) { return GPR_SLICE_LENGTH(default_pem_root_certs); } -grpc_security_status grpc_ssl_channel_security_context_create( +grpc_security_status grpc_ssl_channel_security_connector_create( grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, - grpc_channel_security_context **ctx) { + grpc_channel_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); const unsigned char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); unsigned char *alpn_protocol_string_lengths = gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); tsi_result result = TSI_OK; - grpc_ssl_channel_security_context *c; + grpc_ssl_channel_security_connector *c; size_t i; const unsigned char *pem_root_certs; size_t pem_root_certs_size; @@ -503,8 +493,8 @@ grpc_security_status grpc_ssl_channel_security_context_create( goto error; } - c = gpr_malloc(sizeof(grpc_ssl_channel_security_context)); - memset(c, 0, sizeof(grpc_ssl_channel_security_context)); + c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector)); + memset(c, 0, sizeof(grpc_ssl_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.vtable = &ssl_channel_vtable; @@ -536,10 +526,10 @@ grpc_security_status grpc_ssl_channel_security_context_create( gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); ssl_channel_destroy(&c->base.base); - *ctx = NULL; + *sc = NULL; goto error; } - *ctx = &c->base; + *sc = &c->base; gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_OK; @@ -550,15 +540,15 @@ error: return GRPC_SECURITY_ERROR; } -grpc_security_status grpc_ssl_server_security_context_create( - const grpc_ssl_server_config *config, grpc_security_context **ctx) { +grpc_security_status grpc_ssl_server_security_connector_create( + const grpc_ssl_server_config *config, grpc_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); const unsigned char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); unsigned char *alpn_protocol_string_lengths = gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); tsi_result result = TSI_OK; - grpc_ssl_server_security_context *c; + grpc_ssl_server_security_connector *c; size_t i; for (i = 0; i < num_alpn_protocols; i++) { @@ -572,8 +562,8 @@ grpc_security_status grpc_ssl_server_security_context_create( gpr_log(GPR_ERROR, "An SSL server needs a key and a cert."); goto error; } - c = gpr_malloc(sizeof(grpc_ssl_server_security_context)); - memset(c, 0, sizeof(grpc_ssl_server_security_context)); + c = gpr_malloc(sizeof(grpc_ssl_server_security_connector)); + memset(c, 0, sizeof(grpc_ssl_server_security_connector)); gpr_ref_init(&c->base.refcount, 1); c->base.url_scheme = GRPC_SSL_URL_SCHEME; @@ -583,17 +573,17 @@ grpc_security_status grpc_ssl_server_security_context_create( config->pem_private_keys_sizes, (const unsigned char **)config->pem_cert_chains, config->pem_cert_chains_sizes, config->num_key_cert_pairs, - config->pem_root_certs, config->pem_root_certs_size, - ssl_cipher_suites(), alpn_protocol_strings, - alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory); + config->pem_root_certs, config->pem_root_certs_size, ssl_cipher_suites(), + alpn_protocol_strings, alpn_protocol_string_lengths, num_alpn_protocols, + &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); ssl_server_destroy(&c->base); - *ctx = NULL; + *sc = NULL; goto error; } - *ctx = &c->base; + *sc = &c->base; gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_OK; @@ -604,84 +594,3 @@ error: return GRPC_SECURITY_ERROR; } -/* -- High level objects. -- */ - -grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds, - grpc_credentials *request_metadata_creds, - const char *target, - const grpc_channel_args *args) { - grpc_channel_security_context *ctx = NULL; - grpc_channel *channel = NULL; - grpc_security_status status = GRPC_SECURITY_OK; - size_t i = 0; - const char *overridden_target_name = NULL; - grpc_arg arg; - grpc_channel_args *new_args; - - for (i = 0; args && i < args->num_args; i++) { - grpc_arg *arg = &args->args[i]; - if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 && - arg->type == GRPC_ARG_STRING) { - overridden_target_name = arg->value.string; - break; - } - } - status = grpc_ssl_channel_security_context_create( - request_metadata_creds, grpc_ssl_credentials_get_config(ssl_creds), - target, overridden_target_name, &ctx); - if (status != GRPC_SECURITY_OK) { - return grpc_lame_client_channel_create(); - } - arg.type = GRPC_ARG_STRING; - arg.key = GRPC_ARG_HTTP2_SCHEME; - arg.value.string = "https"; - new_args = grpc_channel_args_copy_and_add(args, &arg); - channel = grpc_secure_channel_create_internal( - target, new_args, ctx, get_or_create_mdctx(request_metadata_creds)); - grpc_security_context_unref(&ctx->base); - grpc_channel_args_destroy(new_args); - return channel; -} - -grpc_channel *grpc_fake_transport_security_channel_create( - grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds, - const char *target, const grpc_channel_args *args) { - grpc_channel_security_context *ctx = - grpc_fake_channel_security_context_create(request_metadata_creds, 1); - grpc_channel *channel = grpc_secure_channel_create_internal( - target, args, ctx, get_or_create_mdctx(request_metadata_creds)); - grpc_security_context_unref(&ctx->base); - return channel; -} - -grpc_channel *grpc_secure_channel_create_with_factories( - const grpc_secure_channel_factory *factories, size_t num_factories, - grpc_credentials *creds, const char *target, - const grpc_channel_args *args) { - size_t i; - if (creds == NULL) { - gpr_log(GPR_ERROR, "No credentials to create a secure channel."); - return grpc_lame_client_channel_create(); - } - if (grpc_credentials_has_request_metadata_only(creds)) { - gpr_log(GPR_ERROR, - "Credentials is insufficient to create a secure channel."); - return grpc_lame_client_channel_create(); - } - - for (i = 0; i < num_factories; i++) { - grpc_credentials *composite_creds = NULL; - grpc_credentials *transport_security_creds = NULL; - transport_security_creds = grpc_credentials_contains_type( - creds, factories[i].creds_type, &composite_creds); - if (transport_security_creds != NULL) { - return factories[i].factory(transport_security_creds, composite_creds, - target, args); - } - } - - gpr_log(GPR_ERROR, - "Unknown credentials type %s for creating a secure channel.", - creds->type); - return grpc_lame_client_channel_create(); -} diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h new file mode 100644 index 0000000000..47abe05cff --- /dev/null +++ b/src/core/security/security_connector.h @@ -0,0 +1,201 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H +#define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H + +#include <grpc/grpc_security.h> +#include "src/core/iomgr/endpoint.h" +#include "src/core/tsi/transport_security_interface.h" + +/* --- status enum. --- */ + +typedef enum { + GRPC_SECURITY_OK = 0, + GRPC_SECURITY_PENDING, + GRPC_SECURITY_ERROR +} grpc_security_status; + +/* --- URL schemes. --- */ + +#define GRPC_SSL_URL_SCHEME "https" +#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security" + +/* --- security_connector object. --- + + A security connector object represents away to configure the underlying + transport security mechanism and check the resulting trusted peer. */ + +typedef struct grpc_security_connector grpc_security_connector; + +#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector" + +typedef void (*grpc_security_check_cb)(void *user_data, + grpc_security_status status); + +typedef struct { + void (*destroy)(grpc_security_connector *sc); + grpc_security_status (*create_handshaker)(grpc_security_connector *sc, + tsi_handshaker **handshaker); + grpc_security_status (*check_peer)(grpc_security_connector *sc, tsi_peer peer, + grpc_security_check_cb cb, + void *user_data); +} grpc_security_connector_vtable; + +struct grpc_security_connector { + const grpc_security_connector_vtable *vtable; + gpr_refcount refcount; + int is_client_side; + const char *url_scheme; +}; + +/* Increments the refcount. */ +grpc_security_connector *grpc_security_connector_ref( + grpc_security_connector *sc); + +/* Decrements the refcount and destroys the object if it reaches 0. */ +void grpc_security_connector_unref(grpc_security_connector *sc); + +/* Handshake creation. */ +grpc_security_status grpc_security_connector_create_handshaker( + grpc_security_connector *sc, tsi_handshaker **handshaker); + +/* Check the peer. + Implementations can choose to check the peer either synchronously or + asynchronously. In the first case, a successful call will return + GRPC_SECURITY_OK. In the asynchronous case, the call will return + GRPC_SECURITY_PENDING unless an error is detected early on. + Ownership of the peer is transfered. +*/ +grpc_security_status grpc_security_connector_check_peer( + grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, + void *user_data); + +/* Util to encapsulate the connector in a channel arg. */ +grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); + +/* Util to get the connector from a channel arg. */ +grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg); + +/* Util to find the connector from channel args. */ +grpc_security_connector *grpc_find_security_connector_in_args( + const grpc_channel_args *args); + +/* --- channel_security_connector object. --- + + A channel security connector object represents away to configure the + underlying transport security mechanism on the client side. */ + +typedef struct grpc_channel_security_connector grpc_channel_security_connector; + +struct grpc_channel_security_connector { + grpc_security_connector base; /* requires is_client_side to be non 0. */ + grpc_credentials *request_metadata_creds; + grpc_security_status (*check_call_host)(grpc_channel_security_connector *sc, + const char *host, + grpc_security_check_cb cb, + void *user_data); +}; + +/* Checks that the host that will be set for a call is acceptable. + Implementations can choose do the check either synchronously or + asynchronously. In the first case, a successful call will return + GRPC_SECURITY_OK. In the asynchronous case, the call will return + GRPC_SECURITY_PENDING unless an error is detected early on. */ +grpc_security_status grpc_channel_security_connector_check_call_host( + grpc_channel_security_connector *sc, const char *host, + grpc_security_check_cb cb, void *user_data); + +/* --- Creation security connectors. --- */ + +/* For TESTING ONLY! + Creates a fake connector that emulates real channel security. */ +grpc_channel_security_connector *grpc_fake_channel_security_connector_create( + grpc_credentials *request_metadata_creds, int call_host_check_is_async); + +/* For TESTING ONLY! + Creates a fake connector that emulates real server security. */ +grpc_security_connector *grpc_fake_server_security_connector_create(void); + +/* Config for ssl clients. */ +typedef struct { + unsigned char *pem_private_key; + size_t pem_private_key_size; + unsigned char *pem_cert_chain; + size_t pem_cert_chain_size; + unsigned char *pem_root_certs; + size_t pem_root_certs_size; +} grpc_ssl_config; + +/* Creates an SSL channel_security_connector. + - request_metadata_creds is the credentials object which metadata + will be sent with each request. This parameter can be NULL. + - config is the SSL config to be used for the SSL channel establishment. + - is_client should be 0 for a server or a non-0 value for a client. + - secure_peer_name is the secure peer name that should be checked in + grpc_channel_security_connector_check_peer. This parameter may be NULL in + which case the peer name will not be checked. Note that if this parameter + is not NULL, then, pem_root_certs should not be NULL either. + - sc is a pointer on the connector to be created. + This function returns GRPC_SECURITY_OK in case of success or a + specific error code otherwise. +*/ +grpc_security_status grpc_ssl_channel_security_connector_create( + grpc_credentials *request_metadata_creds, + const grpc_ssl_config *config, const char *target_name, + const char *overridden_target_name, grpc_channel_security_connector **sc); + +/* Gets the default ssl roots. */ +size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs); + +/* Config for ssl servers. */ +typedef struct { + unsigned char **pem_private_keys; + size_t *pem_private_keys_sizes; + unsigned char **pem_cert_chains; + size_t *pem_cert_chains_sizes; + size_t num_key_cert_pairs; + unsigned char *pem_root_certs; + size_t pem_root_certs_size; +} grpc_ssl_server_config; + +/* Creates an SSL server_security_connector. + - config is the SSL config to be used for the SSL channel establishment. + - sc is a pointer on the connector to be created. + This function returns GRPC_SECURITY_OK in case of success or a + specific error code otherwise. +*/ +grpc_security_status grpc_ssl_server_security_connector_create( + const grpc_ssl_server_config *config, grpc_security_connector **sc); + +#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H */ diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h deleted file mode 100644 index 8e7ba34cac..0000000000 --- a/src/core/security/security_context.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H -#define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H - -#include <grpc/grpc_security.h> -#include "src/core/iomgr/endpoint.h" -#include "src/core/security/credentials.h" -#include "src/core/tsi/transport_security_interface.h" - -/* --- status enum. --- */ - -typedef enum { - GRPC_SECURITY_OK = 0, - GRPC_SECURITY_PENDING, - GRPC_SECURITY_ERROR -} grpc_security_status; - -/* --- URL schemes. --- */ - -#define GRPC_SSL_URL_SCHEME "https" -#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security" - -/* --- security_context object. --- - - A security context object represents away to configure the underlying - transport security mechanism and check the resulting trusted peer. */ - -typedef struct grpc_security_context grpc_security_context; - -#define GRPC_SECURITY_CONTEXT_ARG "grpc.security_context" - -typedef void (*grpc_security_check_cb)(void *user_data, - grpc_security_status status); - -typedef struct { - void (*destroy)(grpc_security_context *ctx); - grpc_security_status (*create_handshaker)(grpc_security_context *ctx, - tsi_handshaker **handshaker); - grpc_security_status (*check_peer)(grpc_security_context *ctx, tsi_peer peer, - grpc_security_check_cb cb, - void *user_data); -} grpc_security_context_vtable; - -struct grpc_security_context { - const grpc_security_context_vtable *vtable; - gpr_refcount refcount; - int is_client_side; - const char *url_scheme; -}; - -/* Increments the refcount. */ -grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx); - -/* Decrements the refcount and destroys the object if it reaches 0. */ -void grpc_security_context_unref(grpc_security_context *ctx); - -/* Handshake creation. */ -grpc_security_status grpc_security_context_create_handshaker( - grpc_security_context *ctx, tsi_handshaker **handshaker); - -/* Check the peer. - Implementations can choose to check the peer either synchronously or - asynchronously. In the first case, a successful call will return - GRPC_SECURITY_OK. In the asynchronous case, the call will return - GRPC_SECURITY_PENDING unless an error is detected early on. - Ownership of the peer is transfered. -*/ -grpc_security_status grpc_security_context_check_peer( - grpc_security_context *ctx, tsi_peer peer, - grpc_security_check_cb cb, void *user_data); - -/* Util to encapsulate the context in a channel arg. */ -grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx); - -/* Util to get the context from a channel arg. */ -grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg); - -/* Util to find the context from channel args. */ -grpc_security_context *grpc_find_security_context_in_args( - const grpc_channel_args *args); - -/* --- channel_security_context object. --- - - A channel security context object represents away to configure the - underlying transport security mechanism on the client side. */ - -typedef struct grpc_channel_security_context grpc_channel_security_context; - -struct grpc_channel_security_context { - grpc_security_context base; /* requires is_client_side to be non 0. */ - grpc_credentials *request_metadata_creds; - grpc_security_status (*check_call_host)( - grpc_channel_security_context *ctx, const char *host, - grpc_security_check_cb cb, void *user_data); -}; - -/* Checks that the host that will be set for a call is acceptable. - Implementations can choose do the check either synchronously or - asynchronously. In the first case, a successful call will return - GRPC_SECURITY_OK. In the asynchronous case, the call will return - GRPC_SECURITY_PENDING unless an error is detected early on. */ -grpc_security_status grpc_channel_security_context_check_call_host( - grpc_channel_security_context *ctx, const char *host, - grpc_security_check_cb cb, void *user_data); - -/* --- Creation security contexts. --- */ - -/* For TESTING ONLY! - Creates a fake context that emulates real channel security. */ -grpc_channel_security_context *grpc_fake_channel_security_context_create( - grpc_credentials *request_metadata_creds, int call_host_check_is_async); - -/* For TESTING ONLY! - Creates a fake context that emulates real server security. */ -grpc_security_context *grpc_fake_server_security_context_create(void); - -/* Creates an SSL channel_security_context. - - request_metadata_creds is the credentials object which metadata - will be sent with each request. This parameter can be NULL. - - config is the SSL config to be used for the SSL channel establishment. - - is_client should be 0 for a server or a non-0 value for a client. - - secure_peer_name is the secure peer name that should be checked in - grpc_channel_security_context_check_peer. This parameter may be NULL in - which case the peer name will not be checked. Note that if this parameter - is not NULL, then, pem_root_certs should not be NULL either. - - ctx is a pointer on the context to be created. - This function returns GRPC_SECURITY_OK in case of success or a - specific error code otherwise. -*/ -grpc_security_status grpc_ssl_channel_security_context_create( - grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, - const char *target_name, const char *overridden_target_name, - grpc_channel_security_context **ctx); - -/* Creates an SSL server_security_context. - - config is the SSL config to be used for the SSL channel establishment. - - ctx is a pointer on the context to be created. - This function returns GRPC_SECURITY_OK in case of success or a - specific error code otherwise. -*/ -grpc_security_status grpc_ssl_server_security_context_create( - const grpc_ssl_server_config *config, grpc_security_context **ctx); - -/* --- Creation of high level objects. --- */ - -/* Secure client channel creation. */ - -size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs); - -grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds, - grpc_credentials *request_metadata_creds, - const char *target, - const grpc_channel_args *args); - -grpc_channel *grpc_fake_transport_security_channel_create( - grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds, - const char *target, const grpc_channel_args *args); - -grpc_channel *grpc_secure_channel_create_internal( - const char *target, const grpc_channel_args *args, - grpc_channel_security_context *ctx, grpc_mdctx *mdctx); - -typedef grpc_channel *(*grpc_secure_channel_factory_func)( - grpc_credentials *transport_security_creds, - grpc_credentials *request_metadata_creds, const char *target, - const grpc_channel_args *args); - -typedef struct { - const char *creds_type; - grpc_secure_channel_factory_func factory; -} grpc_secure_channel_factory; - -grpc_channel *grpc_secure_channel_create_with_factories( - const grpc_secure_channel_factory *factories, size_t num_factories, - grpc_credentials *creds, const char *target, const grpc_channel_args *args); - -/* Secure server context creation. */ - -grpc_security_status grpc_server_security_context_create( - grpc_server_credentials *creds, grpc_security_context **ctx); - -#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */ diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index 165ed5474f..5b7d99ce40 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -40,7 +40,8 @@ #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_server.h" -#include "src/core/security/security_context.h" +#include "src/core/security/credentials.h" +#include "src/core/security/security_connector.h" #include "src/core/security/secure_transport_setup.h" #include "src/core/surface/server.h" #include "src/core/transport/chttp2_transport.h" @@ -52,7 +53,7 @@ typedef struct grpc_server_secure_state { grpc_server *server; grpc_tcp_server *tcp; - grpc_security_context *ctx; + grpc_security_connector *sc; int is_shutdown; gpr_mu mu; gpr_refcount refcount; @@ -64,7 +65,7 @@ static void state_ref(grpc_server_secure_state *state) { static void state_unref(grpc_server_secure_state *state) { if (gpr_unref(&state->refcount)) { - grpc_security_context_unref(state->ctx); + grpc_security_connector_unref(state->sc); gpr_free(state); } } @@ -104,7 +105,7 @@ static void on_secure_transport_setup_done(void *statep, static void on_accept(void *statep, grpc_endpoint *tcp) { grpc_server_secure_state *state = statep; state_ref(state); - grpc_setup_secure_transport(state->ctx, tcp, on_secure_transport_setup_done, + grpc_setup_secure_transport(state->sc, tcp, on_secure_transport_setup_done, state); } @@ -137,11 +138,11 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, int port_num = -1; int port_temp; grpc_security_status status = GRPC_SECURITY_ERROR; - grpc_security_context *ctx = NULL; + grpc_security_connector *sc = NULL; /* create security context */ if (creds == NULL) goto error; - status = grpc_server_security_context_create(creds, &ctx); + status = grpc_server_credentials_create_security_connector(creds, &sc); if (status != GRPC_SECURITY_OK) { gpr_log(GPR_ERROR, "Unable to create secure server with credentials of type %s.", @@ -188,7 +189,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, state = gpr_malloc(sizeof(*state)); state->server = server; state->tcp = tcp; - state->ctx = ctx; + state->sc = sc; state->is_shutdown = 0; gpr_mu_init(&state->mu); gpr_ref_init(&state->refcount, 1); @@ -200,8 +201,8 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, /* Error path: cleanup and return */ error: - if (ctx) { - grpc_security_context_unref(ctx); + if (sc) { + grpc_security_connector_unref(sc); } if (resolved) { grpc_resolved_addresses_destroy(resolved); diff --git a/src/core/support/file.c b/src/core/support/file.c index 70100b7e9b..3a4ac6f2f0 100644 --- a/src/core/support/file.c +++ b/src/core/support/file.c @@ -41,13 +41,14 @@ #include "src/core/support/string.h" -gpr_slice gpr_load_file(const char *filename, int *success) { +gpr_slice gpr_load_file(const char *filename, int add_null_terminator, + int *success) { unsigned char *contents = NULL; size_t contents_size = 0; - unsigned char buf[4096]; char *error_msg = NULL; gpr_slice result = gpr_empty_slice(); FILE *file = fopen(filename, "rb"); + size_t bytes_read = 0; if (file == NULL) { gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename, @@ -55,27 +56,22 @@ gpr_slice gpr_load_file(const char *filename, int *success) { GPR_ASSERT(error_msg != NULL); goto end; } - - while (1) { - size_t bytes_read = fread(buf, 1, sizeof(buf), file); - if (bytes_read > 0) { - contents = gpr_realloc(contents, contents_size + bytes_read); - memcpy(contents + contents_size, buf, bytes_read); - contents_size += bytes_read; - } - if (bytes_read < sizeof(buf)) { - if (ferror(file)) { - gpr_asprintf(&error_msg, "Error %s occured while reading file %s.", - strerror(errno), filename); - GPR_ASSERT(error_msg != NULL); - goto end; - } else { - GPR_ASSERT(feof(file)); - break; - } - } + fseek(file, 0, SEEK_END); + contents_size = ftell(file); + fseek(file, 0, SEEK_SET); + contents = gpr_malloc(contents_size + (add_null_terminator ? 1 : 0)); + bytes_read = fread(contents, 1, contents_size, file); + if (bytes_read < contents_size) { + GPR_ASSERT(ferror(file)); + gpr_asprintf(&error_msg, "Error %s occured while reading file %s.", + strerror(errno), filename); + GPR_ASSERT(error_msg != NULL); + goto end; } if (success != NULL) *success = 1; + if (add_null_terminator) { + contents[contents_size++] = 0; + } result = gpr_slice_new(contents, contents_size, gpr_free); end: diff --git a/src/core/support/file.h b/src/core/support/file.h index ee6ca7b230..1dafe390e3 100644 --- a/src/core/support/file.h +++ b/src/core/support/file.h @@ -44,9 +44,11 @@ extern "C" { /* File utility functions */ -/* Loads the content of a file into a slice. The success parameter, if not NULL, +/* Loads the content of a file into a slice. add_null_terminator will add + a NULL terminator if non-zero. The success parameter, if not NULL, will be set to 1 in case of success and 0 in case of failure. */ -gpr_slice gpr_load_file(const char *filename, int *success); +gpr_slice gpr_load_file(const char *filename, int add_null_terminator, + int *success); /* Creates a temporary file from a prefix. If tmp_filename is not NULL, *tmp_filename is assigned the name of the diff --git a/src/core/surface/init.c b/src/core/surface/init.c index 4de51a666f..5a119a47cc 100644 --- a/src/core/surface/init.c +++ b/src/core/surface/init.c @@ -61,8 +61,8 @@ void grpc_init(void) { grpc_register_tracer("http", &grpc_http_trace); grpc_register_tracer("batch", &grpc_trace_batch); grpc_security_pre_init(); - grpc_tracer_init("GRPC_TRACE"); grpc_iomgr_init(); + grpc_tracer_init("GRPC_TRACE"); census_init(); grpc_timers_log_global_init(); } diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index 96b2fe04fa..e7d223bfda 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -48,7 +48,7 @@ #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/security/auth.h" -#include "src/core/security/security_context.h" +#include "src/core/security/credentials.h" #include "src/core/security/secure_transport_setup.h" #include "src/core/support/string.h" #include "src/core/surface/channel.h" @@ -74,7 +74,7 @@ typedef struct { } request; struct setup { - grpc_channel_security_context *security_context; + grpc_channel_security_connector *security_connector; const char *target; grpc_transport_setup_callback setup_callback; void *setup_user_data; @@ -130,7 +130,7 @@ static void on_connect(void *rp, grpc_endpoint *tcp) { return; } } else { - grpc_setup_secure_transport(&r->setup->security_context->base, tcp, + grpc_setup_secure_transport(&r->setup->security_connector->base, tcp, on_secure_transport_setup_done, r); } } @@ -185,7 +185,7 @@ static void initiate_setup(void *sp, grpc_client_setup_request *cs_request) { static void done_setup(void *sp) { setup *s = sp; gpr_free((void *)s->target); - grpc_security_context_unref(&s->security_context->base); + grpc_security_connector_unref(&s->security_connector->base); gpr_free(s); } @@ -203,23 +203,37 @@ static grpc_transport_setup_result complete_setup(void *channel_stack, Asynchronously: - resolve target - connect to it (trying alternatives as presented) - perform handshakes */ -grpc_channel *grpc_secure_channel_create_internal( - const char *target, const grpc_channel_args *args, - grpc_channel_security_context *context, grpc_mdctx *mdctx) { +grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, + const char *target, + const grpc_channel_args *args) { setup *s; grpc_channel *channel; - grpc_arg context_arg; + grpc_arg connector_arg; grpc_channel_args *args_copy; + grpc_channel_args *new_args_from_connector; + grpc_channel_security_connector* connector; + grpc_mdctx *mdctx; #define MAX_FILTERS 3 const grpc_channel_filter *filters[MAX_FILTERS]; int n = 0; - if (grpc_find_security_context_in_args(args) != NULL) { + + if (grpc_find_security_connector_in_args(args) != NULL) { gpr_log(GPR_ERROR, "Cannot set security context in channel args."); + return grpc_lame_client_channel_create(); + } + + if (grpc_credentials_create_security_connector( + creds, target, args, NULL, &connector, &new_args_from_connector) != + GRPC_SECURITY_OK) { + return grpc_lame_client_channel_create(); } + mdctx = grpc_credentials_get_or_create_metadata_context(creds); s = gpr_malloc(sizeof(setup)); - context_arg = grpc_security_context_to_arg(&context->base); - args_copy = grpc_channel_args_copy_and_add(args, &context_arg); + connector_arg = grpc_security_connector_to_arg(&connector->base); + args_copy = grpc_channel_args_copy_and_add( + new_args_from_connector != NULL ? new_args_from_connector : args, + &connector_arg); filters[n++] = &grpc_client_surface_filter; if (grpc_channel_args_is_census_enabled(args)) { filters[n++] = &grpc_client_census_filter; @@ -228,13 +242,14 @@ grpc_channel *grpc_secure_channel_create_internal( GPR_ASSERT(n <= MAX_FILTERS); channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1); grpc_channel_args_destroy(args_copy); + if (new_args_from_connector != NULL) { + grpc_channel_args_destroy(new_args_from_connector); + } s->target = gpr_strdup(target); s->setup_callback = complete_setup; s->setup_user_data = grpc_channel_get_channel_stack(channel); - s->security_context = - (grpc_channel_security_context *)grpc_security_context_ref( - &context->base); + s->security_connector = connector; grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel), args, mdctx, initiate_setup, done_setup, s); diff --git a/src/ruby/.rubocop_todo.yml b/src/ruby/.rubocop_todo.yml index b4d66c517c..02136a81a9 100644 --- a/src/ruby/.rubocop_todo.yml +++ b/src/ruby/.rubocop_todo.yml @@ -1,18 +1,18 @@ # This configuration was generated by `rubocop --auto-gen-config` -# on 2015-04-15 18:43:23 -0700 using RuboCop version 0.30.0. +# on 2015-04-16 12:30:09 -0700 using RuboCop version 0.30.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 32 +# Offense count: 34 Metrics/AbcSize: Max: 36 # Offense count: 3 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 183 + Max: 185 # Offense count: 35 # Configuration parameters: CountComments. @@ -24,7 +24,7 @@ Metrics/MethodLength: Metrics/ParameterLists: Max: 8 -# Offense count: 6 +# Offense count: 9 # Configuration parameters: AllowedVariables. Style/GlobalVars: Enabled: false diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb index 0819ba9bbc..72570d92f3 100755 --- a/src/ruby/bin/interop/interop_server.rb +++ b/src/ruby/bin/interop/interop_server.rb @@ -185,7 +185,7 @@ def main logger.info("... running insecurely on #{host}") end s.handle(TestTarget) - s.run + s.run_till_terminated end main diff --git a/src/ruby/bin/math_server.rb b/src/ruby/bin/math_server.rb index 5cc7613489..1bfe253b85 100755 --- a/src/ruby/bin/math_server.rb +++ b/src/ruby/bin/math_server.rb @@ -183,7 +183,7 @@ def main end s.handle(Calculator) - s.run + s.run_till_terminated end main diff --git a/src/ruby/bin/noproto_server.rb b/src/ruby/bin/noproto_server.rb index 9979cb7ebb..f71daeadb3 100755 --- a/src/ruby/bin/noproto_server.rb +++ b/src/ruby/bin/noproto_server.rb @@ -105,7 +105,7 @@ def main end s.handle(NoProto) - s.run + s.run_till_terminated end main diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index b0963411d1..6da7d3c830 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -117,6 +117,37 @@ static void grpc_rb_call_destroy(void *p) { } } +static size_t md_ary_datasize(const void *p) { + const grpc_metadata_array* const ary = (grpc_metadata_array*)p; + size_t i, datasize = sizeof(grpc_metadata_array); + for (i = 0; i < ary->count; ++i) { + const grpc_metadata* const md = &ary->metadata[i]; + datasize += strlen(md->key); + datasize += md->value_length; + } + datasize += ary->capacity * sizeof(grpc_metadata); + return datasize; +} + +static const rb_data_type_t grpc_rb_md_ary_data_type = { + "grpc_metadata_array", + {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, md_ary_datasize}, + NULL, NULL, + 0 +}; + +/* Describes grpc_call struct for RTypedData */ +static const rb_data_type_t grpc_call_data_type = { + "grpc_call", + {GRPC_RB_GC_NOT_MARKED, grpc_rb_call_destroy, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because grpc_rb_call_destroy + * touches a hash object. + * TODO(yugui) Directly use st_table and call the free function earlier? + */ + 0 +}; + /* Error code details is a hash containing text strings describing errors */ VALUE rb_error_code_details; @@ -135,7 +166,7 @@ const char *grpc_call_error_detail_of(grpc_call_error err) { static VALUE grpc_rb_call_cancel(VALUE self) { grpc_call *call = NULL; grpc_call_error err; - Data_Get_Struct(self, grpc_call, call); + TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call); err = grpc_call_cancel(call); if (err != GRPC_CALL_OK) { rb_raise(grpc_rb_eCallError, "cancel failed: %s (code=%d)", @@ -205,7 +236,8 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { int i; /* Construct a metadata object from key and value and add it */ - Data_Get_Struct(md_ary_obj, grpc_metadata_array, md_ary); + TypedData_Get_Struct(md_ary_obj, grpc_metadata_array, + &grpc_rb_md_ary_data_type, md_ary); if (TYPE(val) == T_ARRAY) { /* If the value is an array, add capacity for each value in the array */ @@ -243,7 +275,8 @@ static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val, grpc_metadata_array *md_ary = NULL; /* Construct a metadata object from key and value and add it */ - Data_Get_Struct(md_ary_obj, grpc_metadata_array, md_ary); + TypedData_Get_Struct(md_ary_obj, grpc_metadata_array, + &grpc_rb_md_ary_data_type, md_ary); if (TYPE(val) == T_ARRAY) { /* If the value is an array, add capacity for each value in the array */ @@ -270,8 +303,8 @@ static void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ar /* Initialize the array, compute it's capacity, then fill it. */ grpc_metadata_array_init(md_ary); - md_ary_obj = - Data_Wrap_Struct(grpc_rb_cMdAry, GC_NOT_MARKED, GC_DONT_FREE, md_ary); + md_ary_obj = TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, + md_ary); rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj); md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata)); rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj); @@ -556,7 +589,7 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag, grpc_event *ev = NULL; grpc_call_error err; VALUE result = Qnil; - Data_Get_Struct(self, grpc_call, call); + TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call); /* Validate the ops args, adding them to a ruby array */ if (TYPE(ops_hash) != T_HASH) { @@ -736,7 +769,7 @@ void Init_grpc_call() { /* Gets the call from the ruby object */ grpc_call *grpc_rb_get_wrapped_call(VALUE v) { grpc_call *c = NULL; - Data_Get_Struct(v, grpc_call, c); + TypedData_Get_Struct(v, grpc_call, &grpc_call_data_type, c); return c; } @@ -753,6 +786,5 @@ VALUE grpc_rb_wrap_call(grpc_call *c) { rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c), UINT2NUM(NUM2UINT(obj) + 1)); } - return Data_Wrap_Struct(grpc_rb_cCall, GC_NOT_MARKED, - grpc_rb_call_destroy, c); + return TypedData_Wrap_Struct(grpc_rb_cCall, &grpc_call_data_type, c); } diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 9bd7c2edf9..214675af92 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -105,13 +105,19 @@ static void grpc_rb_channel_mark(void *p) { } } +static rb_data_type_t grpc_channel_data_type = { + "grpc_channel", + {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + RUBY_TYPED_FREE_IMMEDIATELY +}; + /* Allocates grpc_rb_channel instances. */ static VALUE grpc_rb_channel_alloc(VALUE cls) { grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel); wrapper->wrapped = NULL; wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_channel_mark, grpc_rb_channel_free, - wrapper); + return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper); } /* @@ -135,7 +141,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { /* "21" == 2 mandatory args, 1 (credentials) is optional */ rb_scan_args(argc, argv, "21", &target, &channel_args, &credentials); - Data_Get_Struct(self, grpc_rb_channel, wrapper); + TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); target_chars = StringValueCStr(target); grpc_rb_hash_convert_to_channel_args(channel_args, &args); if (credentials == Qnil) { @@ -176,8 +182,8 @@ static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) { return Qnil; } - Data_Get_Struct(orig, grpc_rb_channel, orig_ch); - Data_Get_Struct(copy, grpc_rb_channel, copy_ch); + TypedData_Get_Struct(orig, grpc_rb_channel, &grpc_channel_data_type, orig_ch); + TypedData_Get_Struct(copy, grpc_rb_channel, &grpc_channel_data_type, copy_ch); /* use ruby's MEMCPY to make a byte-for-byte copy of the channel wrapper * object. */ @@ -198,7 +204,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE method, char *host_chars = StringValueCStr(host); cq = grpc_rb_get_wrapped_completion_queue(cqueue); - Data_Get_Struct(self, grpc_rb_channel, wrapper); + TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch == NULL) { rb_raise(rb_eRuntimeError, "closed!"); @@ -231,7 +237,7 @@ static VALUE grpc_rb_channel_destroy(VALUE self) { grpc_rb_channel *wrapper = NULL; grpc_channel *ch = NULL; - Data_Get_Struct(self, grpc_rb_channel, wrapper); + TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch != NULL) { grpc_channel_destroy(ch); @@ -277,6 +283,6 @@ void Init_grpc_channel() { /* Gets the wrapped channel from the ruby wrapper */ grpc_channel *grpc_rb_get_wrapped_channel(VALUE v) { grpc_rb_channel *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_channel, wrapper); + TypedData_Get_Struct(v, grpc_rb_channel, &grpc_channel_data_type, wrapper); return wrapper->wrapped; } diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c index 9b92ec1514..acd545f5d2 100644 --- a/src/ruby/ext/grpc/rb_channel_args.c +++ b/src/ruby/ext/grpc/rb_channel_args.c @@ -38,6 +38,13 @@ #include "rb_grpc.h" +static rb_data_type_t grpc_rb_channel_args_data_type = { + "grpc_channel_args", + {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + RUBY_TYPED_FREE_IMMEDIATELY +}; + /* A callback the processes the hash key values in channel_args hash */ static int grpc_rb_channel_create_in_process_add_args_hash_cb(VALUE key, VALUE val, @@ -60,7 +67,8 @@ static int grpc_rb_channel_create_in_process_add_args_hash_cb(VALUE key, return ST_STOP; } - Data_Get_Struct(args_obj, grpc_channel_args, args); + TypedData_Get_Struct(args_obj, grpc_channel_args, + &grpc_rb_channel_args_data_type, args); if (args->num_args <= 0) { rb_raise(rb_eRuntimeError, "hash_cb bug: num_args is %lu for key:%s", args->num_args, StringValueCStr(key)); @@ -126,8 +134,9 @@ static VALUE grpc_rb_hash_convert_to_channel_args0(VALUE as_value) { MEMZERO(params->dst->args, grpc_arg, num_args); rb_hash_foreach(params->src_hash, grpc_rb_channel_create_in_process_add_args_hash_cb, - Data_Wrap_Struct(grpc_rb_cChannelArgs, GC_NOT_MARKED, - GC_DONT_FREE, params->dst)); + TypedData_Wrap_Struct(grpc_rb_cChannelArgs, + &grpc_rb_channel_args_data_type, + params->dst)); /* reset num_args as grpc_rb_channel_create_in_process_add_args_hash_cb * decrements it during has processing */ params->dst->num_args = num_args; diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c index a72f01ffb8..3cf6c313ee 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.c +++ b/src/ruby/ext/grpc/rb_completion_queue.c @@ -33,7 +33,8 @@ #include "rb_completion_queue.h" -#include <ruby.h> +#include <ruby/ruby.h> +#include <ruby/thread.h> #include <grpc/grpc.h> #include <grpc/support/time.h> @@ -52,14 +53,16 @@ typedef struct next_call_stack { } next_call_stack; /* Calls grpc_completion_queue_next without holding the ruby GIL */ -static void *grpc_rb_completion_queue_next_no_gil(next_call_stack *next_call) { +static void *grpc_rb_completion_queue_next_no_gil(void *param) { + next_call_stack *const next_call = (next_call_stack*)param; next_call->event = grpc_completion_queue_next(next_call->cq, next_call->timeout); return NULL; } /* Calls grpc_completion_queue_pluck without holding the ruby GIL */ -static void *grpc_rb_completion_queue_pluck_no_gil(next_call_stack *next_call) { +static void *grpc_rb_completion_queue_pluck_no_gil(void *param) { + next_call_stack *const next_call = (next_call_stack*)param; next_call->event = grpc_completion_queue_pluck(next_call->cq, next_call->tag, next_call->timeout); return NULL; @@ -116,21 +119,31 @@ static void grpc_rb_completion_queue_destroy(void *p) { grpc_completion_queue_destroy(cq); } +static rb_data_type_t grpc_rb_completion_queue_data_type = { + "grpc_completion_queue", + {GRPC_RB_GC_NOT_MARKED, grpc_rb_completion_queue_destroy, + GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + /* cannot immediately free because grpc_rb_completion_queue_shutdown_drain + * calls rb_thread_call_without_gvl. */ + 0 +}; + /* Allocates a completion queue. */ static VALUE grpc_rb_completion_queue_alloc(VALUE cls) { grpc_completion_queue *cq = grpc_completion_queue_create(); if (cq == NULL) { rb_raise(rb_eArgError, "could not create a completion queue: not sure why"); } - return Data_Wrap_Struct(cls, GC_NOT_MARKED, grpc_rb_completion_queue_destroy, - cq); + return TypedData_Wrap_Struct(cls, &grpc_rb_completion_queue_data_type, cq); } /* Blocks until the next event is available, and returns the event. */ static VALUE grpc_rb_completion_queue_next(VALUE self, VALUE timeout) { next_call_stack next_call; MEMZERO(&next_call, next_call_stack, 1); - Data_Get_Struct(self, grpc_completion_queue, next_call.cq); + TypedData_Get_Struct(self, grpc_completion_queue, + &grpc_rb_completion_queue_data_type, next_call.cq); next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0); next_call.event = NULL; rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil, @@ -158,7 +171,8 @@ grpc_event* grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag, VALUE timeout) { next_call_stack next_call; MEMZERO(&next_call, next_call_stack, 1); - Data_Get_Struct(self, grpc_completion_queue, next_call.cq); + TypedData_Get_Struct(self, grpc_completion_queue, + &grpc_rb_completion_queue_data_type, next_call.cq); next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0); next_call.tag = ROBJECT(tag); next_call.event = NULL; @@ -192,6 +206,7 @@ void Init_grpc_completion_queue() { /* Gets the wrapped completion queue from the ruby wrapper */ grpc_completion_queue *grpc_rb_get_wrapped_completion_queue(VALUE v) { grpc_completion_queue *cq = NULL; - Data_Get_Struct(v, grpc_completion_queue, cq); + TypedData_Get_Struct(v, grpc_completion_queue, + &grpc_rb_completion_queue_data_type, cq); return cq; } diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c index 122cffc92f..1ec88914e4 100644 --- a/src/ruby/ext/grpc/rb_credentials.c +++ b/src/ruby/ext/grpc/rb_credentials.c @@ -86,14 +86,21 @@ static void grpc_rb_credentials_mark(void *p) { } } +static rb_data_type_t grpc_rb_credentials_data_type = { + "grpc_credentials", + {grpc_rb_credentials_mark, grpc_rb_credentials_free, + GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, + NULL, + RUBY_TYPED_FREE_IMMEDIATELY}; + /* Allocates Credential instances. Provides safe initial defaults for the instance fields. */ static VALUE grpc_rb_credentials_alloc(VALUE cls) { grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials); wrapper->wrapped = NULL; wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_credentials_mark, - grpc_rb_credentials_free, wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); } /* Clones Credentials instances. @@ -113,8 +120,10 @@ static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) { rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cCredentials)); } - Data_Get_Struct(orig, grpc_rb_credentials, orig_cred); - Data_Get_Struct(copy, grpc_rb_credentials, copy_cred); + TypedData_Get_Struct(orig, grpc_rb_credentials, + &grpc_rb_credentials_data_type, orig_cred); + TypedData_Get_Struct(copy, grpc_rb_credentials, + &grpc_rb_credentials_data_type, copy_cred); /* use ruby's MEMCPY to make a byte-for-byte copy of the credentials * wrapper object. */ @@ -136,8 +145,7 @@ static VALUE grpc_rb_default_credentials_create(VALUE cls) { } wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_credentials_mark, - grpc_rb_credentials_free, wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); } /* @@ -154,8 +162,7 @@ static VALUE grpc_rb_compute_engine_credentials_create(VALUE cls) { } wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_credentials_mark, - grpc_rb_credentials_free, wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); } /* @@ -169,8 +176,10 @@ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) { grpc_rb_credentials *other_wrapper = NULL; grpc_rb_credentials *wrapper = NULL; - Data_Get_Struct(self, grpc_rb_credentials, self_wrapper); - Data_Get_Struct(other, grpc_rb_credentials, other_wrapper); + TypedData_Get_Struct(self, grpc_rb_credentials, + &grpc_rb_credentials_data_type, self_wrapper); + TypedData_Get_Struct(other, grpc_rb_credentials, + &grpc_rb_credentials_data_type, other_wrapper); wrapper = ALLOC(grpc_rb_credentials); wrapper->wrapped = grpc_composite_credentials_create(self_wrapper->wrapped, other_wrapper->wrapped); @@ -181,8 +190,8 @@ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) { } wrapper->mark = Qnil; - return Data_Wrap_Struct(grpc_rb_cCredentials, grpc_rb_credentials_mark, - grpc_rb_credentials_free, wrapper); + return TypedData_Wrap_Struct(grpc_rb_cCredentials, + &grpc_rb_credentials_data_type, wrapper); } /* The attribute used on the mark object to hold the pem_root_certs. */ @@ -217,7 +226,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key, &pem_cert_chain); - Data_Get_Struct(self, grpc_rb_credentials, wrapper); + TypedData_Get_Struct(self, grpc_rb_credentials, + &grpc_rb_credentials_data_type, wrapper); if (pem_root_certs == Qnil) { rb_raise(rb_eRuntimeError, "could not create a credential: nil pem_root_certs"); @@ -228,8 +238,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { } else { key_cert_pair.private_key = RSTRING_PTR(pem_private_key); key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain); - creds = grpc_ssl_credentials_create( - RSTRING_PTR(pem_root_certs), &key_cert_pair); + creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), + &key_cert_pair); } if (creds == NULL) { rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); @@ -253,8 +263,8 @@ void Init_grpc_credentials() { rb_define_alloc_func(grpc_rb_cCredentials, grpc_rb_credentials_alloc); /* Provides a ruby constructor and support for dup/clone. */ - rb_define_method(grpc_rb_cCredentials, "initialize", - grpc_rb_credentials_init, -1); + rb_define_method(grpc_rb_cCredentials, "initialize", grpc_rb_credentials_init, + -1); rb_define_method(grpc_rb_cCredentials, "initialize_copy", grpc_rb_credentials_init_copy, 1); @@ -277,6 +287,7 @@ void Init_grpc_credentials() { /* Gets the wrapped grpc_credentials from the ruby wrapper */ grpc_credentials *grpc_rb_get_wrapped_credentials(VALUE v) { grpc_rb_credentials *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_credentials, wrapper); + TypedData_Get_Struct(v, grpc_rb_credentials, &grpc_rb_credentials_data_type, + wrapper); return wrapper->wrapped; } diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 1cbd1aa8bd..699548b940 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -34,7 +34,8 @@ #include "rb_grpc.h" #include <math.h> -#include <ruby.h> +#include <ruby/ruby.h> +#include <ruby/vm.h> #include <sys/time.h> #include <grpc/grpc.h> @@ -46,12 +47,15 @@ #include "rb_credentials.h" #include "rb_server_credentials.h" -/* Define common vars and funcs declared in rb.h */ -const RUBY_DATA_FUNC GC_NOT_MARKED = NULL; -const RUBY_DATA_FUNC GC_DONT_FREE = NULL; - static VALUE grpc_rb_cTimeVal = Qnil; +static rb_data_type_t grpc_rb_timespec_data_type = { + "gpr_timespec", + {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, + NULL, + RUBY_TYPED_FREE_IMMEDIATELY}; + /* Alloc func that blocks allocation of a given object by raising an * exception. */ VALUE grpc_rb_cannot_alloc(VALUE cls) { @@ -97,7 +101,8 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) { switch (TYPE(time)) { case T_DATA: if (CLASS_OF(time) == grpc_rb_cTimeVal) { - Data_Get_Struct(time, gpr_timespec, time_const); + TypedData_Get_Struct(time, gpr_timespec, &grpc_rb_timespec_data_type, + time_const); t = *time_const; } else if (CLASS_OF(time) == rb_cTime) { t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0)); @@ -201,7 +206,8 @@ static ID id_to_s; /* Converts a wrapped time constant to a standard time. */ static VALUE grpc_rb_time_val_to_time(VALUE self) { gpr_timespec *time_const = NULL; - Data_Get_Struct(self, gpr_timespec, time_const); + TypedData_Get_Struct(self, gpr_timespec, &grpc_rb_timespec_data_type, + time_const); return rb_funcall(rb_cTime, id_at, 2, INT2NUM(time_const->tv_sec), INT2NUM(time_const->tv_nsec)); } @@ -222,18 +228,18 @@ static void Init_grpc_time_consts() { rb_define_module_under(grpc_rb_mGrpcCore, "TimeConsts"); grpc_rb_cTimeVal = rb_define_class_under(grpc_rb_mGrpcCore, "TimeSpec", rb_cObject); - rb_define_const(grpc_rb_mTimeConsts, "ZERO", - Data_Wrap_Struct(grpc_rb_cTimeVal, - GC_NOT_MARKED, GC_DONT_FREE, - (void *)&gpr_time_0)); - rb_define_const(grpc_rb_mTimeConsts, "INFINITE_FUTURE", - Data_Wrap_Struct(grpc_rb_cTimeVal, - GC_NOT_MARKED, GC_DONT_FREE, - (void *)&gpr_inf_future)); - rb_define_const(grpc_rb_mTimeConsts, "INFINITE_PAST", - Data_Wrap_Struct(grpc_rb_cTimeVal, - GC_NOT_MARKED, GC_DONT_FREE, - (void *)&gpr_inf_past)); + rb_define_const( + grpc_rb_mTimeConsts, "ZERO", + TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type, + (void *)&gpr_time_0)); + rb_define_const( + grpc_rb_mTimeConsts, "INFINITE_FUTURE", + TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type, + (void *)&gpr_inf_future)); + rb_define_const( + grpc_rb_mTimeConsts, "INFINITE_PAST", + TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type, + (void *)&gpr_inf_past)); rb_define_method(grpc_rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0); rb_define_method(grpc_rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0); rb_define_method(grpc_rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0); @@ -244,7 +250,7 @@ static void Init_grpc_time_consts() { id_tv_nsec = rb_intern("tv_nsec"); } -static void grpc_rb_shutdown(void *vm) { grpc_shutdown(); } +static void grpc_rb_shutdown(ruby_vm_t *vm) { grpc_shutdown(); } /* Initialize the GRPC module structs */ diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h index 1d411baf5b..a502273de1 100644 --- a/src/ruby/ext/grpc/rb_grpc.h +++ b/src/ruby/ext/grpc/rb_grpc.h @@ -58,12 +58,16 @@ extern VALUE sym_metadata; /* GC_NOT_MARKED is used in calls to Data_Wrap_Struct to indicate that the wrapped struct does not need to participate in ruby gc. */ -extern const RUBY_DATA_FUNC GC_NOT_MARKED; +#define GRPC_RB_GC_NOT_MARKED (RUBY_DATA_FUNC)(NULL) /* GC_DONT_FREED is used in calls to Data_Wrap_Struct to indicate that the wrapped struct should not be freed the wrapped ruby object is released by the garbage collector. */ -extern const RUBY_DATA_FUNC GC_DONT_FREE; +#define GRPC_RB_GC_DONT_FREE (RUBY_DATA_FUNC)(NULL) + +/* GRPC_RB_MEMSIZE_UNAVAILABLE is used in rb_data_type_t to indicate that the + * number of bytes used by the wrapped struct is not available. */ +#define GRPC_RB_MEMSIZE_UNAVAILABLE (size_t (*)(const void*))(NULL) /* A ruby object alloc func that fails by raising an exception. */ VALUE grpc_rb_cannot_alloc(VALUE cls); diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index 80f7760ebb..bc0878af05 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -88,13 +88,23 @@ static void grpc_rb_server_mark(void *p) { } } +static const rb_data_type_t grpc_rb_server_data_type = { + "grpc_server", + {grpc_rb_server_mark, grpc_rb_server_free, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, + NULL, + /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free function would block + * and we might want to unlock GVL + * TODO(yugui) Unlock GVL? + */ + 0}; + /* Allocates grpc_rb_server instances. */ static VALUE grpc_rb_server_alloc(VALUE cls) { grpc_rb_server *wrapper = ALLOC(grpc_rb_server); wrapper->wrapped = NULL; wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_server_mark, grpc_rb_server_free, - wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper); } /* @@ -110,7 +120,8 @@ static VALUE grpc_rb_server_init(VALUE self, VALUE cqueue, VALUE channel_args) { grpc_channel_args args; MEMZERO(&args, grpc_channel_args, 1); cq = grpc_rb_get_wrapped_completion_queue(cqueue); - Data_Get_Struct(self, grpc_rb_server, wrapper); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, + wrapper); grpc_rb_hash_convert_to_channel_args(channel_args, &args); srv = grpc_server_create(cq, &args); @@ -146,8 +157,10 @@ static VALUE grpc_rb_server_init_copy(VALUE copy, VALUE orig) { rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cServer)); } - Data_Get_Struct(orig, grpc_rb_server, orig_srv); - Data_Get_Struct(copy, grpc_rb_server, copy_srv); + TypedData_Get_Struct(orig, grpc_rb_server, &grpc_rb_server_data_type, + orig_srv); + TypedData_Get_Struct(copy, grpc_rb_server, &grpc_rb_server_data_type, + copy_srv); /* use ruby's MEMCPY to make a byte-for-byte copy of the server wrapper object. */ @@ -194,7 +207,7 @@ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, grpc_call_error err; request_call_stack st; VALUE result; - Data_Get_Struct(self, grpc_rb_server, s); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; @@ -245,7 +258,7 @@ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, static VALUE grpc_rb_server_start(VALUE self) { grpc_rb_server *s = NULL; - Data_Get_Struct(self, grpc_rb_server, s); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); } else { @@ -256,7 +269,7 @@ static VALUE grpc_rb_server_start(VALUE self) { static VALUE grpc_rb_server_destroy(VALUE self) { grpc_rb_server *s = NULL; - Data_Get_Struct(self, grpc_rb_server, s); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped != NULL) { grpc_server_shutdown(s->wrapped); grpc_server_destroy(s->wrapped); @@ -288,7 +301,7 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) { /* "11" == 1 mandatory args, 1 (rb_creds) is optional */ rb_scan_args(argc, argv, "11", &port, &rb_creds); - Data_Get_Struct(self, grpc_rb_server, s); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; @@ -340,6 +353,6 @@ void Init_grpc_server() { /* Gets the wrapped server from the ruby wrapper */ grpc_server *grpc_rb_get_wrapped_server(VALUE v) { grpc_rb_server *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_server, wrapper); + TypedData_Get_Struct(v, grpc_rb_server, &grpc_rb_server_data_type, wrapper); return wrapper->wrapped; } diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c index 5109b96b5f..a86389445f 100644 --- a/src/ruby/ext/grpc/rb_server_credentials.c +++ b/src/ruby/ext/grpc/rb_server_credentials.c @@ -86,6 +86,14 @@ static void grpc_rb_server_credentials_mark(void *p) { } } +static const rb_data_type_t grpc_rb_server_credentials_data_type = { + "grpc_server_credentials", + {grpc_rb_server_credentials_mark, grpc_rb_server_credentials_free, + GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + RUBY_TYPED_FREE_IMMEDIATELY +}; + /* Allocates ServerCredential instances. Provides safe initial defaults for the instance fields. */ @@ -93,8 +101,8 @@ static VALUE grpc_rb_server_credentials_alloc(VALUE cls) { grpc_rb_server_credentials *wrapper = ALLOC(grpc_rb_server_credentials); wrapper->wrapped = NULL; wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_server_credentials_mark, - grpc_rb_server_credentials_free, wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_server_credentials_data_type, + wrapper); } /* Clones ServerCredentials instances. @@ -116,8 +124,10 @@ static VALUE grpc_rb_server_credentials_init_copy(VALUE copy, VALUE orig) { rb_obj_classname(grpc_rb_cServerCredentials)); } - Data_Get_Struct(orig, grpc_rb_server_credentials, orig_ch); - Data_Get_Struct(copy, grpc_rb_server_credentials, copy_ch); + TypedData_Get_Struct(orig, grpc_rb_server_credentials, + &grpc_rb_server_credentials_data_type, orig_ch); + TypedData_Get_Struct(copy, grpc_rb_server_credentials, + &grpc_rb_server_credentials_data_type, copy_ch); /* use ruby's MEMCPY to make a byte-for-byte copy of the server_credentials wrapper object. */ @@ -153,7 +163,8 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs, grpc_rb_server_credentials *wrapper = NULL; grpc_server_credentials *creds = NULL; grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL}; - Data_Get_Struct(self, grpc_rb_server_credentials, wrapper); + TypedData_Get_Struct(self, grpc_rb_server_credentials, + &grpc_rb_server_credentials_data_type, wrapper); if (pem_cert_chain == Qnil) { rb_raise(rb_eRuntimeError, "could not create a server credential: nil pem_cert_chain"); @@ -206,6 +217,7 @@ void Init_grpc_server_credentials() { /* Gets the wrapped grpc_server_credentials from the ruby wrapper */ grpc_server_credentials *grpc_rb_get_wrapped_server_credentials(VALUE v) { grpc_rb_server_credentials *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_server_credentials, wrapper); + TypedData_Get_Struct(v, grpc_rb_server_credentials, + &grpc_rb_server_credentials_data_type, wrapper); return wrapper->wrapped; } diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec index 12d4ab17f2..ae48213c8f 100755 --- a/src/ruby/grpc.gemspec +++ b/src/ruby/grpc.gemspec @@ -13,6 +13,9 @@ Gem::Specification.new do |s| s.description = 'Send RPCs from Ruby using GRPC' s.license = 'BSD-3-Clause' + s.required_ruby_version = '>= 2.0.0' + s.requirements << 'libgrpc ~> 0.6.0 needs to be installed' + s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- spec/*`.split("\n") s.executables = `git ls-files -- bin/*.rb`.split("\n").map do |f| @@ -25,13 +28,12 @@ Gem::Specification.new do |s| s.add_dependency 'googleauth', '~> 0.4' # reqd for interop tests s.add_dependency 'logging', '~> 1.8' s.add_dependency 'minitest', '~> 5.4' # reqd for interop tests - s.add_dependency 'xray', '~> 1.1' s.add_development_dependency 'bundler', '~> 1.9' s.add_development_dependency 'rake', '~> 10.4' s.add_development_dependency 'rake-compiler', '~> 0.9' - s.add_development_dependency 'rubocop', '~> 0.30' s.add_development_dependency 'rspec', '~> 3.2' + s.add_development_dependency 'rubocop', '~> 0.30' s.extensions = %w(ext/grpc/extconf.rb) end diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb index dc7672d359..7b2c04aa22 100644 --- a/src/ruby/lib/grpc/generic/client_stub.rb +++ b/src/ruby/lib/grpc/generic/client_stub.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc/generic/active_call' -require 'xray/thread_dump_signal_handler' # GRPC contains the General RPC module. module GRPC diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb index 30a4bf1532..c7c8267fa3 100644 --- a/src/ruby/lib/grpc/generic/rpc_server.rb +++ b/src/ruby/lib/grpc/generic/rpc_server.rb @@ -31,7 +31,9 @@ require 'grpc/grpc' require 'grpc/generic/active_call' require 'grpc/generic/service' require 'thread' -require 'xray/thread_dump_signal_handler' + +# A global that contains signals the gRPC servers should respond to. +$grpc_signals = [] # GRPC contains the General RPC module. module GRPC @@ -50,6 +52,23 @@ module GRPC # Default max_waiting_requests size is 20 DEFAULT_MAX_WAITING_REQUESTS = 20 + # Default poll period is 1s + DEFAULT_POLL_PERIOD = 1 + + # Signal check period is 0.25s + SIGNAL_CHECK_PERIOD = 0.25 + + # Sets up a signal handler that adds signals to the signal handling global. + # + # Signal handlers should do as little as humanly possible. + # Here, they just add themselves to $grpc_signals + # + # RpcServer (and later other parts of gRPC) monitors the signals + # $grpc_signals in its own non-signal context. + def self.trap_signals + %w(INT TERM).each { |sig| trap(sig) { $grpc_signals << sig } } + end + # Creates a new RpcServer. # # The RPC server is configured using keyword arguments. @@ -79,7 +98,7 @@ module GRPC # with not available to new requests def initialize(pool_size:DEFAULT_POOL_SIZE, max_waiting_requests:DEFAULT_MAX_WAITING_REQUESTS, - poll_period:INFINITE_FUTURE, + poll_period:DEFAULT_POLL_PERIOD, completion_queue_override:nil, server_override:nil, **kw) @@ -117,6 +136,13 @@ module GRPC return unless @running @stopped = true @pool.stop + + # TODO: uncomment this: + # + # This segfaults in the c layer, so its commented out for now. Shutdown + # still occurs, but the c layer has to do the cleanup. + # + # @server.close end # determines if the server is currently running @@ -139,7 +165,37 @@ module GRPC running? end - # determines if the server is currently stopped + # Runs the server in its own thread, then waits for signal INT or TERM on + # the current thread to terminate it. + def run_till_terminated + self.class.trap_signals + t = Thread.new { run } + wait_till_running + loop do + sleep SIGNAL_CHECK_PERIOD + break unless handle_signals + end + stop + t.join + end + + # Handles the signals in $grpc_signals. + # + # @return false if the server should exit, true if not. + def handle_signals + loop do + sig = $grpc_signals.shift + case sig + when 'INT' + return false + when 'TERM' + return false + end + end + true + end + + # Determines if the server is currently stopped def stopped? @stopped ||= false end @@ -265,7 +321,10 @@ module GRPC # Pool is a simple thread pool for running server requests. class Pool - def initialize(size) + # Default keep alive period is 1s + DEFAULT_KEEP_ALIVE = 1 + + def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE) fail 'pool size must be positive' unless size > 0 @jobs = Queue.new @size = size @@ -273,6 +332,7 @@ module GRPC @stop_mutex = Mutex.new @stop_cond = ConditionVariable.new @workers = [] + @keep_alive = keep_alive end # Returns the number of jobs waiting @@ -325,15 +385,13 @@ module GRPC @workers.size.times { schedule { throw :exit } } @stopped = true - # TODO: allow configuration of the keepalive period - keep_alive = 5 @stop_mutex.synchronize do - @stop_cond.wait(@stop_mutex, keep_alive) if @workers.size > 0 + @stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0 end # Forcibly shutdown any threads that are still alive. if @workers.size > 0 - logger.warn("forcibly terminating #{@workers.size} worker(s)") + logger.info("forcibly terminating #{@workers.size} worker(s)") @workers.each do |t| next unless t.alive? begin @@ -344,7 +402,6 @@ module GRPC end end end - logger.info('stopped, all workers are shutdown') end end diff --git a/src/ruby/spec/credentials_spec.rb b/src/ruby/spec/credentials_spec.rb index fc97d11a87..8e72e85d54 100644 --- a/src/ruby/spec/credentials_spec.rb +++ b/src/ruby/spec/credentials_spec.rb @@ -61,11 +61,11 @@ describe Credentials do end describe '#compose' do - it 'can be completed OK' do + it 'cannot be completed OK with 2 SSL creds' do certs = load_test_certs cred1 = Credentials.new(*certs) cred2 = Credentials.new(*certs) - expect { cred1.compose(cred2) }.to_not raise_error + expect { cred1.compose(cred2) }.to raise_error end end end diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 193c5f2a03..88c6b44c22 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'xray/thread_dump_signal_handler' # Notifier is useful high-level synchronization primitive. class Notifier diff --git a/src/ruby/spec/generic/rpc_server_pool_spec.rb b/src/ruby/spec/generic/rpc_server_pool_spec.rb index 8383dc1533..3bbc71b822 100644 --- a/src/ruby/spec/generic/rpc_server_pool_spec.rb +++ b/src/ruby/spec/generic/rpc_server_pool_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'xray/thread_dump_signal_handler' Pool = GRPC::RpcServer::Pool diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb index 1323bacfa6..e091c589f5 100644 --- a/src/ruby/spec/generic/rpc_server_spec.rb +++ b/src/ruby/spec/generic/rpc_server_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'xray/thread_dump_signal_handler' def load_test_certs test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata') |