Merge branch 'master' into keepaliveopt

pull/17893/head
Yash Tibrewal 6 years ago
commit a55047e2c1
  1. 1
      .github/CODEOWNERS
  2. 84
      CMakeLists.txt
  3. 84
      Makefile
  4. 31
      build.yaml
  5. 31
      include/grpc/impl/codegen/port_platform.h
  6. 2
      include/grpc/impl/codegen/slice.h
  7. 5
      include/grpcpp/alarm_impl.h
  8. 26
      include/grpcpp/server.h
  9. 21
      src/core/ext/filters/client_channel/subchannel.cc
  10. 2
      src/core/ext/transport/chttp2/transport/flow_control.cc
  11. 2
      src/core/ext/transport/chttp2/transport/hpack_encoder.cc
  12. 8
      src/core/lib/gpr/time.cc
  13. 10
      src/core/lib/gpr/time_posix.cc
  14. 4
      src/core/lib/iomgr/buffer_list.h
  15. 300
      src/core/lib/iomgr/ev_epollex_linux.cc
  16. 21
      src/core/lib/iomgr/tcp_posix.cc
  17. 2
      src/core/lib/security/credentials/alts/alts_credentials.cc
  18. 2
      src/core/lib/security/credentials/credentials.h
  19. 2
      src/core/lib/security/credentials/google_default/google_default_credentials.cc
  20. 6
      src/core/lib/surface/completion_queue.cc
  21. 558
      src/core/lib/transport/static_metadata.cc
  22. 6
      src/core/tsi/ssl_transport_security.cc
  23. 14
      src/cpp/common/alarm.cc
  24. 1
      src/cpp/server/server_builder.cc
  25. 85
      src/cpp/server/server_cc.cc
  26. 41
      src/csharp/Grpc.Core.Api/ServerServiceDefinition.cs
  27. 3
      src/csharp/Grpc.Core.Api/ServiceBinderBase.cs
  28. 3
      src/csharp/Grpc.Core/ForwardedTypes.cs
  29. 52
      src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs
  30. 26
      src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
  31. 78
      src/csharp/Grpc.Core/Internal/ServerServiceDefinitionExtensions.cs
  32. 2
      src/csharp/Grpc.Core/Server.cs
  33. 10
      src/python/grpcio/grpc/_server.py
  34. 28
      src/python/grpcio_tests/tests/unit/_abort_test.py
  35. 5
      templates/tools/dockerfile/bazel.include
  36. 1
      templates/tools/dockerfile/test/sanity/Dockerfile.template
  37. 32
      test/core/bad_connection/BUILD
  38. 764
      test/core/bad_connection/close_fd_test.cc
  39. 2
      test/core/channel/channelz_registry_test.cc
  40. 6
      test/core/iomgr/timer_heap_test.cc
  41. 6
      test/core/security/credentials_test.cc
  42. 17
      test/core/tsi/ssl_transport_security_test.cc
  43. 9
      test/core/util/ubsan_suppressions.txt
  44. 38
      test/cpp/common/alarm_test.cc
  45. 24
      test/cpp/end2end/BUILD
  46. 422
      test/cpp/end2end/time_change_test.cc
  47. 29
      test/cpp/util/channel_trace_proto_helper.cc
  48. 5
      tools/dockerfile/test/bazel/Dockerfile
  49. 8
      tools/dockerfile/test/sanity/Dockerfile
  50. 2
      tools/gce/create_linux_kokoro_performance_worker_from_image.sh
  51. 5
      tools/gce/linux_kokoro_performance_worker_init.sh
  52. 8
      tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
  53. 8
      tools/internal_ci/linux/grpc_run_tests_matrix.sh
  54. 2
      tools/internal_ci/macos/pull_request/grpc_ios_binary_size.cfg
  55. 34
      tools/run_tests/generated/sources_and_headers.json
  56. 46
      tools/run_tests/generated/tests.json
  57. 9
      tools/run_tests/performance/OWNERS
  58. 6
      tools/run_tests/run_interop_tests.py

@ -6,4 +6,3 @@
/cmake/** @jtattermusch @nicolasnoble @apolcyn
/src/core/ext/filters/client_channel/** @markdroth @apolcyn @AspirinSJL
/tools/dockerfile/** @jtattermusch @apolcyn @nicolasnoble
/tools/run_tests/performance/** @ncteisen @apolcyn @jtattermusch

@ -257,6 +257,9 @@ add_dependencies(buildtests_c channel_create_test)
add_dependencies(buildtests_c chttp2_hpack_encoder_test)
add_dependencies(buildtests_c chttp2_stream_map_test)
add_dependencies(buildtests_c chttp2_varint_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c close_fd_test)
endif()
add_dependencies(buildtests_c cmdline_test)
add_dependencies(buildtests_c combiner_test)
add_dependencies(buildtests_c compression_test)
@ -699,6 +702,9 @@ endif()
add_dependencies(buildtests_cxx stress_test)
add_dependencies(buildtests_cxx thread_manager_test)
add_dependencies(buildtests_cxx thread_stress_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx time_change_test)
endif()
add_dependencies(buildtests_cxx transport_pid_controller_test)
add_dependencies(buildtests_cxx transport_security_common_api_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -6302,6 +6308,42 @@ target_link_libraries(chttp2_varint_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(close_fd_test
test/core/bad_connection/close_fd_test.cc
)
target_include_directories(close_fd_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
target_link_libraries(close_fd_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
)
# avoid dependency on libstdc++
if (_gRPC_CORE_NOSTDCXX_FLAGS)
set_target_properties(close_fd_test PROPERTIES LINKER_LANGUAGE C)
target_compile_options(close_fd_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
endif()
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(cmdline_test
test/core/util/cmdline_test.cc
@ -15973,6 +16015,48 @@ target_link_libraries(thread_stress_test
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(time_change_test
test/cpp/end2end/time_change_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(time_change_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(time_change_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc++_test_util
grpc_test_util
grpc++
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)

@ -986,6 +986,7 @@ chttp2_hpack_encoder_test: $(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test
chttp2_stream_map_test: $(BINDIR)/$(CONFIG)/chttp2_stream_map_test
chttp2_varint_test: $(BINDIR)/$(CONFIG)/chttp2_varint_test
client_fuzzer: $(BINDIR)/$(CONFIG)/client_fuzzer
close_fd_test: $(BINDIR)/$(CONFIG)/close_fd_test
cmdline_test: $(BINDIR)/$(CONFIG)/cmdline_test
combiner_test: $(BINDIR)/$(CONFIG)/combiner_test
compression_test: $(BINDIR)/$(CONFIG)/compression_test
@ -1248,6 +1249,7 @@ streaming_throughput_test: $(BINDIR)/$(CONFIG)/streaming_throughput_test
stress_test: $(BINDIR)/$(CONFIG)/stress_test
thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test
thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test
time_change_test: $(BINDIR)/$(CONFIG)/time_change_test
transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
transport_security_common_api_test: $(BINDIR)/$(CONFIG)/transport_security_common_api_test
writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test
@ -1450,6 +1452,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test \
$(BINDIR)/$(CONFIG)/chttp2_stream_map_test \
$(BINDIR)/$(CONFIG)/chttp2_varint_test \
$(BINDIR)/$(CONFIG)/close_fd_test \
$(BINDIR)/$(CONFIG)/cmdline_test \
$(BINDIR)/$(CONFIG)/combiner_test \
$(BINDIR)/$(CONFIG)/compression_test \
@ -1756,6 +1759,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/stress_test \
$(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/time_change_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_common_api_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
@ -1943,6 +1947,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/stress_test \
$(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/time_change_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_common_api_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
@ -1988,6 +1993,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/chttp2_stream_map_test || ( echo test chttp2_stream_map_test failed ; exit 1 )
$(E) "[RUN] Testing chttp2_varint_test"
$(Q) $(BINDIR)/$(CONFIG)/chttp2_varint_test || ( echo test chttp2_varint_test failed ; exit 1 )
$(E) "[RUN] Testing close_fd_test"
$(Q) $(BINDIR)/$(CONFIG)/close_fd_test || ( echo test close_fd_test failed ; exit 1 )
$(E) "[RUN] Testing cmdline_test"
$(Q) $(BINDIR)/$(CONFIG)/cmdline_test || ( echo test cmdline_test failed ; exit 1 )
$(E) "[RUN] Testing combiner_test"
@ -2458,6 +2465,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/thread_manager_test || ( echo test thread_manager_test failed ; exit 1 )
$(E) "[RUN] Testing thread_stress_test"
$(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 )
$(E) "[RUN] Testing time_change_test"
$(Q) $(BINDIR)/$(CONFIG)/time_change_test || ( echo test time_change_test failed ; exit 1 )
$(E) "[RUN] Testing transport_pid_controller_test"
$(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 )
$(E) "[RUN] Testing transport_security_common_api_test"
@ -11123,6 +11132,38 @@ endif
endif
CLOSE_FD_TEST_SRC = \
test/core/bad_connection/close_fd_test.cc \
CLOSE_FD_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CLOSE_FD_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/close_fd_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/close_fd_test: $(CLOSE_FD_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(CLOSE_FD_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/close_fd_test
endif
$(OBJDIR)/$(CONFIG)/test/core/bad_connection/close_fd_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_close_fd_test: $(CLOSE_FD_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(CLOSE_FD_TEST_OBJS:.o=.dep)
endif
endif
CMDLINE_TEST_SRC = \
test/core/util/cmdline_test.cc \
@ -21025,6 +21066,49 @@ endif
endif
TIME_CHANGE_TEST_SRC = \
test/cpp/end2end/time_change_test.cc \
TIME_CHANGE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TIME_CHANGE_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/time_change_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
$(BINDIR)/$(CONFIG)/time_change_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/time_change_test: $(PROTOBUF_DEP) $(TIME_CHANGE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(TIME_CHANGE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/time_change_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/end2end/time_change_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_time_change_test: $(TIME_CHANGE_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(TIME_CHANGE_TEST_OBJS:.o=.dep)
endif
endif
TRANSPORT_PID_CONTROLLER_TEST_SRC = \
test/core/transport/pid_controller_test.cc \

@ -2246,6 +2246,21 @@ targets:
- test/core/end2end/fuzzers/client_fuzzer_corpus
dict: test/core/end2end/fuzzers/hpack.dictionary
maxlen: 2048
- name: close_fd_test
build: test
language: c
src:
- test/core/bad_connection/close_fd_test.cc
deps:
- grpc_test_util
- grpc
- gpr
exclude_configs:
- tsan
platforms:
- mac
- linux
- posix
- name: cmdline_test
build: test
language: c
@ -5558,6 +5573,22 @@ targets:
- grpc++_unsecure
- grpc_unsecure
- gpr
- name: time_change_test
gtest: true
build: test
language: c++
src:
- test/cpp/end2end/time_change_test.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- gpr
platforms:
- mac
- linux
- posix
- name: transport_pid_controller_test
build: test
language: c++

@ -189,6 +189,8 @@
#define GPR_PLATFORM_STRING "ios"
#define GPR_CPU_IPHONE 1
#define GPR_PTHREAD_TLS 1
/* the c-ares resolver isnt safe to enable on iOS */
#define GRPC_ARES 0
#else /* TARGET_OS_IPHONE */
#define GPR_PLATFORM_STRING "osx"
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
@ -520,6 +522,35 @@ typedef unsigned __int64 uint64_t;
#define CENSUSAPI GRPCAPI
#endif
#ifndef GPR_HAS_ATTRIBUTE
#ifdef __has_attribute
#define GPR_HAS_ATTRIBUTE(a) __has_attribute(a)
#else
#define GPR_HAS_ATTRIBUTE(a) 0
#endif
#endif /* GPR_HAS_ATTRIBUTE */
#ifndef GPR_ATTRIBUTE_NOINLINE
#if GPR_HAS_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
#define GPR_ATTRIBUTE_NOINLINE __attribute__((noinline))
#define GPR_HAS_ATTRIBUTE_NOINLINE 1
#else
#define GPR_ATTRIBUTE_NOINLINE
#endif
#endif /* GPR_ATTRIBUTE_NOINLINE */
#ifndef GPR_ATTRIBUTE_WEAK
/* Attribute weak is broken on LLVM/windows:
* https://bugs.llvm.org/show_bug.cgi?id=37598 */
#if (GPR_HAS_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__))) && \
!(defined(__llvm__) && defined(_WIN32))
#define GPR_ATTRIBUTE_WEAK __attribute__((weak))
#define GPR_HAS_ATTRIBUTE_WEAK 1
#else
#define GPR_ATTRIBUTE_WEAK
#endif
#endif /* GPR_ATTRIBUTE_WEAK */
#ifndef GPR_ATTRIBUTE_NO_TSAN /* (1) */
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)

