diff options
author | Craig Tiller <ctiller@google.com> | 2015-02-06 12:49:57 -0800 |
---|---|---|
committer | Craig Tiller <ctiller@google.com> | 2015-02-06 12:49:57 -0800 |
commit | 62d424a1a4ce55a66a7565795db17ff898bc05f5 (patch) | |
tree | 89b6e34c94fb6144c705ecec0751121fa6d0917b /src/core | |
parent | fd6f5079b8e11cb604664994aec08423fca6f836 (diff) | |
parent | 4acf81e90246dffa806de6ad1a830d0e62cf727f (diff) |
Merge github.com:google/grpc into buffer
Diffstat (limited to 'src/core')
24 files changed, 848 insertions, 78 deletions
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index bcb024f2ac..507b91b8a6 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -298,6 +298,7 @@ static void channel_op(grpc_channel_element *elem, grpc_channel_element *from_elem, grpc_channel_op *op) { channel_data *chand = elem->channel_data; grpc_child_channel *child_channel; + grpc_channel_op rop; GPR_ASSERT(elem->filter == &grpc_client_channel_filter); switch (op->type) { @@ -323,6 +324,10 @@ static void channel_op(grpc_channel_element *elem, if (child_channel) { grpc_child_channel_destroy(child_channel, 1); } + /* fake a transport closed to satisfy the refcounting in client */ + rop.type = GRPC_TRANSPORT_CLOSED; + rop.dir = GRPC_CALL_UP; + grpc_channel_next_op(elem, &rop); break; case GRPC_TRANSPORT_GOAWAY: /* receiving goaway: if it's from our active child, drop the active child; diff --git a/src/core/iomgr/pollset_kick.c b/src/core/iomgr/pollset_kick.c index 238ec75c61..f0211b8274 100644 --- a/src/core/iomgr/pollset_kick.c +++ b/src/core/iomgr/pollset_kick.c @@ -48,49 +48,49 @@ /* This implementation is based on a freelist of wakeup fds, with extra logic to * handle kicks while there is no attached fd. */ +/* TODO(klempner): Autosize this, and consider providing a way to disable the + * cap entirely on systems with large fd limits */ #define GRPC_MAX_CACHED_WFDS 50 -#define GRPC_WFD_LOW_WATERMARK 25 static grpc_kick_fd_info *fd_freelist = NULL; static int fd_freelist_count = 0; static gpr_mu fd_freelist_mu; static grpc_kick_fd_info *allocate_wfd(void) { - grpc_kick_fd_info *info; + grpc_kick_fd_info *info = NULL; gpr_mu_lock(&fd_freelist_mu); if (fd_freelist != NULL) { info = fd_freelist; fd_freelist = fd_freelist->next; --fd_freelist_count; - } else { + } + gpr_mu_unlock(&fd_freelist_mu); + if (info == NULL) { info = gpr_malloc(sizeof(*info)); grpc_wakeup_fd_create(&info->wakeup_fd); info->next = NULL; } - gpr_mu_unlock(&fd_freelist_mu); return info; } -static void destroy_wfd(void) { - /* assumes fd_freelist_mu is held */ - grpc_kick_fd_info *current = fd_freelist; - fd_freelist = fd_freelist->next; - fd_freelist_count--; - grpc_wakeup_fd_destroy(¤t->wakeup_fd); - gpr_free(current); +static void destroy_wfd(grpc_kick_fd_info* wfd) { + grpc_wakeup_fd_destroy(&wfd->wakeup_fd); + gpr_free(wfd); } static void free_wfd(grpc_kick_fd_info *fd_info) { gpr_mu_lock(&fd_freelist_mu); - fd_info->next = fd_freelist; - fd_freelist = fd_info; - fd_freelist_count++; - if (fd_freelist_count > GRPC_MAX_CACHED_WFDS) { - while (fd_freelist_count > GRPC_WFD_LOW_WATERMARK) { - destroy_wfd(); - } + if (fd_freelist_count < GRPC_MAX_CACHED_WFDS) { + fd_info->next = fd_freelist; + fd_freelist = fd_info; + fd_freelist_count++; + fd_info = NULL; } gpr_mu_unlock(&fd_freelist_mu); + + if (fd_info) { + destroy_wfd(fd_info); + } } void grpc_pollset_kick_init(grpc_pollset_kick_state *kick_state) { @@ -148,6 +148,11 @@ void grpc_pollset_kick_global_init(void) { } void grpc_pollset_kick_global_destroy(void) { + while (fd_freelist != NULL) { + grpc_kick_fd_info *current = fd_freelist; + fd_freelist = fd_freelist->next; + destroy_wfd(current); + } grpc_wakeup_fd_global_destroy(); gpr_mu_destroy(&fd_freelist_mu); } diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 7b7d8f3211..6f0d72c0c3 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -216,14 +216,10 @@ static void ssl_copy_key_material(const char *input, unsigned char **output, static void ssl_build_config(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, grpc_ssl_config *config) { - if (pem_root_certs == NULL) { - /* TODO(jboeuf): Get them from the environment. */ - gpr_log(GPR_ERROR, "Default SSL roots not yet implemented."); - } else { + if (pem_root_certs != NULL) { ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, &config->pem_root_certs_size); } - if (pem_key_cert_pair != NULL) { GPR_ASSERT(pem_key_cert_pair->private_key != NULL); GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL); diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 58cd458415..1edec29775 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -39,6 +39,8 @@ #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" +#include "src/core/support/file.h" #include "src/core/support/string.h" #include "src/core/surface/lame_client.h" #include "src/core/transport/chttp2/alpn.h" @@ -319,6 +321,28 @@ static grpc_security_context_vtable ssl_channel_vtable = { static grpc_security_context_vtable ssl_server_vtable = { ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer}; +static gpr_slice default_pem_root_certs; + +static void init_default_pem_root_certs(void) { + char *default_root_certs_path = + gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR); + 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); + gpr_free(default_root_certs_path); + } +} + +static size_t get_default_pem_roots(const unsigned char **pem_root_certs) { + /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in + loading all the roots once for the lifetime of the process. */ + static gpr_once once = GPR_ONCE_INIT; + gpr_once_init(&once, init_default_pem_root_certs); + *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs); + return GPR_SLICE_LENGTH(default_pem_root_certs); +} + grpc_security_status grpc_ssl_channel_security_context_create( grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *secure_peer_name, grpc_channel_security_context **ctx) { @@ -330,6 +354,8 @@ grpc_security_status grpc_ssl_channel_security_context_create( tsi_result result = TSI_OK; grpc_ssl_channel_security_context *c; size_t i; + const unsigned char *pem_root_certs; + size_t pem_root_certs_size; for (i = 0; i < num_alpn_protocols; i++) { alpn_protocol_strings[i] = @@ -338,9 +364,8 @@ grpc_security_status grpc_ssl_channel_security_context_create( strlen(grpc_chttp2_get_alpn_version_index(i)); } - if (config == NULL || secure_peer_name == NULL || - config->pem_root_certs == NULL) { - gpr_log(GPR_ERROR, "An ssl channel needs a secure name and root certs."); + if (config == NULL || secure_peer_name == NULL) { + gpr_log(GPR_ERROR, "An ssl channel needs a config and a secure name."); goto error; } if (!check_request_metadata_creds(request_metadata_creds)) { @@ -357,11 +382,20 @@ grpc_security_status grpc_ssl_channel_security_context_create( if (secure_peer_name != NULL) { c->secure_peer_name = gpr_strdup(secure_peer_name); } + if (config->pem_root_certs == NULL) { + pem_root_certs_size = get_default_pem_roots(&pem_root_certs); + if (pem_root_certs == NULL || pem_root_certs_size == 0) { + gpr_log(GPR_ERROR, "Could not get default pem root certs."); + goto error; + } + } else { + pem_root_certs = config->pem_root_certs; + pem_root_certs_size = config->pem_root_certs_size; + } 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, - config->pem_root_certs, config->pem_root_certs_size, - GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings, + config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs, + pem_root_certs_size, GRPC_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_rpc_stats.c b/src/core/statistics/census_rpc_stats.c index 785c091deb..fc66cb951f 100644 --- a/src/core/statistics/census_rpc_stats.c +++ b/src/core/statistics/census_rpc_stats.c @@ -141,7 +141,7 @@ static void record_stats(census_ht* store, census_op_id op_id, const census_rpc_stats* stats) { gpr_mu_lock(&g_mu); if (store != NULL) { - trace_obj* trace = NULL; + census_trace_obj* trace = NULL; census_internal_lock_trace_store(); trace = census_get_trace_obj_locked(op_id); if (trace != NULL) { diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c index 3c4ba66f5f..8b98323e64 100644 --- a/src/core/statistics/census_tracing.c +++ b/src/core/statistics/census_tracing.c @@ -32,38 +32,22 @@ */ #include "src/core/statistics/census_interface.h" +#include "src/core/statistics/census_tracing.h" #include <stdio.h> #include <string.h> -#include "src/core/statistics/census_rpc_stats.h" #include "src/core/statistics/hash_table.h" #include "src/core/support/string.h" #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/port_platform.h> #include <grpc/support/sync.h> -#include <grpc/support/time.h> - -/* Struct for a trace annotation. */ -typedef struct annotation { - gpr_timespec ts; /* timestamp of the annotation */ - char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */ - struct annotation* next; -} annotation; - -typedef struct trace_obj { - census_op_id id; - gpr_timespec ts; - census_rpc_stats rpc_stats; - char* method; - annotation* annotations; -} trace_obj; - -static void trace_obj_destroy(trace_obj* obj) { - annotation* p = obj->annotations; + +void census_trace_obj_destroy(census_trace_obj* obj) { + census_trace_annotation* p = obj->annotations; while (p != NULL) { - annotation* next = p->next; + census_trace_annotation* next = p->next; gpr_free(p); p = next; } @@ -71,7 +55,9 @@ static void trace_obj_destroy(trace_obj* obj) { gpr_free(obj); } -static void delete_trace_obj(void* obj) { trace_obj_destroy((trace_obj*)obj); } +static void delete_trace_obj(void* obj) { + census_trace_obj_destroy((census_trace_obj*)obj); +} static const census_ht_option ht_opt = { CENSUS_HT_UINT64 /* key type*/, 571 /* n_of_buckets */, NULL /* hash */, @@ -103,8 +89,8 @@ static void init_mutex_once(void) { census_op_id census_tracing_start_op(void) { gpr_mu_lock(&g_mu); { - trace_obj* ret = (trace_obj*)gpr_malloc(sizeof(trace_obj)); - memset(ret, 0, sizeof(trace_obj)); + census_trace_obj* ret = gpr_malloc(sizeof(census_trace_obj)); + memset(ret, 0, sizeof(census_trace_obj)); g_id++; memcpy(&ret->id, &g_id, sizeof(census_op_id)); ret->rpc_stats.cnt = 1; @@ -118,7 +104,7 @@ census_op_id census_tracing_start_op(void) { int census_add_method_tag(census_op_id op_id, const char* method) { int ret = 0; - trace_obj* trace = NULL; + census_trace_obj* trace = NULL; gpr_mu_lock(&g_mu); trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); if (trace == NULL) { @@ -131,11 +117,11 @@ int census_add_method_tag(census_op_id op_id, const char* method) { } void census_tracing_print(census_op_id op_id, const char* anno_txt) { - trace_obj* trace = NULL; + census_trace_obj* trace = NULL; gpr_mu_lock(&g_mu); trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); if (trace != NULL) { - annotation* anno = gpr_malloc(sizeof(annotation)); + census_trace_annotation* anno = gpr_malloc(sizeof(census_trace_annotation)); anno->ts = gpr_now(); { char* d = anno->txt; @@ -153,7 +139,7 @@ void census_tracing_print(census_op_id op_id, const char* anno_txt) { } void census_tracing_end_op(census_op_id op_id) { - trace_obj* trace = NULL; + census_trace_obj* trace = NULL; gpr_mu_lock(&g_mu); trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); if (trace != NULL) { @@ -196,14 +182,58 @@ void census_internal_lock_trace_store(void) { gpr_mu_lock(&g_mu); } void census_internal_unlock_trace_store(void) { gpr_mu_unlock(&g_mu); } -trace_obj* census_get_trace_obj_locked(census_op_id op_id) { +census_trace_obj* census_get_trace_obj_locked(census_op_id op_id) { if (g_trace_store == NULL) { gpr_log(GPR_ERROR, "Census trace store is not initialized."); return NULL; } - return (trace_obj*)census_ht_find(g_trace_store, op_id_as_key(&op_id)); + return (census_trace_obj*)census_ht_find(g_trace_store, op_id_as_key(&op_id)); } -const char* census_get_trace_method_name(const trace_obj* trace) { - return (const char*)trace->method; +const char* census_get_trace_method_name(const census_trace_obj* trace) { + return trace->method; +} + +static census_trace_annotation* dup_annotation_chain( + census_trace_annotation* from) { + census_trace_annotation *ret = NULL; + census_trace_annotation **to = &ret; + for (; from != NULL; from = from->next) { + *to = gpr_malloc(sizeof(census_trace_annotation)); + memcpy(*to, from, sizeof(census_trace_annotation)); + to = &(*to)->next; + } + return ret; +} + +static census_trace_obj* trace_obj_dup(census_trace_obj* from) { + census_trace_obj* to = NULL; + GPR_ASSERT(from != NULL); + to = gpr_malloc(sizeof(census_trace_obj)); + to->id = from->id; + to->ts = from->ts; + to->rpc_stats = from->rpc_stats; + to->method = gpr_strdup(from->method); + to->annotations = dup_annotation_chain(from->annotations); + return to; +} + +census_trace_obj** census_get_active_ops(int* num_active_ops) { + census_trace_obj** ret = NULL; + gpr_mu_lock(&g_mu); + if (g_trace_store != NULL) { + size_t n = 0; + census_ht_kv* all_kvs = census_ht_get_all_elements(g_trace_store, &n); + *num_active_ops = (int)n; + if (n != 0 ) { + size_t i = 0; + ret = gpr_malloc(sizeof(census_trace_obj *) * n); + for (i = 0; i < n; i++) { + ret[i] = trace_obj_dup((census_trace_obj*)all_kvs[i].v); + } + } + gpr_free(all_kvs); + } + gpr_mu_unlock(&g_mu); + return ret; } diff --git a/src/core/statistics/census_tracing.h b/src/core/statistics/census_tracing.h index f356c9424d..88a06a4a52 100644 --- a/src/core/statistics/census_tracing.h +++ b/src/core/statistics/census_tracing.h @@ -34,12 +34,35 @@ #ifndef __GRPC_INTERNAL_STATISTICS_CENSUS_TRACING_H_ #define __GRPC_INTERNAL_STATISTICS_CENSUS_TRACING_H_ +#include <grpc/support/time.h> +#include "src/core/statistics/census_rpc_stats.h" + +/* WARNING: The data structures and APIs provided by this file are for GRPC + library's internal use ONLY. They might be changed in backward-incompatible + ways and are not subject to any deprecation policy. + They are not recommended for external use. + */ #ifdef __cplusplus extern "C" { #endif -/* Opaque structure for trace object */ -typedef struct trace_obj trace_obj; +/* Struct for a trace annotation. */ +typedef struct census_trace_annotation { + gpr_timespec ts; /* timestamp of the annotation */ + char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */ + struct census_trace_annotation* next; +} census_trace_annotation; + +typedef struct census_trace_obj { + census_op_id id; + gpr_timespec ts; + census_rpc_stats rpc_stats; + char* method; + census_trace_annotation* annotations; +} census_trace_obj; + +/* Deletes trace object. */ +void census_trace_obj_destroy(census_trace_obj* obj); /* Initializes trace store. This function is thread safe. */ void census_tracing_init(void); @@ -50,15 +73,21 @@ void census_tracing_shutdown(void); /* Gets trace obj corresponding to the input op_id. Returns NULL if trace store is not initialized or trace obj is not found. Requires trace store being locked before calling this function. */ -trace_obj* census_get_trace_obj_locked(census_op_id op_id); +census_trace_obj* census_get_trace_obj_locked(census_op_id op_id); /* The following two functions acquire and release the trace store global lock. They are for census internal use only. */ void census_internal_lock_trace_store(void); void census_internal_unlock_trace_store(void); -/* Gets method tag name associated with the input trace object. */ -const char* census_get_trace_method_name(const trace_obj* trace); +/* Gets method name associated with the input trace object. */ +const char* census_get_trace_method_name(const census_trace_obj* trace); + +/* Returns an array of pointers to trace objects of currently active operations + and fills in number of active operations. Returns NULL if there are no active + operations. + Caller owns the returned objects. */ +census_trace_obj** census_get_active_ops(int* num_active_ops); #ifdef __cplusplus } diff --git a/src/core/support/env.h b/src/core/support/env.h new file mode 100644 index 0000000000..81dda7d838 --- /dev/null +++ b/src/core/support/env.h @@ -0,0 +1,60 @@ +/* + * + * Copyright 2014, 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_SUPPORT_ENV_H__ +#define __GRPC_SUPPORT_ENV_H__ + +#include <stdio.h> + +#include <grpc/support/slice.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Env utility functions */ + +/* Gets the environment variable value with the specified name. + Returns a newly allocated string. It is the responsability of the caller to + gpr_free the return value if not NULL (which means that the environment + variable exists). */ +char *gpr_getenv(const char *name); + +/* Sets the the environment with the specified name to the specified value. */ +void gpr_setenv(const char *name, const char *value); + +#ifdef __cplusplus +} +#endif + +#endif /* __GRPC_SUPPORT_ENV_H__ */ diff --git a/src/core/support/env_linux.c b/src/core/support/env_linux.c new file mode 100644 index 0000000000..28e3d1450f --- /dev/null +++ b/src/core/support/env_linux.c @@ -0,0 +1,61 @@ +/* + * + * Copyright 2014, 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. + * + */ + +/* for secure_getenv. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <grpc/support/port_platform.h> + +#ifdef GPR_LINUX_ENV + +#include "src/core/support/env.h" + +#include <stdlib.h> + +#include <grpc/support/log.h> + +#include "src/core/support/string.h" + +char *gpr_getenv(const char *name) { + char *result = secure_getenv(name); + return result == NULL ? result : gpr_strdup(result); +} + +void gpr_setenv(const char *name, const char *value) { + int res = setenv(name, value, 1); + GPR_ASSERT(res == 0); +} + +#endif /* GPR_LINUX_ENV */ diff --git a/src/core/support/env_posix.c b/src/core/support/env_posix.c new file mode 100644 index 0000000000..bcbff9a177 --- /dev/null +++ b/src/core/support/env_posix.c @@ -0,0 +1,56 @@ +/* + * + * Copyright 2014, 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 <grpc/support/port_platform.h> + +#ifdef GPR_POSIX_ENV + +#include "src/core/support/env.h" + +#include <stdlib.h> + +#include <grpc/support/log.h> + +#include "src/core/support/string.h" + +char *gpr_getenv(const char *name) { + char *result = getenv(name); + return result == NULL ? result : gpr_strdup(result); +} + +void gpr_setenv(const char *name, const char *value) { + int res = setenv(name, value, 1); + GPR_ASSERT(res == 0); +} + +#endif /* GPR_POSIX_ENV */ diff --git a/src/core/support/env_win32.c b/src/core/support/env_win32.c new file mode 100644 index 0000000000..3159c20f7d --- /dev/null +++ b/src/core/support/env_win32.c @@ -0,0 +1,61 @@ +/* + * + * Copyright 2014, 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 <grpc/support/port_platform.h> + +#ifdef GPR_WIN32 + +#include "src/core/support/env.h" + +#include <stdlib.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +char *gpr_getenv(const char *name) { + size_t required_size; + char *result = NULL; + + getenv_s(&required_size, NULL, 0, name); + if (required_size == 0) return NULL; + result = gpr_malloc(required_size); + getenv_s(&required_size, result, required_size, name); + return result; +} + +void gpr_setenv(const char *name, const char *value) { + errno_t res = _putenv_s(name, value); + GPR_ASSERT(res == 0); +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/support/file.c b/src/core/support/file.c new file mode 100644 index 0000000000..c0bb1b66a0 --- /dev/null +++ b/src/core/support/file.c @@ -0,0 +1,89 @@ +/* + * + * Copyright 2014, 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 "src/core/support/file.h" + +#include <errno.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +#include "src/core/support/string.h" + +gpr_slice gpr_load_file(const char *filename, 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"); + + if (file == NULL) { + gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename, + strerror(errno)); + 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; + } + } + } + if (success != NULL) *success = 1; + result = gpr_slice_new(contents, contents_size, gpr_free); + +end: + if (error_msg != NULL) { + gpr_log(GPR_ERROR, "%s", error_msg); + gpr_free(error_msg); + if (success != NULL) *success = 0; + } + if (file != NULL) fclose(file); + return result; +} diff --git a/src/core/support/file.h b/src/core/support/file.h new file mode 100644 index 0000000000..92f420e7ce --- /dev/null +++ b/src/core/support/file.h @@ -0,0 +1,61 @@ +/* + * + * Copyright 2014, 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_SUPPORT_FILE_H__ +#define __GRPC_SUPPORT_FILE_H__ + +#include <stdio.h> + +#include <grpc/support/slice.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* File utility functions */ + +/* Loads the content of a file into a slice. 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); + +/* Creates a temporary file from a prefix. + If tmp_filename is not NULL, *tmp_filename is assigned the name of the + created file and it is the responsibility of the caller to gpr_free it + unless an error occurs in which case it will be set to NULL. */ +FILE *gpr_tmpfile(const char *prefix, char **tmp_filename); + +#ifdef __cplusplus +} +#endif + +#endif /* __GRPC_SUPPORT_FILE_H__ */ diff --git a/src/core/support/file_posix.c b/src/core/support/file_posix.c new file mode 100644 index 0000000000..cb48b3d52f --- /dev/null +++ b/src/core/support/file_posix.c @@ -0,0 +1,97 @@ +/* + * + * Copyright 2014, 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. + * + */ + +/* Posix code for gpr fdopen and mkstemp support. */ + +#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 200112L +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif + +/* Don't know why I have to do this for mkstemp, looks like _POSIX_C_SOURCE + should be enough... */ +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif + +#include <grpc/support/port_platform.h> + +#ifdef GPR_POSIX_FILE + +#include "src/core/support/file.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +#include "src/core/support/string.h" + +FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) { + FILE *result = NULL; + char *template; + int fd; + + if (tmp_filename != NULL) *tmp_filename = NULL; + + gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix); + GPR_ASSERT(template != NULL); + + fd = mkstemp(template); + if (fd == -1) { + gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.", + template, strerror(errno)); + goto end; + } + result = fdopen(fd, "w+"); + if (result == NULL) { + gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).", + template, fd, strerror(errno)); + unlink(template); + close(fd); + goto end; + } + +end: + if (result != NULL && tmp_filename != NULL) { + *tmp_filename = template; + } else { + gpr_free(template); + } + return result; +} + +#endif /* GPR_POSIX_FILE */ diff --git a/src/core/support/file_win32.c b/src/core/support/file_win32.c new file mode 100644 index 0000000000..af7eebe3de --- /dev/null +++ b/src/core/support/file_win32.c @@ -0,0 +1,83 @@ +/* + * + * Copyright 2014, 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 <grpc/support/port_platform.h> + +#ifdef GPR_WIN32 + +#include <io.h> +#include <stdio.h> +#include <string.h> +#include <tchar.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +#include "src/core/support/file.h" +#include "src/core/support/string_win32.h" + +FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) { + FILE *result = NULL; + LPTSTR template_string = NULL; + TCHAR tmp_path[MAX_PATH]; + TCHAR tmp_filename[MAX_PATH]; + DWORD status; + UINT success; + + if (tmp_filename_out != NULL) *tmp_filename_out = NULL; + + /* Convert our prefix to TCHAR. */ + template_string = gpr_char_to_tchar(prefix); + GPR_ASSERT(template_string); + + /* Get the path to the best temporary folder available. */ + status = GetTempPath(MAX_PATH, tmp_path); + if (status == 0 || status > MAX_PATH) goto end; + + /* Generate a unique filename with our template + temporary path. */ + success = GetTempFileName(tmp_path, template_string, 0, tmp_filename); + if (!success) goto end; + + /* Open a file there. */ + if (_tfopen_s(&result, tmp_filename, TEXT("wb+")) != 0) goto end; + +end: + if (result && tmp_filename) { + *tmp_filename_out = gpr_tchar_to_char(tmp_filename); + } + + gpr_free(tmp_filename); + return result; +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/support/string_win32.c b/src/core/support/string_win32.c index 1c4c8547dc..02e1c74d9c 100644 --- a/src/core/support/string_win32.c +++ b/src/core/support/string_win32.c @@ -37,6 +37,7 @@ #ifdef GPR_WIN32 +#include <windows.h> #include <stdio.h> #include <stdarg.h> #include <string.h> @@ -78,4 +79,32 @@ int gpr_asprintf(char **strp, const char *format, ...) { return -1; } +#if defined UNICODE || defined _UNICODE +LPTSTR gpr_char_to_tchar(LPCSTR input) { + LPTSTR ret; + int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); + if (needed == 0) return NULL; + ret = gpr_malloc(needed * sizeof(TCHAR)); + MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed); + return ret; +} + +LPSTR gpr_tchar_to_char(LPCTSTR input) { + LPSTR ret; + int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); + if (needed == 0) return NULL; + ret = gpr_malloc(needed); + WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL); + return ret; +} +#else +char *gpr_tchar_to_char(LPTSTR input) { + return gpr_strdup(input); +} + +char *gpr_char_to_tchar(LPTSTR input) { + return gpr_strdup(input); +} +#endif + #endif /* GPR_WIN32 */ diff --git a/src/core/support/string_win32.h b/src/core/support/string_win32.h new file mode 100644 index 0000000000..9102d98256 --- /dev/null +++ b/src/core/support/string_win32.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2014, 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_SUPPORT_STRING_WIN32_H__ +#define __GRPC_SUPPORT_STRING_WIN32_H__ + +#include <grpc/support/port_platform.h> + +#ifdef GPR_WIN32 + +#include <windows.h> + +/* These allocate new strings using gpr_malloc to convert from and to utf-8. */ +LPTSTR gpr_char_to_tchar(LPCSTR input); +LPSTR gpr_tchar_to_char(LPCTSTR input); + +#endif /* GPR_WIN32 */ + +#endif /* __GRPC_SUPPORT_STRING_WIN32_H__ */ diff --git a/src/core/surface/byte_buffer_queue.c b/src/core/surface/byte_buffer_queue.c index dc280a60c5..9709a665ba 100644 --- a/src/core/surface/byte_buffer_queue.c +++ b/src/core/surface/byte_buffer_queue.c @@ -35,7 +35,13 @@ #include <grpc/support/alloc.h> #include <grpc/support/useful.h> -static void bba_destroy(grpc_bbq_array *array) { gpr_free(array->data); } +static void bba_destroy(grpc_bbq_array *array, size_t start_pos) { + size_t i; + for (i = start_pos; i < array->count; i++) { + grpc_byte_buffer_destroy(array->data[i]); + } + gpr_free(array->data); +} /* Append an operation to an array, expanding as needed */ static void bba_push(grpc_bbq_array *a, grpc_byte_buffer *buffer) { @@ -47,8 +53,8 @@ static void bba_push(grpc_bbq_array *a, grpc_byte_buffer *buffer) { } void grpc_bbq_destroy(grpc_byte_buffer_queue *q) { - bba_destroy(&q->filling); - bba_destroy(&q->draining); + bba_destroy(&q->filling, 0); + bba_destroy(&q->draining, q->drain_pos); } int grpc_bbq_empty(grpc_byte_buffer_queue *q) { diff --git a/src/core/surface/call.c b/src/core/surface/call.c index feb3926281..0af524cead 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -275,6 +275,7 @@ static void destroy_call(void *call, int ignored_success) { if (c->legacy_state) { destroy_legacy_state(c->legacy_state); } + grpc_bbq_destroy(&c->incoming_queue); gpr_free(c); } @@ -335,8 +336,10 @@ static void unlock(grpc_call *call) { send_action sa = SEND_NOTHING; completed_request completed_requests[GRPC_IOREQ_OP_COUNT]; int num_completed_requests = call->num_completed_requests; - int need_more_data = call->need_more_data && - !is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA); + int need_more_data = + call->need_more_data && + !call->sending && + call->write_state >= WRITE_STATE_STARTED; int i; if (need_more_data) { @@ -960,6 +963,8 @@ struct legacy_state { char *details; grpc_status_code status; + char *send_details; + size_t msg_in_read_idx; grpc_byte_buffer *msg_in; @@ -985,6 +990,8 @@ static void destroy_legacy_state(legacy_state *ls) { } gpr_free(ls->initial_md_in.metadata); gpr_free(ls->trailing_md_in.metadata); + gpr_free(ls->details); + gpr_free(ls->send_details); gpr_free(ls); } @@ -1233,8 +1240,7 @@ grpc_call_error grpc_call_start_write_status_old(grpc_call *call, reqs[0].data.send_metadata.metadata = ls->md_out[ls->md_out_buffer]; reqs[1].op = GRPC_IOREQ_SEND_STATUS; reqs[1].data.send_status.code = status; - /* MEMLEAK */ - reqs[1].data.send_status.details = gpr_strdup(details); + reqs[1].data.send_status.details = ls->send_details = gpr_strdup(details); reqs[2].op = GRPC_IOREQ_SEND_CLOSE; err = start_ioreq(call, reqs, 3, finish_finish, tag); unlock(call); diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c index c33ea923e8..b33bd7b357 100644 --- a/src/core/surface/channel.c +++ b/src/core/surface/channel.c @@ -52,6 +52,9 @@ struct grpc_channel { }; #define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c)+1)) +#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) (((grpc_channel *)(channel_stack)) - 1) +#define CHANNEL_FROM_TOP_ELEM(top_elem) \ + CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem)) grpc_channel *grpc_channel_create_from_filters( const grpc_channel_filter **filters, size_t num_filters, @@ -60,8 +63,8 @@ grpc_channel *grpc_channel_create_from_filters( sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters); grpc_channel *channel = gpr_malloc(size); channel->is_client = is_client; - /* decremented by grpc_channel_destroy */ - gpr_ref_init(&channel->refs, 1); + /* decremented by grpc_channel_destroy, and grpc_client_channel_closed if is_client */ + gpr_ref_init(&channel->refs, 1 + is_client); channel->metadata_context = mdctx; channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status"); channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message"); @@ -158,6 +161,10 @@ void grpc_channel_destroy(grpc_channel *channel) { grpc_channel_internal_unref(channel); } +void grpc_client_channel_closed(grpc_channel_element *elem) { + grpc_channel_internal_unref(CHANNEL_FROM_TOP_ELEM(elem)); +} + grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) { return CHANNEL_STACK_FROM_CHANNEL(channel); } diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h index b3ea2ede40..ff9bbc237e 100644 --- a/src/core/surface/channel.h +++ b/src/core/surface/channel.h @@ -45,6 +45,8 @@ grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel); grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel); grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel); +void grpc_client_channel_closed(grpc_channel_element *elem); + void grpc_channel_internal_ref(grpc_channel *channel); void grpc_channel_internal_unref(grpc_channel *channel); diff --git a/src/core/surface/client.c b/src/core/surface/client.c index fa63e855cc..64ee9d51e8 100644 --- a/src/core/surface/client.c +++ b/src/core/surface/client.c @@ -34,6 +34,7 @@ #include "src/core/surface/client.h" #include "src/core/surface/call.h" +#include "src/core/surface/channel.h" #include "src/core/support/string.h" #include <grpc/support/alloc.h> #include <grpc/support/log.h> @@ -87,7 +88,7 @@ static void channel_op(grpc_channel_element *elem, gpr_log(GPR_ERROR, "Client cannot accept new calls"); break; case GRPC_TRANSPORT_CLOSED: - gpr_log(GPR_ERROR, "Transport closed"); + grpc_client_channel_closed(elem); break; case GRPC_TRANSPORT_GOAWAY: gpr_slice_unref(op->data.goaway.message); diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c index 2f5eff5584..411dbabfd3 100644 --- a/src/core/surface/lame_client.c +++ b/src/core/surface/lame_client.c @@ -76,6 +76,9 @@ static void channel_op(grpc_channel_element *elem, case GRPC_CHANNEL_GOAWAY: gpr_slice_unref(op->data.goaway.message); break; + case GRPC_CHANNEL_DISCONNECT: + grpc_client_channel_closed(elem); + break; default: break; } diff --git a/src/core/surface/server.c b/src/core/surface/server.c index a057694f13..455bd4337f 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -258,7 +258,6 @@ static void stream_closed(grpc_call_element *elem) { gpr_mu_lock(&chand->server->mu); switch (calld->state) { case ACTIVATED: - grpc_call_stream_closed(elem); break; case PENDING: call_list_remove(chand->server, calld, PENDING_START); @@ -271,6 +270,7 @@ static void stream_closed(grpc_call_element *elem) { break; } gpr_mu_unlock(&chand->server->mu); + grpc_call_stream_closed(elem); } static void read_closed(grpc_call_element *elem) { |