diff options
author | David Klempner <klempner@google.com> | 2015-02-23 17:09:23 -0800 |
---|---|---|
committer | David Klempner <klempner@google.com> | 2015-02-23 17:09:23 -0800 |
commit | c75beaa0164452326d7fc91ddbe6b607c1272649 (patch) | |
tree | 1241df1299bf5180b90e2ab01ebe963f7ab8b904 /src/core | |
parent | 9869cd3c7a4d786c398d35af65bdb15969b8ce03 (diff) | |
parent | ebda87a9a77d6cb358d992f17c129f34c5871a58 (diff) |
Merge branch 'master' into unary_promotion_with_concurrent_poll
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/httpcli/httpcli.c | 1 | ||||
-rw-r--r-- | src/core/json/json.c | 4 | ||||
-rw-r--r-- | src/core/json/json_reader.c | 2 | ||||
-rw-r--r-- | src/core/json/json_writer.c | 9 | ||||
-rw-r--r-- | src/core/security/auth.c | 6 | ||||
-rw-r--r-- | src/core/security/credentials.c | 4 | ||||
-rw-r--r-- | src/core/security/credentials.h | 7 | ||||
-rw-r--r-- | src/core/security/credentials_posix.c | 60 | ||||
-rw-r--r-- | src/core/security/credentials_win32.c | 60 | ||||
-rw-r--r-- | src/core/security/google_default_credentials.c | 185 | ||||
-rw-r--r-- | src/core/security/security_context.c | 6 | ||||
-rw-r--r-- | src/core/support/log_win32.c | 2 | ||||
-rw-r--r-- | src/core/support/string_posix.c | 2 | ||||
-rw-r--r-- | src/core/support/sync.c | 4 | ||||
-rw-r--r-- | src/core/support/time.c | 14 |
15 files changed, 338 insertions, 28 deletions
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c index d372e694e9..d2cf09a8df 100644 --- a/src/core/httpcli/httpcli.c +++ b/src/core/httpcli/httpcli.c @@ -216,6 +216,7 @@ static void on_resolved(void *arg, grpc_resolved_addresses *addresses) { gpr_log(GPR_DEBUG, "%s", __FUNCTION__); if (!addresses) { finish(req, 0); + return; } req->addresses = addresses; req->next_address = 0; diff --git a/src/core/json/json.c b/src/core/json/json.c index df7108a94d..96e11eebb1 100644 --- a/src/core/json/json.c +++ b/src/core/json/json.c @@ -38,8 +38,8 @@ #include "src/core/json/json.h" grpc_json *grpc_json_create(grpc_json_type type) { - grpc_json *json = gpr_malloc(sizeof(grpc_json)); - memset(json, 0, sizeof(grpc_json)); + grpc_json *json = gpr_malloc(sizeof(*json)); + memset(json, 0, sizeof(*json)); json->type = type; return json; diff --git a/src/core/json/json_reader.c b/src/core/json/json_reader.c index 774faa5f23..5ea4e9569c 100644 --- a/src/core/json/json_reader.c +++ b/src/core/json/json_reader.c @@ -93,7 +93,7 @@ static void json_reader_set_null(grpc_json_reader* reader) { /* Call this function to initialize the reader structure. */ void grpc_json_reader_init(grpc_json_reader* reader, grpc_json_reader_vtable* vtable, void* userdata) { - memset(reader, 0, sizeof(grpc_json_reader)); + memset(reader, 0, sizeof(*reader)); reader->vtable = vtable; reader->userdata = userdata; json_reader_string_clear(reader); diff --git a/src/core/json/json_writer.c b/src/core/json/json_writer.c index 4c0bf30780..a40bf1733e 100644 --- a/src/core/json/json_writer.c +++ b/src/core/json/json_writer.c @@ -51,7 +51,7 @@ static void json_writer_output_string_with_len(grpc_json_writer* writer, const c void grpc_json_writer_init(grpc_json_writer* writer, int indent, grpc_json_writer_vtable* vtable, void* userdata) { - memset(writer, 0, sizeof(grpc_json_writer)); + memset(writer, 0, sizeof(*writer)); writer->container_empty = 1; writer->indent = indent; writer->vtable = vtable; @@ -77,7 +77,7 @@ static void json_writer_output_indent( while (spaces >= (sizeof(spacesstr) - 1)) { json_writer_output_string_with_len(writer, spacesstr, - sizeof(spacesstr) - 1); + sizeof(spacesstr) - 1); spaces -= (sizeof(spacesstr) - 1); } @@ -117,10 +117,10 @@ static void json_writer_escape_string(grpc_json_writer* writer, gpr_uint8 c = (gpr_uint8)*string++; if (c == 0) { break; - } else if ((c >= 32) && (c <= 127)) { + } else if ((c >= 32) && (c <= 126)) { if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\'); json_writer_output_char(writer, c); - } else if (c < 32) { + } else if ((c < 32) || (c == 127)) { switch (c) { case '\b': json_writer_output_string_with_len(writer, "\\b", 2); @@ -161,6 +161,7 @@ static void json_writer_escape_string(grpc_json_writer* writer, for (i = 0; i < extra; i++) { utf32 <<= 6; c = *string++; + /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */ if ((c & 0xc0) != 0x80) { valid = 0; break; diff --git a/src/core/security/auth.c b/src/core/security/auth.c index 92878e3b7e..9b67d59cb8 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -234,6 +234,9 @@ static void destroy_call_elem(grpc_call_element *elem) { if (calld->host != NULL) { grpc_mdstr_unref(calld->host); } + if (calld->method != NULL) { + grpc_mdstr_unref(calld->method); + } } /* Constructor for channel_data */ @@ -276,6 +279,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) { if (channeld->error_msg_key != NULL) { grpc_mdstr_unref(channeld->error_msg_key); } + if (channeld->path_string != NULL) { + grpc_mdstr_unref(channeld->path_string); + } } const grpc_channel_filter grpc_client_auth_filter = { diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 42d1a900fc..7e72b238c8 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -1076,7 +1076,3 @@ grpc_credentials *grpc_iam_credentials_create(const char *token, c->md_ctx, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); return &c->base; } - -/* -- Default credentials TODO(jboeuf). -- */ - -grpc_credentials *grpc_default_credentials_create(void) { return NULL; } diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 7b8929492b..0a0074c1d5 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -60,8 +60,15 @@ typedef enum { "x-goog-iam-authorization-token" #define GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY "x-goog-iam-authority-selector" +#define GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY "gcloud" +#define GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE \ + "application_default_credentials.json" + /* --- grpc_credentials. --- */ +/* It is the caller's responsibility to gpr_free the result if not NULL. */ +char *grpc_get_well_known_google_credentials_file_path(void); + typedef void (*grpc_credentials_metadata_cb)(void *user_data, grpc_mdelem **md_elems, size_t num_md, diff --git a/src/core/security/credentials_posix.c b/src/core/security/credentials_posix.c new file mode 100644 index 0000000000..79622cb024 --- /dev/null +++ b/src/core/security/credentials_posix.c @@ -0,0 +1,60 @@ +/* + * + * 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 <grpc/support/port_platform.h> + +#ifdef GPR_POSIX_FILE + +#include "src/core/security/credentials.h" + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +#include "src/core/support/env.h" +#include "src/core/support/string.h" + +char *grpc_get_well_known_google_credentials_file_path(void) { + char *result = NULL; + char *home = gpr_getenv("HOME"); + if (home == NULL) { + gpr_log(GPR_ERROR, "Could not get HOME environment variable."); + return NULL; + } + gpr_asprintf(&result, "%s/.config/%s/%s", home, + GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY, + GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE); + gpr_free(home); + return result; +} + +#endif /* GPR_POSIX_FILE */ diff --git a/src/core/security/credentials_win32.c b/src/core/security/credentials_win32.c new file mode 100644 index 0000000000..ddb310468b --- /dev/null +++ b/src/core/security/credentials_win32.c @@ -0,0 +1,60 @@ +/* + * + * 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 <grpc/support/port_platform.h> + +#ifdef GPR_WIN32 + +#include "src/core/security/credentials.h" + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +#include "src/core/support/env.h" +#include "src/core/support/string.h" + +char *grpc_get_well_known_google_credentials_file_path(void) { + char *result = NULL; + char *appdata_path = gpr_getenv("APPDATA"); + if (appdata_path == NULL) { + gpr_log(GPR_ERROR, "Could not get APPDATA environment variable."); + return NULL; + } + gpr_asprintf(&result, "%s/%s/%s", appdata_path, + GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY, + GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE); + gpr_free(appdata_path); + return result; +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c new file mode 100644 index 0000000000..dc0e453b87 --- /dev/null +++ b/src/core/security/google_default_credentials.c @@ -0,0 +1,185 @@ +/* + * + * 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 "src/core/security/credentials.h" + +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/sync.h> + +#include "src/core/httpcli/httpcli.h" +#include "src/core/support/env.h" +#include "src/core/support/file.h" + +/* -- Constants. -- */ + +#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal" +#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS" + +/* -- Default credentials. -- */ + +static grpc_credentials *default_credentials = NULL; +static int compute_engine_detection_done = 0; +static gpr_mu g_mu; +static gpr_once g_once = GPR_ONCE_INIT; + +static void init_default_credentials(void) { + gpr_mu_init(&g_mu); +} + +typedef struct { + gpr_cv cv; + gpr_mu mu; + int is_done; + int success; +} compute_engine_detector; + +static void on_compute_engine_detection_http_response( + void *user_data, const grpc_httpcli_response *response) { + compute_engine_detector *detector = (compute_engine_detector *)user_data; + if (response != NULL && response->status == 200 && response->hdr_count > 0) { + /* Internet providers can return a generic response to all requests, so + it is necessary to check that metadata header is present also. */ + size_t i; + for (i = 0; i < response->hdr_count; i++) { + grpc_httpcli_header *header = &response->hdrs[i]; + if (!strcmp(header->key, "Metadata-Flavor") && + !strcmp(header->value, "Google")) { + detector->success = 1; + break; + } + } + } + gpr_mu_lock(&detector->mu); + detector->is_done = 1; + gpr_mu_unlock(&detector->mu); + gpr_cv_signal(&detector->cv); +} + +static int is_stack_running_on_compute_engine(void) { + compute_engine_detector detector; + grpc_httpcli_request request; + + /* The http call is local. If it takes more than one sec, it is for sure not + on compute engine. */ + gpr_timespec max_detection_delay = {1, 0}; + + gpr_mu_init(&detector.mu); + gpr_cv_init(&detector.cv); + detector.is_done = 0; + detector.success = 0; + + memset(&request, 0, sizeof(grpc_httpcli_request)); + request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST; + request.path = "/"; + + grpc_httpcli_get(&request, gpr_time_add(gpr_now(), max_detection_delay), + on_compute_engine_detection_http_response, &detector); + + /* Block until we get the response. This is not ideal but this should only be + called once for the lifetime of the process by the default credentials. */ + gpr_mu_lock(&detector.mu); + while (!detector.is_done) { + gpr_cv_wait(&detector.cv, &detector.mu, gpr_inf_future); + } + gpr_mu_unlock(&detector.mu); + + gpr_mu_destroy(&detector.mu); + gpr_cv_destroy(&detector.cv); + return detector.success; +} + +/* Takes ownership of creds_path if not NULL. */ +static grpc_credentials *create_jwt_creds_from_path(char *creds_path) { + grpc_credentials *result = NULL; + gpr_slice creds_data; + int file_ok = 0; + if (creds_path == NULL) return NULL; + creds_data = gpr_load_file(creds_path, &file_ok); + gpr_free(creds_path); + if (file_ok) { + result = grpc_jwt_credentials_create( + (const char *)GPR_SLICE_START_PTR(creds_data), + grpc_max_auth_token_lifetime); + gpr_slice_unref(creds_data); + } + return result; +} + +grpc_credentials *grpc_google_default_credentials_create(void) { + grpc_credentials *result = NULL; + int serving_cached_credentials = 0; + gpr_once_init(&g_once, init_default_credentials); + + gpr_mu_lock(&g_mu); + + if (default_credentials != NULL) { + result = default_credentials; + serving_cached_credentials = 1; + goto end; + } + + /* First, try the environment variable. */ + result = + create_jwt_creds_from_path(gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR)); + if (result != NULL) goto end; + + /* Then the well-known file. */ + result = create_jwt_creds_from_path( + grpc_get_well_known_google_credentials_file_path()); + if (result != NULL) goto end; + + /* At last try to see if we're on compute engine (do the detection only once + since it requires a network test). */ + if (!compute_engine_detection_done) { + int need_compute_engine_creds = is_stack_running_on_compute_engine(); + compute_engine_detection_done = 1; + if (need_compute_engine_creds) { + result = grpc_compute_engine_credentials_create(); + } + } + +end: + if (!serving_cached_credentials && result != NULL) { + /* Blend with default ssl credentials and add a global reference so that it + can be cached and re-served. */ + result = grpc_composite_credentials_create( + grpc_ssl_credentials_create(NULL, NULL), result); + GPR_ASSERT(result != NULL); + default_credentials = grpc_credentials_ref(result); + } + gpr_mu_unlock(&g_mu); + return result; +} diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index fd8baff539..9dce5af740 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -641,9 +641,3 @@ grpc_channel *grpc_secure_channel_create_with_factories( creds->type); return grpc_lame_client_channel_create(); } - -grpc_channel *grpc_default_secure_channel_create( - const char *target, const grpc_channel_args *args) { - return grpc_secure_channel_create(grpc_default_credentials_create(), target, - args); -} diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c index cff130ae18..720dc141f5 100644 --- a/src/core/support/log_win32.c +++ b/src/core/support/log_win32.c @@ -90,7 +90,7 @@ void gpr_default_log(gpr_log_func_args *args) { strcpy(time_buffer, "error:strftime"); } - fprintf(stderr, "%s%s.%09u %5u %s:%d: %s\n", + fprintf(stderr, "%s%s.%09u %5u %s:%d] %s\n", gpr_log_severity_string(args->severity), time_buffer, (int)(now.tv_nsec), GetCurrentThreadId(), args->file, args->line, args->message); diff --git a/src/core/support/string_posix.c b/src/core/support/string_posix.c index 8a678b3103..25c333db4e 100644 --- a/src/core/support/string_posix.c +++ b/src/core/support/string_posix.c @@ -51,7 +51,7 @@ int gpr_asprintf(char **strp, const char *format, ...) { va_start(args, format); ret = vsnprintf(buf, sizeof(buf), format, args); va_end(args); - if (!(0 <= ret)) { + if (ret < 0) { *strp = NULL; return -1; } diff --git a/src/core/support/sync.c b/src/core/support/sync.c index 1a5cf57c4f..ccfe1e25f4 100644 --- a/src/core/support/sync.c +++ b/src/core/support/sync.c @@ -41,7 +41,7 @@ Should be a prime. */ enum { event_sync_partitions = 31 }; -/* Event are partitioned by address to avoid lock contention. */ +/* Events are partitioned by address to avoid lock contention. */ static struct sync_array_s { gpr_mu mu; gpr_cv cv; @@ -71,10 +71,10 @@ void gpr_event_set(gpr_event *ev, void *value) { struct sync_array_s *s = hash(ev); gpr_mu_lock(&s->mu); GPR_ASSERT(gpr_atm_acq_load(&ev->state) == 0); - GPR_ASSERT(value != NULL); gpr_atm_rel_store(&ev->state, (gpr_atm)value); gpr_cv_broadcast(&s->cv); gpr_mu_unlock(&s->mu); + GPR_ASSERT(value != NULL); } void *gpr_event_get(gpr_event *ev) { diff --git a/src/core/support/time.c b/src/core/support/time.c index 67f7665650..7dbf95059f 100644 --- a/src/core/support/time.c +++ b/src/core/support/time.c @@ -85,12 +85,12 @@ gpr_timespec gpr_time_from_nanos(long ns) { } else if (ns == LONG_MIN) { result = gpr_inf_past; } else if (ns >= 0) { - result.tv_sec = ns / 1000000000; - result.tv_nsec = ns - result.tv_sec * 1000000000; + result.tv_sec = ns / GPR_NS_PER_SEC; + result.tv_nsec = ns - result.tv_sec * GPR_NS_PER_SEC; } else { /* Calculation carefully formulated to avoid any possible under/overflow. */ - result.tv_sec = (-(999999999 - (ns + 1000000000)) / 1000000000) - 1; - result.tv_nsec = ns - result.tv_sec * 1000000000; + result.tv_sec = (-(999999999 - (ns + GPR_NS_PER_SEC)) / GPR_NS_PER_SEC) - 1; + result.tv_nsec = ns - result.tv_sec * GPR_NS_PER_SEC; } return result; } @@ -172,8 +172,8 @@ gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) { gpr_timespec sum; int inc = 0; sum.tv_nsec = a.tv_nsec + b.tv_nsec; - if (sum.tv_nsec >= 1000000000) { - sum.tv_nsec -= 1000000000; + if (sum.tv_nsec >= GPR_NS_PER_SEC) { + sum.tv_nsec -= GPR_NS_PER_SEC; inc++; } if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) { @@ -200,7 +200,7 @@ gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) { int dec = 0; diff.tv_nsec = a.tv_nsec - b.tv_nsec; if (diff.tv_nsec < 0) { - diff.tv_nsec += 1000000000; + diff.tv_nsec += GPR_NS_PER_SEC; dec++; } if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) { |