diff options
24 files changed, 462 insertions, 56 deletions
diff --git a/examples/ruby/errors_and_cancellation/README.md b/examples/ruby/errors_and_cancellation/README.md new file mode 100644 index 0000000000..126518c4aa --- /dev/null +++ b/examples/ruby/errors_and_cancellation/README.md @@ -0,0 +1,25 @@ +#Errors and Cancelletion code samples for grpc-ruby + +The examples in this directory show use of grpc errors. + +On the server side, errors are returned from service +implementations by raising a certain `GRPC::BadStatus` exception. + +On the client side, GRPC errors get raised when either: + * the call completes (unary and client-streaming call types) + * the response `Enumerable` is iterated through (server-streaming and + bidi call types). + +## To run the examples here: + +Start the server: + +``` +> ruby error_examples_server.rb +``` + +Then run the client: + +``` +> ruby error_examples_client.rb +``` diff --git a/examples/ruby/errors_and_cancellation/error_examples_client.rb b/examples/ruby/errors_and_cancellation/error_examples_client.rb new file mode 100755 index 0000000000..90456d066d --- /dev/null +++ b/examples/ruby/errors_and_cancellation/error_examples_client.rb @@ -0,0 +1,117 @@ +#!/usr/bin/env ruby + +# 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. + +# Sample app that connects to an error-throwing implementation of +# Route Guide service. +# +# Usage: $ path/to/route_guide_client.rb + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(File.dirname(this_dir), 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'route_guide_services_pb' + +include Routeguide + +def run_get_feature_expect_error(stub) + resp = stub.get_feature(Point.new) +end + +def run_list_features_expect_error(stub) + resps = stub.list_features(Rectangle.new) + + # NOOP iteration to pick up error + resps.each { } +end + +def run_record_route_expect_error(stub) + stub.record_route([]) +end + +def run_route_chat_expect_error(stub) + resps = stub.route_chat([]) + + # NOOP iteration to pick up error + resps.each { } +end + +def main + stub = RouteGuide::Stub.new('localhost:50051', :this_channel_is_insecure) + + begin + run_get_feature_expect_error(stub) + rescue GRPC::BadStatus => e + puts "===== GetFeature exception: =====" + puts e.inspect + puts "e.code: #{e.code}" + puts "e.details: #{e.details}" + puts "e.metadata: #{e.metadata}" + puts "=================================" + end + + begin + run_list_features_expect_error(stub) + rescue GRPC::BadStatus => e + error = true + puts "===== ListFeatures exception: =====" + puts e.inspect + puts "e.code: #{e.code}" + puts "e.details: #{e.details}" + puts "e.metadata: #{e.metadata}" + puts "=================================" + end + + begin + run_route_chat_expect_error(stub) + rescue GRPC::BadStatus => e + puts "==== RouteChat exception: ====" + puts e.inspect + puts "e.code: #{e.code}" + puts "e.details: #{e.details}" + puts "e.metadata: #{e.metadata}" + puts "=================================" + end + + begin + run_record_route_expect_error(stub) + rescue GRPC::BadStatus => e + puts "==== RecordRoute exception: ====" + puts e.inspect + puts "e.code: #{e.code}" + puts "e.details: #{e.details}" + puts "e.metadata: #{e.metadata}" + puts "=================================" + end +end + +main diff --git a/examples/ruby/errors_and_cancellation/error_examples_server.rb b/examples/ruby/errors_and_cancellation/error_examples_server.rb new file mode 100755 index 0000000000..66751882d9 --- /dev/null +++ b/examples/ruby/errors_and_cancellation/error_examples_server.rb @@ -0,0 +1,76 @@ +#!/usr/bin/env ruby +# -*- coding: utf-8 -*- + +# 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. + +# Error-throwing implementation of Route Guide service. +# +# Usage: $ path/to/route_guide_server.rb + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(File.dirname(this_dir), 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'route_guide_services_pb' + +include Routeguide + +include GRPC::Core::StatusCodes + +# CanellingandErrorReturningServiceImpl provides an implementation of the RouteGuide service. +class CancellingAndErrorReturningServerImpl < RouteGuide::Service + # def get_feature + # Note get_feature isn't implemented in this subclass, so the server + # will get a gRPC UNIMPLEMENTED error when it's called. + + def list_features(rectangle, _call) + raise "string appears on the client in the 'details' field of a 'GRPC::Unknown' exception" + end + + def record_route(call) + raise GRPC::BadStatus.new_status_exception(CANCELLED) + end + + def route_chat(notes) + raise GRPC::BadStatus.new_status_exception(ABORTED, details = 'arbitrary', metadata = {somekey: 'val'}) + end +end + +def main + port = '0.0.0.0:50051' + s = GRPC::RpcServer.new + s.add_http2_port(port, :this_port_is_insecure) + GRPC.logger.info("... running insecurely on #{port}") + s.handle(CancellingAndErrorReturningServerImpl.new) + s.run_till_terminated +end + +main diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 5eaa7070e0..c082a80f5c 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -198,14 +198,14 @@ typedef struct { #define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size" /** After a duration of this time the client pings the server to see if the transport is still alive. Int valued, seconds. */ -#define GRPC_ARG_HTTP2_KEEPALIVE_TIME "grpc.http2.keepalive_time" +#define GRPC_ARG_CLIENT_KEEPALIVE_TIME_S "grpc.client_keepalive_time" /** After waiting for a duration of this time, if the client does not receive the ping ack, it will close the transport. Int valued, seconds. */ -#define GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT "grpc.http2.keepalive_timeout" +#define GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S "grpc.client_keepalive_timeout" /** Is it permissible to send keepalive pings without any outstanding streams. Int valued, 0(false)/1(true). */ -#define GRPC_ARG_HTTP2_KEEPALIVE_PERMIT_WITHOUT_CALLS \ - "grpc.http2.keepalive_permit_without_calls" +#define GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS \ + "grpc.keepalive_permit_without_calls" /** Default authority to pass if none specified on call construction. A string. * */ #define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority" diff --git a/src/compiler/README.md b/src/compiler/README.md index a2f49b3cd5..d5684af7ff 100644 --- a/src/compiler/README.md +++ b/src/compiler/README.md @@ -1,4 +1,4 @@ -#Overview +# Overview This directory contains source code for gRPC protocol buffer compiler (*protoc*) plugins. Along with `protoc`, these plugins are used to generate gRPC client and server stubs from `.proto` files. diff --git a/src/core/README.md b/src/core/README.md index 44c6f24772..130d2652b3 100644 --- a/src/core/README.md +++ b/src/core/README.md @@ -1,4 +1,4 @@ -#Overview +# Overview This directory contains source code for C library (a.k.a the *gRPC C core*) that provides all gRPC's core functionality through a low level API. Libraries in other languages in this repository (C++, Ruby, Python, PHP, NodeJS, Objective-C) are layered on top of this library. diff --git a/src/core/ext/census/gen/README.md b/src/core/ext/census/gen/README.md index fdbac1084c..d4612bc7c8 100644 --- a/src/core/ext/census/gen/README.md +++ b/src/core/ext/census/gen/README.md @@ -1,6 +1,6 @@ Files generated for use by Census stats and trace recording subsystem. -#Files +# Files * census.pb.{h,c} - Generated from src/core/ext/census/census.proto, using the script `tools/codegen/core/gen_nano_proto.sh src/proto/census/census.proto $PWD/src/core/ext/census/gen src/core/ext/census/gen` diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 967470be51..73f9454f7a 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -69,10 +69,16 @@ #define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024) #define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024) -#define DEFAULT_KEEPALIVE_TIME_SECOND INT_MAX -#define DEFAULT_KEEPALIVE_TIMEOUT_SECOND 20 +#define DEFAULT_CLIENT_KEEPALIVE_TIME_S INT_MAX +#define DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S 20 #define DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS false +static int g_default_client_keepalive_time_s = DEFAULT_CLIENT_KEEPALIVE_TIME_S; +static int g_default_client_keepalive_timeout_s = + DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S; +static bool g_default_keepalive_permit_without_calls = + DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS; + #define MAX_CLIENT_STREAM_ID 0x7fffffffu int grpc_http_trace = 0; int grpc_flowctl_trace = 0; @@ -142,6 +148,8 @@ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_ping_type ping_type, grpc_closure *on_initiate, grpc_closure *on_complete); +static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error); #define DEFAULT_MIN_TIME_BETWEEN_PINGS_MS 0 #define DEFAULT_MAX_PINGS_BETWEEN_DATA 3 @@ -267,6 +275,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_closure_init(&t->destructive_reclaimer_locked, destructive_reclaimer_locked, t, grpc_combiner_scheduler(t->combiner, false)); + grpc_closure_init(&t->retry_initiate_ping_locked, retry_initiate_ping_locked, + t, grpc_combiner_scheduler(t->combiner, false)); grpc_closure_init(&t->start_bdp_ping_locked, start_bdp_ping_locked, t, grpc_combiner_scheduler(t->combiner, false)); grpc_closure_init(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t, @@ -345,15 +355,16 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, /* client-side keepalive setting */ t->keepalive_time = - DEFAULT_KEEPALIVE_TIME_SECOND == INT_MAX + g_default_client_keepalive_time_s == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) - : gpr_time_from_seconds(DEFAULT_KEEPALIVE_TIME_SECOND, GPR_TIMESPAN); + : gpr_time_from_seconds(g_default_client_keepalive_time_s, + GPR_TIMESPAN); t->keepalive_timeout = - DEFAULT_KEEPALIVE_TIMEOUT_SECOND == INT_MAX + g_default_client_keepalive_timeout_s == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) - : gpr_time_from_seconds(DEFAULT_KEEPALIVE_TIMEOUT_SECOND, + : gpr_time_from_seconds(g_default_client_keepalive_timeout_s, GPR_TIMESPAN); - t->keepalive_permit_without_calls = DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS; + t->keepalive_permit_without_calls = g_default_keepalive_permit_without_calls; if (channel_args) { for (i = 0; i < channel_args->num_args; i++) { @@ -403,24 +414,25 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->enable_bdp_probe = grpc_channel_arg_get_integer( &channel_args->args[i], (grpc_integer_options){1, 0, 1}); } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_KEEPALIVE_TIME)) { + GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) { const int value = grpc_channel_arg_get_integer( &channel_args->args[i], - (grpc_integer_options){DEFAULT_KEEPALIVE_TIME_SECOND, 1, INT_MAX}); + (grpc_integer_options){g_default_client_keepalive_time_s, 1, + INT_MAX}); t->keepalive_time = value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) : gpr_time_from_seconds(value, GPR_TIMESPAN); } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT)) { + GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) { const int value = grpc_channel_arg_get_integer( &channel_args->args[i], - (grpc_integer_options){DEFAULT_KEEPALIVE_TIMEOUT_SECOND, 0, + (grpc_integer_options){g_default_client_keepalive_timeout_s, 0, INT_MAX}); t->keepalive_timeout = value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) : gpr_time_from_seconds(value, GPR_TIMESPAN); } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { + GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { t->keepalive_permit_without_calls = (uint32_t)grpc_channel_arg_get_integer( &channel_args->args[i], (grpc_integer_options){0, 0, 1}); @@ -474,6 +486,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->ping_state.pings_before_data_required = t->ping_policy.max_pings_without_data; + t->ping_state.is_delayed_ping_timer_set = false; /** Start client-side keepalive pings */ if (t->is_client) { @@ -1399,6 +1412,13 @@ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } } +static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; + t->ping_state.is_delayed_ping_timer_set = false; + grpc_chttp2_initiate_write(exec_ctx, t, false, "retry_send_ping"); +} + void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, uint64_t id) { grpc_chttp2_ping_queue *pq = @@ -2108,6 +2128,32 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); } +void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args) { + size_t i; + if (args) { + for (i = 0; i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) { + g_default_client_keepalive_time_s = grpc_channel_arg_get_integer( + &args->args[i], (grpc_integer_options){ + g_default_client_keepalive_time_s, 1, INT_MAX}); + } else if (0 == strcmp(args->args[i].key, + GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) { + g_default_client_keepalive_timeout_s = grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){g_default_client_keepalive_timeout_s, 0, + INT_MAX}); + } else if (0 == strcmp(args->args[i].key, + GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { + g_default_keepalive_permit_without_calls = + (uint32_t)grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){g_default_keepalive_permit_without_calls, + 0, 1}); + } + } + } +} + static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_chttp2_transport *t = arg; @@ -2151,9 +2197,7 @@ static void finish_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_timer_init( exec_ctx, &t->keepalive_ping_timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time), - grpc_closure_create(init_keepalive_ping_locked, t, - grpc_combiner_scheduler(t->combiner, false)), - gpr_now(GPR_CLOCK_MONOTONIC)); + &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC)); } } GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keepalive ping end"); diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c index de8462a17e..46dafdb62f 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.c +++ b/src/core/ext/transport/chttp2/transport/frame_ping.c @@ -40,6 +40,8 @@ #include <grpc/support/log.h> #include <grpc/support/string_util.h> +static bool g_disable_ping_ack = false; + grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) { grpc_slice slice = grpc_slice_malloc(9 + 8); uint8_t *p = GRPC_SLICE_START_PTR(slice); @@ -101,15 +103,21 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, if (p->is_ack) { grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes); } else { - if (t->ping_ack_count == t->ping_ack_capacity) { - t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3); - t->ping_acks = gpr_realloc( - t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks)); + if (!g_disable_ping_ack) { + if (t->ping_ack_count == t->ping_ack_capacity) { + t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3); + t->ping_acks = gpr_realloc( + t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks)); + } + t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes; + grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response"); } - t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes; - grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response"); } } return GRPC_ERROR_NONE; } + +void grpc_set_disable_ping_ack(bool disable_ping_ack) { + g_disable_ping_ack = disable_ping_ack; +} diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h index ef642465d7..01983d2b12 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.h +++ b/src/core/ext/transport/chttp2/transport/frame_ping.h @@ -53,4 +53,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_stream *s, grpc_slice slice, int is_last); +/* Test-only function for disabling ping ack */ +void grpc_set_disable_ping_ack(bool disable_ping_ack); + #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H */ diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 3c56c21599..8b718e963c 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -102,6 +102,8 @@ typedef struct { typedef struct { gpr_timespec last_ping_sent_time; int pings_before_data_required; + grpc_timer delayed_ping_timer; + bool is_delayed_ping_timer_set; } grpc_chttp2_repeated_ping_state; /* deframer state for the overall http2 stream of bytes */ @@ -308,6 +310,7 @@ struct grpc_chttp2_transport { grpc_chttp2_repeated_ping_policy ping_policy; grpc_chttp2_repeated_ping_state ping_state; uint64_t ping_ctr; /* unique id for pings */ + grpc_closure retry_initiate_ping_locked; /** ping acks */ size_t ping_ack_count; @@ -827,4 +830,8 @@ void grpc_chttp2_fail_pending_writes(grpc_exec_ctx *exec_ctx, uint32_t grpc_chttp2_target_incoming_window(grpc_chttp2_transport *t); +/** Set the default keepalive configurations, must only be called at + initialization */ +void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args); + #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */ diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index 2b9d93cae7..0869056f56 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -101,6 +101,14 @@ static void maybe_initiate_ping(grpc_exec_ctx *exec_ctx, "Ping delayed [%p]: not enough time elapsed since last ping", t->peer_string); } + if (!t->ping_state.is_delayed_ping_timer_set) { + t->ping_state.is_delayed_ping_timer_set = true; + grpc_timer_init(exec_ctx, &t->ping_state.delayed_ping_timer, + gpr_time_add(t->ping_state.last_ping_sent_time, + t->ping_policy.min_time_between_pings), + &t->retry_initiate_ping_locked, + gpr_now(GPR_CLOCK_MONOTONIC)); + } return; } /* coalesce equivalent pings into this one */ diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c index 511ffdcdf1..8dcd80d001 100644 --- a/src/core/lib/iomgr/resource_quota.c +++ b/src/core/lib/iomgr/resource_quota.c @@ -279,11 +279,17 @@ static void rq_step_sched(grpc_exec_ctx *exec_ctx, /* update the atomically available resource estimate - use no barriers since timeliness of delivery really doesn't matter much */ static void rq_update_estimate(grpc_resource_quota *resource_quota) { + gpr_atm memory_usage_estimation = MEMORY_USAGE_ESTIMATION_MAX; + if (resource_quota->size != 0) { + memory_usage_estimation = + GPR_CLAMP((gpr_atm)((1.0 - + ((double)resource_quota->free_pool) / + ((double)resource_quota->size)) * + MEMORY_USAGE_ESTIMATION_MAX), + 0, MEMORY_USAGE_ESTIMATION_MAX); + } gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, - (gpr_atm)((1.0 - - ((double)resource_quota->free_pool) / - ((double)resource_quota->size)) * - MEMORY_USAGE_ESTIMATION_MAX)); + memory_usage_estimation); } /* returns true if all allocations are completed */ diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c index 895a8a3b06..9342c5f8e9 100644 --- a/src/core/lib/surface/call.c +++ b/src/core/lib/surface/call.c @@ -625,7 +625,7 @@ static bool get_final_status_from( void (*set_value)(grpc_status_code code, void *user_data), void *set_value_user_data, grpc_slice *details) { grpc_status_code code; - grpc_slice slice; + grpc_slice slice = grpc_empty_slice(); grpc_error_get_status(error, call->send_deadline, &code, &slice, NULL); if (code == GRPC_STATUS_OK && !allow_ok_status) { return false; diff --git a/src/cpp/README.md b/src/cpp/README.md index d9b521317a..e9ef489a7c 100644 --- a/src/cpp/README.md +++ b/src/cpp/README.md @@ -1,17 +1,17 @@ -#Overview +# Overview This directory contains source code for C++ implementation of gRPC. -#Pre-requisites +# Pre-requisites -##Linux +## Linux ```sh $ [sudo] apt-get install build-essential autoconf libtool ``` -##Mac OSX +## Mac OSX For a Mac system, git is not available by default. You will first need to install Xcode from the Mac AppStore and then run the following command from a @@ -21,7 +21,7 @@ terminal: $ [sudo] xcode-select --install ``` -##Protoc +## Protoc By default gRPC uses [protocol buffers](https://github.com/google/protobuf), you will need the `protoc` compiler to generate stub server and client code. @@ -39,12 +39,12 @@ $ sudo make install # 'make' should have been run by core grpc Alternatively, you can download `protoc` binaries from [the protocol buffers Github repository](https://github.com/google/protobuf/releases). -#Installation +# Installation Currently to install gRPC for C++, you need to build from source as described below. -#Build from Source +# Build from Source ```sh $ git clone -b $(curl -L http://grpc.io/release) https://github.com/grpc/grpc @@ -54,7 +54,7 @@ below. $ [sudo] make install ``` -#Documentation +# Documentation You can find out how to build and run our simplest gRPC C++ example in our [C++ quick start](../../examples/cpp). diff --git a/src/php/README.md b/src/php/README.md index f08541f16c..f9f93ba815 100644 --- a/src/php/README.md +++ b/src/php/README.md @@ -1,5 +1,5 @@ -#Overview +# Overview This directory contains source code for PHP implementation of gRPC layered on shared C library. diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php index 4833fdc7b6..a59bfa3ba3 100644 --- a/src/php/lib/Grpc/AbstractCall.php +++ b/src/php/lib/Grpc/AbstractCall.php @@ -131,7 +131,7 @@ abstract class AbstractCall // Proto3 implementation if (method_exists($data, 'encode')) { return $data->encode(); - } else if (method_exists($data, 'serializeToString')) { + } elseif (method_exists($data, 'serializeToString')) { return $data->serializeToString(); } diff --git a/src/php/tests/unit_tests/ServerTest.php b/src/php/tests/unit_tests/ServerTest.php index 5f40202f18..3e7c01f20e 100644 --- a/src/php/tests/unit_tests/ServerTest.php +++ b/src/php/tests/unit_tests/ServerTest.php @@ -69,7 +69,7 @@ class ServerTest extends PHPUnit_Framework_TestCase $this->server = new Grpc\Server(); $port = $this->server->addHttp2Port('0.0.0.0:0'); $this->server->start(); - $channel = new Grpc\Channel('localhost:' . $port, + $channel = new Grpc\Channel('localhost:'.$port, ['credentials' => Grpc\ChannelCredentials::createInsecure()]); $deadline = Grpc\Timeval::infFuture(); diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/crash-59a56fa18034a104fb9f16cd58071b6ff93b8756 b/test/core/end2end/fuzzers/api_fuzzer_corpus/crash-59a56fa18034a104fb9f16cd58071b6ff93b8756 Binary files differnew file mode 100644 index 0000000000..1460bc9fbf --- /dev/null +++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/crash-59a56fa18034a104fb9f16cd58071b6ff93b8756 diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/poc-c726ee220e980ed6ad17809fd9efe2844ee61555ac08e4f88afd8901cc2dd53a b/test/core/end2end/fuzzers/api_fuzzer_corpus/poc-c726ee220e980ed6ad17809fd9efe2844ee61555ac08e4f88afd8901cc2dd53a Binary files differnew file mode 100644 index 0000000000..01428693cf --- /dev/null +++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/poc-c726ee220e980ed6ad17809fd9efe2844ee61555ac08e4f88afd8901cc2dd53a diff --git a/test/core/end2end/tests/keepalive_timeout.c b/test/core/end2end/tests/keepalive_timeout.c index 66dcc1cd10..3666abe3f7 100644 --- a/test/core/end2end/tests/keepalive_timeout.c +++ b/test/core/end2end/tests/keepalive_timeout.c @@ -41,6 +41,7 @@ #include <grpc/support/log.h> #include <grpc/support/time.h> #include <grpc/support/useful.h> +#include "src/core/ext/transport/chttp2/transport/frame_ping.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/support/env.h" @@ -110,13 +111,15 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) { grpc_raw_byte_buffer_create(&response_payload_slice, 1); gpr_timespec deadline = five_seconds_time(); - grpc_arg keepalive_args[2]; - keepalive_args[0].type = GRPC_ARG_INTEGER; - keepalive_args[0].key = GRPC_ARG_HTTP2_KEEPALIVE_TIME; - keepalive_args[0].value.integer = 2; - keepalive_args[1].type = GRPC_ARG_INTEGER; - keepalive_args[1].key = GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT; - keepalive_args[1].value.integer = 0; + grpc_arg keepalive_args[] = {{.type = GRPC_ARG_INTEGER, + .key = GRPC_ARG_CLIENT_KEEPALIVE_TIME_S, + .value.integer = 2}, + {.type = GRPC_ARG_INTEGER, + .key = GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S, + .value.integer = 0}, + {.type = GRPC_ARG_INTEGER, + .key = GRPC_ARG_HTTP2_BDP_PROBE, + .value.integer = 1}}; grpc_channel_args *client_args = NULL; client_args = grpc_channel_args_copy_and_add(client_args, keepalive_args, 2); @@ -135,6 +138,9 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) { grpc_call_error error; grpc_slice details; + /* Disable ping ack to trigger the keepalive timeout */ + grpc_set_disable_ping_ack(true); + c = grpc_channel_create_call( f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, grpc_slice_from_static_string("/foo"), diff --git a/test/core/end2end/tests/ping.c b/test/core/end2end/tests/ping.c index 966288239c..93969fa7e7 100644 --- a/test/core/end2end/tests/ping.c +++ b/test/core/end2end/tests/ping.c @@ -41,9 +41,12 @@ #include "test/core/end2end/cq_verifier.h" +#define PING_NUM 5 + static void *tag(intptr_t t) { return (void *)t; } -static void test_ping(grpc_end2end_test_config config) { +static void test_ping(grpc_end2end_test_config config, + int min_time_between_pings_ms) { grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL); cq_verifier *cqv = cq_verifier_create(f.cq); grpc_connectivity_state state = GRPC_CHANNEL_IDLE; @@ -51,7 +54,7 @@ static void test_ping(grpc_end2end_test_config config) { grpc_arg a[] = {{.type = GRPC_ARG_INTEGER, .key = GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS, - .value.integer = 0}, + .value.integer = min_time_between_pings_ms}, {.type = GRPC_ARG_INTEGER, .key = GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, .value.integer = 20}}; @@ -70,7 +73,11 @@ static void test_ping(grpc_end2end_test_config config) { READY is reached */ while (state != GRPC_CHANNEL_READY) { grpc_channel_watch_connectivity_state( - f.client, state, grpc_timeout_seconds_to_deadline(3), f.cq, tag(99)); + f.client, state, + gpr_time_add(grpc_timeout_seconds_to_deadline(3), + gpr_time_from_millis(min_time_between_pings_ms * PING_NUM, + GPR_TIMESPAN)), + f.cq, tag(99)); CQ_EXPECT_COMPLETION(cqv, tag(99), 1); cq_verify(cqv); state = grpc_channel_check_connectivity_state(f.client, 0); @@ -79,7 +86,7 @@ static void test_ping(grpc_end2end_test_config config) { state == GRPC_CHANNEL_TRANSIENT_FAILURE); } - for (i = 1; i <= 5; i++) { + for (i = 1; i <= PING_NUM; i++) { grpc_channel_ping(f.client, f.cq, tag(i), NULL); CQ_EXPECT_COMPLETION(cqv, tag(i), 1); cq_verify(cqv); @@ -105,7 +112,8 @@ static void test_ping(grpc_end2end_test_config config) { void ping(grpc_end2end_test_config config) { GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION); - test_ping(config); + test_ping(config, 0); + test_ping(config, 100); } void ping_pre_init(void) {} diff --git a/test/core/iomgr/resource_quota_test.c b/test/core/iomgr/resource_quota_test.c index a5b28f210d..ebce8b9da6 100644 --- a/test/core/iomgr/resource_quota_test.c +++ b/test/core/iomgr/resource_quota_test.c @@ -682,6 +682,56 @@ static void test_one_slice_deleted_late(void) { } } +static void test_resize_to_zero(void) { + gpr_log(GPR_INFO, "** test_resize_to_zero **"); + grpc_resource_quota *q = grpc_resource_quota_create("test_resize_to_zero"); + grpc_resource_quota_resize(q, 0); + grpc_resource_quota_unref(q); +} + +static void test_negative_rq_free_pool(void) { + gpr_log(GPR_INFO, "** test_negative_rq_free_pool **"); + grpc_resource_quota *q = + grpc_resource_quota_create("test_negative_rq_free_pool"); + grpc_resource_quota_resize(q, 1024); + + grpc_resource_user *usr = grpc_resource_user_create(q, "usr"); + + grpc_resource_user_slice_allocator alloc; + int num_allocs = 0; + grpc_resource_user_slice_allocator_init(&alloc, usr, inc_int_cb, &num_allocs); + + grpc_slice_buffer buffer; + grpc_slice_buffer_init(&buffer); + + { + const int start_allocs = num_allocs; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_resource_user_alloc_slices(&exec_ctx, &alloc, 1024, 1, &buffer); + grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(num_allocs == start_allocs + 1); + } + + grpc_resource_quota_resize(q, 512); + + double eps = 0.0001; + GPR_ASSERT(grpc_resource_quota_get_memory_pressure(q) < 1 + eps); + GPR_ASSERT(grpc_resource_quota_get_memory_pressure(q) > 1 - eps); + + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_resource_user_unref(&exec_ctx, usr); + grpc_exec_ctx_finish(&exec_ctx); + } + + grpc_resource_quota_unref(q); + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer); + grpc_exec_ctx_finish(&exec_ctx); + } +} + int main(int argc, char **argv) { grpc_test_init(argc, argv); grpc_init(); @@ -705,6 +755,8 @@ int main(int argc, char **argv) { test_reclaimers_can_be_posted_repeatedly(); test_one_slice(); test_one_slice_deleted_late(); + test_resize_to_zero(); + test_negative_rq_free_pool(); grpc_shutdown(); return 0; } diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 6202346fc2..87142f585c 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -83125,6 +83125,29 @@ }, { "args": [ + "test/core/end2end/fuzzers/api_fuzzer_corpus/crash-59a56fa18034a104fb9f16cd58071b6ff93b8756" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [ + "tsan" + ], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "api_fuzzer_one_entry", + "platforms": [ + "mac", + "linux" + ], + "uses_polling": false + }, + { + "args": [ "test/core/end2end/fuzzers/api_fuzzer_corpus/crash-59b587d15c0bcdb985417cd7a133cecfcc232698" ], "ci_platforms": [ @@ -94211,6 +94234,29 @@ }, { "args": [ + "test/core/end2end/fuzzers/api_fuzzer_corpus/poc-c726ee220e980ed6ad17809fd9efe2844ee61555ac08e4f88afd8901cc2dd53a" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [ + "tsan" + ], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "api_fuzzer_one_entry", + "platforms": [ + "mac", + "linux" + ], + "uses_polling": false + }, + { + "args": [ "test/core/end2end/fuzzers/api_fuzzer_corpus/timeout-0fa0559576ad2a45b06d0bfb84115963d7d48206" ], "ci_platforms": [ |