diff options
author | Craig Tiller <ctiller@google.com> | 2015-02-26 11:23:01 -0800 |
---|---|---|
committer | Craig Tiller <ctiller@google.com> | 2015-02-26 11:23:01 -0800 |
commit | 29f131428272e3b0f5c13d9ec6417f9e3b6dbc9b (patch) | |
tree | cda68966326c8350e4385952d7bde9efe4e8ef2e /src/core | |
parent | a348fa8a07c207617874127e110e6b952f447272 (diff) | |
parent | bc53734c2ec3a329b10272f4dceb7612cbdcde7e (diff) |
Merge github.com:grpc/grpc into credit
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/debug/trace.c | 2 | ||||
-rw-r--r-- | src/core/debug/trace.h | 3 | ||||
-rw-r--r-- | src/core/iomgr/fd_posix.c | 4 | ||||
-rw-r--r-- | src/core/iomgr/pollset.h | 5 | ||||
-rw-r--r-- | src/core/iomgr/pollset_posix.c | 155 | ||||
-rw-r--r-- | src/core/iomgr/pollset_posix.h | 4 | ||||
-rw-r--r-- | src/core/iomgr/pollset_windows.c | 6 | ||||
-rw-r--r-- | src/core/iomgr/resolve_address_posix.c | 17 | ||||
-rw-r--r-- | src/core/security/security_context.c | 64 | ||||
-rw-r--r-- | src/core/statistics/census_init.c | 2 | ||||
-rw-r--r-- | src/core/statistics/census_rpc_stats.c | 2 | ||||
-rw-r--r-- | src/core/statistics/census_tracing.c | 2 | ||||
-rw-r--r-- | src/core/support/cpu_posix.c | 3 | ||||
-rw-r--r-- | src/core/surface/completion_queue.c | 9 | ||||
-rw-r--r-- | src/core/transport/chttp2/frame_settings.c | 18 | ||||
-rw-r--r-- | src/core/transport/chttp2_transport.c | 46 | ||||
-rw-r--r-- | src/core/tsi/ssl_transport_security.c | 106 | ||||
-rw-r--r-- | src/core/tsi/ssl_transport_security.h | 7 |
18 files changed, 357 insertions, 98 deletions
diff --git a/src/core/debug/trace.c b/src/core/debug/trace.c index 92acbe924d..b8eb755bff 100644 --- a/src/core/debug/trace.c +++ b/src/core/debug/trace.c @@ -81,6 +81,8 @@ static void parse(const char *s) { grpc_trace_bits |= GRPC_TRACE_TCP; } else if (0 == strcmp(s, "secure_endpoint")) { grpc_trace_bits |= GRPC_TRACE_SECURE_ENDPOINT; + } else if (0 == strcmp(s, "http")) { + grpc_trace_bits |= GRPC_TRACE_HTTP; } else if (0 == strcmp(s, "all")) { grpc_trace_bits = -1; } else { diff --git a/src/core/debug/trace.h b/src/core/debug/trace.h index 167ef3c6ea..bf9b8a3642 100644 --- a/src/core/debug/trace.h +++ b/src/core/debug/trace.h @@ -45,7 +45,8 @@ typedef enum { GRPC_TRACE_SURFACE = 1 << 0, GRPC_TRACE_CHANNEL = 1 << 1, GRPC_TRACE_TCP = 1 << 2, - GRPC_TRACE_SECURE_ENDPOINT = 1 << 3 + GRPC_TRACE_SECURE_ENDPOINT = 1 << 3, + GRPC_TRACE_HTTP = 1 << 4 } grpc_trace_bit_value; #if GRPC_ENABLE_TRACING diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c index 41fd24e05a..abdd49bbda 100644 --- a/src/core/iomgr/fd_posix.c +++ b/src/core/iomgr/fd_posix.c @@ -38,6 +38,7 @@ #include "src/core/iomgr/fd_posix.h" #include <assert.h> +#include <sys/socket.h> #include <unistd.h> #include "src/core/iomgr/iomgr_internal.h" @@ -113,6 +114,7 @@ static void ref_by(grpc_fd *fd, int n) { static void unref_by(grpc_fd *fd, int n) { gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n); if (old == n) { + close(fd->fd); grpc_iomgr_add_callback(fd->on_done, fd->on_done_user_data); freelist_fd(fd); grpc_iomgr_unref(); @@ -158,9 +160,9 @@ static void wake_watchers(grpc_fd *fd) { void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_cb_func on_done, void *user_data) { fd->on_done = on_done ? on_done : do_nothing; fd->on_done_user_data = user_data; + shutdown(fd->fd, SHUT_RDWR); ref_by(fd, 1); /* remove active status, but keep referenced */ wake_watchers(fd); - close(fd->fd); unref_by(fd, 2); /* drop the reference */ } diff --git a/src/core/iomgr/pollset.h b/src/core/iomgr/pollset.h index 9d04b014ba..c26947f37c 100644 --- a/src/core/iomgr/pollset.h +++ b/src/core/iomgr/pollset.h @@ -52,9 +52,14 @@ #include "src/core/iomgr/pollset_windows.h" #endif + void grpc_pollset_init(grpc_pollset *pollset); +void grpc_pollset_shutdown(grpc_pollset *pollset, + void (*shutdown_done)(void *arg), + void *shutdown_done_arg); void grpc_pollset_destroy(grpc_pollset *pollset); + /* Do some work on a pollset. May involve invoking asynchronous callbacks, or actually polling file descriptors. diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c index 87e7aa85ee..f0a8453fd7 100644 --- a/src/core/iomgr/pollset_posix.c +++ b/src/core/iomgr/pollset_posix.c @@ -55,6 +55,7 @@ static grpc_pollset g_backup_pollset; static int g_shutdown_backup_poller; static gpr_event g_backup_poller_done; +static gpr_event g_backup_pollset_shutdown_done; static void backup_poller(void *p) { gpr_timespec delta = gpr_time_from_millis(100); @@ -104,9 +105,14 @@ void grpc_pollset_global_init(void) { /* start the backup poller thread */ g_shutdown_backup_poller = 0; gpr_event_init(&g_backup_poller_done); + gpr_event_init(&g_backup_pollset_shutdown_done); gpr_thd_new(&id, backup_poller, NULL, NULL); } +static void on_backup_pollset_shutdown_done(void *arg) { + gpr_event_set(&g_backup_pollset_shutdown_done, (void *)1); +} + void grpc_pollset_global_shutdown(void) { /* terminate the backup poller thread */ gpr_mu_lock(&g_backup_pollset.mu); @@ -114,6 +120,10 @@ void grpc_pollset_global_shutdown(void) { gpr_mu_unlock(&g_backup_pollset.mu); gpr_event_wait(&g_backup_poller_done, gpr_inf_future); + grpc_pollset_shutdown(&g_backup_pollset, on_backup_pollset_shutdown_done, + NULL); + gpr_event_wait(&g_backup_pollset_shutdown_done, gpr_inf_future); + /* destroy the backup pollset */ grpc_pollset_destroy(&g_backup_pollset); @@ -130,6 +140,8 @@ void grpc_pollset_init(grpc_pollset *pollset) { gpr_mu_init(&pollset->mu); gpr_cv_init(&pollset->cv); grpc_pollset_kick_init(&pollset->kick_state); + pollset->in_flight_cbs = 0; + pollset->shutting_down = 0; become_empty_pollset(pollset); } @@ -163,7 +175,24 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) { return pollset->vtable->maybe_work(pollset, deadline, now, 1); } +void grpc_pollset_shutdown(grpc_pollset *pollset, + void (*shutdown_done)(void *arg), + void *shutdown_done_arg) { + int in_flight_cbs; + gpr_mu_lock(&pollset->mu); + pollset->shutting_down = 1; + in_flight_cbs = pollset->in_flight_cbs; + pollset->shutdown_done_cb = shutdown_done; + pollset->shutdown_done_arg = shutdown_done_arg; + gpr_mu_unlock(&pollset->mu); + if (in_flight_cbs == 0) { + shutdown_done(shutdown_done_arg); + } +} + void grpc_pollset_destroy(grpc_pollset *pollset) { + GPR_ASSERT(pollset->shutting_down); + GPR_ASSERT(pollset->in_flight_cbs == 0); pollset->vtable->destroy(pollset); grpc_pollset_kick_destroy(&pollset->kick_state); gpr_mu_destroy(&pollset->mu); @@ -201,21 +230,119 @@ static void become_empty_pollset(grpc_pollset *pollset) { * via poll() */ + +typedef struct grpc_unary_promote_args { + const grpc_pollset_vtable *original_vtable; + grpc_pollset *pollset; + grpc_fd *fd; +} grpc_unary_promote_args; + +static void unary_poll_do_promote(void *args, int success) { + grpc_unary_promote_args *up_args = args; + const grpc_pollset_vtable *original_vtable = up_args->original_vtable; + grpc_pollset *pollset = up_args->pollset; + grpc_fd *fd = up_args->fd; + int do_shutdown_cb = 0; + gpr_free(up_args); + + /* + * This is quite tricky. There are a number of cases to keep in mind here: + * 1. fd may have been orphaned + * 2. The pollset may no longer be a unary poller (and we can't let case #1 + * leak to other pollset types!) + * 3. pollset's fd (which may have changed) may have been orphaned + * 4. The pollset may be shutting down. + */ + + gpr_mu_lock(&pollset->mu); + /* First we need to ensure that nobody is polling concurrently */ + while (pollset->counter != 0) { + grpc_pollset_kick(pollset); + gpr_cv_wait(&pollset->cv, &pollset->mu, gpr_inf_future); + } + /* At this point the pollset may no longer be a unary poller. In that case + * we should just call the right add function and be done. */ + /* TODO(klempner): If we're not careful this could cause infinite recursion. + * That's not a problem for now because empty_pollset has a trivial poller + * and we don't have any mechanism to unbecome multipoller. */ + pollset->in_flight_cbs--; + if (pollset->shutting_down) { + gpr_log(GPR_INFO, "Shutting down"); + /* We don't care about this pollset anymore. */ + if (pollset->in_flight_cbs == 0) { + do_shutdown_cb = 1; + } + } else if (grpc_fd_is_orphaned(fd)) { + /* Don't try to add it to anything, we'll drop our ref on it below */ + } else if (pollset->vtable != original_vtable) { + gpr_log(GPR_INFO, "Not original vtable"); + pollset->vtable->add_fd(pollset, fd); + } else if (fd != pollset->data.ptr) { + grpc_fd *fds[2]; + fds[0] = pollset->data.ptr; + fds[1] = fd; + + if (!grpc_fd_is_orphaned(fds[0])) { + grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds)); + grpc_fd_unref(fds[0]); + } else { + /* old fd is orphaned and we haven't cleaned it up until now, so remain a + * unary poller */ + /* Note that it is possible that fds[1] is also orphaned at this point. + * That's okay, we'll correct it at the next add or poll. */ + grpc_fd_unref(fds[0]); + pollset->data.ptr = fd; + grpc_fd_ref(fd); + } + } + + gpr_cv_broadcast(&pollset->cv); + gpr_mu_unlock(&pollset->mu); + + if (do_shutdown_cb) { + pollset->shutdown_done_cb(pollset->shutdown_done_arg); + } + + /* Matching ref in unary_poll_pollset_add_fd */ + grpc_fd_unref(fd); +} + static void unary_poll_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) { - grpc_fd *fds[2]; + grpc_unary_promote_args *up_args; if (fd == pollset->data.ptr) return; - fds[0] = pollset->data.ptr; - fds[1] = fd; - if (!grpc_fd_is_orphaned(fds[0])) { - grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds)); - grpc_fd_unref(fds[0]); - } else { - /* old fd is orphaned and we haven't cleaned it up until now, so remain a - * unary poller */ - grpc_fd_unref(fds[0]); - pollset->data.ptr = fd; - grpc_fd_ref(fd); + + if (!pollset->counter) { + /* Fast path -- no in flight cbs */ + /* TODO(klempner): Comment this out and fix any test failures or establish + * they are due to timing issues */ + grpc_fd *fds[2]; + fds[0] = pollset->data.ptr; + fds[1] = fd; + + if (!grpc_fd_is_orphaned(fds[0])) { + grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds)); + grpc_fd_unref(fds[0]); + } else { + /* old fd is orphaned and we haven't cleaned it up until now, so remain a + * unary poller */ + grpc_fd_unref(fds[0]); + pollset->data.ptr = fd; + grpc_fd_ref(fd); + } + return; } + + /* Now we need to promote. This needs to happen when we're not polling. Since + * this may be called from poll, the wait needs to happen asynchronously. */ + grpc_fd_ref(fd); + pollset->in_flight_cbs++; + up_args = gpr_malloc(sizeof(*up_args)); + up_args->pollset = pollset; + up_args->fd = fd; + up_args->original_vtable = pollset->vtable; + grpc_iomgr_add_callback(unary_poll_do_promote, up_args); + + grpc_pollset_kick(pollset); } static void unary_poll_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) { @@ -238,6 +365,10 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset, if (pollset->counter) { return 0; } + if (pollset->in_flight_cbs) { + /* Give do_promote priority so we don't starve it out */ + return 0; + } fd = pollset->data.ptr; if (grpc_fd_is_orphaned(fd)) { grpc_fd_unref(fd); diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h index 03b4c775b7..86b6c9f20e 100644 --- a/src/core/iomgr/pollset_posix.h +++ b/src/core/iomgr/pollset_posix.h @@ -55,6 +55,10 @@ typedef struct grpc_pollset { gpr_cv cv; grpc_pollset_kick_state kick_state; int counter; + int in_flight_cbs; + int shutting_down; + void (*shutdown_done_cb)(void *arg); + void *shutdown_done_arg; union { int fd; void *ptr; diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c index d21072b283..bea6711611 100644 --- a/src/core/iomgr/pollset_windows.c +++ b/src/core/iomgr/pollset_windows.c @@ -46,6 +46,12 @@ void grpc_pollset_init(grpc_pollset *pollset) { gpr_cv_init(&pollset->cv); } +void grpc_pollset_shutdown(grpc_pollset *pollset, + void (*shutdown_done)(void *arg), + void *shutdown_done_arg) { + shutdown_done(shutdown_done_arg); +} + void grpc_pollset_destroy(grpc_pollset *pollset) { gpr_mu_destroy(&pollset->mu); gpr_cv_destroy(&pollset->cv); diff --git a/src/core/iomgr/resolve_address_posix.c b/src/core/iomgr/resolve_address_posix.c index edf40b5ad1..989b968ae2 100644 --- a/src/core/iomgr/resolve_address_posix.c +++ b/src/core/iomgr/resolve_address_posix.c @@ -66,7 +66,6 @@ grpc_resolved_addresses *grpc_blocking_resolve_address( int s; size_t i; grpc_resolved_addresses *addrs = NULL; - const gpr_timespec start_time = gpr_now(); struct sockaddr_un *un; if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' && @@ -121,22 +120,6 @@ grpc_resolved_addresses *grpc_blocking_resolve_address( i++; } - /* Temporary logging, to help identify flakiness in dualstack_socket_test. */ - { - const gpr_timespec delay = gpr_time_sub(gpr_now(), start_time); - const int delay_ms = - delay.tv_sec * GPR_MS_PER_SEC + delay.tv_nsec / GPR_NS_PER_MS; - gpr_log(GPR_INFO, "logspam: getaddrinfo(%s, %s) resolved %d addrs in %dms:", - host, port, addrs->naddrs, delay_ms); - for (i = 0; i < addrs->naddrs; i++) { - char *buf; - grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr, - 0); - gpr_log(GPR_INFO, "logspam: [%d] %s", i, buf); - gpr_free(buf); - } - } - done: gpr_free(host); gpr_free(port); diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 0a65480b2f..62264e4105 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -43,7 +43,9 @@ #include "src/core/support/file.h" #include "src/core/support/string.h" #include "src/core/transport/chttp2/alpn.h" + #include <grpc/support/alloc.h> +#include <grpc/support/host_port.h> #include <grpc/support/log.h> #include <grpc/support/slice_buffer.h> #include "src/core/tsi/fake_transport_security.h" @@ -51,20 +53,33 @@ /* -- Constants. -- */ -/* Defines the cipher suites that we accept. All these cipher suites are - compliant with TLS 1.2 and use an RSA public key. We prefer GCM over CBC - and ECDHE-RSA over just RSA. */ -#define GRPC_SSL_CIPHER_SUITES \ - "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:AES128-GCM-SHA256:" \ - "AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-" \ - "SHA256:AES256-SHA256" - #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"; #endif +/* -- Cipher suites. -- */ + +/* Defines the cipher suites that we accept by default. All these cipher suites + are compliant with HTTP2. */ +#define GRPC_SSL_CIPHER_SUITES \ + "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \ + "SHA384:ECDHE-RSA-AES256-GCM-SHA384" + +static gpr_once cipher_suites_once = GPR_ONCE_INIT; +static const char *cipher_suites = NULL; + +static void init_cipher_suites(void) { + char *overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES"); + cipher_suites = overridden != NULL ? overridden : GRPC_SSL_CIPHER_SUITES; +} + +static const char *ssl_cipher_suites(void) { + gpr_once_init(&cipher_suites_once, init_cipher_suites); + return cipher_suites; +} + /* -- Common methods. -- */ grpc_security_status grpc_security_context_create_handshaker( @@ -322,6 +337,24 @@ static grpc_security_status ssl_server_create_handshaker( return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker); } +static int ssl_host_matches_name(const tsi_peer *peer, + const char *peer_name) { + char *allocated_name = NULL; + int r; + + if (strchr(peer_name, ':') != NULL) { + char *ignored_port; + gpr_split_host_port(peer_name, &allocated_name, &ignored_port); + gpr_free(ignored_port); + peer_name = allocated_name; + if (!peer_name) return 0; + } + + r = tsi_ssl_peer_matches_name(peer, peer_name); + gpr_free(allocated_name); + return r; +} + static grpc_security_status ssl_check_peer(const char *peer_name, const tsi_peer *peer) { /* Check the ALPN. */ @@ -343,10 +376,11 @@ static grpc_security_status ssl_check_peer(const char *peer_name, /* Check the peer name if specified. */ if (peer_name != NULL && - !tsi_ssl_peer_matches_name(peer, peer_name)) { + !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; } + return GRPC_SECURITY_OK; } @@ -382,7 +416,7 @@ static grpc_security_status ssl_channel_check_call_host( grpc_ssl_channel_security_context *c = (grpc_ssl_channel_security_context *)ctx; - if (tsi_ssl_peer_matches_name(&c->peer, host)) return GRPC_SECURITY_OK; + if (ssl_host_matches_name(&c->peer, host)) return GRPC_SECURITY_OK; /* If the target name was overridden, then the original target_name was 'checked' transitively during the previous peer check at the end of the @@ -442,6 +476,7 @@ grpc_security_status grpc_ssl_channel_security_context_create( size_t i; const unsigned char *pem_root_certs; size_t pem_root_certs_size; + char *port; for (i = 0; i < num_alpn_protocols; i++) { alpn_protocol_strings[i] = @@ -467,9 +502,8 @@ grpc_security_status grpc_ssl_channel_security_context_create( c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); c->base.check_call_host = ssl_channel_check_call_host; - if (target_name != NULL) { - c->target_name = gpr_strdup(target_name); - } + gpr_split_host_port(target_name, &c->target_name, &port); + gpr_free(port); if (overridden_target_name != NULL) { c->overridden_target_name = gpr_strdup(overridden_target_name); } @@ -486,7 +520,7 @@ grpc_security_status grpc_ssl_channel_security_context_create( result = tsi_create_ssl_client_handshaker_factory( config->pem_private_key, config->pem_private_key_size, config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs, - pem_root_certs_size, GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings, + 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.", @@ -540,7 +574,7 @@ grpc_security_status grpc_ssl_server_security_context_create( (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, - GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings, + 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.", diff --git a/src/core/statistics/census_init.c b/src/core/statistics/census_init.c index 820d75f795..e6306f5e6f 100644 --- a/src/core/statistics/census_init.c +++ b/src/core/statistics/census_init.c @@ -38,13 +38,11 @@ #include "src/core/statistics/census_tracing.h" void census_init(void) { - gpr_log(GPR_INFO, "Initialize census library."); census_tracing_init(); census_stats_store_init(); } void census_shutdown(void) { - gpr_log(GPR_INFO, "Shutdown census library."); census_stats_store_shutdown(); census_tracing_shutdown(); } diff --git a/src/core/statistics/census_rpc_stats.c b/src/core/statistics/census_rpc_stats.c index 388ce4fe2c..0491c91947 100644 --- a/src/core/statistics/census_rpc_stats.c +++ b/src/core/statistics/census_rpc_stats.c @@ -222,7 +222,6 @@ void census_get_server_stats(census_aggregated_rpc_stats* data) { } void census_stats_store_init(void) { - gpr_log(GPR_INFO, "Initialize census stats store."); init_mutex_once(); gpr_mu_lock(&g_mu); if (g_client_stats_store == NULL && g_server_stats_store == NULL) { @@ -235,7 +234,6 @@ void census_stats_store_init(void) { } void census_stats_store_shutdown(void) { - gpr_log(GPR_INFO, "Shutdown census stats store."); init_mutex_once(); gpr_mu_lock(&g_mu); if (g_client_stats_store != NULL) { diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c index adfcbecb4c..05e72b99c0 100644 --- a/src/core/statistics/census_tracing.c +++ b/src/core/statistics/census_tracing.c @@ -154,7 +154,6 @@ void census_tracing_end_op(census_op_id op_id) { } void census_tracing_init(void) { - gpr_log(GPR_INFO, "Initialize census trace store."); init_mutex_once(); gpr_mu_lock(&g_mu); if (g_trace_store == NULL) { @@ -167,7 +166,6 @@ void census_tracing_init(void) { } void census_tracing_shutdown(void) { - gpr_log(GPR_INFO, "Shutdown census trace store."); gpr_mu_lock(&g_mu); if (g_trace_store != NULL) { census_ht_destroy(g_trace_store); diff --git a/src/core/support/cpu_posix.c b/src/core/support/cpu_posix.c index 33c7b90b0b..5f45fb0bc3 100644 --- a/src/core/support/cpu_posix.c +++ b/src/core/support/cpu_posix.c @@ -40,6 +40,7 @@ #include <string.h> #include <grpc/support/log.h> +#include <grpc/support/sync.h> static __thread char magic_thread_local; @@ -55,7 +56,7 @@ static void init_ncpus() { unsigned gpr_cpu_num_cores(void) { static gpr_once once = GPR_ONCE_INIT; - gpr_once_init(&once, init_num_cpus); + gpr_once_init(&once, init_ncpus); return ncpus; } diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c index 2efc084d7b..c4b8d60782 100644 --- a/src/core/surface/completion_queue.c +++ b/src/core/surface/completion_queue.c @@ -389,12 +389,17 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) { } } -void grpc_completion_queue_destroy(grpc_completion_queue *cc) { - GPR_ASSERT(cc->queue == NULL); +static void on_pollset_destroy_done(void *arg) { + grpc_completion_queue *cc = arg; grpc_pollset_destroy(&cc->pollset); gpr_free(cc); } +void grpc_completion_queue_destroy(grpc_completion_queue *cc) { + GPR_ASSERT(cc->queue == NULL); + grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc); +} + void grpc_event_finish(grpc_event *base) { event *ev = (event *)base; ev->on_finish(ev->on_finish_user_data, GRPC_OP_OK); diff --git a/src/core/transport/chttp2/frame_settings.c b/src/core/transport/chttp2/frame_settings.c index 06429e220b..e6c4b7e38f 100644 --- a/src/core/transport/chttp2/frame_settings.c +++ b/src/core/transport/chttp2/frame_settings.c @@ -35,6 +35,7 @@ #include <string.h> +#include "src/core/debug/trace.h" #include "src/core/transport/chttp2/frame.h" #include <grpc/support/log.h> #include <grpc/support/useful.h> @@ -53,7 +54,8 @@ const grpc_chttp2_setting_parameters {"MAX_FRAME_SIZE", 16384, 16384, 16777215, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE}, {"MAX_HEADER_LIST_SIZE", 0xffffffffu, 0, 0xffffffffu, - GRPC_CHTTP2_CLAMP_INVALID_VALUE}, }; + GRPC_CHTTP2_CLAMP_INVALID_VALUE}, +}; static gpr_uint8 *fill_header(gpr_uint8 *out, gpr_uint32 length, gpr_uint8 flags) { @@ -155,7 +157,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( } return GRPC_CHTTP2_PARSE_OK; } - parser->id = ((gpr_uint16) * cur) << 8; + parser->id = ((gpr_uint16)*cur) << 8; cur++; /* fallthrough */ case GRPC_CHTTP2_SPS_ID1: @@ -171,7 +173,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( parser->state = GRPC_CHTTP2_SPS_VAL0; return GRPC_CHTTP2_PARSE_OK; } - parser->value = ((gpr_uint32) * cur) << 24; + parser->value = ((gpr_uint32)*cur) << 24; cur++; /* fallthrough */ case GRPC_CHTTP2_SPS_VAL1: @@ -179,7 +181,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( parser->state = GRPC_CHTTP2_SPS_VAL1; return GRPC_CHTTP2_PARSE_OK; } - parser->value |= ((gpr_uint32) * cur) << 16; + parser->value |= ((gpr_uint32)*cur) << 16; cur++; /* fallthrough */ case GRPC_CHTTP2_SPS_VAL2: @@ -187,7 +189,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( parser->state = GRPC_CHTTP2_SPS_VAL2; return GRPC_CHTTP2_PARSE_OK; } - parser->value |= ((gpr_uint32) * cur) << 8; + parser->value |= ((gpr_uint32)*cur) << 8; cur++; /* fallthrough */ case GRPC_CHTTP2_SPS_VAL3: @@ -216,8 +218,10 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( } } parser->incoming_settings[parser->id] = parser->value; - gpr_log(GPR_DEBUG, "CHTTP2: got setting %d = %d", parser->id, - parser->value); + if (grpc_trace_bits & GRPC_TRACE_HTTP) { + gpr_log(GPR_DEBUG, "CHTTP2: got setting %d = %d", parser->id, + parser->value); + } } else { gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", parser->id, parser->value); diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index ccd8d0c376..476cc4b226 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -37,6 +37,7 @@ #include <stdio.h> #include <string.h> +#include "src/core/debug/trace.h" #include "src/core/support/string.h" #include "src/core/transport/chttp2/frame_data.h" #include "src/core/transport/chttp2/frame_goaway.h" @@ -66,6 +67,12 @@ typedef struct transport transport; typedef struct stream stream; +#define IF_TRACING(stmt) \ + if (!(grpc_trace_bits & GRPC_TRACE_HTTP)) \ + ; \ + else \ + stmt + /* streams are kept in various linked lists depending on what things need to happen to them... this enum labels each list */ typedef enum { @@ -301,7 +308,7 @@ static void push_setting(transport *t, grpc_chttp2_setting_id id, gpr_uint32 value); static int prepare_callbacks(transport *t); -static void run_callbacks(transport *t); +static void run_callbacks(transport *t, const grpc_transport_callbacks *cb); static int prepare_write(transport *t); static void perform_write(transport *t, grpc_endpoint *ep); @@ -552,7 +559,7 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs, lock(t); s->id = 0; } else { - s->id = (gpr_uint32)(gpr_uintptr)server_data; + s->id = (gpr_uint32)(gpr_uintptr) server_data; t->incoming_stream = s; grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); } @@ -706,6 +713,7 @@ static void unlock(transport *t) { pending_goaway *goaways = NULL; grpc_endpoint *ep = t->ep; grpc_stream_op_buffer nuke_now; + const grpc_transport_callbacks *cb = t->cb; grpc_sopb_init(&nuke_now); if (t->nuke_later_sopb.nops) { @@ -725,7 +733,7 @@ static void unlock(transport *t) { } /* gather any callbacks that need to be made */ - if (!t->calling_back && t->cb) { + if (!t->calling_back && cb) { perform_callbacks = prepare_callbacks(t); if (perform_callbacks) { t->calling_back = 1; @@ -733,6 +741,7 @@ static void unlock(transport *t) { if (t->error_state == ERROR_STATE_SEEN) { call_closed = 1; t->calling_back = 1; + t->cb = NULL; /* no more callbacks */ t->error_state = ERROR_STATE_NOTIFIED; } if (t->num_pending_goaways) { @@ -754,16 +763,16 @@ static void unlock(transport *t) { /* perform some callbacks if necessary */ for (i = 0; i < num_goaways; i++) { - t->cb->goaway(t->cb_user_data, &t->base, goaways[i].status, - goaways[i].debug); + cb->goaway(t->cb_user_data, &t->base, goaways[i].status, + goaways[i].debug); } if (perform_callbacks) { - run_callbacks(t); + run_callbacks(t, cb); } if (call_closed) { - t->cb->closed(t->cb_user_data, &t->base); + cb->closed(t->cb_user_data, &t->base); } /* write some bytes if necessary */ @@ -1206,6 +1215,11 @@ static void on_header(void *tp, grpc_mdelem *md) { stream *s = t->incoming_stream; GPR_ASSERT(s); + + IF_TRACING(gpr_log(GPR_INFO, "HTTP:%d:HDR: %s: %s", s->id, + grpc_mdstr_as_c_string(md->key), + grpc_mdstr_as_c_string(md->value))); + stream_list_join(t, s, PENDING_CALLBACKS); if (md->key == t->str_grpc_timeout) { gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); @@ -1269,7 +1283,7 @@ static int init_header_frame_parser(transport *t, int is_continuation) { t->incoming_stream = NULL; /* if stream is accepted, we set incoming_stream in init_stream */ t->cb->accept_stream(t->cb_user_data, &t->base, - (void *)(gpr_uintptr)t->incoming_stream_id); + (void *)(gpr_uintptr) t->incoming_stream_id); s = t->incoming_stream; if (!s) { gpr_log(GPR_ERROR, "stream not accepted"); @@ -1534,8 +1548,8 @@ static int process_read(transport *t, gpr_slice slice) { "Connect string mismatch: expected '%c' (%d) got '%c' (%d) " "at byte %d", CLIENT_CONNECT_STRING[t->deframe_state], - (int)(gpr_uint8)CLIENT_CONNECT_STRING[t->deframe_state], *cur, - (int)*cur, t->deframe_state); + (int)(gpr_uint8) CLIENT_CONNECT_STRING[t->deframe_state], + *cur, (int)*cur, t->deframe_state); drop_connection(t); return 0; } @@ -1741,13 +1755,13 @@ static int prepare_callbacks(transport *t) { return n; } -static void run_callbacks(transport *t) { +static void run_callbacks(transport *t, const grpc_transport_callbacks *cb) { stream *s; while ((s = stream_list_remove_head(t, EXECUTING_CALLBACKS))) { size_t nops = s->callback_sopb.nops; s->callback_sopb.nops = 0; - t->cb->recv_batch(t->cb_user_data, &t->base, (grpc_stream *)s, - s->callback_sopb.ops, nops, s->callback_state); + cb->recv_batch(t->cb_user_data, &t->base, (grpc_stream *)s, + s->callback_sopb.ops, nops, s->callback_state); } } @@ -1765,9 +1779,9 @@ static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) { */ static const grpc_transport_vtable vtable = { - sizeof(stream), init_stream, send_batch, set_allow_window_updates, - add_to_pollset, destroy_stream, abort_stream, goaway, close_transport, - send_ping, destroy_transport}; + sizeof(stream), init_stream, send_batch, set_allow_window_updates, + add_to_pollset, destroy_stream, abort_stream, goaway, + close_transport, send_ping, destroy_transport}; void grpc_create_chttp2_transport(grpc_transport_setup_callback setup, void *arg, diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c index 85b0922a43..8446cc4fdc 100644 --- a/src/core/tsi/ssl_transport_security.c +++ b/src/core/tsi/ssl_transport_security.c @@ -180,6 +180,30 @@ static void ssl_info_callback(const SSL* ssl, int where, int ret) { ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE"); } +/* Returns 1 if name looks like an IP address, 0 otherwise. + This is a very rough heuristic as it does not handle IPV6 or things like: + 0300.0250.00.01, 0xC0.0Xa8.0x0.0x1, 000030052000001, 0xc0.052000001 */ +static int looks_like_ip_address(const char *name) { + size_t i; + size_t dot_count = 0; + size_t num_size = 0; + for (i = 0; i < strlen(name); i++) { + if (name[i] >= '0' && name[i] <= '9') { + if (num_size > 3) return 0; + num_size++; + } else if (name[i] == '.') { + if (dot_count > 3 || num_size == 0) return 0; + dot_count++; + num_size = 0; + } else { + return 0; + } + } + if (dot_count < 3 || num_size == 0) return 0; + return 1; +} + + /* Gets the subject CN from an X509 cert. */ static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8, size_t* utf8_size) { @@ -226,10 +250,18 @@ static tsi_result peer_property_from_x509_common_name( size_t common_name_size; tsi_result result = ssl_get_x509_common_name(cert, &common_name, &common_name_size); - if (result != TSI_OK) return result; + if (result != TSI_OK) { + if (result == TSI_NOT_FOUND) { + common_name = NULL; + common_name_size = 0; + } else { + return result; + } + } result = tsi_construct_string_peer_property( - TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, (const char*)common_name, - common_name_size, property); + TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, + common_name == NULL ? "" : (const char*)common_name, common_name_size, + property); OPENSSL_free(common_name); return result; } @@ -1036,9 +1068,22 @@ static void ssl_server_handshaker_factory_destroy( static int does_entry_match_name(const char* entry, size_t entry_length, const char* name) { + const char *dot; const char* name_subdomain = NULL; + size_t name_length = strlen(name); + size_t name_subdomain_length; if (entry_length == 0) return 0; - if (!strncmp(name, entry, entry_length) && (strlen(name) == entry_length)) { + + /* Take care of '.' terminations. */ + if (name[name_length - 1] == '.') { + name_length--; + } + if (entry[entry_length - 1] == '.') { + entry_length--; + if (entry_length == 0) return 0; + } + + if ((name_length == entry_length) && !strncmp(name, entry, entry_length)) { return 1; /* Perfect match. */ } if (entry[0] != '*') return 0; @@ -1049,18 +1094,29 @@ static int does_entry_match_name(const char* entry, size_t entry_length, return 0; } name_subdomain = strchr(name, '.'); - if (name_subdomain == NULL || strlen(name_subdomain) < 2) return 0; + if (name_subdomain == NULL) return 0; + name_subdomain_length = strlen(name_subdomain); + if (name_subdomain_length < 2) return 0; name_subdomain++; /* Starts after the dot. */ + name_subdomain_length--; entry += 2; /* Remove *. */ entry_length -= 2; - return (!strncmp(entry, name_subdomain, entry_length) && - (strlen(name_subdomain) == entry_length)); + dot = strchr(name_subdomain, '.'); + if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) { + gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain); + return 0; + } + if (name_subdomain[name_subdomain_length - 1] == '.') { + name_subdomain_length--; + } + return ((entry_length > 0) && (name_subdomain_length == entry_length) && + !strncmp(entry, name_subdomain, entry_length)); } static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap, void* arg) { tsi_ssl_server_handshaker_factory* impl = - (tsi_ssl_server_handshaker_factory*)arg; + (tsi_ssl_server_handshaker_factory*)arg; size_t i = 0; const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (servername == NULL || strlen(servername) == 0) { @@ -1283,17 +1339,13 @@ tsi_result tsi_create_ssl_server_handshaker_factory( int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) { size_t i = 0; - const tsi_peer_property* property = tsi_peer_get_property_by_name( - peer, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY); - if (property == NULL || property->type != TSI_PEER_PROPERTY_TYPE_STRING) { - gpr_log(GPR_ERROR, "Invalid x509 subject common name property."); - return 0; - } - if (does_entry_match_name(property->value.string.data, - property->value.string.length, name)) { - return 1; - } + size_t san_count = 0; + const tsi_peer_property* property = NULL; + /* For now reject what looks like an IP address. */ + if (looks_like_ip_address(name)) return 0; + + /* Check the SAN first. */ property = tsi_peer_get_property_by_name( peer, TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY); if (property == NULL || property->type != TSI_PEER_PROPERTY_TYPE_LIST) { @@ -1301,7 +1353,8 @@ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) { return 0; } - for (i = 0; i < property->value.list.child_count; i++) { + san_count = property->value.list.child_count; + for (i = 0; i < san_count; i++) { const tsi_peer_property* alt_name_property = &property->value.list.children[i]; if (alt_name_property->type != TSI_PEER_PROPERTY_TYPE_STRING) { @@ -1313,5 +1366,20 @@ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) { return 1; } } + + /* If there's no SAN, try the CN. */ + if (san_count == 0) { + property = tsi_peer_get_property_by_name( + peer, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY); + if (property == NULL || property->type != TSI_PEER_PROPERTY_TYPE_STRING) { + gpr_log(GPR_ERROR, "Invalid x509 subject common name property."); + return 0; + } + if (does_entry_match_name(property->value.string.data, + property->value.string.length, name)) { + return 1; + } + } + return 0; /* Not found. */ } diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h index 3c1c4c01a2..eecf2d7c2d 100644 --- a/src/core/tsi/ssl_transport_security.h +++ b/src/core/tsi/ssl_transport_security.h @@ -158,7 +158,12 @@ tsi_result tsi_ssl_handshaker_factory_create_handshaker( while handshakers created with this factory are still in use. */ void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory* self); -/* Util that checks that an ssl peer matches a specific name. */ +/* Util that checks that an ssl peer matches a specific name. + Still TODO(jboeuf): + - handle mixed case. + - handle %encoded chars. + - handle public suffix wildchar more strictly (e.g. *.co.uk) + - handle IP addresses in SAN. */ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name); #ifdef __cplusplus |