@ -81,8 +81,8 @@ struct grpc_slice {
struct grpc_slice_refcount* refcount;
union grpc_slice_data {
struct grpc_slice_refcounted {
uint8_t* bytes;
size_t length;
uint8_t* bytes;
} refcounted;
struct grpc_slice_inlined {
uint8_t length;

@ -16,8 +16,8 @@
*
*/
/// An Alarm posts the user provided tag to its associated completion queue upon
/// expiry or cancellation.
/// An Alarm posts the user-provided tag to its associated completion queue or
/// invokes the user-provided function on expiry or cancellation.
#ifndef GRPCPP_ALARM_IMPL_H
#define GRPCPP_ALARM_IMPL_H
@ -32,7 +32,6 @@
namespace grpc_impl {
/// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h).
class Alarm : private ::grpc::GrpcLibraryCodegen {
public:
/// Create an unset completion queue alarm

@ -26,6 +26,7 @@
#include <vector>
#include <grpc/compression.h>
#include <grpc/support/atm.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
@ -248,22 +249,15 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
/// the \a sync_server_cqs)
std::vector<std::unique_ptr<SyncRequestThreadManager>> sync_req_mgrs_;
// Outstanding callback requests. The vector is indexed by method with a list
// per method. Each element should store its own iterator in the list and
// should erase it when the request is actually bound to an RPC. Synchronize
// this list with its own mu_ (not the server mu_) since these must be active
// at Shutdown when the server mu_ is locked.
// TODO(vjpai): Merge with the core request matcher to avoid duplicate work
struct MethodReqList {
std::mutex reqs_mu;
// Maintain our own list size count since list::size is still linear
// for some libraries (supposed to be constant since C++11)
// TODO(vjpai): Remove reqs_list_sz and use list::size when possible
size_t reqs_list_sz{0};
std::list<CallbackRequest*> reqs_list;
using iterator = decltype(reqs_list)::iterator;
};
std::vector<MethodReqList*> callback_reqs_;
// Outstanding unmatched callback requests, indexed by method.
// NOTE: Using a gpr_atm rather than atomic_int because atomic_int isn't
// copyable or movable and thus will cause compilation errors. We
// actually only want to extend the vector before the threaded use
// starts, but this is still a limitation.
std::vector<gpr_atm> callback_unmatched_reqs_count_;
// List of callback requests to start when server actually starts.
std::list<CallbackRequest*> callback_reqs_to_start_;
// Server status
std::mutex mu_;

@ -405,18 +405,23 @@ class Subchannel::ConnectedSubchannelStateWatcher
static void OnHealthChanged(void* arg, grpc_error* error) {
auto* self = static_cast<ConnectedSubchannelStateWatcher*>(arg);
Subchannel* c = self->subchannel_;
{
MutexLock lock(&c->mu_);
if (self->health_state_ == GRPC_CHANNEL_SHUTDOWN) {
self->Unref();
return;
}
if (self->health_state_ != GRPC_CHANNEL_SHUTDOWN &&
self->health_check_client_ != nullptr) {
if (self->last_connectivity_state_ == GRPC_CHANNEL_READY) {
grpc_connectivity_state_set(&c->state_and_health_tracker_,
self->health_state_, GRPC_ERROR_REF(error),
"health_changed");
self->health_state_,
GRPC_ERROR_REF(error), "health_changed");
}
self->health_check_client_->NotifyOnHealthChange(
&self->health_state_, &self->on_health_changed_);
self = nullptr; // So we don't unref below.
}
self->health_check_client_->NotifyOnHealthChange(&self->health_state_,
&self->on_health_changed_);
}
// Don't unref until we've released the lock, because this might
// cause the subchannel (which contains the lock) to be destroyed.
if (self != nullptr) self->Unref();
}
Subchannel* subchannel_;

@ -111,7 +111,7 @@ void FlowControlTrace::Finish() {
saw_str = gpr_leftpad("", ' ', kTracePadding);
}
gpr_log(GPR_DEBUG,
"%p[%u][%s] | %s | trw:%s, ttw:%s, taw:%s, srw:%s, slw:%s, saw:%s",
"%p[%u][%s] | %s | trw:%s, tlw:%s, taw:%s, srw:%s, slw:%s, saw:%s",
tfc_, sfc_ != nullptr ? sfc_->stream()->id : 0,
tfc_->transport()->is_client ? "cli" : "svr", reason_, trw_str,
tlw_str, taw_str, srw_str, slw_str, saw_str);

@ -59,7 +59,7 @@
static grpc_slice_refcount terminal_slice_refcount = {nullptr, nullptr};
static const grpc_slice terminal_slice = {
&terminal_slice_refcount, /* refcount */
{{nullptr, 0}} /* data.refcounted */
{{0, nullptr}} /* data.refcounted */
};
typedef struct {

@ -135,6 +135,10 @@ gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
gpr_timespec sum;
int64_t inc = 0;
GPR_ASSERT(b.clock_type == GPR_TIMESPAN);
// tv_nsec in a timespan is always +ve. -ve timespan is represented as (-ve
// tv_sec, +ve tv_nsec). For example, timespan = -2.5 seconds is represented
// as {-3, 5e8, GPR_TIMESPAN}
GPR_ASSERT(b.tv_nsec >= 0);
sum.clock_type = a.clock_type;
sum.tv_nsec = a.tv_nsec + b.tv_nsec;
if (sum.tv_nsec >= GPR_NS_PER_SEC) {
@ -165,6 +169,10 @@ gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
int64_t dec = 0;
if (b.clock_type == GPR_TIMESPAN) {
diff.clock_type = a.clock_type;
// tv_nsec in a timespan is always +ve. -ve timespan is represented as (-ve
// tv_sec, +ve tv_nsec). For example, timespan = -2.5 seconds is represented
// as {-3, 5e8, GPR_TIMESPAN}
GPR_ASSERT(b.tv_nsec >= 0);
} else {
GPR_ASSERT(a.clock_type == b.clock_type);
diff.clock_type = GPR_TIMESPAN;

@ -133,12 +133,18 @@ gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type) = now_impl;
#ifdef GPR_LOW_LEVEL_COUNTERS
gpr_atm gpr_now_call_count;
#endif
gpr_timespec gpr_now(gpr_clock_type clock_type) {
#ifdef GPR_LOW_LEVEL_COUNTERS
__atomic_fetch_add(&gpr_now_call_count, 1, __ATOMIC_RELAXED);
#endif
return gpr_now_impl(clock_type);
// validate clock type
GPR_ASSERT(clock_type == GPR_CLOCK_MONOTONIC ||
clock_type == GPR_CLOCK_REALTIME ||
clock_type == GPR_CLOCK_PRECISE);
gpr_timespec ts = gpr_now_impl(clock_type);
// tv_nsecs must be in the range [0, 1e9).
GPR_ASSERT(ts.tv_nsec >= 0 && ts.tv_nsec < 1e9);
return ts;
}
void gpr_sleep_until(gpr_timespec until) {

@ -148,7 +148,9 @@ class TracedBuffer {
public:
/* Dummy shutdown function */
static void Shutdown(grpc_core::TracedBuffer** head, void* remaining,
grpc_error* shutdown_err) {}
grpc_error* shutdown_err) {
GRPC_ERROR_UNREF(shutdown_err);
}
};
#endif /* GRPC_LINUX_ERRQUEUE */

@ -45,6 +45,7 @@
#include "src/core/lib/gpr/spinlock.h"
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/inlined_vector.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/mutex_lock.h"
#include "src/core/lib/iomgr/block_annotate.h"
@ -78,18 +79,6 @@ typedef enum { PO_MULTI, PO_FD, PO_EMPTY } pollable_type;
typedef struct pollable pollable;
typedef struct cached_fd {
// Set to the grpc_fd's salt value. See 'salt' variable' in grpc_fd for more
// details
intptr_t salt;
// The underlying fd
int fd;
// A recency time counter that helps to determine the LRU fd in the cache
uint64_t last_used;
} cached_fd;
/// A pollable is something that can be polled: it has an epoll set to poll on,
/// and a wakeup fd for kicks
/// There are three broad types:
@ -120,33 +109,6 @@ struct pollable {
int event_cursor;
int event_count;
struct epoll_event events[MAX_EPOLL_EVENTS];
// We may be calling pollable_add_fd() on the same (pollable, fd) multiple
// times. To prevent pollable_add_fd() from making multiple sys calls to
// epoll_ctl() to add the fd, we maintain a cache of what fds are already
// present in the underlying epoll-set.
//
// Since this is not a correctness issue, we do not need to maintain all the
// fds in the cache. Hence we just use an LRU cache of size 'MAX_FDS_IN_CACHE'
//
// NOTE: An ideal implementation of this should do the following:
// 1) Add fds to the cache in pollable_add_fd() function (i.e whenever the fd
// is added to the pollable's epoll set)
// 2) Remove the fd from the cache whenever the fd is removed from the
// underlying epoll set (i.e whenever fd_orphan() is called).
//
// Implementing (2) above (i.e removing fds from cache on fd_orphan) adds a
// lot of complexity since an fd can be present in multiple pollables. So our
// implementation ONLY DOES (1) and NOT (2).
//
// The cache_fd.salt variable helps here to maintain correctness (it serves as
// an epoch that differentiates one grpc_fd from the other even though both of
// them may have the same fd number)
//
// The following implements LRU-eviction cache of fds in this pollable
cached_fd fd_cache[MAX_FDS_IN_CACHE];
int fd_cache_size;
uint64_t fd_cache_counter; // Recency timer tick counter
};
static const char* pollable_type_string(pollable_type t) {
@ -189,37 +151,86 @@ static void pollable_unref(pollable* p, int line, const char* reason);
* Fd Declarations
*/
// Monotonically increasing Epoch counter that is assinged to each grpc_fd. See
// the description of 'salt' variable in 'grpc_fd' for more details
// TODO: (sreek/kpayson) gpr_atm is intptr_t which may not be wide-enough on
// 32-bit systems. Change this to int_64 - atleast on 32-bit systems
static gpr_atm g_fd_salt;
struct grpc_fd {
int fd;
grpc_fd(int fd, const char* name, bool track_err)
: fd(fd), track_err(track_err) {
gpr_mu_init(&orphan_mu);
gpr_mu_init(&pollable_mu);
read_closure.InitEvent();
write_closure.InitEvent();
error_closure.InitEvent();
char* fd_name;
gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
grpc_iomgr_register_object(&iomgr_object, fd_name);
#ifndef NDEBUG
if (grpc_trace_fd_refcount.enabled()) {
gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, this, fd_name);
}
#endif
gpr_free(fd_name);
}
// This is really the dtor, but the poller threads waking up from
// epoll_wait() may access the (read|write|error)_closure after destruction.
// Since the object will be added to the free pool, this behavior is
// not going to cause issues, except spurious events if the FD is reused
// while the race happens.
void destroy() {
grpc_iomgr_unregister_object(&iomgr_object);
POLLABLE_UNREF(pollable_obj, "fd_pollable");
pollsets.clear();
gpr_mu_destroy(&pollable_mu);
gpr_mu_destroy(&orphan_mu);
read_closure.DestroyEvent();
write_closure.DestroyEvent();
error_closure.DestroyEvent();
invalidate();
}
#ifndef NDEBUG
/* Since an fd is never really destroyed (i.e gpr_free() is not called), it is
* hard-to-debug cases where fd fields are accessed even after calling
* fd_destroy(). The following invalidates fd fields to make catching such
* errors easier */
void invalidate() {
fd = -1;
gpr_atm_no_barrier_store(&refst, -1);
memset(&orphan_mu, -1, sizeof(orphan_mu));
memset(&pollable_mu, -1, sizeof(pollable_mu));
pollable_obj = nullptr;
on_done_closure = nullptr;
memset(&iomgr_object, -1, sizeof(iomgr_object));
track_err = false;
}
#else
void invalidate() {}
#endif
// Since fd numbers can be reused (after old fds are closed), this serves as
// an epoch that uniquely identifies this fd (i.e the pair (salt, fd) is
// unique (until the salt counter (i.e g_fd_salt) overflows)
intptr_t salt;
int fd;
// refst format:
// bit 0 : 1=Active / 0=Orphaned
// bits 1-n : refcount
// Ref/Unref by two to avoid altering the orphaned bit
gpr_atm refst;
gpr_atm refst = 1;
gpr_mu orphan_mu;
// Protects pollable_obj and pollsets.
gpr_mu pollable_mu;
pollable* pollable_obj;
grpc_core::InlinedVector<grpc_pollset*, 1> pollsets; // Used in PO_MULTI.
pollable* pollable_obj = nullptr; // Used in PO_FD.
grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure;
grpc_core::LockfreeEvent read_closure;
grpc_core::LockfreeEvent write_closure;
grpc_core::LockfreeEvent error_closure;
struct grpc_fd* freelist_next;
grpc_closure* on_done_closure;
struct grpc_fd* freelist_next = nullptr;
grpc_closure* on_done_closure = nullptr;
grpc_iomgr_object iomgr_object;
@ -258,6 +269,7 @@ struct grpc_pollset_worker {
struct grpc_pollset {
gpr_mu mu;
gpr_atm worker_count;
gpr_atm active_pollable_type;
pollable* active_pollable;
bool kicked_without_poller;
grpc_closure* shutdown_closure;
@ -337,39 +349,10 @@ static void ref_by(grpc_fd* fd, int n) {
GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0);
}
#ifndef NDEBUG
#define INVALIDATE_FD(fd) invalidate_fd(fd)
/* Since an fd is never really destroyed (i.e gpr_free() is not called), it is
* hard to cases where fd fields are accessed even after calling fd_destroy().
* The following invalidates fd fields to make catching such errors easier */
static void invalidate_fd(grpc_fd* fd) {
fd->fd = -1;
fd->salt = -1;
gpr_atm_no_barrier_store(&fd->refst, -1);
memset(&fd->orphan_mu, -1, sizeof(fd->orphan_mu));
memset(&fd->pollable_mu, -1, sizeof(fd->pollable_mu));
fd->pollable_obj = nullptr;
fd->on_done_closure = nullptr;
memset(&fd->iomgr_object, -1, sizeof(fd->iomgr_object));
fd->track_err = false;
}
#else
#define INVALIDATE_FD(fd)
#endif
/* Uninitialize and add to the freelist */
static void fd_destroy(void* arg, grpc_error* error) {
grpc_fd* fd = static_cast<grpc_fd*>(arg);
grpc_iomgr_unregister_object(&fd->iomgr_object);
POLLABLE_UNREF(fd->pollable_obj, "fd_pollable");
gpr_mu_destroy(&fd->pollable_mu);
gpr_mu_destroy(&fd->orphan_mu);
fd->read_closure->DestroyEvent();
fd->write_closure->DestroyEvent();
fd->error_closure->DestroyEvent();
INVALIDATE_FD(fd);
fd->destroy();
/* Add the fd to the freelist */
gpr_mu_lock(&fd_freelist_mu);
@ -429,35 +412,9 @@ static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
if (new_fd == nullptr) {
new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
new_fd->read_closure.Init();
new_fd->write_closure.Init();
new_fd->error_closure.Init();
}
new_fd->fd = fd;
new_fd->salt = gpr_atm_no_barrier_fetch_add(&g_fd_salt, 1);
gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
gpr_mu_init(&new_fd->orphan_mu);
gpr_mu_init(&new_fd->pollable_mu);
new_fd->pollable_obj = nullptr;
new_fd->read_closure->InitEvent();
new_fd->write_closure->InitEvent();
new_fd->error_closure->InitEvent();
new_fd->freelist_next = nullptr;
new_fd->on_done_closure = nullptr;
char* fd_name;
gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name);
#ifndef NDEBUG
if (grpc_trace_fd_refcount.enabled()) {
gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, new_fd, fd_name);
}
#endif
gpr_free(fd_name);
new_fd->track_err = track_err;
return new_fd;
return new (new_fd) grpc_fd(fd, name, track_err);
}
static int fd_wrapped_fd(grpc_fd* fd) {
@ -465,6 +422,7 @@ static int fd_wrapped_fd(grpc_fd* fd) {
return (gpr_atm_acq_load(&fd->refst) & 1) ? ret_fd : -1;
}
static int pollset_epoll_fd_locked(grpc_pollset* pollset);
static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
const char* reason) {
bool is_fd_closed = false;
@ -475,7 +433,6 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
// true so that the pollable will no longer access its owner_fd field.
gpr_mu_lock(&fd->pollable_mu);
pollable* pollable_obj = fd->pollable_obj;
gpr_mu_unlock(&fd->pollable_mu);
if (pollable_obj) {
gpr_mu_lock(&pollable_obj->owner_orphan_mu);
@ -487,6 +444,20 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
/* If release_fd is not NULL, we should be relinquishing control of the file
descriptor fd->fd (but we still own the grpc_fd structure). */
if (release_fd != nullptr) {
// Remove the FD from all epolls sets, before releasing it.
// Otherwise, we will receive epoll events after we release the FD.
epoll_event ev_fd;
memset(&ev_fd, 0, sizeof(ev_fd));
if (release_fd != nullptr) {
if (pollable_obj != nullptr) { // For PO_FD.
epoll_ctl(pollable_obj->epfd, EPOLL_CTL_DEL, fd->fd, &ev_fd);
}
for (size_t i = 0; i < fd->pollsets.size(); ++i) { // For PO_MULTI.
grpc_pollset* pollset = fd->pollsets[i];
const int epfd = pollset_epoll_fd_locked(pollset);
epoll_ctl(epfd, EPOLL_CTL_DEL, fd->fd, &ev_fd);
}
}
*release_fd = fd->fd;
} else {
close(fd->fd);
@ -508,40 +479,56 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
gpr_mu_unlock(&pollable_obj->owner_orphan_mu);
}
gpr_mu_unlock(&fd->pollable_mu);
gpr_mu_unlock(&fd->orphan_mu);
UNREF_BY(fd, 2, reason); /* Drop the reference */
}
static bool fd_is_shutdown(grpc_fd* fd) {
return fd->read_closure->IsShutdown();
return fd->read_closure.IsShutdown();
}
/* Might be called multiple times */
static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
if (fd->read_closure.SetShutdown(GRPC_ERROR_REF(why))) {
if (shutdown(fd->fd, SHUT_RDWR)) {
if (errno != ENOTCONN) {
gpr_log(GPR_ERROR, "Error shutting down fd %d. errno: %d",
grpc_fd_wrapped_fd(fd), errno);
}
}
fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
fd->error_closure->SetShutdown(GRPC_ERROR_REF(why));
fd->write_closure.SetShutdown(GRPC_ERROR_REF(why));
fd->error_closure.SetShutdown(GRPC_ERROR_REF(why));
}
GRPC_ERROR_UNREF(why);
}
static void fd_notify_on_read(grpc_fd* fd, grpc_closure* closure) {
fd->read_closure->NotifyOn(closure);
fd->read_closure.NotifyOn(closure);
}
static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
fd->write_closure->NotifyOn(closure);
fd->write_closure.NotifyOn(closure);
}
static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
fd->error_closure->NotifyOn(closure);
fd->error_closure.NotifyOn(closure);
}
static bool fd_has_pollset(grpc_fd* fd, grpc_pollset* pollset) {
grpc_core::MutexLock lock(&fd->pollable_mu);
for (size_t i = 0; i < fd->pollsets.size(); ++i) {
if (fd->pollsets[i] == pollset) {
return true;
}
}
return false;
}
static void fd_add_pollset(grpc_fd* fd, grpc_pollset* pollset) {
grpc_core::MutexLock lock(&fd->pollable_mu);
fd->pollsets.push_back(pollset);
}
/*******************************************************************************
@ -594,8 +581,6 @@ static grpc_error* pollable_create(pollable_type type, pollable** p) {
(*p)->root_worker = nullptr;
(*p)->event_cursor = 0;
(*p)->event_count = 0;
(*p)->fd_cache_size = 0;
(*p)->fd_cache_counter = 0;
return GRPC_ERROR_NONE;
}
@ -637,39 +622,6 @@ static grpc_error* pollable_add_fd(pollable* p, grpc_fd* fd) {
grpc_error* error = GRPC_ERROR_NONE;
static const char* err_desc = "pollable_add_fd";
const int epfd = p->epfd;
gpr_mu_lock(&p->mu);
p->fd_cache_counter++;
// Handle the case of overflow for our cache counter by
// reseting the recency-counter on all cache objects
if (p->fd_cache_counter == 0) {
for (int i = 0; i < p->fd_cache_size; i++) {
p->fd_cache[i].last_used = 0;
}
}
int lru_idx = 0;
for (int i = 0; i < p->fd_cache_size; i++) {
if (p->fd_cache[i].fd == fd->fd && p->fd_cache[i].salt == fd->salt) {
GRPC_STATS_INC_POLLSET_FD_CACHE_HITS();
p->fd_cache[i].last_used = p->fd_cache_counter;
gpr_mu_unlock(&p->mu);
return GRPC_ERROR_NONE;
} else if (p->fd_cache[i].last_used < p->fd_cache[lru_idx].last_used) {
lru_idx = i;
}
}
// Add to cache
if (p->fd_cache_size < MAX_FDS_IN_CACHE) {
lru_idx = p->fd_cache_size;
p->fd_cache_size++;
}
p->fd_cache[lru_idx].fd = fd->fd;
p->fd_cache[lru_idx].salt = fd->salt;
p->fd_cache[lru_idx].last_used = p->fd_cache_counter;
gpr_mu_unlock(&p->mu);
if (grpc_polling_trace.enabled()) {
gpr_log(GPR_INFO, "add fd %p (%d) to pollable %p", fd, fd->fd, p);
}
@ -849,6 +801,7 @@ static grpc_error* pollset_kick_all(grpc_pollset* pollset) {
static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
gpr_mu_init(&pollset->mu);
gpr_atm_no_barrier_store(&pollset->worker_count, 0);
gpr_atm_no_barrier_store(&pollset->active_pollable_type, PO_EMPTY);
pollset->active_pollable = POLLABLE_REF(g_empty_pollable, "pollset");
pollset->kicked_without_poller = false;
pollset->shutdown_closure = nullptr;
@ -869,11 +822,11 @@ static int poll_deadline_to_millis_timeout(grpc_millis millis) {
return static_cast<int>(delta);
}
static void fd_become_readable(grpc_fd* fd) { fd->read_closure->SetReady(); }
static void fd_become_readable(grpc_fd* fd) { fd->read_closure.SetReady(); }
static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
static void fd_become_writable(grpc_fd* fd) { fd->write_closure.SetReady(); }
static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
static void fd_has_errors(grpc_fd* fd) { fd->error_closure.SetReady(); }
/* Get the pollable_obj attached to this fd. If none is attached, create a new
* pollable object (of type PO_FD), attach it to the fd and return it
@ -1283,6 +1236,8 @@ static grpc_error* pollset_add_fd_locked(grpc_pollset* pollset, grpc_fd* fd) {
POLLABLE_UNREF(pollset->active_pollable, "pollset");
pollset->active_pollable = po_at_start;
} else {
gpr_atm_rel_store(&pollset->active_pollable_type,
pollset->active_pollable->type);
POLLABLE_UNREF(po_at_start, "pollset_add_fd");
}
return error;
@ -1329,17 +1284,38 @@ static grpc_error* pollset_as_multipollable_locked(grpc_pollset* pollset,
pollset->active_pollable = po_at_start;
*pollable_obj = nullptr;
} else {
gpr_atm_rel_store(&pollset->active_pollable_type,
pollset->active_pollable->type);
*pollable_obj = POLLABLE_REF(pollset->active_pollable, "pollset_set");
POLLABLE_UNREF(po_at_start, "pollset_as_multipollable");
}
return error;
}
// Caller must hold the lock for `pollset->mu`.
static int pollset_epoll_fd_locked(grpc_pollset* pollset) {
return pollset->active_pollable->epfd;
}
static void pollset_add_fd(grpc_pollset* pollset, grpc_fd* fd) {
GPR_TIMER_SCOPE("pollset_add_fd", 0);
gpr_mu_lock(&pollset->mu);
// We never transition from PO_MULTI to other modes (i.e., PO_FD or PO_EMOPTY)
// and, thus, it is safe to simply store and check whether the FD has already
// been added to the active pollable previously.
if (gpr_atm_acq_load(&pollset->active_pollable_type) == PO_MULTI &&
fd_has_pollset(fd, pollset)) {
return;
}
grpc_core::MutexLock lock(&pollset->mu);
grpc_error* error = pollset_add_fd_locked(pollset, fd);
gpr_mu_unlock(&pollset->mu);
// If we are in PO_MULTI mode, we should update the pollsets of the FD.
if (gpr_atm_no_barrier_load(&pollset->active_pollable_type) == PO_MULTI) {
fd_add_pollset(fd, pollset);
}
GRPC_LOG_IF_ERROR("pollset_add_fd", error);
}

@ -195,7 +195,7 @@ static void run_poller(void* bp, grpc_error* error_ignored) {
static void drop_uncovered(grpc_tcp* tcp) {
backup_poller* p = (backup_poller*)gpr_atm_acq_load(&g_backup_poller);
gpr_atm old_count =
gpr_atm_no_barrier_fetch_add(&g_uncovered_notifications_pending, -1);
gpr_atm_full_fetch_add(&g_uncovered_notifications_pending, -1);
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_INFO, "BACKUP_POLLER:%p uncover cnt %d->%d", p,
static_cast<int>(old_count), static_cast<int>(old_count) - 1);
@ -343,6 +343,13 @@ static void tcp_free(grpc_tcp* tcp) {
grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer);
grpc_resource_user_unref(tcp->resource_user);
gpr_free(tcp->peer_string);
/* The lock is not really necessary here, since all refs have been released */
gpr_mu_lock(&tcp->tb_mu);
grpc_core::TracedBuffer::Shutdown(
&tcp->tb_head, tcp->outgoing_buffer_arg,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("endpoint destroyed"));
gpr_mu_unlock(&tcp->tb_mu);
tcp->outgoing_buffer_arg = nullptr;
gpr_mu_destroy(&tcp->tb_mu);
gpr_free(tcp);
}
@ -389,12 +396,6 @@ static void tcp_destroy(grpc_endpoint* ep) {
grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
if (grpc_event_engine_can_track_errors()) {
gpr_mu_lock(&tcp->tb_mu);
grpc_core::TracedBuffer::Shutdown(
&tcp->tb_head, tcp->outgoing_buffer_arg,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("endpoint destroyed"));
gpr_mu_unlock(&tcp->tb_mu);
tcp->outgoing_buffer_arg = nullptr;
gpr_atm_no_barrier_store(&tcp->stop_error_notification, true);
grpc_fd_set_error(tcp->em_fd);
}
@ -1184,12 +1185,6 @@ void grpc_tcp_destroy_and_release_fd(grpc_endpoint* ep, int* fd,
grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
if (grpc_event_engine_can_track_errors()) {
/* Stop errors notification. */
gpr_mu_lock(&tcp->tb_mu);
grpc_core::TracedBuffer::Shutdown(
&tcp->tb_head, tcp->outgoing_buffer_arg,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("endpoint destroyed"));
gpr_mu_unlock(&tcp->tb_mu);
tcp->outgoing_buffer_arg = nullptr;
gpr_atm_no_barrier_store(&tcp->stop_error_notification, true);
grpc_fd_set_error(tcp->em_fd);
}

@ -31,7 +31,7 @@
#include "src/core/lib/security/security_connector/alts/alts_security_connector.h"
#define GRPC_CREDENTIALS_TYPE_ALTS "Alts"
#define GRPC_ALTS_HANDSHAKER_SERVICE_URL "metadata.google.internal:8080"
#define GRPC_ALTS_HANDSHAKER_SERVICE_URL "metadata.google.internal.:8080"
grpc_alts_credentials::grpc_alts_credentials(
const grpc_alts_credentials_options* options,

@ -60,7 +60,7 @@ typedef enum {
#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60
#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata.google.internal"
#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata.google.internal."
#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
"/computeMetadata/v1/instance/service-accounts/default/token"

@ -46,7 +46,7 @@
/* -- Constants. -- */
#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal."
/* -- Default credentials. -- */

@ -854,15 +854,11 @@ static void cq_end_op_for_callback(
// for reserved storage. Invoke the done callback right away to release it.
done(done_arg, storage);
gpr_mu_lock(cq->mu);
cq_check_tag(cq, tag, false); /* Used in debug builds only */
cq_check_tag(cq, tag, true); /* Used in debug builds only */
gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1);
if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
gpr_mu_unlock(cq->mu);
cq_finish_shutdown_callback(cq);
} else {
gpr_mu_unlock(cq->mu);
}
GRPC_ERROR_UNREF(error);

@ -236,113 +236,113 @@ grpc_slice_refcount grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {
};
const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[3], {{g_bytes + 19, 10}}},
{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}},
{&grpc_static_metadata_refcounts[6], {{g_bytes + 38, 12}}},
{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
{&grpc_static_metadata_refcounts[8], {{g_bytes + 61, 16}}},
{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[11], {{g_bytes + 110, 21}}},
{&grpc_static_metadata_refcounts[12], {{g_bytes + 131, 13}}},
{&grpc_static_metadata_refcounts[13], {{g_bytes + 144, 14}}},
{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[17], {{g_bytes + 201, 30}}},
{&grpc_static_metadata_refcounts[18], {{g_bytes + 231, 37}}},
{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
{&grpc_static_metadata_refcounts[22], {{g_bytes + 290, 26}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 316, 22}}},
{&grpc_static_metadata_refcounts[24], {{g_bytes + 338, 12}}},
{&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}},
{&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}},
{&grpc_static_metadata_refcounts[27], {{g_bytes + 352, 1}}},
{&grpc_static_metadata_refcounts[28], {{g_bytes + 353, 1}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}},
{&grpc_static_metadata_refcounts[30], {{g_bytes + 354, 19}}},
{&grpc_static_metadata_refcounts[31], {{g_bytes + 373, 12}}},
{&grpc_static_metadata_refcounts[32], {{g_bytes + 385, 30}}},
{&grpc_static_metadata_refcounts[33], {{g_bytes + 415, 31}}},
{&grpc_static_metadata_refcounts[34], {{g_bytes + 446, 36}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 28}}},
{&grpc_static_metadata_refcounts[36], {{g_bytes + 510, 80}}},
{&grpc_static_metadata_refcounts[37], {{g_bytes + 590, 7}}},
{&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}},
{&grpc_static_metadata_refcounts[39], {{g_bytes + 601, 11}}},
{&grpc_static_metadata_refcounts[40], {{g_bytes + 612, 3}}},
{&grpc_static_metadata_refcounts[41], {{g_bytes + 615, 4}}},
{&grpc_static_metadata_refcounts[42], {{g_bytes + 619, 1}}},
{&grpc_static_metadata_refcounts[43], {{g_bytes + 620, 11}}},
{&grpc_static_metadata_refcounts[44], {{g_bytes + 631, 4}}},
{&grpc_static_metadata_refcounts[45], {{g_bytes + 635, 5}}},
{&grpc_static_metadata_refcounts[46], {{g_bytes + 640, 3}}},
{&grpc_static_metadata_refcounts[47], {{g_bytes + 643, 3}}},
{&grpc_static_metadata_refcounts[48], {{g_bytes + 646, 3}}},
{&grpc_static_metadata_refcounts[49], {{g_bytes + 649, 3}}},
{&grpc_static_metadata_refcounts[50], {{g_bytes + 652, 3}}},
{&grpc_static_metadata_refcounts[51], {{g_bytes + 655, 3}}},
{&grpc_static_metadata_refcounts[52], {{g_bytes + 658, 3}}},
{&grpc_static_metadata_refcounts[53], {{g_bytes + 661, 14}}},
{&grpc_static_metadata_refcounts[54], {{g_bytes + 675, 13}}},
{&grpc_static_metadata_refcounts[55], {{g_bytes + 688, 15}}},
{&grpc_static_metadata_refcounts[56], {{g_bytes + 703, 13}}},
{&grpc_static_metadata_refcounts[57], {{g_bytes + 716, 6}}},
{&grpc_static_metadata_refcounts[58], {{g_bytes + 722, 27}}},
{&grpc_static_metadata_refcounts[59], {{g_bytes + 749, 3}}},
{&grpc_static_metadata_refcounts[60], {{g_bytes + 752, 5}}},
{&grpc_static_metadata_refcounts[61], {{g_bytes + 757, 13}}},
{&grpc_static_metadata_refcounts[62], {{g_bytes + 770, 13}}},
{&grpc_static_metadata_refcounts[63], {{g_bytes + 783, 19}}},
{&grpc_static_metadata_refcounts[64], {{g_bytes + 802, 16}}},
{&grpc_static_metadata_refcounts[65], {{g_bytes + 818, 14}}},
{&grpc_static_metadata_refcounts[66], {{g_bytes + 832, 16}}},
{&grpc_static_metadata_refcounts[67], {{g_bytes + 848, 13}}},
{&grpc_static_metadata_refcounts[68], {{g_bytes + 861, 6}}},
{&grpc_static_metadata_refcounts[69], {{g_bytes + 867, 4}}},
{&grpc_static_metadata_refcounts[70], {{g_bytes + 871, 4}}},
{&grpc_static_metadata_refcounts[71], {{g_bytes + 875, 6}}},
{&grpc_static_metadata_refcounts[72], {{g_bytes + 881, 7}}},
{&grpc_static_metadata_refcounts[73], {{g_bytes + 888, 4}}},
{&grpc_static_metadata_refcounts[74], {{g_bytes + 892, 8}}},
{&grpc_static_metadata_refcounts[75], {{g_bytes + 900, 17}}},
{&grpc_static_metadata_refcounts[76], {{g_bytes + 917, 13}}},
{&grpc_static_metadata_refcounts[77], {{g_bytes + 930, 8}}},
{&grpc_static_metadata_refcounts[78], {{g_bytes + 938, 19}}},
{&grpc_static_metadata_refcounts[79], {{g_bytes + 957, 13}}},
{&grpc_static_metadata_refcounts[80], {{g_bytes + 970, 4}}},
{&grpc_static_metadata_refcounts[81], {{g_bytes + 974, 8}}},
{&grpc_static_metadata_refcounts[82], {{g_bytes + 982, 12}}},
{&grpc_static_metadata_refcounts[83], {{g_bytes + 994, 18}}},
{&grpc_static_metadata_refcounts[84], {{g_bytes + 1012, 19}}},
{&grpc_static_metadata_refcounts[85], {{g_bytes + 1031, 5}}},
{&grpc_static_metadata_refcounts[86], {{g_bytes + 1036, 7}}},
{&grpc_static_metadata_refcounts[87], {{g_bytes + 1043, 7}}},
{&grpc_static_metadata_refcounts[88], {{g_bytes + 1050, 11}}},
{&grpc_static_metadata_refcounts[89], {{g_bytes + 1061, 6}}},
{&grpc_static_metadata_refcounts[90], {{g_bytes + 1067, 10}}},
{&grpc_static_metadata_refcounts[91], {{g_bytes + 1077, 25}}},
{&grpc_static_metadata_refcounts[92], {{g_bytes + 1102, 17}}},
{&grpc_static_metadata_refcounts[93], {{g_bytes + 1119, 4}}},
{&grpc_static_metadata_refcounts[94], {{g_bytes + 1123, 3}}},
{&grpc_static_metadata_refcounts[95], {{g_bytes + 1126, 16}}},
{&grpc_static_metadata_refcounts[96], {{g_bytes + 1142, 1}}},
{&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}},
{&grpc_static_metadata_refcounts[98], {{g_bytes + 1151, 8}}},
{&grpc_static_metadata_refcounts[99], {{g_bytes + 1159, 16}}},
{&grpc_static_metadata_refcounts[100], {{g_bytes + 1175, 4}}},
{&grpc_static_metadata_refcounts[101], {{g_bytes + 1179, 3}}},
{&grpc_static_metadata_refcounts[102], {{g_bytes + 1182, 11}}},
{&grpc_static_metadata_refcounts[103], {{g_bytes + 1193, 16}}},
{&grpc_static_metadata_refcounts[104], {{g_bytes + 1209, 13}}},
{&grpc_static_metadata_refcounts[105], {{g_bytes + 1222, 12}}},
{&grpc_static_metadata_refcounts[106], {{g_bytes + 1234, 21}}},
{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[3], {{10, g_bytes + 19}}},
{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[5], {{2, g_bytes + 36}}},
{&grpc_static_metadata_refcounts[6], {{12, g_bytes + 38}}},
{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[8], {{16, g_bytes + 61}}},
{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[11], {{21, g_bytes + 110}}},
{&grpc_static_metadata_refcounts[12], {{13, g_bytes + 131}}},
{&grpc_static_metadata_refcounts[13], {{14, g_bytes + 144}}},
{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[17], {{30, g_bytes + 201}}},
{&grpc_static_metadata_refcounts[18], {{37, g_bytes + 231}}},
{&grpc_static_metadata_refcounts[19], {{10, g_bytes + 268}}},
{&grpc_static_metadata_refcounts[20], {{4, g_bytes + 278}}},
{&grpc_static_metadata_refcounts[21], {{8, g_bytes + 282}}},
{&grpc_static_metadata_refcounts[22], {{26, g_bytes + 290}}},
{&grpc_static_metadata_refcounts[23], {{22, g_bytes + 316}}},
{&grpc_static_metadata_refcounts[24], {{12, g_bytes + 338}}},
{&grpc_static_metadata_refcounts[25], {{1, g_bytes + 350}}},
{&grpc_static_metadata_refcounts[26], {{1, g_bytes + 351}}},
{&grpc_static_metadata_refcounts[27], {{1, g_bytes + 352}}},
{&grpc_static_metadata_refcounts[28], {{1, g_bytes + 353}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}},
{&grpc_static_metadata_refcounts[30], {{19, g_bytes + 354}}},
{&grpc_static_metadata_refcounts[31], {{12, g_bytes + 373}}},
{&grpc_static_metadata_refcounts[32], {{30, g_bytes + 385}}},
{&grpc_static_metadata_refcounts[33], {{31, g_bytes + 415}}},
{&grpc_static_metadata_refcounts[34], {{36, g_bytes + 446}}},
{&grpc_static_metadata_refcounts[35], {{28, g_bytes + 482}}},
{&grpc_static_metadata_refcounts[36], {{80, g_bytes + 510}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}},
{&grpc_static_metadata_refcounts[39], {{11, g_bytes + 601}}},
{&grpc_static_metadata_refcounts[40], {{3, g_bytes + 612}}},
{&grpc_static_metadata_refcounts[41], {{4, g_bytes + 615}}},
{&grpc_static_metadata_refcounts[42], {{1, g_bytes + 619}}},
{&grpc_static_metadata_refcounts[43], {{11, g_bytes + 620}}},
{&grpc_static_metadata_refcounts[44], {{4, g_bytes + 631}}},
{&grpc_static_metadata_refcounts[45], {{5, g_bytes + 635}}},
{&grpc_static_metadata_refcounts[46], {{3, g_bytes + 640}}},
{&grpc_static_metadata_refcounts[47], {{3, g_bytes + 643}}},
{&grpc_static_metadata_refcounts[48], {{3, g_bytes + 646}}},
{&grpc_static_metadata_refcounts[49], {{3, g_bytes + 649}}},
{&grpc_static_metadata_refcounts[50], {{3, g_bytes + 652}}},
{&grpc_static_metadata_refcounts[51], {{3, g_bytes + 655}}},
{&grpc_static_metadata_refcounts[52], {{3, g_bytes + 658}}},
{&grpc_static_metadata_refcounts[53], {{14, g_bytes + 661}}},
{&grpc_static_metadata_refcounts[54], {{13, g_bytes + 675}}},
{&grpc_static_metadata_refcounts[55], {{15, g_bytes + 688}}},
{&grpc_static_metadata_refcounts[56], {{13, g_bytes + 703}}},
{&grpc_static_metadata_refcounts[57], {{6, g_bytes + 716}}},
{&grpc_static_metadata_refcounts[58], {{27, g_bytes + 722}}},
{&grpc_static_metadata_refcounts[59], {{3, g_bytes + 749}}},
{&grpc_static_metadata_refcounts[60], {{5, g_bytes + 752}}},
{&grpc_static_metadata_refcounts[61], {{13, g_bytes + 757}}},
{&grpc_static_metadata_refcounts[62], {{13, g_bytes + 770}}},
{&grpc_static_metadata_refcounts[63], {{19, g_bytes + 783}}},
{&grpc_static_metadata_refcounts[64], {{16, g_bytes + 802}}},
{&grpc_static_metadata_refcounts[65], {{14, g_bytes + 818}}},
{&grpc_static_metadata_refcounts[66], {{16, g_bytes + 832}}},
{&grpc_static_metadata_refcounts[67], {{13, g_bytes + 848}}},
{&grpc_static_metadata_refcounts[68], {{6, g_bytes + 861}}},
{&grpc_static_metadata_refcounts[69], {{4, g_bytes + 867}}},
{&grpc_static_metadata_refcounts[70], {{4, g_bytes + 871}}},
{&grpc_static_metadata_refcounts[71], {{6, g_bytes + 875}}},
{&grpc_static_metadata_refcounts[72], {{7, g_bytes + 881}}},
{&grpc_static_metadata_refcounts[73], {{4, g_bytes + 888}}},
{&grpc_static_metadata_refcounts[74], {{8, g_bytes + 892}}},
{&grpc_static_metadata_refcounts[75], {{17, g_bytes + 900}}},
{&grpc_static_metadata_refcounts[76], {{13, g_bytes + 917}}},
{&grpc_static_metadata_refcounts[77], {{8, g_bytes + 930}}},
{&grpc_static_metadata_refcounts[78], {{19, g_bytes + 938}}},
{&grpc_static_metadata_refcounts[79], {{13, g_bytes + 957}}},
{&grpc_static_metadata_refcounts[80], {{4, g_bytes + 970}}},
{&grpc_static_metadata_refcounts[81], {{8, g_bytes + 974}}},
{&grpc_static_metadata_refcounts[82], {{12, g_bytes + 982}}},
{&grpc_static_metadata_refcounts[83], {{18, g_bytes + 994}}},
{&grpc_static_metadata_refcounts[84], {{19, g_bytes + 1012}}},
{&grpc_static_metadata_refcounts[85], {{5, g_bytes + 1031}}},
{&grpc_static_metadata_refcounts[86], {{7, g_bytes + 1036}}},
{&grpc_static_metadata_refcounts[87], {{7, g_bytes + 1043}}},
{&grpc_static_metadata_refcounts[88], {{11, g_bytes + 1050}}},
{&grpc_static_metadata_refcounts[89], {{6, g_bytes + 1061}}},
{&grpc_static_metadata_refcounts[90], {{10, g_bytes + 1067}}},
{&grpc_static_metadata_refcounts[91], {{25, g_bytes + 1077}}},
{&grpc_static_metadata_refcounts[92], {{17, g_bytes + 1102}}},
{&grpc_static_metadata_refcounts[93], {{4, g_bytes + 1119}}},
{&grpc_static_metadata_refcounts[94], {{3, g_bytes + 1123}}},
{&grpc_static_metadata_refcounts[95], {{16, g_bytes + 1126}}},
{&grpc_static_metadata_refcounts[96], {{1, g_bytes + 1142}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}},
{&grpc_static_metadata_refcounts[98], {{8, g_bytes + 1151}}},
{&grpc_static_metadata_refcounts[99], {{16, g_bytes + 1159}}},
{&grpc_static_metadata_refcounts[100], {{4, g_bytes + 1175}}},
{&grpc_static_metadata_refcounts[101], {{3, g_bytes + 1179}}},
{&grpc_static_metadata_refcounts[102], {{11, g_bytes + 1182}}},
{&grpc_static_metadata_refcounts[103], {{16, g_bytes + 1193}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}},
{&grpc_static_metadata_refcounts[105], {{12, g_bytes + 1222}}},
{&grpc_static_metadata_refcounts[106], {{21, g_bytes + 1234}}},
};
uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
@ -404,178 +404,178 @@ grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
}
grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
{{&grpc_static_metadata_refcounts[3], {{g_bytes + 19, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
{&grpc_static_metadata_refcounts[40], {{g_bytes + 612, 3}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
{&grpc_static_metadata_refcounts[41], {{g_bytes + 615, 4}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
{&grpc_static_metadata_refcounts[42], {{g_bytes + 619, 1}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
{&grpc_static_metadata_refcounts[43], {{g_bytes + 620, 11}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
{&grpc_static_metadata_refcounts[44], {{g_bytes + 631, 4}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
{&grpc_static_metadata_refcounts[45], {{g_bytes + 635, 5}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[46], {{g_bytes + 640, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[47], {{g_bytes + 643, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[48], {{g_bytes + 646, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[49], {{g_bytes + 649, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[50], {{g_bytes + 652, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[51], {{g_bytes + 655, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[52], {{g_bytes + 658, 3}}}},
{{&grpc_static_metadata_refcounts[53], {{g_bytes + 661, 14}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[54], {{g_bytes + 675, 13}}}},
{{&grpc_static_metadata_refcounts[55], {{g_bytes + 688, 15}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[56], {{g_bytes + 703, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[57], {{g_bytes + 716, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[58], {{g_bytes + 722, 27}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[59], {{g_bytes + 749, 3}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[60], {{g_bytes + 752, 5}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[61], {{g_bytes + 757, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[62], {{g_bytes + 770, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[63], {{g_bytes + 783, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[64], {{g_bytes + 802, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[65], {{g_bytes + 818, 14}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[66], {{g_bytes + 832, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[67], {{g_bytes + 848, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[68], {{g_bytes + 861, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[69], {{g_bytes + 867, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[70], {{g_bytes + 871, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[71], {{g_bytes + 875, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[72], {{g_bytes + 881, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[73], {{g_bytes + 888, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[74], {{g_bytes + 892, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[75], {{g_bytes + 900, 17}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[76], {{g_bytes + 917, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[77], {{g_bytes + 930, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[78], {{g_bytes + 938, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[79], {{g_bytes + 957, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[80], {{g_bytes + 970, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[81], {{g_bytes + 974, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[82], {{g_bytes + 982, 12}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[83], {{g_bytes + 994, 18}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[84], {{g_bytes + 1012, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[85], {{g_bytes + 1031, 5}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[86], {{g_bytes + 1036, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[87], {{g_bytes + 1043, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[88], {{g_bytes + 1050, 11}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[89], {{g_bytes + 1061, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[90], {{g_bytes + 1067, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[91], {{g_bytes + 1077, 25}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[92], {{g_bytes + 1102, 17}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[93], {{g_bytes + 1119, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[94], {{g_bytes + 1123, 3}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[95], {{g_bytes + 1126, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
{&grpc_static_metadata_refcounts[96], {{g_bytes + 1142, 1}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
{&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
{&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
{&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
{&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
{&grpc_static_metadata_refcounts[37], {{g_bytes + 590, 7}}}},
{{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}},
{&grpc_static_metadata_refcounts[98], {{g_bytes + 1151, 8}}}},
{{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
{&grpc_static_metadata_refcounts[99], {{g_bytes + 1159, 16}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
{&grpc_static_metadata_refcounts[100], {{g_bytes + 1175, 4}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
{&grpc_static_metadata_refcounts[101], {{g_bytes + 1179, 3}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
{&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
{&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}}},
{{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[102], {{g_bytes + 1182, 11}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[37], {{g_bytes + 590, 7}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[103], {{g_bytes + 1193, 16}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[104], {{g_bytes + 1209, 13}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[105], {{g_bytes + 1222, 12}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[106], {{g_bytes + 1234, 21}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[97], {{g_bytes + 1143, 8}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[38], {{g_bytes + 597, 4}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[104], {{g_bytes + 1209, 13}}}},
{{&grpc_static_metadata_refcounts[3], {{10, g_bytes + 19}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[40], {{3, g_bytes + 612}}}},
{{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[41], {{4, g_bytes + 615}}}},
{{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[42], {{1, g_bytes + 619}}}},
{{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[43], {{11, g_bytes + 620}}}},
{{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[44], {{4, g_bytes + 631}}}},
{{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[45], {{5, g_bytes + 635}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[46], {{3, g_bytes + 640}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[47], {{3, g_bytes + 643}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[48], {{3, g_bytes + 646}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[49], {{3, g_bytes + 649}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[50], {{3, g_bytes + 652}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[51], {{3, g_bytes + 655}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[52], {{3, g_bytes + 658}}}},
{{&grpc_static_metadata_refcounts[53], {{14, g_bytes + 661}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[54], {{13, g_bytes + 675}}}},
{{&grpc_static_metadata_refcounts[55], {{15, g_bytes + 688}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[56], {{13, g_bytes + 703}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[57], {{6, g_bytes + 716}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[58], {{27, g_bytes + 722}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[59], {{3, g_bytes + 749}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[60], {{5, g_bytes + 752}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[61], {{13, g_bytes + 757}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[62], {{13, g_bytes + 770}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[63], {{19, g_bytes + 783}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[64], {{16, g_bytes + 802}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[65], {{14, g_bytes + 818}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[66], {{16, g_bytes + 832}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[67], {{13, g_bytes + 848}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[68], {{6, g_bytes + 861}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[69], {{4, g_bytes + 867}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[70], {{4, g_bytes + 871}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[71], {{6, g_bytes + 875}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[72], {{7, g_bytes + 881}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[73], {{4, g_bytes + 888}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[20], {{4, g_bytes + 278}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[74], {{8, g_bytes + 892}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[75], {{17, g_bytes + 900}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[76], {{13, g_bytes + 917}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[77], {{8, g_bytes + 930}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[78], {{19, g_bytes + 938}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[79], {{13, g_bytes + 957}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[80], {{4, g_bytes + 970}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[81], {{8, g_bytes + 974}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[82], {{12, g_bytes + 982}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[83], {{18, g_bytes + 994}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[84], {{19, g_bytes + 1012}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[85], {{5, g_bytes + 1031}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[86], {{7, g_bytes + 1036}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[87], {{7, g_bytes + 1043}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[88], {{11, g_bytes + 1050}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[89], {{6, g_bytes + 1061}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[90], {{10, g_bytes + 1067}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[91], {{25, g_bytes + 1077}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[92], {{17, g_bytes + 1102}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[19], {{10, g_bytes + 268}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[93], {{4, g_bytes + 1119}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[94], {{3, g_bytes + 1123}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[95], {{16, g_bytes + 1126}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[96], {{1, g_bytes + 1142}}}},
{{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[25], {{1, g_bytes + 350}}}},
{{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[26], {{1, g_bytes + 351}}}},
{{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}},
{{&grpc_static_metadata_refcounts[5], {{2, g_bytes + 36}}},
{&grpc_static_metadata_refcounts[98], {{8, g_bytes + 1151}}}},
{{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[99], {{16, g_bytes + 1159}}}},
{{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[100], {{4, g_bytes + 1175}}}},
{{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[101], {{3, g_bytes + 1179}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[21], {{8, g_bytes + 282}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[102], {{11, g_bytes + 1182}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[103], {{16, g_bytes + 1193}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[105], {{12, g_bytes + 1222}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[106], {{21, g_bytes + 1234}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}},
};
const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78,
79, 80, 81, 82};

@ -619,15 +619,19 @@ static tsi_result x509_store_load_certs(X509_STORE* cert_store,
sk_X509_NAME_push(*root_names, root_name);
root_name = nullptr;
}
ERR_clear_error();
if (!X509_STORE_add_cert(cert_store, root)) {
unsigned long error = ERR_get_error();
if (ERR_GET_LIB(error) != ERR_LIB_X509 ||
ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
result = TSI_INTERNAL_ERROR;
break;
}
}
X509_free(root);
num_roots++;
}
if (num_roots == 0) {
gpr_log(GPR_ERROR, "Could not load any root certificate.");
result = TSI_INVALID_ARGUMENT;

@ -40,12 +40,7 @@ class AlarmImpl : public ::grpc::internal::CompletionQueueTag {
gpr_ref_init(&refs_, 1);
grpc_timer_init_unset(&timer_);
}
~AlarmImpl() {
grpc_core::ExecCtx exec_ctx;
if (cq_ != nullptr) {
GRPC_CQ_INTERNAL_UNREF(cq_, "alarm");
}
}
~AlarmImpl() {}
bool FinalizeResult(void** tag, bool* status) override {
*tag = tag_;
Unref();
@ -63,10 +58,15 @@ class AlarmImpl : public ::grpc::internal::CompletionQueueTag {
// queue the op on the completion queue
AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
alarm->Ref();
// Preserve the cq and reset the cq_ so that the alarm
// can be reset when the alarm tag is delivered.
grpc_completion_queue* cq = alarm->cq_;
alarm->cq_ = nullptr;
grpc_cq_end_op(
alarm->cq_, alarm, error,
cq, alarm, error,
[](void* arg, grpc_cq_completion* completion) {},
arg, &alarm->completion_);
GRPC_CQ_INTERNAL_UNREF(cq, "alarm");
},
this, grpc_schedule_on_exec_ctx);
grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline),

@ -139,6 +139,7 @@ ServerBuilder& ServerBuilder::SetCompressionAlgorithmSupportStatus(
ServerBuilder& ServerBuilder::SetDefaultCompressionLevel(
grpc_compression_level level) {
maybe_default_compression_level_.is_set = true;
maybe_default_compression_level_.level = level;
return *this;
}

@ -350,10 +350,10 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
class Server::CallbackRequest final : public internal::CompletionQueueTag {
public:
CallbackRequest(Server* server, Server::MethodReqList* list,
CallbackRequest(Server* server, size_t method_idx,
internal::RpcServiceMethod* method, void* method_tag)
: server_(server),
req_list_(list),
method_index_(method_idx),
method_(method),
method_tag_(method_tag),
has_request_payload_(
@ -428,46 +428,32 @@ class Server::CallbackRequest final : public internal::CompletionQueueTag {
GPR_ASSERT(!req_->FinalizeResult(&ignored, &new_ok));
GPR_ASSERT(ignored == req_);
bool spawn_new = false;
{
std::unique_lock<std::mutex> l(req_->req_list_->reqs_mu);
req_->req_list_->reqs_list.erase(req_->req_list_iterator_);
req_->req_list_->reqs_list_sz--;
int count =
static_cast<int>(gpr_atm_no_barrier_fetch_add(
&req_->server_
->callback_unmatched_reqs_count_[req_->method_index_],
-1)) -
1;
if (!ok) {
// The call has been shutdown.
// Delete its contents to free up the request.
// First release the lock in case the deletion of the request
// completes the full server shutdown and allows the destructor
// of the req_list to proceed.
l.unlock();
delete req_;
return;
}
// If this was the last request in the list or it is below the soft
// minimum and there are spare requests available, set up a new one, but
// do it outside the lock since the Request could otherwise deadlock
if (req_->req_list_->reqs_list_sz == 0 ||
(req_->req_list_->reqs_list_sz <
SOFT_MINIMUM_SPARE_CALLBACK_REQS_PER_METHOD &&
// minimum and there are spare requests available, set up a new one.
if (count == 0 || (count < SOFT_MINIMUM_SPARE_CALLBACK_REQS_PER_METHOD &&
req_->server_->callback_reqs_outstanding_ <
SOFT_MAXIMUM_CALLBACK_REQS_OUTSTANDING)) {
spawn_new = true;
}
}
if (spawn_new) {
auto* new_req = new CallbackRequest(req_->server_, req_->req_list_,
auto* new_req = new CallbackRequest(req_->server_, req_->method_index_,
req_->method_, req_->method_tag_);
if (!new_req->Request()) {
// The server must have just decided to shutdown. Erase
// from the list under lock but release the lock before
// deleting the new_req (in case that request was what
// would allow the destruction of the req_list)
{
std::lock_guard<std::mutex> l(new_req->req_list_->reqs_mu);
new_req->req_list_->reqs_list.erase(new_req->req_list_iterator_);
new_req->req_list_->reqs_list_sz--;
}
// The server must have just decided to shutdown.
gpr_atm_no_barrier_fetch_add(
&new_req->server_
->callback_unmatched_reqs_count_[new_req->method_index_],
-1);
delete new_req;
}
}
@ -557,20 +543,17 @@ class Server::CallbackRequest final : public internal::CompletionQueueTag {
}
void Setup() {
gpr_atm_no_barrier_fetch_add(
&server_->callback_unmatched_reqs_count_[method_index_], 1);
grpc_metadata_array_init(&request_metadata_);
ctx_.Setup(gpr_inf_future(GPR_CLOCK_REALTIME));
request_payload_ = nullptr;
request_ = nullptr;
request_status_ = Status();
std::lock_guard<std::mutex> l(req_list_->reqs_mu);
req_list_->reqs_list.push_front(this);
req_list_->reqs_list_sz++;
req_list_iterator_ = req_list_->reqs_list.begin();
}
Server* const server_;
Server::MethodReqList* req_list_;
Server::MethodReqList::iterator req_list_iterator_;
size_t method_index_;
internal::RpcServiceMethod* const method_;
void* const method_tag_;
const bool has_request_payload_;
@ -791,12 +774,12 @@ Server::~Server() {
}
grpc_server_destroy(server_);
for (auto* method_list : callback_reqs_) {
// The entries of the method_list should have already been emptied
// during Shutdown as each request is failed by Shutdown. Check that
// this actually happened.
GPR_ASSERT(method_list->reqs_list.empty());
delete method_list;
for (auto& per_method_count : callback_unmatched_reqs_count_) {
// There should be no more unmatched callbacks for any method
// as each request is failed by Shutdown. Check that this actually
// happened
GPR_ASSERT(static_cast<int>(gpr_atm_no_barrier_load(&per_method_count)) ==
0);
}
}
@ -852,6 +835,7 @@ bool Server::RegisterService(const grpc::string* host, Service* service) {
}
const char* method_name = nullptr;
for (auto it = service->methods_.begin(); it != service->methods_.end();
++it) {
if (it->get() == nullptr) { // Handled by generic service if any.
@ -877,15 +861,15 @@ bool Server::RegisterService(const grpc::string* host, Service* service) {
}
} else {
// a callback method. Register at least some callback requests
callback_reqs_.push_back(new Server::MethodReqList);
auto* method_req_list = callback_reqs_.back();
callback_unmatched_reqs_count_.push_back(0);
auto method_index = callback_unmatched_reqs_count_.size() - 1;
// TODO(vjpai): Register these dynamically based on need
for (int i = 0; i < DEFAULT_CALLBACK_REQS_PER_METHOD; i++) {
new CallbackRequest(this, method_req_list, method,
method_registration_tag);
callback_reqs_to_start_.push_back(new CallbackRequest(
this, method_index, method, method_registration_tag));
}
// Enqueue it so that it will be Request'ed later once
// all request matchers are created at core server startup
// Enqueue it so that it will be Request'ed later after all request
// matchers are created at core server startup
}
method_name = method->name();
@ -974,11 +958,10 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
(*it)->Start();
}
for (auto* cbmethods : callback_reqs_) {
for (auto* cbreq : cbmethods->reqs_list) {
for (auto* cbreq : callback_reqs_to_start_) {
GPR_ASSERT(cbreq->Request());
}
}
callback_reqs_to_start_.clear();
if (default_health_check_service_impl != nullptr) {
default_health_check_service_impl->StartServingThread();

@ -18,33 +18,31 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Grpc.Core.Interceptors;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
/// Mapping of method names to server call handlers.
/// Stores mapping of methods to server call handlers.
/// Normally, the <c>ServerServiceDefinition</c> objects will be created by the <c>BindService</c> factory method
/// that is part of the autogenerated code for a protocol buffers service definition.
/// </summary>
public class ServerServiceDefinition
{
readonly ReadOnlyDictionary<string, IServerCallHandler> callHandlers;
readonly IReadOnlyList<Action<ServiceBinderBase>> addMethodActions;
internal ServerServiceDefinition(Dictionary<string, IServerCallHandler> callHandlers)
internal ServerServiceDefinition(List<Action<ServiceBinderBase>> addMethodActions)
{
this.callHandlers = new ReadOnlyDictionary<string, IServerCallHandler>(callHandlers);
this.addMethodActions = addMethodActions.AsReadOnly();
}
internal IDictionary<string, IServerCallHandler> CallHandlers
/// <summary>
/// Forwards all the previously stored <c>AddMethod</c> calls to the service binder.
/// </summary>
internal void BindService(ServiceBinderBase serviceBinder)
{
get
foreach (var addMethodAction in addMethodActions)
{
return this.callHandlers;
addMethodAction(serviceBinder);
}
}
@ -62,7 +60,10 @@ namespace Grpc.Core
/// </summary>
public class Builder
{
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
// to maintain legacy behavior, we need to detect duplicate keys and throw the same exception as before
readonly Dictionary<string, object> duplicateDetector = new Dictionary<string, object>();
// for each AddMethod call, we store an action that will later register the method and handler with ServiceBinderBase
readonly List<Action<ServiceBinderBase>> addMethodActions = new List<Action<ServiceBinderBase>>();
/// <summary>
/// Creates a new instance of builder.
@ -85,7 +86,8 @@ namespace Grpc.Core
where TRequest : class
where TResponse : class
{
callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler));
duplicateDetector.Add(method.FullName, null);
addMethodActions.Add((serviceBinder) => serviceBinder.AddMethod(method, handler));
return this;
}
@ -103,7 +105,8 @@ namespace Grpc.Core
where TRequest : class
where TResponse : class
{
callHandlers.Add(method.FullName, ServerCalls.ClientStreamingCall(method, handler));
duplicateDetector.Add(method.FullName, null);
addMethodActions.Add((serviceBinder) => serviceBinder.AddMethod(method, handler));
return this;
}
@ -121,7 +124,8 @@ namespace Grpc.Core
where TRequest : class
where TResponse : class
{
callHandlers.Add(method.FullName, ServerCalls.ServerStreamingCall(method, handler));
duplicateDetector.Add(method.FullName, null);
addMethodActions.Add((serviceBinder) => serviceBinder.AddMethod(method, handler));
return this;
}
@ -139,7 +143,8 @@ namespace Grpc.Core
where TRequest : class
where TResponse : class
{
callHandlers.Add(method.FullName, ServerCalls.DuplexStreamingCall(method, handler));
duplicateDetector.Add(method.FullName, null);
addMethodActions.Add((serviceBinder) => serviceBinder.AddMethod(method, handler));
return this;
}
@ -149,7 +154,7 @@ namespace Grpc.Core
/// <returns>The <c>ServerServiceDefinition</c> object.</returns>
public ServerServiceDefinition Build()
{
return new ServerServiceDefinition(callHandlers);
return new ServerServiceDefinition(addMethodActions);
}
}
}

@ -20,8 +20,6 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Grpc.Core.Interceptors;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core
@ -30,7 +28,6 @@ namespace Grpc.Core
/// Allows binding server-side method implementations in alternative serving stacks.
/// Instances of this class are usually populated by the <c>BindService</c> method
/// that is part of the autogenerated code for a protocol buffers service definition.
/// <seealso cref="ServerServiceDefinition"/>
/// </summary>
public class ServiceBinderBase
{

@ -25,7 +25,6 @@ using Grpc.Core.Utils;
// https://docs.microsoft.com/en-us/dotnet/framework/app-domains/type-forwarding-in-the-common-language-runtime
// TODO(jtattermusch): move types needed for implementing a client
// TODO(jtattermusch): ServerServiceDefinition depends on IServerCallHandler (which depends on other stuff)
[assembly:TypeForwardedToAttribute(typeof(ILogger))]
[assembly:TypeForwardedToAttribute(typeof(LogLevel))]
@ -50,6 +49,8 @@ using Grpc.Core.Utils;
[assembly:TypeForwardedToAttribute(typeof(ClientStreamingServerMethod<,>))]
[assembly:TypeForwardedToAttribute(typeof(ServerStreamingServerMethod<,>))]
[assembly:TypeForwardedToAttribute(typeof(DuplexStreamingServerMethod<,>))]
[assembly:TypeForwardedToAttribute(typeof(ServerServiceDefinition))]
[assembly:TypeForwardedToAttribute(typeof(ServiceBinderBase))]
[assembly:TypeForwardedToAttribute(typeof(Status))]
[assembly:TypeForwardedToAttribute(typeof(StatusCode))]
[assembly:TypeForwardedToAttribute(typeof(WriteOptions))]

@ -44,7 +44,10 @@ namespace Grpc.Core.Interceptors
{
GrpcPreconditions.CheckNotNull(serverServiceDefinition, nameof(serverServiceDefinition));
GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
return new ServerServiceDefinition(serverServiceDefinition.CallHandlers.ToDictionary(x => x.Key, x => x.Value.Intercept(interceptor)));
var binder = new InterceptingServiceBinder(interceptor);
serverServiceDefinition.BindService(binder);
return binder.GetInterceptedServerServiceDefinition();
}
/// <summary>
@ -75,5 +78,52 @@ namespace Grpc.Core.Interceptors
return serverServiceDefinition;
}
/// <summary>
/// Helper for creating <c>ServerServiceDefinition</c> with intercepted handlers.
/// </summary>
private class InterceptingServiceBinder : ServiceBinderBase
{
readonly ServerServiceDefinition.Builder builder = ServerServiceDefinition.CreateBuilder();
readonly Interceptor interceptor;
public InterceptingServiceBinder(Interceptor interceptor)
{
this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
}
internal ServerServiceDefinition GetInterceptedServerServiceDefinition()
{
return builder.Build();
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
UnaryServerMethod<TRequest, TResponse> handler)
{
builder.AddMethod(method, (request, context) => interceptor.UnaryServerHandler(request, context, handler));
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
ClientStreamingServerMethod<TRequest, TResponse> handler)
{
builder.AddMethod(method, (requestStream, context) => interceptor.ClientStreamingServerHandler(requestStream, context, handler));
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
ServerStreamingServerMethod<TRequest, TResponse> handler)
{
builder.AddMethod(method, (request, responseStream, context) => interceptor.ServerStreamingServerHandler(request, responseStream, context, handler));
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
DuplexStreamingServerMethod<TRequest, TResponse> handler)
{
builder.AddMethod(method, (requestStream, responseStream, context) => interceptor.DuplexStreamingServerHandler(requestStream, responseStream, context, handler));
}
}
}
}

@ -31,7 +31,6 @@ namespace Grpc.Core.Internal
internal interface IServerCallHandler
{
Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq);
IServerCallHandler Intercept(Interceptor interceptor);
}
internal class UnaryServerCallHandler<TRequest, TResponse> : IServerCallHandler
@ -91,11 +90,6 @@ namespace Grpc.Core.Internal
}
await finishedTask.ConfigureAwait(false);
}
public IServerCallHandler Intercept(Interceptor interceptor)
{
return new UnaryServerCallHandler<TRequest, TResponse>(method, (request, context) => interceptor.UnaryServerHandler(request, context, handler));
}
}
internal class ServerStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler
@ -154,11 +148,6 @@ namespace Grpc.Core.Internal
}
await finishedTask.ConfigureAwait(false);
}
public IServerCallHandler Intercept(Interceptor interceptor)
{
return new ServerStreamingServerCallHandler<TRequest, TResponse>(method, (request, responseStream, context) => interceptor.ServerStreamingServerHandler(request, responseStream, context, handler));
}
}
internal class ClientStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler
@ -217,11 +206,6 @@ namespace Grpc.Core.Internal
}
await finishedTask.ConfigureAwait(false);
}
public IServerCallHandler Intercept(Interceptor interceptor)
{
return new ClientStreamingServerCallHandler<TRequest, TResponse>(method, (requestStream, context) => interceptor.ClientStreamingServerHandler(requestStream, context, handler));
}
}
internal class DuplexStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler
@ -277,11 +261,6 @@ namespace Grpc.Core.Internal
}
await finishedTask.ConfigureAwait(false);
}
public IServerCallHandler Intercept(Interceptor interceptor)
{
return new DuplexStreamingServerCallHandler<TRequest, TResponse>(method, (requestStream, responseStream, context) => interceptor.DuplexStreamingServerHandler(requestStream, responseStream, context, handler));
}
}
internal class UnimplementedMethodCallHandler : IServerCallHandler
@ -310,11 +289,6 @@ namespace Grpc.Core.Internal
{
return callHandlerImpl.HandleCall(newRpc, cq);
}
public IServerCallHandler Intercept(Interceptor interceptor)
{
return this; // Do not intercept unimplemented methods.
}
}
internal static class HandlerUtils

@ -0,0 +1,78 @@
#region Copyright notice and license
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Grpc.Core.Internal;
namespace Grpc.Core.Internal
{
internal static class ServerServiceDefinitionExtensions
{
/// <summary>
/// Maps methods from <c>ServerServiceDefinition</c> to server call handlers.
/// </summary>
internal static ReadOnlyDictionary<string, IServerCallHandler> GetCallHandlers(this ServerServiceDefinition serviceDefinition)
{
var binder = new DefaultServiceBinder();
serviceDefinition.BindService(binder);
return binder.GetCallHandlers();
}
/// <summary>
/// Helper for converting <c>ServerServiceDefinition</c> to server call handlers.
/// </summary>
private class DefaultServiceBinder : ServiceBinderBase
{
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
internal ReadOnlyDictionary<string, IServerCallHandler> GetCallHandlers()
{
return new ReadOnlyDictionary<string, IServerCallHandler>(this.callHandlers);
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
UnaryServerMethod<TRequest, TResponse> handler)
{
callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler));
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
ClientStreamingServerMethod<TRequest, TResponse> handler)
{
callHandlers.Add(method.FullName, ServerCalls.ClientStreamingCall(method, handler));
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
ServerStreamingServerMethod<TRequest, TResponse> handler)
{
callHandlers.Add(method.FullName, ServerCalls.ServerStreamingCall(method, handler));
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
DuplexStreamingServerMethod<TRequest, TResponse> handler)
{
callHandlers.Add(method.FullName, ServerCalls.DuplexStreamingCall(method, handler));
}
}
}
}

@ -257,7 +257,7 @@ namespace Grpc.Core
lock (myLock)
{
GrpcPreconditions.CheckState(!startRequested);
foreach (var entry in serviceDefinition.CallHandlers)
foreach (var entry in serviceDefinition.GetCallHandlers())
{
callHandlers.Add(entry.Key, entry.Value);
}

@ -100,7 +100,7 @@ class _RPCState(object):
self.statused = False
self.rpc_errors = []
self.callbacks = []
self.abortion = None
self.aborted = False
def _raise_rpc_error(state):
@ -287,8 +287,8 @@ class _Context(grpc.ServicerContext):
with self._state.condition:
self._state.code = code
self._state.details = _common.encode(details)
self._state.abortion = Exception()
raise self._state.abortion
self._state.aborted = True
raise Exception()
def abort_with_status(self, status):
self._state.trailing_metadata = status.trailing_metadata
@ -392,7 +392,7 @@ def _call_behavior(rpc_event, state, behavior, argument, request_deserializer):
return behavior(argument, context), True
except Exception as exception: # pylint: disable=broad-except
with state.condition:
if exception is state.abortion:
if state.aborted:
_abort(state, rpc_event.call, cygrpc.StatusCode.unknown,
b'RPC Aborted')
elif exception not in state.rpc_errors:
@ -410,7 +410,7 @@ def _take_response_from_response_iterator(rpc_event, state, response_iterator):
return None, True
except Exception as exception: # pylint: disable=broad-except
with state.condition:
if exception is state.abortion:
if state.aborted:
_abort(state, rpc_event.call, cygrpc.StatusCode.unknown,
b'RPC Aborted')
elif exception not in state.rpc_errors:

@ -15,7 +15,9 @@
import unittest
import collections
import gc
import logging
import weakref
import grpc
@ -39,7 +41,15 @@ class _Status(
pass
class _Object(object):
pass
do_not_leak_me = _Object()
def abort_unary_unary(request, servicer_context):
this_should_not_be_leaked = do_not_leak_me
servicer_context.abort(
grpc.StatusCode.INTERNAL,
_ABORT_DETAILS,
@ -101,6 +111,24 @@ class AbortTest(unittest.TestCase):
self.assertEqual(rpc_error.code(), grpc.StatusCode.INTERNAL)
self.assertEqual(rpc_error.details(), _ABORT_DETAILS)
# This test ensures that abort() does not store the raised exception, which
# on Python 3 (via the `__traceback__` attribute) holds a reference to
# all local vars. Storing the raised exception can prevent GC and stop the
# grpc_call from being unref'ed, even after server shutdown.
def test_abort_does_not_leak_local_vars(self):
global do_not_leak_me # pylint: disable=global-statement
weak_ref = weakref.ref(do_not_leak_me)
# Servicer will abort() after creating a local ref to do_not_leak_me.
with self.assertRaises(grpc.RpcError):
self._channel.unary_unary(_ABORT)(_REQUEST)
# Server may still have a stack frame reference to the exception even
# after client sees error, so ensure server has shutdown.
self._server.stop(None)
do_not_leak_me = None
self.assertIsNone(weak_ref())
def test_abort_with_status(self):
with self.assertRaises(grpc.RpcError) as exception_context:
self._channel.unary_unary(_ABORT_WITH_STATUS)(_REQUEST)

@ -2,5 +2,6 @@
# Bazel installation
RUN apt-get update && apt-get install -y wget && apt-get clean
RUN wget -q https://github.com/bazelbuild/bazel/releases/download/0.17.1/bazel-0.17.1-linux-x86_64 -O /usr/local/bin/bazel
RUN chmod 755 /usr/local/bin/bazel
RUN wget https://github.com/bazelbuild/bazel/releases/download/0.20.0/bazel-0.20.0-installer-linux-x86_64.sh && ${'\\'}
bash ./bazel-0.20.0-installer-linux-x86_64.sh && ${'\\'}
rm bazel-0.20.0-installer-linux-x86_64.sh

@ -32,6 +32,7 @@
RUN python3 -m pip install simplejson mako virtualenv lxml
<%include file="../../clang5.include"/>
<%include file="../../bazel.include"/>
# Define the default command.
CMD ["bash"]

@ -0,0 +1,32 @@
# Copyright 2016 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package")
licenses(["notice"]) # Apache v2
grpc_package(name = "test/core/bad_connection")
grpc_cc_binary(
name = "close_fd_test",
srcs = [
"close_fd_test.cc",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)

@ -0,0 +1,764 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* close_fd_test tests the behavior of grpc core when the transport gets
* disconnected.
* The test creates an http2 transport over a socket pair and closes the
* client or server file descriptor to simulate connection breakage while
* an RPC call is in progress.
*
*/
#include "src/core/lib/iomgr/port.h"
// This test won't work except with posix sockets enabled
#ifdef GRPC_POSIX_SOCKET
#include "test/core/util/test_config.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <grpc/byte_buffer.h>
#include <grpc/byte_buffer_reader.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/iomgr/endpoint_pair.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/completion_queue.h"
#include "src/core/lib/surface/server.h"
static void* tag(intptr_t t) { return (void*)t; }
typedef struct test_ctx test_ctx;
struct test_ctx {
/* completion queue for call notifications on the server */
grpc_completion_queue* cq;
/* completion queue registered to server for shutdown events */
grpc_completion_queue* shutdown_cq;
/* client's completion queue */
grpc_completion_queue* client_cq;
/* completion queue bound to call on the server */
grpc_completion_queue* bound_cq;
/* Server responds to client calls */
grpc_server* server;
/* Client calls are sent over the channel */
grpc_channel* client;
/* encapsulates client, server endpoints */
grpc_endpoint_pair* ep;
};
static test_ctx g_ctx;
/* chttp2 transport that is immediately available (used for testing
connected_channel without a client_channel */
static void server_setup_transport(grpc_transport* transport) {
grpc_core::ExecCtx exec_ctx;
grpc_endpoint_add_to_pollset(g_ctx.ep->server, grpc_cq_pollset(g_ctx.cq));
grpc_server_setup_transport(g_ctx.server, transport, nullptr,
grpc_server_get_channel_args(g_ctx.server),
nullptr);
}
static void client_setup_transport(grpc_transport* transport) {
grpc_core::ExecCtx exec_ctx;
grpc_endpoint_add_to_pollset(g_ctx.ep->client,
grpc_cq_pollset(g_ctx.client_cq));
grpc_arg authority_arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_ARG_DEFAULT_AUTHORITY),
const_cast<char*>("test-authority"));
grpc_channel_args* args =
grpc_channel_args_copy_and_add(nullptr, &authority_arg, 1);
/* TODO (pjaikumar): use GRPC_CLIENT_CHANNEL instead of
* GRPC_CLIENT_DIRECT_CHANNEL */
g_ctx.client = grpc_channel_create("socketpair-target", args,
GRPC_CLIENT_DIRECT_CHANNEL, transport);
grpc_channel_args_destroy(args);
}
static void init_client() {
grpc_core::ExecCtx exec_ctx;
grpc_transport* transport;
transport = grpc_create_chttp2_transport(nullptr, g_ctx.ep->client, true);
client_setup_transport(transport);
GPR_ASSERT(g_ctx.client);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
}
static void init_server() {
grpc_core::ExecCtx exec_ctx;
grpc_transport* transport;
GPR_ASSERT(!g_ctx.server);
g_ctx.server = grpc_server_create(nullptr, nullptr);
grpc_server_register_completion_queue(g_ctx.server, g_ctx.cq, nullptr);
grpc_server_start(g_ctx.server);
transport = grpc_create_chttp2_transport(nullptr, g_ctx.ep->server, false);
server_setup_transport(transport);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
}
static void test_init() {
grpc_endpoint_pair* sfd =
static_cast<grpc_endpoint_pair*>(gpr_malloc(sizeof(grpc_endpoint_pair)));
memset(&g_ctx, 0, sizeof(g_ctx));
g_ctx.ep = sfd;
g_ctx.cq = grpc_completion_queue_create_for_next(nullptr);
g_ctx.shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
g_ctx.bound_cq = grpc_completion_queue_create_for_next(nullptr);
g_ctx.client_cq = grpc_completion_queue_create_for_next(nullptr);
/* Create endpoints */
*sfd = grpc_iomgr_create_endpoint_pair("fixture", nullptr);
/* Create client, server and setup transport over endpoint pair */
init_server();
init_client();
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event event;
do {
event = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(1),
nullptr);
} while (event.type != GRPC_QUEUE_SHUTDOWN);
}
static void drain_and_destroy_cq(grpc_completion_queue* cq) {
grpc_completion_queue_shutdown(cq);
drain_cq(cq);
grpc_completion_queue_destroy(cq);
}
static void shutdown_server() {
if (!g_ctx.server) return;
grpc_server_shutdown_and_notify(g_ctx.server, g_ctx.shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(g_ctx.shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(1),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(g_ctx.server);
g_ctx.server = nullptr;
}
static void shutdown_client() {
if (!g_ctx.client) return;
grpc_channel_destroy(g_ctx.client);
g_ctx.client = nullptr;
}
static void end_test() {
shutdown_server();
shutdown_client();
drain_and_destroy_cq(g_ctx.cq);
drain_and_destroy_cq(g_ctx.client_cq);
drain_and_destroy_cq(g_ctx.bound_cq);
grpc_completion_queue_destroy(g_ctx.shutdown_cq);
gpr_free(g_ctx.ep);
}
typedef enum fd_type { CLIENT_FD, SERVER_FD } fd_type;
static const char* fd_type_str(fd_type fdtype) {
if (fdtype == CLIENT_FD) {
return "client";
} else if (fdtype == SERVER_FD) {
return "server";
} else {
gpr_log(GPR_ERROR, "Unexpected fd_type %d", fdtype);
abort();
}
}
static void _test_close_before_server_recv(fd_type fdtype) {
grpc_core::ExecCtx exec_ctx;
grpc_call* call;
grpc_call* server_call;
grpc_event event;
grpc_slice request_payload_slice =
grpc_slice_from_copied_string("hello world");
grpc_slice response_payload_slice =
grpc_slice_from_copied_string("hello you");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
gpr_log(GPR_INFO, "Running test: test_close_%s_before_server_recv",
fd_type_str(fdtype));
test_init();
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_call_details call_details;
grpc_status_code status = GRPC_STATUS__DO_NOT_USE;
grpc_call_error error;
grpc_slice details;
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(1);
call = grpc_channel_create_call(
g_ctx.client, nullptr, GRPC_PROPAGATE_DEFAULTS, g_ctx.client_cq,
grpc_slice_from_static_string("/foo"), nullptr, deadline, nullptr);
GPR_ASSERT(call);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->flags = 0;
op->reserved = nullptr;
op++;
error = grpc_call_start_batch(call, ops, static_cast<size_t>(op - ops),
tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error = grpc_server_request_call(g_ctx.server, &server_call, &call_details,
&request_metadata_recv, g_ctx.bound_cq,
g_ctx.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
event = grpc_completion_queue_next(
g_ctx.cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
GPR_ASSERT(event.success == 1);
GPR_ASSERT(event.tag == tag(101));
GPR_ASSERT(event.type == GRPC_OP_COMPLETE);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request_payload_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
grpc_endpoint_pair* sfd = g_ctx.ep;
int fd;
if (fdtype == SERVER_FD) {
fd = sfd->server->vtable->get_fd(sfd->server);
} else {
GPR_ASSERT(fdtype == CLIENT_FD);
fd = sfd->client->vtable->get_fd(sfd->client);
}
/* Connection is closed before the server receives the client's message. */
close(fd);
error = grpc_call_start_batch(server_call, ops, static_cast<size_t>(op - ops),
tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
event = grpc_completion_queue_next(
g_ctx.bound_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
/* Batch operation completes on the server side.
* event.success will be true if the op completes successfully.
* event.success will be false if the op completes with an error. This can
* happen due to a race with closing the fd resulting in pending writes
* failing due to stream closure.
* */
GPR_ASSERT(event.type == GRPC_OP_COMPLETE);
GPR_ASSERT(event.tag == tag(102));
event = grpc_completion_queue_next(
g_ctx.client_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
/* When the client fd is closed, the server gets EPIPE.
* When server fd is closed, server gets EBADF.
* In both cases server sends GRPC_STATUS_UNAVALABLE to the client. However,
* the client may not receive this grpc_status as it's socket is being closed.
* If the client didn't get grpc_status from the server it will time out
* waiting on the completion queue. So there 2 2 possibilities:
* 1. client times out waiting for server's response
* 2. client receives GRPC_STATUS_UNAVAILABLE from server
*/
if (event.type == GRPC_QUEUE_TIMEOUT) {
GPR_ASSERT(event.success == 0);
GPR_ASSERT(event.tag == nullptr);
/* status is not initialized */
GPR_ASSERT(status == GRPC_STATUS__DO_NOT_USE);
} else {
GPR_ASSERT(event.type == GRPC_OP_COMPLETE);
GPR_ASSERT(event.success == 1);
GPR_ASSERT(event.tag == tag(1));
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
}
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_unref(call);
grpc_call_unref(server_call);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
end_test();
}
static void test_close_before_server_recv() {
/* Close client side of the connection before server receives message from
* client */
_test_close_before_server_recv(CLIENT_FD);
/* Close server side of the connection before server receives message from
* client */
_test_close_before_server_recv(SERVER_FD);
}
static void _test_close_before_server_send(fd_type fdtype) {
grpc_core::ExecCtx exec_ctx;
grpc_call* call;
grpc_call* server_call;
grpc_event event;
grpc_slice request_payload_slice =
grpc_slice_from_copied_string("hello world");
grpc_slice response_payload_slice =
grpc_slice_from_copied_string("hello you");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
gpr_log(GPR_INFO, "Running test: test_close_%s_before_server_send",
fd_type_str(fdtype));
test_init();
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_call_details call_details;
grpc_status_code status = GRPC_STATUS__DO_NOT_USE;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(1);
call = grpc_channel_create_call(
g_ctx.client, nullptr, GRPC_PROPAGATE_DEFAULTS, g_ctx.client_cq,
grpc_slice_from_static_string("/foo"), nullptr, deadline, nullptr);
GPR_ASSERT(call);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->flags = 0;
op->reserved = nullptr;
op++;
error = grpc_call_start_batch(call, ops, static_cast<size_t>(op - ops),
tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error = grpc_server_request_call(g_ctx.server, &server_call, &call_details,
&request_metadata_recv, g_ctx.bound_cq,
g_ctx.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
event = grpc_completion_queue_next(
g_ctx.cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
GPR_ASSERT(event.success == 1);
GPR_ASSERT(event.tag == tag(101));
GPR_ASSERT(event.type == GRPC_OP_COMPLETE);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request_payload_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
error = grpc_call_start_batch(server_call, ops, static_cast<size_t>(op - ops),
tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
event = grpc_completion_queue_next(
g_ctx.bound_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
GPR_ASSERT(event.type == GRPC_OP_COMPLETE);
GPR_ASSERT(event.success == 1);
GPR_ASSERT(event.tag == tag(102));
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = response_payload;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_OK;
grpc_slice status_details = grpc_slice_from_static_string("xyz");
op->data.send_status_from_server.status_details = &status_details;
op->flags = 0;
op->reserved = nullptr;
op++;
grpc_endpoint_pair* sfd = g_ctx.ep;
int fd;
if (fdtype == SERVER_FD) {
fd = sfd->server->vtable->get_fd(sfd->server);
} else {
GPR_ASSERT(fdtype == CLIENT_FD);
fd = sfd->client->vtable->get_fd(sfd->client);
}
/* Connection is closed before the server sends message and status to the
* client. */
close(fd);
error = grpc_call_start_batch(server_call, ops, static_cast<size_t>(op - ops),
tag(103), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
/* Batch operation succeeds on the server side */
event = grpc_completion_queue_next(
g_ctx.bound_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
GPR_ASSERT(event.type == GRPC_OP_COMPLETE);
GPR_ASSERT(event.success == 1);
GPR_ASSERT(event.tag == tag(103));
event = grpc_completion_queue_next(
g_ctx.client_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
/* In both cases server sends GRPC_STATUS_UNAVALABLE to the client. However,
* the client may not receive this grpc_status as it's socket is being closed.
* If the client didn't get grpc_status from the server it will time out
* waiting on the completion queue
*/
if (event.type == GRPC_OP_COMPLETE) {
GPR_ASSERT(event.success == 1);
GPR_ASSERT(event.tag == tag(1));
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
} else {
GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT);
GPR_ASSERT(event.success == 0);
GPR_ASSERT(event.tag == nullptr);
/* status is not initialized */
GPR_ASSERT(status == GRPC_STATUS__DO_NOT_USE);
}
GPR_ASSERT(was_cancelled == 0);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_unref(call);
grpc_call_unref(server_call);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
end_test();
}
static void test_close_before_server_send() {
/* Close client side of the connection before server sends message to client
* */
_test_close_before_server_send(CLIENT_FD);
/* Close server side of the connection before server sends message to client
* */
_test_close_before_server_send(SERVER_FD);
}
static void _test_close_before_client_send(fd_type fdtype) {
grpc_core::ExecCtx exec_ctx;
grpc_call* call;
grpc_event event;
grpc_slice request_payload_slice =
grpc_slice_from_copied_string("hello world");
grpc_slice response_payload_slice =
grpc_slice_from_copied_string("hello you");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
gpr_log(GPR_INFO, "Running test: test_close_%s_before_client_send",
fd_type_str(fdtype));
test_init();
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_call_details call_details;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(1);
call = grpc_channel_create_call(
g_ctx.client, nullptr, GRPC_PROPAGATE_DEFAULTS, g_ctx.client_cq,
grpc_slice_from_static_string("/foo"), nullptr, deadline, nullptr);
GPR_ASSERT(call);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->flags = 0;
op->reserved = nullptr;
op++;
grpc_endpoint_pair* sfd = g_ctx.ep;
int fd;
if (fdtype == SERVER_FD) {
fd = sfd->server->vtable->get_fd(sfd->server);
} else {
GPR_ASSERT(fdtype == CLIENT_FD);
fd = sfd->client->vtable->get_fd(sfd->client);
}
/* Connection is closed before the client sends a batch to the server */
close(fd);
error = grpc_call_start_batch(call, ops, static_cast<size_t>(op - ops),
tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
/* Status unavailable is returned to the client when client or server fd is
* closed */
event = grpc_completion_queue_next(
g_ctx.client_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
GPR_ASSERT(event.success == 1);
GPR_ASSERT(event.type == GRPC_OP_COMPLETE);
GPR_ASSERT(event.tag == tag(1));
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
/* No event is received on the server */
event = grpc_completion_queue_next(
g_ctx.cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
GPR_ASSERT(event.success == 0);
GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT);
GPR_ASSERT(event.tag == nullptr);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_unref(call);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
end_test();
}
static void test_close_before_client_send() {
/* Close client side of the connection before client sends message to server
* */
_test_close_before_client_send(CLIENT_FD);
/* Close server side of the connection before client sends message to server
* */
_test_close_before_client_send(SERVER_FD);
}
static void _test_close_before_call_create(fd_type fdtype) {
grpc_core::ExecCtx exec_ctx;
grpc_call* call;
grpc_event event;
test_init();
gpr_timespec deadline = grpc_timeout_milliseconds_to_deadline(100);
grpc_endpoint_pair* sfd = g_ctx.ep;
int fd;
if (fdtype == SERVER_FD) {
fd = sfd->server->vtable->get_fd(sfd->server);
} else {
GPR_ASSERT(fdtype == CLIENT_FD);
fd = sfd->client->vtable->get_fd(sfd->client);
}
/* Connection is closed before the client creates a call */
close(fd);
call = grpc_channel_create_call(
g_ctx.client, nullptr, GRPC_PROPAGATE_DEFAULTS, g_ctx.client_cq,
grpc_slice_from_static_string("/foo"), nullptr, deadline, nullptr);
GPR_ASSERT(call);
/* Client and server time out waiting on their completion queues and nothing
* is sent or received */
event = grpc_completion_queue_next(
g_ctx.client_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT);
GPR_ASSERT(event.success == 0);
GPR_ASSERT(event.tag == nullptr);
event = grpc_completion_queue_next(
g_ctx.cq, grpc_timeout_milliseconds_to_deadline(100), nullptr);
GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT);
GPR_ASSERT(event.success == 0);
GPR_ASSERT(event.tag == nullptr);
grpc_call_unref(call);
end_test();
}
static void test_close_before_call_create() {
/* Close client side of the connection before client creates a call */
_test_close_before_call_create(CLIENT_FD);
/* Close server side of the connection before client creates a call */
_test_close_before_call_create(SERVER_FD);
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
/* Init grpc */
grpc_init();
int iterations = 10;
for (int i = 0; i < iterations; ++i) {
test_close_before_call_create();
test_close_before_client_send();
test_close_before_server_recv();
test_close_before_server_send();
}
grpc_shutdown();
return 0;
}
#else /* GRPC_POSIX_SOCKET */
int main(int argc, char** argv) { return 1; }
#endif /* GRPC_POSIX_SOCKET */

@ -112,7 +112,7 @@ TEST_F(ChannelzRegistryTest, NullIfNotPresentTest) {
}
TEST_F(ChannelzRegistryTest, TestCompaction) {
const int kLoopIterations = 100;
const int kLoopIterations = 300;
// These channels that will stay in the registry for the duration of the test.
std::vector<UniquePtr<BaseNode>> even_channels;
even_channels.reserve(kLoopIterations);

@ -164,13 +164,13 @@ static void test2(void) {
size_t num_inserted = 0;
grpc_timer_heap_init(&pq);
memset(elems, 0, elems_size);
memset(elems, 0, elems_size * sizeof(elems[0]));
for (size_t round = 0; round < 10000; round++) {
int r = rand() % 1000;
if (r <= 550) {
/* 55% of the time we try to add something */
elem_struct* el = search_elems(elems, GPR_ARRAY_SIZE(elems), false);
elem_struct* el = search_elems(elems, elems_size, false);
if (el != nullptr) {
el->elem.deadline = random_deadline();
grpc_timer_heap_add(&pq, &el->elem);
@ -180,7 +180,7 @@ static void test2(void) {
}
} else if (r <= 650) {
/* 10% of the time we try to remove something */
elem_struct* el = search_elems(elems, GPR_ARRAY_SIZE(elems), true);
elem_struct* el = search_elems(elems, elems_size, true);
if (el != nullptr) {
grpc_timer_heap_remove(&pq, &el->elem);
el->inserted = false;

@ -534,7 +534,7 @@ static void test_channel_oauth2_google_iam_composite_creds(void) {
static void validate_compute_engine_http_request(
const grpc_httpcli_request* request) {
GPR_ASSERT(request->handshaker != &grpc_httpcli_ssl);
GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
GPR_ASSERT(strcmp(request->host, "metadata.google.internal.") == 0);
GPR_ASSERT(
strcmp(request->http.path,
"/computeMetadata/v1/instance/service-accounts/default/token") ==
@ -930,7 +930,7 @@ static int default_creds_metadata_server_detection_httpcli_get_success_override(
response->hdr_count = 1;
response->hdrs = headers;
GPR_ASSERT(strcmp(request->http.path, "/") == 0);
GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
GPR_ASSERT(strcmp(request->host, "metadata.google.internal.") == 0);
GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
return 1;
}
@ -1020,7 +1020,7 @@ static int default_creds_gce_detection_httpcli_get_failure_override(
grpc_closure* on_done, grpc_httpcli_response* response) {
/* No magic header. */
GPR_ASSERT(strcmp(request->http.path, "/") == 0);
GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
GPR_ASSERT(strcmp(request->host, "metadata.google.internal.") == 0);
*response = http_response(200, "");
GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
return 1;

@ -776,10 +776,24 @@ void ssl_tsi_test_handshaker_factory_internals() {
test_tsi_ssl_client_handshaker_factory_bad_params();
}
void ssl_tsi_test_duplicate_root_certificates() {
char* root_cert = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "ca.pem");
char* dup_root_cert = static_cast<char*>(
gpr_zalloc(sizeof(char) * (strlen(root_cert) * 2 + 1)));
memcpy(dup_root_cert, root_cert, strlen(root_cert));
memcpy(dup_root_cert + strlen(root_cert), root_cert, strlen(root_cert));
tsi_ssl_root_certs_store* root_store =
tsi_ssl_root_certs_store_create(dup_root_cert);
GPR_ASSERT(root_store != nullptr);
// Free memory.
tsi_ssl_root_certs_store_destroy(root_store);
gpr_free(root_cert);
gpr_free(dup_root_cert);
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
ssl_tsi_test_do_handshake_tiny_handshake_buffer();
ssl_tsi_test_do_handshake_small_handshake_buffer();
ssl_tsi_test_do_handshake();
@ -801,6 +815,7 @@ int main(int argc, char** argv) {
ssl_tsi_test_do_round_trip_for_all_configs();
ssl_tsi_test_do_round_trip_odd_buffer_size();
ssl_tsi_test_handshaker_factory_internals();
ssl_tsi_test_duplicate_root_certificates();
grpc_shutdown();
return 0;
}

@ -1,11 +1,4 @@
# boringssl stuff
nonnull-attribute:bn_wexpand
nonnull-attribute:CBB_add_bytes
nonnull-attribute:rsa_blinding_get
nonnull-attribute:ssl_copy_key_material
alignment:CRYPTO_cbc128_encrypt
alignment:CRYPTO_gcm128_encrypt
alignment:poly1305_block_copy
# Protobuf stuff
nonnull-attribute:google::protobuf::*
alignment:google::protobuf::*
nonnull-attribute:_tr_stored_block

@ -47,6 +47,44 @@ TEST(AlarmTest, RegularExpiry) {
EXPECT_EQ(junk, output_tag);
}
TEST(AlarmTest, RegularExpiryMultiSet) {
CompletionQueue cq;
void* junk = reinterpret_cast<void*>(1618033);
Alarm alarm;
for (int i = 0; i < 3; i++) {
alarm.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
void* output_tag;
bool ok;
const CompletionQueue::NextStatus status =
cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
EXPECT_TRUE(ok);
EXPECT_EQ(junk, output_tag);
}
}
TEST(AlarmTest, RegularExpiryMultiSetMultiCQ) {
void* junk = reinterpret_cast<void*>(1618033);
Alarm alarm;
for (int i = 0; i < 3; i++) {
CompletionQueue cq;
alarm.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk);
void* output_tag;
bool ok;
const CompletionQueue::NextStatus status =
cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
EXPECT_TRUE(ok);
EXPECT_EQ(junk, output_tag);
}
}
struct Completion {
bool completed = false;
std::mutex mu;

@ -80,6 +80,27 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "time_change_test",
srcs = ["time_change_test.cc"],
data = [
":client_crash_test_server",
],
external_deps = [
"gtest",
],
deps = [
":test_service_impl",
"//:gpr",
"//:grpc",
"//:grpc++",
"//src/proto/grpc/testing:echo_messages_proto",
"//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util",
"//test/cpp/util:test_util",
],
)
grpc_cc_test(
name = "client_crash_test",
srcs = ["client_crash_test.cc"],
@ -110,6 +131,7 @@ grpc_cc_binary(
"gtest",
],
deps = [
":test_service_impl",
"//:gpr",
"//:grpc",
"//:grpc++",
@ -219,10 +241,10 @@ grpc_cc_test(
grpc_cc_test(
name = "end2end_test",
size = "large", # with poll-cv this takes long, see #17493
deps = [
":end2end_test_lib",
],
size = "large", # with poll-cv this takes long, see #17493
)
grpc_cc_test(

@ -0,0 +1,422 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include <grpcpp/server_context.h>
#include "src/core/lib/iomgr/timer.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/end2end/test_service_impl.h"
#include "test/cpp/util/subprocess.h"
#include <gtest/gtest.h>
#include <pthread.h>
#include <sys/time.h>
#include <thread>
using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse;
static std::string g_root;
static gpr_mu g_mu;
extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
gpr_timespec (*gpr_now_impl_orig)(gpr_clock_type clock_type) = gpr_now_impl;
static int g_time_shift_sec = 0;
static int g_time_shift_nsec = 0;
static gpr_timespec now_impl(gpr_clock_type clock) {
auto ts = gpr_now_impl_orig(clock);
// We only manipulate the realtime clock to simulate changes in wall-clock
// time
if (clock != GPR_CLOCK_REALTIME) {
return ts;
}
GPR_ASSERT(ts.tv_nsec >= 0);
GPR_ASSERT(ts.tv_nsec < GPR_NS_PER_SEC);
gpr_mu_lock(&g_mu);
ts.tv_sec += g_time_shift_sec;
ts.tv_nsec += g_time_shift_nsec;
gpr_mu_unlock(&g_mu);
if (ts.tv_nsec >= GPR_NS_PER_SEC) {
ts.tv_nsec -= GPR_NS_PER_SEC;
++ts.tv_sec;
} else if (ts.tv_nsec < 0) {
--ts.tv_sec;
ts.tv_nsec = GPR_NS_PER_SEC + ts.tv_nsec;
}
return ts;
}
// offset the value returned by gpr_now(GPR_CLOCK_REALTIME) by msecs
// milliseconds
static void set_now_offset(int msecs) {
g_time_shift_sec = msecs / 1000;
g_time_shift_nsec = (msecs % 1000) * 1e6;
}
// restore the original implementation of gpr_now()
static void reset_now_offset() {
g_time_shift_sec = 0;
g_time_shift_nsec = 0;
}
namespace grpc {
namespace testing {
namespace {
// gpr_now() is called with invalid clock_type
TEST(TimespecTest, GprNowInvalidClockType) {
// initialize to some junk value
gpr_clock_type invalid_clock_type = (gpr_clock_type)32641;
EXPECT_DEATH(gpr_now(invalid_clock_type), ".*");
}
// Add timespan with negative nanoseconds
TEST(TimespecTest, GprTimeAddNegativeNs) {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec bad_ts = {1, -1000, GPR_TIMESPAN};
EXPECT_DEATH(gpr_time_add(now, bad_ts), ".*");
}
// Subtract timespan with negative nanoseconds
TEST(TimespecTest, GprTimeSubNegativeNs) {
// Nanoseconds must always be positive. Negative timestamps are represented by
// (negative seconds, positive nanoseconds)
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec bad_ts = {1, -1000, GPR_TIMESPAN};
EXPECT_DEATH(gpr_time_sub(now, bad_ts), ".*");
}
// Add negative milliseconds to gpr_timespec
TEST(TimespecTest, GrpcNegativeMillisToTimespec) {
// -1500 milliseconds converts to timespec (-2 secs, 5 * 10^8 nsec)
gpr_timespec ts = grpc_millis_to_timespec(-1500, GPR_CLOCK_MONOTONIC);
GPR_ASSERT(ts.tv_sec = -2);
GPR_ASSERT(ts.tv_nsec = 5e8);
GPR_ASSERT(ts.clock_type == GPR_CLOCK_MONOTONIC);
}
class TimeChangeTest : public ::testing::Test {
protected:
TimeChangeTest() {}
void SetUp() {
auto port = grpc_pick_unused_port_or_die();
std::ostringstream addr_stream;
addr_stream << "localhost:" << port;
auto addr = addr_stream.str();
server_.reset(new SubProcess({
g_root + "/client_crash_test_server",
"--address=" + addr,
}));
GPR_ASSERT(server_);
channel_ = CreateChannel(addr, InsecureChannelCredentials());
GPR_ASSERT(channel_);
stub_ = grpc::testing::EchoTestService::NewStub(channel_);
}
void TearDown() {
server_.reset();
reset_now_offset();
}
std::unique_ptr<grpc::testing::EchoTestService::Stub> CreateStub() {
return grpc::testing::EchoTestService::NewStub(channel_);
}
std::shared_ptr<Channel> GetChannel() { return channel_; }
// time jump offsets in milliseconds
const int TIME_OFFSET1 = 20123;
const int TIME_OFFSET2 = 5678;
private:
std::unique_ptr<SubProcess> server_;
std::shared_ptr<Channel> channel_;
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
};
// Wall-clock time jumps forward on client before bidi stream is created
TEST_F(TimeChangeTest, TimeJumpForwardBeforeStreamCreated) {
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
context.AddMetadata(kServerResponseStreamsToSend, "1");
auto channel = GetChannel();
GPR_ASSERT(channel);
EXPECT_TRUE(
channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
auto stub = CreateStub();
// time jumps forward by TIME_OFFSET1 milliseconds
set_now_offset(TIME_OFFSET1);
auto stream = stub->BidiStream(&context);
request.set_message("Hello");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->WritesDone());
EXPECT_TRUE(stream->Read(&response));
auto status = stream->Finish();
EXPECT_TRUE(status.ok());
}
// Wall-clock time jumps back on client before bidi stream is created
TEST_F(TimeChangeTest, TimeJumpBackBeforeStreamCreated) {
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
context.AddMetadata(kServerResponseStreamsToSend, "1");
auto channel = GetChannel();
GPR_ASSERT(channel);
EXPECT_TRUE(
channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
auto stub = CreateStub();
// time jumps back by TIME_OFFSET1 milliseconds
set_now_offset(-TIME_OFFSET1);
auto stream = stub->BidiStream(&context);
request.set_message("Hello");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->WritesDone());
EXPECT_TRUE(stream->Read(&response));
EXPECT_EQ(request.message(), response.message());
auto status = stream->Finish();
EXPECT_TRUE(status.ok());
}
// Wall-clock time jumps forward on client while call is in progress
TEST_F(TimeChangeTest, TimeJumpForwardAfterStreamCreated) {
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
context.AddMetadata(kServerResponseStreamsToSend, "2");
auto channel = GetChannel();
GPR_ASSERT(channel);
EXPECT_TRUE(
channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
auto stub = CreateStub();
auto stream = stub->BidiStream(&context);
request.set_message("Hello");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->Read(&response));
// time jumps forward by TIME_OFFSET1 milliseconds.
set_now_offset(TIME_OFFSET1);
request.set_message("World");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->WritesDone());
EXPECT_TRUE(stream->Read(&response));
auto status = stream->Finish();
EXPECT_TRUE(status.ok());
}
// Wall-clock time jumps back on client while call is in progress
TEST_F(TimeChangeTest, TimeJumpBackAfterStreamCreated) {
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
context.AddMetadata(kServerResponseStreamsToSend, "2");
auto channel = GetChannel();
GPR_ASSERT(channel);
EXPECT_TRUE(
channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
auto stub = CreateStub();
auto stream = stub->BidiStream(&context);
request.set_message("Hello");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->Read(&response));
// time jumps back TIME_OFFSET1 milliseconds.
set_now_offset(-TIME_OFFSET1);
request.set_message("World");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->WritesDone());
EXPECT_TRUE(stream->Read(&response));
auto status = stream->Finish();
EXPECT_TRUE(status.ok());
}
// Wall-clock time jumps forward on client before connection to server is up
TEST_F(TimeChangeTest, TimeJumpForwardBeforeServerConnect) {
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
context.AddMetadata(kServerResponseStreamsToSend, "2");
auto channel = GetChannel();
GPR_ASSERT(channel);
// time jumps forward by TIME_OFFSET2 milliseconds
set_now_offset(TIME_OFFSET2);
auto ret =
channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000));
// We use monotonic clock for pthread_cond_timedwait() deadline on linux, and
// realtime clock on other platforms - see gpr_cv_wait() in sync_posix.cc.
// So changes in system clock affect deadlines on non-linux platforms
#ifdef GPR_LINUX
EXPECT_TRUE(ret);
auto stub = CreateStub();
auto stream = stub->BidiStream(&context);
request.set_message("Hello");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->Read(&response));
request.set_message("World");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->WritesDone());
EXPECT_TRUE(stream->Read(&response));
auto status = stream->Finish();
EXPECT_TRUE(status.ok());
#else
EXPECT_FALSE(ret);
#endif
}
// Wall-clock time jumps back on client before connection to server is up
TEST_F(TimeChangeTest, TimeJumpBackBeforeServerConnect) {
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
context.AddMetadata(kServerResponseStreamsToSend, "2");
auto channel = GetChannel();
GPR_ASSERT(channel);
// time jumps back by TIME_OFFSET2 milliseconds
set_now_offset(-TIME_OFFSET2);
EXPECT_TRUE(
channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
auto stub = CreateStub();
auto stream = stub->BidiStream(&context);
request.set_message("Hello");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->Read(&response));
request.set_message("World");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->WritesDone());
EXPECT_TRUE(stream->Read(&response));
auto status = stream->Finish();
EXPECT_TRUE(status.ok());
}
// Wall-clock time jumps forward and backwards during call
TEST_F(TimeChangeTest, TimeJumpForwardAndBackDuringCall) {
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(5000));
context.AddMetadata(kServerResponseStreamsToSend, "2");
auto channel = GetChannel();
GPR_ASSERT(channel);
EXPECT_TRUE(
channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(5000)));
auto stub = CreateStub();
auto stream = stub->BidiStream(&context);
request.set_message("Hello");
EXPECT_TRUE(stream->Write(request));
// time jumps back by TIME_OFFSET2 milliseconds
set_now_offset(-TIME_OFFSET2);
EXPECT_TRUE(stream->Read(&response));
request.set_message("World");
// time jumps forward by TIME_OFFSET milliseconds
set_now_offset(TIME_OFFSET1);
EXPECT_TRUE(stream->Write(request));
// time jumps back by TIME_OFFSET2 milliseconds
set_now_offset(-TIME_OFFSET2);
EXPECT_TRUE(stream->WritesDone());
// time jumps back by TIME_OFFSET2 milliseconds
set_now_offset(-TIME_OFFSET2);
EXPECT_TRUE(stream->Read(&response));
// time jumps back by TIME_OFFSET2 milliseconds
set_now_offset(-TIME_OFFSET2);
auto status = stream->Finish();
EXPECT_TRUE(status.ok());
}
} // namespace
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
std::string me = argv[0];
// get index of last slash in path to test binary
auto lslash = me.rfind('/');
// set g_root = path to directory containing test binary
if (lslash != std::string::npos) {
g_root = me.substr(0, lslash);
} else {
g_root = ".";
}
gpr_mu_init(&g_mu);
gpr_now_impl = now_impl;
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
auto ret = RUN_ALL_TESTS();
return ret;
}

@ -16,19 +16,19 @@
*
*/
#include "test/cpp/util/channel_trace_proto_helper.h"
#include <grpc/support/port_platform.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/util/json_util.h>
#include "test/cpp/util/channel_trace_proto_helper.h"
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/config_protobuf.h>
#include <gtest/gtest.h>
#include "src/proto/grpc/channelz/channelz.pb.h"
namespace grpc {
namespace testing {
namespace {
@ -37,25 +37,24 @@ namespace {
// according to https://developers.google.com/protocol-buffers/docs/proto3#json
template <typename Message>
void VaidateProtoJsonTranslation(char* json_c_str) {
std::string json_str(json_c_str);
grpc::string json_str(json_c_str);
Message msg;
google::protobuf::util::JsonParseOptions parse_options;
grpc::protobuf::json::JsonParseOptions parse_options;
// If the following line is failing, then uncomment the last line of the
// comment, and uncomment the lines that print the two strings. You can
// then compare the output, and determine what fields are missing.
//
// parse_options.ignore_unknown_fields = true;
EXPECT_EQ(google::protobuf::util::JsonStringToMessage(json_str, &msg,
parse_options),
google::protobuf::util::Status::OK);
std::string proto_json_str;
google::protobuf::util::JsonPrintOptions print_options;
grpc::protobuf::util::Status s =
grpc::protobuf::json::JsonStringToMessage(json_str, &msg, parse_options);
EXPECT_TRUE(s.ok());
grpc::string proto_json_str;
grpc::protobuf::json::JsonPrintOptions print_options;
// We usually do not want this to be true, however it can be helpful to
// uncomment and see the output produced then all fields are printed.
// print_options.always_print_primitive_fields = true;
EXPECT_EQ(google::protobuf::util::MessageToJsonString(msg, &proto_json_str,
print_options),
google::protobuf::util::Status::OK);
s = grpc::protobuf::json::MessageToJsonString(msg, &proto_json_str);
EXPECT_TRUE(s.ok());
// uncomment these to compare the the json strings.
// gpr_log(GPR_ERROR, "tracer json: %s", json_str.c_str());
// gpr_log(GPR_ERROR, "proto json: %s", proto_json_str.c_str());
@ -64,6 +63,8 @@ void VaidateProtoJsonTranslation(char* json_c_str) {
} // namespace
namespace testing {
void ValidateChannelTraceProtoJsonTranslation(char* json_c_str) {
VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>(json_c_str);
}

@ -52,8 +52,9 @@ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 t
# Bazel installation
RUN apt-get update && apt-get install -y wget && apt-get clean
RUN wget -q https://github.com/bazelbuild/bazel/releases/download/0.17.1/bazel-0.17.1-linux-x86_64 -O /usr/local/bin/bazel
RUN chmod 755 /usr/local/bin/bazel
RUN wget https://github.com/bazelbuild/bazel/releases/download/0.20.0/bazel-0.20.0-installer-linux-x86_64.sh && \
bash ./bazel-0.20.0-installer-linux-x86_64.sh && \
rm bazel-0.20.0-installer-linux-x86_64.sh
RUN mkdir -p /var/local/jenkins

@ -94,6 +94,14 @@ ENV CLANG_FORMAT=clang-format
RUN ln -s /clang+llvm-5.0.0-linux-x86_64-ubuntu14.04/bin/clang-tidy /usr/local/bin/clang-tidy
ENV CLANG_TIDY=clang-tidy
#========================
# Bazel installation
RUN apt-get update && apt-get install -y wget && apt-get clean
RUN wget https://github.com/bazelbuild/bazel/releases/download/0.20.0/bazel-0.20.0-installer-linux-x86_64.sh && \
bash ./bazel-0.20.0-installer-linux-x86_64.sh && \
rm bazel-0.20.0-installer-linux-x86_64.sh
# Define the default command.
CMD ["bash"]

@ -22,7 +22,7 @@ cd "$(dirname "$0")"
CLOUD_PROJECT=grpc-testing
ZONE=us-central1-b # this zone allows 32core machines
LATEST_PERF_WORKER_IMAGE=grpc-performance-kokoro-v3 # update if newer image exists
LATEST_PERF_WORKER_IMAGE=grpc-performance-kokoro-v4 # update if newer image exists
INSTANCE_NAME="${1:-grpc-kokoro-performance-server}"
MACHINE_TYPE="${2:-n1-standard-32}"

@ -215,6 +215,11 @@ sudo mkdir /tmpfs
sudo chown kbuilder /tmpfs
touch /tmpfs/READY
# Disable automatic updates to prevent spurious apt-get install failures
# See https://github.com/grpc/grpc/issues/17794
sudo sed -i 's/APT::Periodic::Update-Package-Lists "1"/APT::Periodic::Update-Package-Lists "0"/' /etc/apt/apt.conf.d/10periodic
sudo sed -i 's/APT::Periodic::AutocleanInterval "1"/APT::Periodic::AutocleanInterval "0"/' /etc/apt/apt.conf.d/10periodic
# Restart for VM to pick up kernel update
echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
sleep 10

@ -21,13 +21,7 @@ ulimit -c unlimited
# Performance PR testing needs GH API key and PR metadata to comment results
if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ]; then
retry=0
until [ $retry -ge 3 ]
do
sudo apt-get install -y jq && break
retry=$[$retry+1]
sleep 5
done
sudo apt-get install -y jq
export ghprbTargetBranch=$(curl -s https://api.github.com/repos/grpc/grpc/pulls/$KOKORO_GITHUB_PULL_REQUEST_NUMBER | jq -r .base.ref)
fi

@ -23,13 +23,7 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_rc
# If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests
if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ] && [ -n "$RUN_TESTS_FLAGS" ]; then
sudo apt-get update
retry=0
until [ $retry -ge 3 ]
do
sudo apt-get install -y jq && break
retry=$[$retry+1]
sleep 5
done
sudo apt-get install -y jq
ghprbTargetBranch=$(curl -s https://api.github.com/repos/grpc/grpc/pulls/$KOKORO_GITHUB_PULL_REQUEST_NUMBER | jq -r .base.ref)
export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$ghprbTargetBranch"
fi

@ -16,7 +16,7 @@
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/macos/grpc_ios_binary_size.sh"
timeout_mins: 60
timeout_mins: 90
before_action {
fetch_keystore {
keystore_resource {

@ -271,6 +271,22 @@
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
"grpc",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c",
"name": "close_fd_test",
"src": [
"test/core/bad_connection/close_fd_test.cc"
],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
@ -4894,6 +4910,24 @@
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
"grpc",
"grpc++",
"grpc++_test_util",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c++",
"name": "time_change_test",
"src": [
"test/cpp/end2end/time_change_test.cc"
],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",

@ -311,6 +311,30 @@
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix"
],
"cpu_cost": 1.0,
"exclude_configs": [
"tsan"
],
"exclude_iomgrs": [],
"flaky": false,
"gtest": false,
"language": "c",
"name": "close_fd_test",
"platforms": [
"linux",
"mac",
"posix"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
@ -5548,6 +5572,28 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "time_change_test",
"platforms": [
"linux",
"mac",
"posix"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,

@ -1,9 +0,0 @@
set noparent
# These owners are in place to ensure that scenario_result_schema.json is not
# modified without also running tools/run_tests/performance/patch_scenario_results_schema.py
# to update the BigQuery schema
@ncteisen
@apolcyn
@jtattermusch

@ -229,7 +229,7 @@ class JavaLanguage:
return {}
def unimplemented_test_cases(self):
return _SKIP_GOOGLE_DEFAULT_CREDS
return []
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
@ -254,7 +254,7 @@ class JavaOkHttpClient:
return {}
def unimplemented_test_cases(self):
return _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE + _SKIP_GOOGLE_DEFAULT_CREDS
return _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def __str__(self):
return 'javaokhttp'
@ -285,7 +285,7 @@ class GoLanguage:
return {}
def unimplemented_test_cases(self):
return _SKIP_COMPRESSION + _SKIP_GOOGLE_DEFAULT_CREDS
return _SKIP_COMPRESSION
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION

Loading…
Cancel
Save