Merge remote-tracking branch 'upstream/master' into lazy-deframe

pull/9626/head
Muxi Yan 8 years ago
commit 3a0b8477c2
  1. 16
      BUILD
  2. 48
      CMakeLists.txt
  3. 51
      Makefile
  4. 78
      binding.gyp
  5. 21
      build.yaml
  6. 2
      cmake/msvc_static_runtime.cmake
  7. 3
      doc/PROTOCOL-WEB.md
  8. 2
      grpc.gemspec
  9. 1
      include/grpc++/impl/codegen/call.h
  10. 1
      include/grpc++/impl/codegen/core_codegen.h
  11. 1
      include/grpc++/impl/codegen/core_codegen_interface.h
  12. 30
      include/grpc/impl/codegen/grpc_types.h
  13. 2
      package.json
  14. 20
      src/core/ext/filters/client_channel/client_channel.c
  15. 5
      src/core/ext/filters/client_channel/subchannel.c
  16. 29
      src/core/ext/filters/max_age/max_age_filter.c
  17. 7
      src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
  18. 184
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  19. 22
      src/core/ext/transport/chttp2/transport/frame_ping.c
  20. 18
      src/core/ext/transport/chttp2/transport/internal.h
  21. 20
      src/core/ext/transport/chttp2/transport/writing.c
  22. 2
      src/core/ext/transport/cronet/transport/cronet_transport.c
  23. 5
      src/core/lib/iomgr/endpoint_pair.h
  24. 17
      src/core/lib/iomgr/endpoint_pair_posix.c
  25. 5
      src/core/lib/iomgr/endpoint_pair_uv.c
  26. 15
      src/core/lib/iomgr/endpoint_pair_windows.c
  27. 35
      src/core/lib/iomgr/error.c
  28. 4
      src/core/lib/iomgr/ev_epoll_linux.c
  29. 4
      src/core/lib/iomgr/ev_poll_posix.c
  30. 6
      src/core/lib/iomgr/ev_posix.c
  31. 3
      src/core/lib/iomgr/ev_posix.h
  32. 4
      src/core/lib/iomgr/pollset.h
  33. 4
      src/core/lib/iomgr/pollset_windows.c
  34. 9
      src/core/lib/iomgr/resource_quota.c
  35. 2
      src/core/lib/iomgr/resource_quota.h
  36. 4
      src/core/lib/iomgr/tcp_client.h
  37. 24
      src/core/lib/iomgr/tcp_client_posix.c
  38. 21
      src/core/lib/iomgr/tcp_client_windows.c
  39. 114
      src/core/lib/iomgr/tcp_posix.c
  40. 7
      src/core/lib/iomgr/tcp_posix.h
  41. 22
      src/core/lib/iomgr/tcp_server_posix.c
  42. 3
      src/core/lib/iomgr/tcp_server_utils_posix.h
  43. 25
      src/core/lib/iomgr/tcp_server_windows.c
  44. 14
      src/core/lib/iomgr/tcp_windows.c
  45. 4
      src/core/lib/iomgr/tcp_windows.h
  46. 9
      src/core/lib/security/transport/security_handshaker.c
  47. 30
      src/core/lib/slice/slice_buffer.c
  48. 143
      src/core/lib/surface/call.c
  49. 5
      src/core/lib/surface/completion_queue.c
  50. 2
      src/cpp/common/core_codegen.cc
  51. 2
      src/csharp/global.json
  52. 39
      src/node/ext/byte_buffer.cc
  53. 4
      src/node/ext/byte_buffer.h
  54. 5
      src/node/ext/slice.cc
  55. 115
      src/node/index.js
  56. 2
      src/node/interop/interop_server.js
  57. 10
      src/node/performance/benchmark_server.js
  58. 11
      src/node/performance/generic_service.js
  59. 4
      src/node/performance/worker.js
  60. 23
      src/node/performance/worker_service_impl.js
  61. 22
      src/node/src/client.js
  62. 117
      src/node/src/common.js
  63. 181
      src/node/src/protobuf_js_5_common.js
  64. 170
      src/node/src/protobuf_js_6_common.js
  65. 22
      src/node/src/server.js
  66. 2
      src/node/stress/metrics_server.js
  67. 107
      src/node/test/common_test.js
  68. 2
      src/node/test/credentials_test.js
  69. 115
      src/node/test/surface_test.js
  70. 17
      src/node/test/test_messages.proto
  71. 16
      src/objective-c/tests/run_tests.sh
  72. 4
      src/python/grpcio/grpc/_server.py
  73. 4
      src/python/grpcio_reflection/MANIFEST.in
  74. 5
      src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
  75. 2
      src/ruby/end2end/channel_closing_driver.rb
  76. 2
      src/ruby/end2end/channel_state_driver.rb
  77. 5
      src/ruby/end2end/end2end_common.rb
  78. 58
      src/ruby/end2end/killed_client_thread_client.rb
  79. 114
      src/ruby/end2end/killed_client_thread_driver.rb
  80. 2
      src/ruby/end2end/sig_handling_driver.rb
  81. 2
      src/ruby/end2end/sig_int_during_channel_watch_driver.rb
  82. 18
      src/ruby/ext/grpc/rb_call.c
  83. 66
      templates/binding.gyp.template
  84. 2
      templates/grpc.gemspec.template
  85. 2
      templates/package.json.template
  86. 4
      templates/tools/dockerfile/csharp_dotnetcli_deps.include
  87. 5
      test/core/bad_client/bad_client.c
  88. 8
      test/core/end2end/end2end_nosec_tests.c
  89. 8
      test/core/end2end/end2end_tests.c
  90. 4
      test/core/end2end/fixtures/h2_sockpair+trace.c
  91. 4
      test/core/end2end/fixtures/h2_sockpair.c
  92. 14
      test/core/end2end/fixtures/h2_sockpair_1byte.c
  93. BIN
      test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128
  94. 1
      test/core/end2end/gen_build_yaml.py
  95. 1
      test/core/end2end/generate_tests.bzl
  96. 10
      test/core/end2end/tests/authority_not_supported.c
  97. 10
      test/core/end2end/tests/bad_hostname.c
  98. 237
      test/core/end2end/tests/bad_ping.c
  99. 10
      test/core/end2end/tests/binary_metadata.c
  100. 12
      test/core/end2end/tests/call_creds.c
  101. Some files were not shown because too many files have changed in this diff Show More

16
BUILD

@ -41,7 +41,7 @@ g_stands_for = "green"
core_version = "3.0.0-dev"
version = "1.2.0"
version = "1.3.0-dev"
grpc_cc_library(
name = "gpr",
@ -67,6 +67,7 @@ grpc_cc_library(
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
"grpc_load_reporting",
"grpc_max_age_filter",
"grpc_resolver_dns_ares",
"grpc_resolver_dns_native",
"grpc_resolver_sockaddr",
@ -75,7 +76,6 @@ grpc_cc_library(
"grpc_transport_chttp2_client_secure",
"grpc_transport_chttp2_server_insecure",
"grpc_transport_chttp2_server_secure",
"grpc_max_age_filter",
],
)
@ -109,11 +109,11 @@ grpc_cc_library(
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
"grpc_load_reporting",
"grpc_max_age_filter",
"grpc_resolver_dns_native",
"grpc_resolver_sockaddr",
"grpc_transport_chttp2_client_insecure",
"grpc_transport_chttp2_server_insecure",
"grpc_max_age_filter",
],
)
@ -177,8 +177,6 @@ grpc_cc_library(
],
hdrs = [
"src/compiler/config.h",
"src/compiler/schema_interface.h",
"src/compiler/protobuf_plugin.h",
"src/compiler/cpp_generator.h",
"src/compiler/cpp_generator_helpers.h",
"src/compiler/csharp_generator.h",
@ -190,6 +188,7 @@ grpc_cc_library(
"src/compiler/objective_c_generator_helpers.h",
"src/compiler/php_generator.h",
"src/compiler/php_generator_helpers.h",
"src/compiler/protobuf_plugin.h",
"src/compiler/python_generator.h",
"src/compiler/python_generator_helpers.h",
"src/compiler/python_private_generator.h",
@ -197,6 +196,7 @@ grpc_cc_library(
"src/compiler/ruby_generator_helpers-inl.h",
"src/compiler/ruby_generator_map-inl.h",
"src/compiler/ruby_generator_string-inl.h",
"src/compiler/schema_interface.h",
],
external_deps = [
"protobuf_clib",
@ -884,14 +884,14 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h",
],
external_deps = [
"cares",
],
language = "c",
deps = [
"grpc_base",
"grpc_client_channel",
],
external_deps = [
"cares",
],
)
grpc_cc_library(

@ -626,6 +626,9 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bm_cq)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bm_cq_multiple_threads)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bm_error)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -4386,6 +4389,7 @@ add_library(end2end_tests
test/core/end2end/end2end_test_utils.c
test/core/end2end/tests/authority_not_supported.c
test/core/end2end/tests/bad_hostname.c
test/core/end2end/tests/bad_ping.c
test/core/end2end/tests/binary_metadata.c
test/core/end2end/tests/call_creds.c
test/core/end2end/tests/cancel_after_accept.c
@ -4483,6 +4487,7 @@ add_library(end2end_nosec_tests
test/core/end2end/end2end_test_utils.c
test/core/end2end/tests/authority_not_supported.c
test/core/end2end/tests/bad_hostname.c
test/core/end2end/tests/bad_ping.c
test/core/end2end/tests/binary_metadata.c
test/core/end2end/tests/cancel_after_accept.c
test/core/end2end/tests/cancel_after_client_done.c
@ -8977,6 +8982,49 @@ endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(bm_cq_multiple_threads
test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
third_party/googletest/src/gtest-all.cc
)
target_include_directories(bm_cq_multiple_threads
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${BORINGSSL_ROOT_DIR}/include
PRIVATE ${PROTOBUF_ROOT_DIR}/src
PRIVATE ${BENCHMARK_ROOT_DIR}/include
PRIVATE ${ZLIB_ROOT_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
PRIVATE ${CARES_BUILD_INCLUDE_DIR}
PRIVATE ${CARES_INCLUDE_DIR}
PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
PRIVATE third_party/googletest/include
PRIVATE third_party/googletest
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(bm_cq_multiple_threads
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_benchmark
benchmark
grpc++_test_util
grpc_test_util
grpc++
grpc
gpr_test_util
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(bm_error
test/cpp/microbenchmarks/bm_error.cc
third_party/googletest/src/gtest-all.cc

@ -1105,6 +1105,7 @@ bm_chttp2_hpack: $(BINDIR)/$(CONFIG)/bm_chttp2_hpack
bm_chttp2_transport: $(BINDIR)/$(CONFIG)/bm_chttp2_transport
bm_closure: $(BINDIR)/$(CONFIG)/bm_closure
bm_cq: $(BINDIR)/$(CONFIG)/bm_cq
bm_cq_multiple_threads: $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads
bm_error: $(BINDIR)/$(CONFIG)/bm_error
bm_fullstack_streaming_ping_pong: $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_ping_pong
bm_fullstack_streaming_pump: $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_pump
@ -1530,6 +1531,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/bm_chttp2_transport \
$(BINDIR)/$(CONFIG)/bm_closure \
$(BINDIR)/$(CONFIG)/bm_cq \
$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads \
$(BINDIR)/$(CONFIG)/bm_error \
$(BINDIR)/$(CONFIG)/bm_fullstack_streaming_ping_pong \
$(BINDIR)/$(CONFIG)/bm_fullstack_streaming_pump \
@ -1648,6 +1650,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/bm_chttp2_transport \
$(BINDIR)/$(CONFIG)/bm_closure \
$(BINDIR)/$(CONFIG)/bm_cq \
$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads \
$(BINDIR)/$(CONFIG)/bm_error \
$(BINDIR)/$(CONFIG)/bm_fullstack_streaming_ping_pong \
$(BINDIR)/$(CONFIG)/bm_fullstack_streaming_pump \
@ -1997,6 +2000,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/bm_closure || ( echo test bm_closure failed ; exit 1 )
$(E) "[RUN] Testing bm_cq"
$(Q) $(BINDIR)/$(CONFIG)/bm_cq || ( echo test bm_cq failed ; exit 1 )
$(E) "[RUN] Testing bm_cq_multiple_threads"
$(Q) $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads || ( echo test bm_cq_multiple_threads failed ; exit 1 )
$(E) "[RUN] Testing bm_error"
$(Q) $(BINDIR)/$(CONFIG)/bm_error || ( echo test bm_error failed ; exit 1 )
$(E) "[RUN] Testing bm_fullstack_streaming_ping_pong"
@ -8221,6 +8226,7 @@ LIBEND2END_TESTS_SRC = \
test/core/end2end/end2end_test_utils.c \
test/core/end2end/tests/authority_not_supported.c \
test/core/end2end/tests/bad_hostname.c \
test/core/end2end/tests/bad_ping.c \
test/core/end2end/tests/binary_metadata.c \
test/core/end2end/tests/call_creds.c \
test/core/end2end/tests/cancel_after_accept.c \
@ -8313,6 +8319,7 @@ LIBEND2END_NOSEC_TESTS_SRC = \
test/core/end2end/end2end_test_utils.c \
test/core/end2end/tests/authority_not_supported.c \
test/core/end2end/tests/bad_hostname.c \
test/core/end2end/tests/bad_ping.c \
test/core/end2end/tests/binary_metadata.c \
test/core/end2end/tests/cancel_after_accept.c \
test/core/end2end/tests/cancel_after_client_done.c \
@ -13358,6 +13365,50 @@ endif
endif
BM_CQ_MULTIPLE_THREADS_SRC = \
test/cpp/microbenchmarks/bm_cq_multiple_threads.cc \
BM_CQ_MULTIPLE_THREADS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_CQ_MULTIPLE_THREADS_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads: 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.0.0+.
$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads: $(PROTOBUF_DEP) $(BM_CQ_MULTIPLE_THREADS_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(BM_CQ_MULTIPLE_THREADS_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads
endif
endif
$(BM_CQ_MULTIPLE_THREADS_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_cq_multiple_threads.o: $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_bm_cq_multiple_threads: $(BM_CQ_MULTIPLE_THREADS_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(BM_CQ_MULTIPLE_THREADS_OBJS:.o=.dep)
endif
endif
BM_ERROR_SRC = \
test/cpp/microbenchmarks/bm_error.cc \

@ -45,9 +45,42 @@
# Some Node installations use the system installation of OpenSSL, and on
# some systems, the system OpenSSL still does not have ALPN support. This
# will let users recompile gRPC to work without ALPN.
'grpc_alpn%': 'true'
'grpc_alpn%': 'true',
# Indicates that the library should be built with gcov.
'grpc_gcov%': 'false'
},
'target_defaults': {
'configurations': {
'Release': {
'cflags': [
'-O2',
],
'defines': [
'NDEBUG',
],
},
'Debug': {
'cflags': [
'-O0',
],
'defines': [
'_DEBUG',
'DEBUG',
],
},
},
'cflags': [
'-g',
'-Wall',
'-Wextra',
'-Werror',
'-Wno-long-long',
'-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
],
'ldflags': [
'-g',
],
'include_dirs': [
'.',
'include'
@ -64,6 +97,24 @@
'GRPC_UV'
]
}],
['grpc_gcov=="true"', {
'cflags': [
'-O0',
'-fprofile-arcs',
'-ftest-coverage',
'-Wno-return-type',
],
'defines': [
'_DEBUG',
'DEBUG',
'GPR_GCOV',
],
'ldflags': [
'-fprofile-arcs',
'-ftest-coverage',
'-rdynamic',
],
}],
['OS!="win" and runtime=="electron"', {
"defines": [
'OPENSSL_NO_THREADS'
@ -126,26 +177,9 @@
"ws2_32"
]
}, { # OS != "win"
'variables': {
'config': '<!(echo $CONFIG)',
},
'include_dirs': [
'<(node_root_dir)/deps/zlib',
'<(node_root_dir)/deps/cares/include',
],
'conditions': [
['config=="gcov"', {
'cflags': [
'-ftest-coverage',
'-fprofile-arcs',
'-O0'
],
'ldflags': [
'-ftest-coverage',
'-fprofile-arcs'
]
}
]
'<(node_root_dir)/deps/cares/include'
]
}]
]
@ -862,16 +896,10 @@
],
'cflags': [
'-std=c++11',
'-Wall',
'-pthread',
'-g',
'-zdefs',
'-Werror',
'-Wno-error=deprecated-declarations'
],
'ldflags': [
'-g'
],
"conditions": [
['OS=="win" or runtime=="electron"', {
'dependencies': [

@ -3217,6 +3217,27 @@ targets:
- mac
- linux
- posix
- name: bm_cq_multiple_threads
build: test
language: c++
src:
- test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- gpr_test_util
- gpr
args:
- --benchmark_min_time=0
defaults: benchmark
platforms:
- mac
- linux
- posix
- name: bm_error
build: test
language: c++

@ -3,6 +3,8 @@ option(gRPC_MSVC_STATIC_RUNTIME "Link with static msvc runtime libraries" OFF)
if(gRPC_MSVC_STATIC_RUNTIME)
# switch from dynamic to static linking of msvcrt
foreach(flag_var
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)

@ -83,7 +83,8 @@ in the body.
User Agent
* U-A: grpc-web-javascript
* Do NOT use User-Agent header (which is to be set by browsers, by default)
* Use X-User-Agent: grpc-web-javascript/0.1 (follow the same format as specified in [gRPC over HTTP2](http://www.grpc.io/docs/guides/wire.html))
---

@ -24,7 +24,7 @@ Gem::Specification.new do |s|
s.files += Dir.glob('include/grpc/**/*')
s.test_files = Dir.glob('src/ruby/spec/**/*')
s.bindir = 'src/ruby/bin'
s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
s.require_paths = %w( src/ruby/lib src/ruby/bin src/ruby/pb )
s.platform = Gem::Platform::RUBY
s.add_dependency 'google-protobuf', '~> 3.1'

@ -528,6 +528,7 @@ class CallOpClientRecvStatus {
void ClientRecvStatus(ClientContext* context, Status* status) {
metadata_map_ = &context->trailing_metadata_;
recv_status_ = status;
status_details_ = g_core_codegen_interface->grpc_empty_slice();
}
protected:

@ -76,6 +76,7 @@ class CoreCodegen : public CoreCodegenInterface {
grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
size_t nslices) override;
grpc_slice grpc_empty_slice() override;
grpc_slice grpc_slice_malloc(size_t length) override;
void grpc_slice_unref(grpc_slice slice) override;
grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) override;

@ -94,6 +94,7 @@ class CoreCodegenInterface {
virtual grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
size_t nslices) = 0;
virtual grpc_slice grpc_empty_slice() = 0;
virtual grpc_slice grpc_slice_malloc(size_t length) = 0;
virtual void grpc_slice_unref(grpc_slice slice) = 0;
virtual grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) = 0;

@ -205,15 +205,25 @@ typedef struct {
a data frame or header frame) */
#define GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA \
"grpc.http2.max_pings_without_data"
/** How many misbehaving pings the server can bear before sending goaway and
closing the transport?
(0 indicates that the server can bear an infinite number of misbehaving
pings) */
#define GRPC_ARG_HTTP2_MAX_PING_STRIKES "grpc.http2.max_ping_strikes"
/** Minimum allowed time between two pings without sending any data frame. Int
valued, seconds */
#define GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS \
"grpc.http2.min_ping_interval_without_data_ms"
/** How much data are we willing to queue up per stream if
GRPC_WRITE_BUFFER_HINT is set? This is an upper bound */
#define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size"
/** After a duration of this time the client pings the server to see if the
transport is still alive. Int valued, seconds. */
#define GRPC_ARG_CLIENT_KEEPALIVE_TIME_S "grpc.client_keepalive_time"
/** After waiting for a duration of this time, if the client does not receive
the ping ack, it will close the transport. Int valued, seconds. */
#define GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S "grpc.client_keepalive_timeout"
/** After a duration of this time the client/server pings its peer to see if the
transport is still alive. Int valued, milliseconds. */
#define GRPC_ARG_KEEPALIVE_TIME_MS "grpc.keepalive_time_ms"
/** After waiting for a duration of this time, if the keepalive ping sender does
not receive the ping ack, it will close the transport. Int valued,
milliseconds. */
#define GRPC_ARG_KEEPALIVE_TIMEOUT_MS "grpc.keepalive_timeout_ms"
/** Is it permissible to send keepalive pings without any outstanding streams.
Int valued, 0(false)/1(true). */
#define GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS \
@ -261,6 +271,14 @@ typedef struct {
* possible. */
#define GRPC_ARG_USE_CRONET_PACKET_COALESCING \
"grpc.use_cronet_packet_coalescing"
/* Channel arg (integer) setting how large a slice to try and read from the wire
each time recvmsg (or equivalent) is called */
#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size"
#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
#define GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE \
"grpc.experimental.tcp_min_read_chunk_size"
#define GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE \
"grpc.experimental.tcp_max_read_chunk_size"
/** \} */
/** Result of a grpc call. If the caller satisfies the prerequisites of a

@ -34,7 +34,7 @@
"lodash": "^4.15.0",
"nan": "^2.0.0",
"node-pre-gyp": "^0.6.0",
"protobufjs": "^5.0.0",
"protobufjs": "^6.7.0",
"cares": "^1.1.5"
},
"devDependencies": {

@ -914,14 +914,14 @@ static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
.arena = calld->arena};
grpc_error *new_error = grpc_connected_subchannel_create_call(
exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
gpr_atm_rel_store(&calld->subchannel_call,
(gpr_atm)(uintptr_t)subchannel_call);
if (new_error != GRPC_ERROR_NONE) {
new_error = grpc_error_add_child(new_error, error);
subchannel_call = CANCELLED_CALL;
fail_locked(exec_ctx, calld, new_error);
} else {
retry_waiting_locked(exec_ctx, calld);
}
gpr_atm_rel_store(&calld->subchannel_call,
(gpr_atm)(uintptr_t)subchannel_call);
retry_waiting_locked(exec_ctx, calld);
}
GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel");
}
@ -1152,16 +1152,16 @@ static void start_transport_stream_op_batch_locked_inner(
.arena = calld->arena};
grpc_error *error = grpc_connected_subchannel_create_call(
exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
gpr_atm_rel_store(&calld->subchannel_call,
(gpr_atm)(uintptr_t)subchannel_call);
if (error != GRPC_ERROR_NONE) {
subchannel_call = CANCELLED_CALL;
fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
} else {
retry_waiting_locked(exec_ctx, calld);
/* recurse to retry */
start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
}
gpr_atm_rel_store(&calld->subchannel_call,
(gpr_atm)(uintptr_t)subchannel_call);
retry_waiting_locked(exec_ctx, calld);
/* recurse to retry */
start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
/* early out */
return;
}

@ -769,7 +769,7 @@ grpc_error *grpc_connected_subchannel_create_call(
*call = gpr_arena_alloc(
args->arena, sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
(*call)->connection = con; // Ref is added below.
(*call)->connection = GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
const grpc_call_element_args call_args = {.call_stack = callstk,
.server_transport_data = NULL,
.context = NULL,
@ -782,11 +782,8 @@ grpc_error *grpc_connected_subchannel_create_call(
if (error != GRPC_ERROR_NONE) {
const char *error_string = grpc_error_string(error);
gpr_log(GPR_ERROR, "error: %s", error_string);
gpr_free(*call);
return error;
}
GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, args->pollent);
return GRPC_ERROR_NONE;
}

@ -31,7 +31,7 @@
*
*/
#include "src/core/lib/channel/message_size_filter.h"
#include "src/core/ext/filters/max_age/max_age_filter.h"
#include <limits.h>
#include <string.h>
@ -41,11 +41,11 @@
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/surface/channel_init.h"
#include "src/core/lib/transport/http2_errors.h"
#include "src/core/lib/transport/service_config.h"
#define DEFAULT_MAX_CONNECTION_AGE_MS INT_MAX
#define DEFAULT_MAX_CONNECTION_AGE_GRACE_MS INT_MAX
#define DEFAULT_MAX_CONNECTION_IDLE_MS INT_MAX
#define MAX_CONNECTION_AGE_JITTER 0.1
typedef struct channel_data {
/* We take a reference to the channel stack for the timer callback */
@ -254,6 +254,21 @@ static void channel_connectivity_changed(grpc_exec_ctx* exec_ctx, void* arg,
}
}
/* A random jitter of +/-10% will be added to MAX_CONNECTION_AGE to spread out
connection storms. Note that the MAX_CONNECTION_AGE option without jitter
would not create connection storms by itself, but if there happened to be a
connection storm it could cause it to repeat at a fixed period. */
static int add_random_max_connection_age_jitter(int value) {
/* generate a random number between 1 - MAX_CONNECTION_AGE_JITTER and
1 + MAX_CONNECTION_AGE_JITTER */
double multiplier = rand() * MAX_CONNECTION_AGE_JITTER * 2.0 / RAND_MAX +
1.0 - MAX_CONNECTION_AGE_JITTER;
double result = multiplier * value;
/* INT_MAX - 0.5 converts the value to float, so that result will not be
cast to int implicitly before the comparison. */
return result > INT_MAX - 0.5 ? INT_MAX : (int)result;
}
/* Constructor for call_data. */
static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
@ -283,7 +298,9 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
chand->max_connection_age =
DEFAULT_MAX_CONNECTION_AGE_MS == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(DEFAULT_MAX_CONNECTION_AGE_MS, GPR_TIMESPAN);
: gpr_time_from_millis(add_random_max_connection_age_jitter(
DEFAULT_MAX_CONNECTION_AGE_MS),
GPR_TIMESPAN);
chand->max_connection_age_grace =
DEFAULT_MAX_CONNECTION_AGE_GRACE_MS == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
@ -300,8 +317,10 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
&args->channel_args->args[i],
(grpc_integer_options){DEFAULT_MAX_CONNECTION_AGE_MS, 1, INT_MAX});
chand->max_connection_age =
value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(value, GPR_TIMESPAN);
value == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(
add_random_max_connection_age_jitter(value), GPR_TIMESPAN);
} else if (0 == strcmp(args->channel_args->args[i].key,
GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS)) {
const int value = grpc_channel_arg_get_integer(

@ -57,12 +57,9 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server *server,
char *name;
gpr_asprintf(&name, "fd:%d", fd);
grpc_resource_quota *resource_quota = grpc_resource_quota_from_channel_args(
grpc_server_get_channel_args(server));
grpc_endpoint *server_endpoint =
grpc_tcp_create(grpc_fd_create(fd, name), resource_quota,
GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name);
grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
grpc_tcp_create(&exec_ctx, grpc_fd_create(fd, name),
grpc_server_get_channel_args(server), name);
gpr_free(name);

@ -69,13 +69,21 @@
#define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024)
#define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024)
#define DEFAULT_CLIENT_KEEPALIVE_TIME_S INT_MAX
#define DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S 20
#define DEFAULT_CLIENT_KEEPALIVE_TIME_MS INT_MAX
#define DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_MS 20000 /* 20 seconds */
#define DEFAULT_SERVER_KEEPALIVE_TIME_MS 7200000 /* 2 hours */
#define DEFAULT_SERVER_KEEPALIVE_TIMEOUT_MS 20000 /* 20 seconds */
#define DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS false
static int g_default_client_keepalive_time_s = DEFAULT_CLIENT_KEEPALIVE_TIME_S;
static int g_default_client_keepalive_timeout_s =
DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S;
#define KEEPALIVE_TIME_BACKOFF_MULTIPLIER 2
static int g_default_client_keepalive_time_ms =
DEFAULT_CLIENT_KEEPALIVE_TIME_MS;
static int g_default_client_keepalive_timeout_ms =
DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_MS;
static int g_default_server_keepalive_time_ms =
DEFAULT_SERVER_KEEPALIVE_TIME_MS;
static int g_default_server_keepalive_timeout_ms =
DEFAULT_SERVER_KEEPALIVE_TIMEOUT_MS;
static bool g_default_keepalive_permit_without_calls =
DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS;
@ -158,6 +166,8 @@ static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
#define DEFAULT_MIN_TIME_BETWEEN_PINGS_MS 0
#define DEFAULT_MAX_PINGS_BETWEEN_DATA 3
#define DEFAULT_MAX_PING_STRIKES 2
#define DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS 300000 /* 5 minutes */
/** keepalive-relevant functions */
static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
@ -363,19 +373,35 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
.max_pings_without_data = DEFAULT_MAX_PINGS_BETWEEN_DATA,
.min_time_between_pings =
gpr_time_from_millis(DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, GPR_TIMESPAN),
.max_ping_strikes = DEFAULT_MAX_PING_STRIKES,
.min_ping_interval_without_data = gpr_time_from_millis(
DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS, GPR_TIMESPAN),
};
/* client-side keepalive setting */
t->keepalive_time =
g_default_client_keepalive_time_s == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(g_default_client_keepalive_time_s,
GPR_TIMESPAN);
t->keepalive_timeout =
g_default_client_keepalive_timeout_s == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(g_default_client_keepalive_timeout_s,
GPR_TIMESPAN);
/* Keepalive setting */
if (t->is_client) {
t->keepalive_time =
g_default_client_keepalive_time_ms == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(g_default_client_keepalive_time_ms,
GPR_TIMESPAN);
t->keepalive_timeout =
g_default_client_keepalive_timeout_ms == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(g_default_client_keepalive_timeout_ms,
GPR_TIMESPAN);
} else {
t->keepalive_time =
g_default_server_keepalive_time_ms == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(g_default_server_keepalive_time_ms,
GPR_TIMESPAN);
t->keepalive_timeout =
g_default_server_keepalive_timeout_ms == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis(g_default_server_keepalive_timeout_ms,
GPR_TIMESPAN);
}
t->keepalive_permit_without_calls = g_default_keepalive_permit_without_calls;
if (channel_args) {
@ -408,6 +434,11 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->ping_policy.max_pings_without_data = grpc_channel_arg_get_integer(
&channel_args->args[i],
(grpc_integer_options){DEFAULT_MAX_PINGS_BETWEEN_DATA, 0, INT_MAX});
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_MAX_PING_STRIKES)) {
t->ping_policy.max_ping_strikes = grpc_channel_arg_get_integer(
&channel_args->args[i],
(grpc_integer_options){DEFAULT_MAX_PING_STRIKES, 0, INT_MAX});
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS)) {
t->ping_policy.min_time_between_pings = gpr_time_from_millis(
@ -416,6 +447,15 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
(grpc_integer_options){DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, 0,
INT_MAX}),
GPR_TIMESPAN);
} else if (0 ==
strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS)) {
t->ping_policy.min_ping_interval_without_data = gpr_time_from_millis(
grpc_channel_arg_get_integer(
&channel_args->args[i],
(grpc_integer_options){
DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS, 0, INT_MAX}),
GPR_TIMESPAN);
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) {
t->write_buffer_size = (uint32_t)grpc_channel_arg_get_integer(
@ -426,23 +466,27 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->enable_bdp_probe = grpc_channel_arg_get_integer(
&channel_args->args[i], (grpc_integer_options){1, 0, 1});
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) {
GRPC_ARG_KEEPALIVE_TIME_MS)) {
const int value = grpc_channel_arg_get_integer(
&channel_args->args[i],
(grpc_integer_options){g_default_client_keepalive_time_s, 1,
INT_MAX});
(grpc_integer_options){t->is_client
? g_default_client_keepalive_time_ms
: g_default_server_keepalive_time_ms,
1, INT_MAX});
t->keepalive_time = value == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(value, GPR_TIMESPAN);
: gpr_time_from_millis(value, GPR_TIMESPAN);
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) {
GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
const int value = grpc_channel_arg_get_integer(
&channel_args->args[i],
(grpc_integer_options){g_default_client_keepalive_timeout_s, 0,
INT_MAX});
(grpc_integer_options){t->is_client
? g_default_client_keepalive_timeout_ms
: g_default_server_keepalive_timeout_ms,
0, INT_MAX});
t->keepalive_timeout = value == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(value, GPR_TIMESPAN);
: gpr_time_from_millis(value, GPR_TIMESPAN);
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
t->keepalive_permit_without_calls =
@ -500,8 +544,11 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->ping_policy.max_pings_without_data;
t->ping_state.is_delayed_ping_timer_set = false;
/** Start client-side keepalive pings */
if (t->is_client) {
t->ping_recv_state.last_ping_recv_time = gpr_inf_past(GPR_CLOCK_MONOTONIC);
t->ping_recv_state.ping_strikes = 0;
/* Start keepalive pings */
if (gpr_time_cmp(t->keepalive_time, gpr_inf_future(GPR_TIMESPAN)) != 0) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING;
GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
grpc_timer_init(
@ -936,6 +983,26 @@ void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx,
// GRPC_CHTTP2_IF_TRACING(
// gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
t->seen_goaway = 1;
/* When a client receives a GOAWAY with error code ENHANCE_YOUR_CALM and debug
* data equal to too_many_pings, it should log the occurrence at a log level
* that is enabled by default and double the configured KEEPALIVE_TIME used
* for new connections on that channel. */
if (t->is_client && goaway_error == GRPC_HTTP2_ENHANCE_YOUR_CALM &&
grpc_slice_str_cmp(goaway_text, "too_many_pings") == 0) {
gpr_log(GPR_ERROR,
"Received a GOAWAY with error code ENHANCE_YOUR_CALM and debug "
"data equal to \"too_many_pings\"");
double current_keepalive_time_ms =
gpr_timespec_to_micros(t->keepalive_time) / 1000;
t->keepalive_time =
current_keepalive_time_ms > INT_MAX / KEEPALIVE_TIME_BACKOFF_MULTIPLIER
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_millis((int64_t)(current_keepalive_time_ms *
KEEPALIVE_TIME_BACKOFF_MULTIPLIER),
GPR_TIMESPAN);
}
/* lie: use transient failure from the transport to indicate goaway has been
* received */
connectivity_state_set(
@ -1483,6 +1550,21 @@ static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GRPC_ERROR_UNREF(error);
}
void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) {
gpr_log(GPR_DEBUG, "PING strike");
if (++t->ping_recv_state.ping_strikes > t->ping_policy.max_ping_strikes &&
t->ping_policy.max_ping_strikes != 0) {
send_goaway(exec_ctx, t,
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("too_many_pings"),
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
/*The transport will be closed after the write is done */
close_transport_locked(
exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"));
}
}
static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
void *stream_op,
grpc_error *error_ignored) {
@ -2176,6 +2258,10 @@ static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
if (grpc_http_trace) {
gpr_log(GPR_DEBUG, "%s: Start BDP ping", t->peer_string);
}
/* Reset the keepalive ping timer */
if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) {
grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
}
grpc_bdp_estimator_start_ping(&t->bdp_estimator);
}
@ -2190,20 +2276,32 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
}
void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args) {
void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args,
bool is_client) {
size_t i;
if (args) {
for (i = 0; i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) {
g_default_client_keepalive_time_s = grpc_channel_arg_get_integer(
&args->args[i], (grpc_integer_options){
g_default_client_keepalive_time_s, 1, INT_MAX});
} else if (0 == strcmp(args->args[i].key,
GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) {
g_default_client_keepalive_timeout_s = grpc_channel_arg_get_integer(
if (0 == strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
const int value = grpc_channel_arg_get_integer(
&args->args[i],
(grpc_integer_options){g_default_client_keepalive_time_ms, 1,
INT_MAX});
if (is_client) {
g_default_client_keepalive_time_ms = value;
} else {
g_default_server_keepalive_time_ms = value;
}
} else if (0 ==
strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
const int value = grpc_channel_arg_get_integer(
&args->args[i],
(grpc_integer_options){g_default_client_keepalive_timeout_s, 0,
(grpc_integer_options){g_default_client_keepalive_timeout_ms, 0,
INT_MAX});
if (is_client) {
g_default_client_keepalive_timeout_ms = value;
} else {
g_default_server_keepalive_timeout_ms = value;
}
} else if (0 == strcmp(args->args[i].key,
GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
g_default_keepalive_permit_without_calls =
@ -2221,7 +2319,8 @@ static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_chttp2_transport *t = arg;
GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING);
if (error == GRPC_ERROR_NONE && !(t->destroying || t->closed)) {
if (t->keepalive_permit_without_calls || t->stream_map.count > 0) {
if (t->keepalive_permit_without_calls ||
grpc_chttp2_stream_map_size(&t->stream_map) > 0) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_PINGING;
GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive ping end");
send_ping_locked(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE,
@ -2234,6 +2333,13 @@ static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
&t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
}
} else if (error == GRPC_ERROR_CANCELLED && !(t->destroying || t->closed)) {
/* The keepalive ping timer may be cancelled by bdp */
GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
grpc_timer_init(
exec_ctx, &t->keepalive_ping_timer,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
&t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
}
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "init keepalive ping");
}
@ -2276,8 +2382,8 @@ static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("keepalive watchdog timeout"));
}
} else {
/** The watchdog timer should have been cancelled by
finish_keepalive_ping_locked. */
/* The watchdog timer should have been cancelled by
* finish_keepalive_ping_locked. */
if (error != GRPC_ERROR_CANCELLED) {
gpr_log(GPR_ERROR, "keepalive_ping_end state error: %d (expect: %d)",
t->keepalive_state, GRPC_CHTTP2_KEEPALIVE_STATE_PINGING);

@ -103,6 +103,28 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
if (p->is_ack) {
grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes);
} else {
if (!t->is_client) {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec next_allowed_ping =
gpr_time_add(t->ping_recv_state.last_ping_recv_time,
t->ping_policy.min_ping_interval_without_data);
if (t->keepalive_permit_without_calls == 0 &&
grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
/* According to RFC1122, the interval of TCP Keep-Alive is default to
no less than two hours. When there is no outstanding streams, we
restrict the number of PINGS equivalent to TCP Keep-Alive. */
next_allowed_ping =
gpr_time_add(t->ping_recv_state.last_ping_recv_time,
gpr_time_from_seconds(7200, GPR_TIMESPAN));
}
if (gpr_time_cmp(next_allowed_ping, now) > 0) {
grpc_chttp2_add_ping_strike(exec_ctx, t);
}
t->ping_recv_state.last_ping_recv_time = now;
}
if (!g_disable_ping_ack) {
if (t->ping_ack_count == t->ping_ack_capacity) {
t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3);

@ -97,6 +97,8 @@ typedef struct {
typedef struct {
gpr_timespec min_time_between_pings;
int max_pings_without_data;
int max_ping_strikes;
gpr_timespec min_ping_interval_without_data;
} grpc_chttp2_repeated_ping_policy;
typedef struct {
@ -106,6 +108,11 @@ typedef struct {
bool is_delayed_ping_timer_set;
} grpc_chttp2_repeated_ping_state;
typedef struct {
gpr_timespec last_ping_recv_time;
int ping_strikes;
} grpc_chttp2_server_ping_recv_state;
/* deframer state for the overall http2 stream of bytes */
typedef enum {
/* prefix: one entry per http2 connection prefix byte */
@ -314,6 +321,7 @@ struct grpc_chttp2_transport {
size_t ping_ack_count;
size_t ping_ack_capacity;
uint64_t *ping_acks;
grpc_chttp2_server_ping_recv_state ping_recv_state;
/** parser for headers */
grpc_chttp2_hpack_parser hpack_parser;
@ -797,6 +805,13 @@ void grpc_chttp2_incoming_byte_stream_notify(
void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
uint64_t id);
/** Add a new ping strike to ping_recv_state.ping_strikes. If
ping_recv_state.ping_strikes > ping_policy.max_ping_strikes, it sends GOAWAY
with error code ENHANCE_YOUR_CALM and additional debug data resembling
too_many_pings followed by immediately closing the connection. */
void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t);
typedef enum {
/* don't initiate a transport write, but piggyback on the next one */
GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK,
@ -836,6 +851,7 @@ uint32_t grpc_chttp2_target_incoming_window(grpc_chttp2_transport *t);
/** Set the default keepalive configurations, must only be called at
initialization */
void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args);
void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args,
bool is_client);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */

@ -229,6 +229,11 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
now_writing = true;
t->ping_state.pings_before_data_required =
t->ping_policy.max_pings_without_data;
if (!t->is_client) {
t->ping_recv_state.last_ping_recv_time =
gpr_inf_past(GPR_CLOCK_MONOTONIC);
t->ping_recv_state.ping_strikes = 0;
}
}
/* send any window updates */
if (s->announce_window > 0) {
@ -238,6 +243,11 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
s->id, s->announce_window, &s->stats.outgoing));
t->ping_state.pings_before_data_required =
t->ping_policy.max_pings_without_data;
if (!t->is_client) {
t->ping_recv_state.last_ping_recv_time =
gpr_inf_past(GPR_CLOCK_MONOTONIC);
t->ping_recv_state.ping_strikes = 0;
}
GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, announce_window, announce);
}
if (sent_initial_metadata) {
@ -270,6 +280,11 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
send_bytes);
t->ping_state.pings_before_data_required =
t->ping_policy.max_pings_without_data;
if (!t->is_client) {
t->ping_recv_state.last_ping_recv_time =
gpr_inf_past(GPR_CLOCK_MONOTONIC);
t->ping_recv_state.ping_strikes = 0;
}
if (is_last_frame) {
s->send_trailing_metadata = NULL;
s->sent_trailing_metadata = true;
@ -345,6 +360,11 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
0, announced, &throwaway_stats));
t->ping_state.pings_before_data_required =
t->ping_policy.max_pings_without_data;
if (!t->is_client) {
t->ping_recv_state.last_ping_recv_time =
gpr_inf_past(GPR_CLOCK_MONOTONIC);
t->ping_recv_state.ping_strikes = 0;
}
}
for (size_t i = 0; i < t->ping_ack_count; i++) {

@ -1185,7 +1185,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
if (stream_state->rs.compressed) {
stream_state->rs.sbs.base.flags = GRPC_WRITE_INTERNAL_COMPRESS;
}
*((grpc_byte_buffer **)stream_op->recv_message) =
*((grpc_byte_buffer **)stream_op->payload->recv_message.recv_message) =
(grpc_byte_buffer *)&stream_state->rs.sbs;
grpc_closure_sched(exec_ctx,
stream_op->payload->recv_message.recv_message_ready,

@ -41,8 +41,7 @@ typedef struct {
grpc_endpoint *server;
} grpc_endpoint_pair;
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
const char *name, grpc_resource_quota *resource_quota,
size_t read_slice_size);
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
grpc_channel_args *args);
#endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H */

@ -62,22 +62,25 @@ static void create_sockets(int sv[2]) {
GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]) == GRPC_ERROR_NONE);
}
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
const char *name, grpc_resource_quota *resource_quota,
size_t read_slice_size) {
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
grpc_channel_args *args) {
int sv[2];
grpc_endpoint_pair p;
char *final_name;
create_sockets(sv);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
gpr_asprintf(&final_name, "%s:client", name);
p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), resource_quota,
read_slice_size, "socketpair-server");
p.client = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], final_name), args,
"socketpair-server");
gpr_free(final_name);
gpr_asprintf(&final_name, "%s:server", name);
p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), resource_quota,
read_slice_size, "socketpair-client");
p.server = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[0], final_name), args,
"socketpair-client");
gpr_free(final_name);
grpc_exec_ctx_finish(&exec_ctx);
return p;
}

@ -41,9 +41,8 @@
#include "src/core/lib/iomgr/endpoint_pair.h"
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
const char *name, grpc_resource_quota *resource_quota,
size_t read_slice_size) {
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
grpc_channel_args *args) {
grpc_endpoint_pair endpoint_pair;
// TODO(mlumish): implement this properly under libuv
GPR_ASSERT(false &&

@ -83,15 +83,18 @@ static void create_sockets(SOCKET sv[2]) {
}
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
const char *name, grpc_resource_quota *resource_quota,
size_t read_slice_size) {
const char *name, grpc_channel_args *channel_args) {
SOCKET sv[2];
grpc_endpoint_pair p;
create_sockets(sv);
p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"),
resource_quota, "endpoint:server");
p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"),
resource_quota, "endpoint:client");
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
p.client = grpc_tcp_create(&exec_ctx,
grpc_winsocket_create(sv[1], "endpoint:client"),
channel_args, "endpoint:server");
p.server = grpc_tcp_create(&exec_ctx,
grpc_winsocket_create(sv[0], "endpoint:server"),
channel_args, "endpoint:client");
grpc_exec_ctx_finish(&exec_ctx);
return p;
}

@ -212,7 +212,11 @@ static uint8_t get_placement(grpc_error **err, size_t size) {
GPR_ASSERT(*err);
uint8_t slots = (uint8_t)(size / sizeof(intptr_t));
if ((*err)->arena_size + slots > (*err)->arena_capacity) {
(*err)->arena_capacity = (uint8_t)(3 * (*err)->arena_capacity / 2);
(*err)->arena_capacity =
(uint8_t)GPR_MIN(UINT8_MAX - 1, (3 * (*err)->arena_capacity / 2));
if ((*err)->arena_size + slots > (*err)->arena_capacity) {
return UINT8_MAX;
}
*err = gpr_realloc(
*err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t));
}
@ -223,10 +227,14 @@ static uint8_t get_placement(grpc_error **err, size_t size) {
static void internal_set_int(grpc_error **err, grpc_error_ints which,
intptr_t value) {
// GPR_ASSERT((*err)->ints[which] == UINT8_MAX); // TODO, enforce this
uint8_t slot = (*err)->ints[which];
if (slot == UINT8_MAX) {
slot = get_placement(err, sizeof(value));
if (slot == UINT8_MAX) {
gpr_log(GPR_ERROR, "Error %p is full, dropping int {\"%s\":%" PRIiPTR "}",
*err, error_int_name(which), value);
return;
}
}
(*err)->ints[which] = slot;
(*err)->arena[slot] = value;
@ -234,10 +242,16 @@ static void internal_set_int(grpc_error **err, grpc_error_ints which,
static void internal_set_str(grpc_error **err, grpc_error_strs which,
grpc_slice value) {
// GPR_ASSERT((*err)->strs[which] == UINT8_MAX); // TODO, enforce this
uint8_t slot = (*err)->strs[which];
if (slot == UINT8_MAX) {
slot = get_placement(err, sizeof(value));
if (slot == UINT8_MAX) {
const char *str = grpc_slice_to_c_string(value);
gpr_log(GPR_ERROR, "Error %p is full, dropping string {\"%s\":\"%s\"}",
*err, error_str_name(which), str);
gpr_free((void *)str);
return;
}
} else {
unref_slice(*(grpc_slice *)((*err)->arena + slot));
}
@ -245,12 +259,19 @@ static void internal_set_str(grpc_error **err, grpc_error_strs which,
memcpy((*err)->arena + slot, &value, sizeof(value));
}
static char *fmt_time(gpr_timespec tm);
static void internal_set_time(grpc_error **err, grpc_error_times which,
gpr_timespec value) {
// GPR_ASSERT((*err)->times[which] == UINT8_MAX); // TODO, enforce this
uint8_t slot = (*err)->times[which];
if (slot == UINT8_MAX) {
slot = get_placement(err, sizeof(value));
if (slot == UINT8_MAX) {
const char *time_str = fmt_time(value);
gpr_log(GPR_ERROR, "Error %p is full, dropping \"%s\":\"%s\"}", *err,
error_time_name(which), time_str);
gpr_free((void *)time_str);
return;
}
}
(*err)->times[which] = slot;
memcpy((*err)->arena + slot, &value, sizeof(value));
@ -259,6 +280,12 @@ static void internal_set_time(grpc_error **err, grpc_error_times which,
static void internal_add_error(grpc_error **err, grpc_error *new) {
grpc_linked_error new_last = {new, UINT8_MAX};
uint8_t slot = get_placement(err, sizeof(grpc_linked_error));
if (slot == UINT8_MAX) {
gpr_log(GPR_ERROR, "Error %p is full, dropping error %p = %s", *err, new,
grpc_error_string(new));
GRPC_ERROR_UNREF(new);
return;
}
if ((*err)->first_err == UINT8_MAX) {
GPR_ASSERT((*err)->last_err == UINT8_MAX);
(*err)->last_err = slot;

@ -1717,7 +1717,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
worker.pt_id = pthread_self();
gpr_atm_no_barrier_store(&worker.is_kicked, (gpr_atm)0);
*worker_hdl = &worker;
if (worker_hdl) *worker_hdl = &worker;
gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
@ -1795,7 +1795,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
gpr_mu_lock(&pollset->po.mu);
}
*worker_hdl = NULL;
if (worker_hdl) *worker_hdl = NULL;
gpr_tls_set(&g_current_thread_pollset, (intptr_t)0);
gpr_tls_set(&g_current_thread_worker, (intptr_t)0);

@ -871,7 +871,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker **worker_hdl,
gpr_timespec now, gpr_timespec deadline) {
grpc_pollset_worker worker;
*worker_hdl = &worker;
if (worker_hdl) *worker_hdl = &worker;
grpc_error *error = GRPC_ERROR_NONE;
/* Avoid malloc for small number of elements. */
@ -1092,7 +1092,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
gpr_mu_lock(&pollset->mu);
}
}
*worker_hdl = NULL;
if (worker_hdl) *worker_hdl = NULL;
GPR_TIMER_END("pollset_work", 0);
GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
return error;

@ -111,6 +111,12 @@ static void try_engine(const char *engine) {
}
}
/* This should be used for testing purposes ONLY */
void grpc_set_event_engine_test_only(
const grpc_event_engine_vtable *ev_engine) {
g_event_engine = ev_engine;
}
/* Call this only after calling grpc_event_engine_init() */
const char *grpc_get_poll_strategy_name() { return g_poll_strategy_name; }

@ -183,4 +183,7 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int);
extern grpc_poll_function_type grpc_poll_function;
/* This should be used for testing purposes ONLY */
void grpc_set_event_engine_test_only(const grpc_event_engine_vtable *);
#endif /* GRPC_CORE_LIB_IOMGR_EV_POSIX_H */

@ -75,6 +75,10 @@ void grpc_pollset_destroy(grpc_pollset *pollset);
and it is guaranteed that it will not be released by grpc_pollset_work
AFTER worker has been destroyed.
It's legal for worker to be NULL: in that case, this specific thread can not
be directly woken with a kick, but maybe be indirectly (with a kick against
the pollset as a whole).
Tries not to block past deadline.
May call grpc_closure_list_run on grpc_closure_list, without holding the
pollset

@ -120,7 +120,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker **worker_hdl,
gpr_timespec now, gpr_timespec deadline) {
grpc_pollset_worker worker;
*worker_hdl = &worker;
if (worker_hdl) *worker_hdl = &worker;
int added_worker = 0;
worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
@ -185,7 +185,7 @@ done:
remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
}
gpr_cv_destroy(&worker.cv);
*worker_hdl = NULL;
if (worker_hdl) *worker_hdl = NULL;
return GRPC_ERROR_NONE;
}

@ -142,6 +142,8 @@ struct grpc_resource_quota {
/* Amount of free memory in the resource quota */
int64_t free_pool;
gpr_atm last_size;
/* Has rq_step been scheduled to occur? */
bool step_scheduled;
/* Are we currently reclaiming memory */
@ -581,6 +583,7 @@ grpc_resource_quota *grpc_resource_quota_create(const char *name) {
resource_quota->combiner = grpc_combiner_create(NULL);
resource_quota->free_pool = INT64_MAX;
resource_quota->size = INT64_MAX;
gpr_atm_no_barrier_store(&resource_quota->last_size, GPR_ATM_MAX);
resource_quota->step_scheduled = false;
resource_quota->reclaiming = false;
gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, 0);
@ -643,11 +646,17 @@ void grpc_resource_quota_resize(grpc_resource_quota *resource_quota,
rq_resize_args *a = gpr_malloc(sizeof(*a));
a->resource_quota = grpc_resource_quota_ref_internal(resource_quota);
a->size = (int64_t)size;
gpr_atm_no_barrier_store(&resource_quota->last_size,
(gpr_atm)GPR_MIN((size_t)GPR_ATM_MAX, size));
grpc_closure_init(&a->closure, rq_resize, a, grpc_schedule_on_exec_ctx);
grpc_closure_sched(&exec_ctx, &a->closure, GRPC_ERROR_NONE);
grpc_exec_ctx_finish(&exec_ctx);
}
size_t grpc_resource_quota_peek_size(grpc_resource_quota *resource_quota) {
return (size_t)gpr_atm_no_barrier_load(&resource_quota->last_size);
}
/*******************************************************************************
* grpc_resource_user channel args api
*/

@ -90,6 +90,8 @@ grpc_resource_quota *grpc_resource_quota_from_channel_args(
double grpc_resource_quota_get_memory_pressure(
grpc_resource_quota *resource_quota);
size_t grpc_resource_quota_peek_size(grpc_resource_quota *resource_quota);
typedef struct grpc_resource_user grpc_resource_user;
grpc_resource_user *grpc_resource_user_create(

@ -40,10 +40,6 @@
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/iomgr/resolve_address.h"
/* Channel arg (integer) setting how large a slice to try and read from the wire
each time recvmsg (or equivalent) is called */
#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size"
/* Asynchronously connect to an address (specified as (addr, len)), and call
cb with arg and the completed connection when done (or call cb with arg and
NULL on failure).

@ -137,29 +137,7 @@ static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
grpc_endpoint *grpc_tcp_client_create_from_fd(
grpc_exec_ctx *exec_ctx, grpc_fd *fd, const grpc_channel_args *channel_args,
const char *addr_str) {
size_t tcp_read_chunk_size = GRPC_TCP_DEFAULT_READ_SLICE_SIZE;
grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
if (channel_args != NULL) {
for (size_t i = 0; i < channel_args->num_args; i++) {
if (0 ==
strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) {
grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
8 * 1024 * 1024};
tcp_read_chunk_size = (size_t)grpc_channel_arg_get_integer(
&channel_args->args[i], options);
} else if (0 ==
strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
resource_quota = grpc_resource_quota_ref_internal(
channel_args->args[i].value.pointer.p);
}
}
}
grpc_endpoint *ep =
grpc_tcp_create(fd, resource_quota, tcp_read_chunk_size, addr_str);
grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
return ep;
return grpc_tcp_create(exec_ctx, fd, channel_args, addr_str);
}
static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {

@ -63,7 +63,7 @@ typedef struct {
int refs;
grpc_closure on_connect;
grpc_endpoint **endpoint;
grpc_resource_quota *resource_quota;
grpc_channel_args *channel_args;
} async_connect;
static void async_connect_unlock_and_cleanup(grpc_exec_ctx *exec_ctx,
@ -72,7 +72,7 @@ static void async_connect_unlock_and_cleanup(grpc_exec_ctx *exec_ctx,
int done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu);
if (done) {
grpc_resource_quota_unref_internal(exec_ctx, ac->resource_quota);
grpc_channel_args_destroy(exec_ctx, ac->channel_args);
gpr_mu_destroy(&ac->mu);
gpr_free(ac->addr_name);
gpr_free(ac);
@ -119,7 +119,8 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
if (!wsa_success) {
error = GRPC_WSA_ERROR(WSAGetLastError(), "ConnectEx");
} else {
*ep = grpc_tcp_create(socket, ac->resource_quota, ac->addr_name);
*ep =
grpc_tcp_create(exec_ctx, socket, ac->channel_args, ac->addr_name);
socket = NULL;
}
} else {
@ -152,17 +153,6 @@ static void tcp_client_connect_impl(
grpc_winsocket_callback_info *info;
grpc_error *error = GRPC_ERROR_NONE;
grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
if (channel_args != NULL) {
for (size_t i = 0; i < channel_args->num_args; i++) {
if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
resource_quota = grpc_resource_quota_ref_internal(
channel_args->args[i].value.pointer.p);
}
}
}
*endpoint = NULL;
/* Use dualstack sockets where available. */
@ -225,7 +215,7 @@ static void tcp_client_connect_impl(
ac->refs = 2;
ac->addr_name = grpc_sockaddr_to_uri(addr);
ac->endpoint = endpoint;
ac->resource_quota = resource_quota;
ac->channel_args = grpc_channel_args_copy(channel_args);
grpc_closure_init(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx);
grpc_closure_init(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx);
@ -247,7 +237,6 @@ failure:
} else if (sock != INVALID_SOCKET) {
closesocket(sock);
}
grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
grpc_closure_sched(exec_ctx, on_done, final_error);
}

@ -52,7 +52,9 @@
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/profiling/timers.h"
@ -80,10 +82,14 @@ typedef struct {
int fd;
bool finished_edge;
msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */
size_t slice_size;
double target_length;
double bytes_read_this_round;
gpr_refcount refcount;
gpr_atm shutdown_count;
int min_read_chunk_size;
int max_read_chunk_size;
/* garbage after the last read */
grpc_slice_buffer last_read_buffer;
@ -108,6 +114,42 @@ typedef struct {
grpc_resource_user_slice_allocator slice_allocator;
} grpc_tcp;
static void add_to_estimate(grpc_tcp *tcp, size_t bytes) {
tcp->bytes_read_this_round += (double)bytes;
}
static void finish_estimate(grpc_tcp *tcp) {
/* If we read >80% of the target buffer in one read loop, increase the size
of the target buffer to either the amount read, or twice its previous
value */
if (tcp->bytes_read_this_round > tcp->target_length * 0.8) {
tcp->target_length =
GPR_MAX(2 * tcp->target_length, tcp->bytes_read_this_round);
} else {
tcp->target_length =
0.99 * tcp->target_length + 0.01 * tcp->bytes_read_this_round;
}
tcp->bytes_read_this_round = 0;
}
static size_t get_target_read_size(grpc_tcp *tcp) {
grpc_resource_quota *rq = grpc_resource_user_quota(tcp->resource_user);
double pressure = grpc_resource_quota_get_memory_pressure(rq);
double target =
tcp->target_length * (pressure > 0.8 ? (1.0 - pressure) / 0.2 : 1.0);
size_t sz = (((size_t)GPR_CLAMP(target, tcp->min_read_chunk_size,
tcp->max_read_chunk_size)) +
255) &
~(size_t)255;
/* don't use more than 1/16th of the overall resource quota for a single read
* alloc */
size_t rqmax = grpc_resource_quota_peek_size(rq);
if (sz > rqmax / 16 && rqmax > 1024) {
sz = rqmax / 16;
}
return sz;
}
static grpc_error *tcp_annotate_error(grpc_error *src_error, grpc_tcp *tcp) {
return grpc_error_set_str(
grpc_error_set_int(src_error, GRPC_ERROR_INT_FD, tcp->fd),
@ -232,9 +274,7 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
/* NB: After calling call_read_cb a parallel call of the read handler may
* be running. */
if (errno == EAGAIN) {
if (tcp->iov_size > 1) {
tcp->iov_size /= 2;
}
finish_estimate(tcp);
/* We've consumed the edge, request a new one */
grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
} else {
@ -253,14 +293,13 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Socket closed"), tcp));
TCP_UNREF(exec_ctx, tcp, "read");
} else {
add_to_estimate(tcp, (size_t)read_bytes);
GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
if ((size_t)read_bytes < tcp->incoming_buffer->length) {
grpc_slice_buffer_trim_end(
tcp->incoming_buffer,
tcp->incoming_buffer->length - (size_t)read_bytes,
&tcp->last_read_buffer);
} else if (tcp->iov_size < MAX_READ_IOVEC) {
++tcp->iov_size;
}
GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
call_read_cb(exec_ctx, tcp, GRPC_ERROR_NONE);
@ -285,11 +324,11 @@ static void tcp_read_allocation_done(grpc_exec_ctx *exec_ctx, void *tcpp,
}
static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
if (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
grpc_resource_user_alloc_slices(
exec_ctx, &tcp->slice_allocator, tcp->slice_size,
(size_t)tcp->iov_size - tcp->incoming_buffer->count,
tcp->incoming_buffer);
size_t target_read_size = get_target_read_size(tcp);
if (tcp->incoming_buffer->length < target_read_size &&
tcp->incoming_buffer->count < MAX_READ_IOVEC) {
grpc_resource_user_alloc_slices(exec_ctx, &tcp->slice_allocator,
target_read_size, 1, tcp->incoming_buffer);
} else {
tcp_do_read(exec_ctx, tcp);
}
@ -540,9 +579,50 @@ static const grpc_endpoint_vtable vtable = {tcp_read,
tcp_get_peer,
tcp_get_fd};
grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
grpc_resource_quota *resource_quota,
size_t slice_size, const char *peer_string) {
#define MAX_CHUNK_SIZE 32 * 1024 * 1024
grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_fd *em_fd,
const grpc_channel_args *channel_args,
const char *peer_string) {
int tcp_read_chunk_size = GRPC_TCP_DEFAULT_READ_SLICE_SIZE;
int tcp_max_read_chunk_size = 4 * 1024 * 1024;
int tcp_min_read_chunk_size = 256;
grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
if (channel_args != NULL) {
for (size_t i = 0; i < channel_args->num_args; i++) {
if (0 ==
strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) {
grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
MAX_CHUNK_SIZE};
tcp_read_chunk_size =
grpc_channel_arg_get_integer(&channel_args->args[i], options);
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE)) {
grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
MAX_CHUNK_SIZE};
tcp_min_read_chunk_size =
grpc_channel_arg_get_integer(&channel_args->args[i], options);
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE)) {
grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
MAX_CHUNK_SIZE};
tcp_max_read_chunk_size =
grpc_channel_arg_get_integer(&channel_args->args[i], options);
} else if (0 ==
strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
resource_quota = grpc_resource_quota_ref_internal(
channel_args->args[i].value.pointer.p);
}
}
}
if (tcp_min_read_chunk_size > tcp_max_read_chunk_size) {
tcp_min_read_chunk_size = tcp_max_read_chunk_size;
}
tcp_read_chunk_size = GPR_CLAMP(tcp_read_chunk_size, tcp_min_read_chunk_size,
tcp_max_read_chunk_size);
grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
tcp->base.vtable = &vtable;
tcp->peer_string = gpr_strdup(peer_string);
@ -552,7 +632,10 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
tcp->release_fd_cb = NULL;
tcp->release_fd = NULL;
tcp->incoming_buffer = NULL;
tcp->slice_size = slice_size;
tcp->target_length = (double)tcp_read_chunk_size;
tcp->min_read_chunk_size = tcp_min_read_chunk_size;
tcp->max_read_chunk_size = tcp_max_read_chunk_size;
tcp->bytes_read_this_round = 0;
tcp->iov_size = 1;
tcp->finished_edge = true;
/* paired with unref in grpc_tcp_destroy */
@ -569,6 +652,7 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
&tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp);
/* Tell network status tracker about new endpoint */
grpc_network_status_register_endpoint(&tcp->base);
grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
return &tcp->base;
}

@ -47,14 +47,13 @@
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/ev_posix.h"
#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
extern int grpc_tcp_trace;
/* Create a tcp endpoint given a file desciptor and a read slice size.
Takes ownership of fd. */
grpc_endpoint *grpc_tcp_create(grpc_fd *fd, grpc_resource_quota *resource_quota,
size_t read_slice_size, const char *peer_string);
grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
const grpc_channel_args *args,
const char *peer_string);
/* Return the tcp endpoint's fd, or -1 if this is not available. Does not
release the fd.

@ -59,6 +59,7 @@
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
@ -90,7 +91,6 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
grpc_tcp_server *s = gpr_zalloc(sizeof(grpc_tcp_server));
s->so_reuseport = has_so_reuseport;
s->resource_quota = grpc_resource_quota_create(NULL);
s->expand_wildcard_addrs = false;
for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
if (0 == strcmp(GRPC_ARG_ALLOW_REUSEPORT, args->args[i].key)) {
@ -98,27 +98,14 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
s->so_reuseport =
has_so_reuseport && (args->args[i].value.integer != 0);
} else {
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
gpr_free(s);
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(GRPC_ARG_ALLOW_REUSEPORT
" must be an integer");
}
} else if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
if (args->args[i].type == GRPC_ARG_POINTER) {
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
s->resource_quota =
grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
} else {
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
gpr_free(s);
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
}
} else if (0 == strcmp(GRPC_ARG_EXPAND_WILDCARD_ADDRS, args->args[i].key)) {
if (args->args[i].type == GRPC_ARG_INTEGER) {
s->expand_wildcard_addrs = (args->args[i].value.integer != 0);
} else {
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
gpr_free(s);
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ARG_EXPAND_WILDCARD_ADDRS " must be an integer");
@ -138,6 +125,7 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
s->head = NULL;
s->tail = NULL;
s->nports = 0;
s->channel_args = grpc_channel_args_copy(args);
gpr_atm_no_barrier_store(&s->next_pollset_to_assign, 0);
*server = s;
return GRPC_ERROR_NONE;
@ -158,8 +146,7 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
s->head = sp->next;
gpr_free(sp);
}
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
grpc_channel_args_destroy(exec_ctx, s->channel_args);
gpr_free(s);
}
@ -286,8 +273,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) {
sp->server->on_accept_cb(
exec_ctx, sp->server->on_accept_cb_arg,
grpc_tcp_create(fdobj, sp->server->resource_quota,
GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str),
grpc_tcp_create(exec_ctx, fdobj, sp->server->channel_args, addr_str),
read_notifier_pollset, acceptor);
gpr_free(name);

@ -103,7 +103,8 @@ struct grpc_tcp_server {
/* next pollset to assign a channel to */
gpr_atm next_pollset_to_assign;
grpc_resource_quota *resource_quota;
/* channel args for this server */
grpc_channel_args *channel_args;
};
/* If successful, add a listener to \a s for \a addr, set \a dsmode for the

@ -46,6 +46,7 @@
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/iocp_windows.h"
#include "src/core/lib/iomgr/pollset_windows.h"
#include "src/core/lib/iomgr/resolve_address.h"
@ -102,7 +103,7 @@ struct grpc_tcp_server {
/* shutdown callback */
grpc_closure *shutdown_complete;
grpc_resource_quota *resource_quota;
grpc_channel_args *channel_args;
};
/* Public function. Allocates the proper data structures to hold a
@ -112,21 +113,7 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
const grpc_channel_args *args,
grpc_tcp_server **server) {
grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
s->resource_quota = grpc_resource_quota_create(NULL);
for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
if (args->args[i].type == GRPC_ARG_POINTER) {
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
s->resource_quota =
grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
} else {
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
gpr_free(s);
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
}
}
}
s->channel_args = grpc_channel_args_copy(args);
gpr_ref_init(&s->refs, 1);
gpr_mu_init(&s->mu);
s->active_ports = 0;
@ -155,7 +142,7 @@ static void destroy_server(grpc_exec_ctx *exec_ctx, void *arg,
grpc_winsocket_destroy(sp->socket);
gpr_free(sp);
}
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
grpc_channel_args_destroy(exec_ctx, s->channel_args);
gpr_free(s);
}
@ -383,8 +370,8 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
gpr_free(utf8_message);
}
gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
sp->server->resource_quota, peer_name_string);
ep = grpc_tcp_create(exec_ctx, grpc_winsocket_create(sock, fd_name),
sp->server->channel_args, peer_name_string);
gpr_free(fd_name);
gpr_free(peer_name_string);
} else {

@ -430,9 +430,19 @@ static grpc_endpoint_vtable vtable = {win_read,
win_get_peer,
win_get_fd};
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket,
grpc_resource_quota *resource_quota,
grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
grpc_channel_args *channel_args,
char *peer_string) {
grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
if (channel_args != NULL) {
for (size_t i = 0; i < channel_args->num_args; i++) {
if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
resource_quota = grpc_resource_quota_ref_internal(
channel_args->args[i].value.pointer.p);
}
}
}
grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
memset(tcp, 0, sizeof(grpc_tcp));
tcp->base.vtable = &vtable;

@ -50,8 +50,8 @@
/* Create a tcp endpoint given a winsock handle.
* Takes ownership of the handle.
*/
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket,
grpc_resource_quota *resource_quota,
grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
grpc_channel_args *channel_args,
char *peer_string);
grpc_error *grpc_tcp_prepare_socket(SOCKET sock);

@ -287,12 +287,11 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
if (num_left_overs > 0) {
/* Put the leftovers in our buffer (ownership transfered). */
if (has_left_overs_in_current_slice) {
grpc_slice_buffer_add(
&h->left_overs,
grpc_slice_split_tail(&h->args->read_buffer->slices[i],
consumed_slice_size));
grpc_slice tail = grpc_slice_split_tail(&h->args->read_buffer->slices[i],
consumed_slice_size);
grpc_slice_buffer_add(&h->left_overs, tail);
/* split_tail above increments refcount. */
grpc_slice_unref_internal(exec_ctx, h->args->read_buffer->slices[i]);
grpc_slice_unref_internal(exec_ctx, tail);
}
grpc_slice_buffer_addn(
&h->left_overs, &h->args->read_buffer->slices[i + 1],

@ -46,27 +46,29 @@
#define GROW(x) (3 * (x) / 2)
static void maybe_embiggen(grpc_slice_buffer *sb) {
if (sb->base_slices != sb->slices) {
memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
sb->slices = sb->base_slices;
}
/* How far away from sb->base_slices is sb->slices pointer */
size_t slice_offset = (size_t)(sb->slices - sb->base_slices);
size_t slice_count = sb->count + slice_offset;
if (slice_count == sb->capacity) {
sb->capacity = GROW(sb->capacity);
GPR_ASSERT(sb->capacity > slice_count);
if (sb->base_slices == sb->inlined) {
sb->base_slices = gpr_malloc(sb->capacity * sizeof(grpc_slice));
memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
if (sb->base_slices != sb->slices) {
/* Make room by moving elements if there's still space unused */
memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
sb->slices = sb->base_slices;
} else {
sb->base_slices =
gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice));
}
/* Allocate more memory if no more space is available */
sb->capacity = GROW(sb->capacity);
GPR_ASSERT(sb->capacity > slice_count);
if (sb->base_slices == sb->inlined) {
sb->base_slices = gpr_malloc(sb->capacity * sizeof(grpc_slice));
memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
} else {
sb->base_slices =
gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice));
}
sb->slices = sb->base_slices + slice_offset;
sb->slices = sb->base_slices + slice_offset;
}
}
}

@ -145,16 +145,28 @@ typedef struct batch_control {
grpc_transport_stream_op_batch op;
} batch_control;
typedef struct {
gpr_mu child_list_mu;
grpc_call *first_child;
} parent_call;
typedef struct {
grpc_call *parent;
/** siblings: children of the same parent form a list, and this list is
protected under
parent->mu */
grpc_call *sibling_next;
grpc_call *sibling_prev;
} child_call;
struct grpc_call {
gpr_arena *arena;
grpc_completion_queue *cq;
grpc_polling_entity pollent;
grpc_channel *channel;
grpc_call *parent;
grpc_call *first_child;
gpr_timespec start_time;
/* protects first_child, and child next/prev links */
gpr_mu child_list_mu;
/* parent_call* */ gpr_atm parent_call_atm;
child_call *child_call;
/* client or server call */
bool is_client;
@ -175,7 +187,7 @@ struct grpc_call {
/* have we received initial metadata */
bool has_initial_md_been_received;
batch_control active_batches[MAX_CONCURRENT_BATCHES];
batch_control *active_batches[MAX_CONCURRENT_BATCHES];
grpc_transport_stream_op_batch_payload stream_op_payload;
/* first idx: is_receiving, second idx: is_trailing */
@ -206,12 +218,6 @@ struct grpc_call {
int send_extra_metadata_count;
gpr_timespec send_deadline;
/** siblings: children of the same parent form a list, and this list is
protected under
parent->mu */
grpc_call *sibling_next;
grpc_call *sibling_prev;
grpc_slice_buffer_stream sending_stream;
grpc_byte_stream *receiving_stream;
@ -276,6 +282,23 @@ static void add_init_error(grpc_error **composite, grpc_error *new) {
*composite = grpc_error_add_child(*composite, new);
}
static parent_call *get_or_create_parent_call(grpc_call *call) {
parent_call *p = (parent_call *)gpr_atm_acq_load(&call->parent_call_atm);
if (p == NULL) {
p = gpr_arena_alloc(call->arena, sizeof(*p));
gpr_mu_init(&p->child_list_mu);
if (!gpr_atm_rel_cas(&call->parent_call_atm, (gpr_atm)NULL, (gpr_atm)p)) {
gpr_mu_destroy(&p->child_list_mu);
p = (parent_call *)gpr_atm_acq_load(&call->parent_call_atm);
}
}
return p;
}
static parent_call *get_parent_call(grpc_call *call) {
return (parent_call *)gpr_atm_acq_load(&call->parent_call_atm);
}
grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
const grpc_call_create_args *args,
grpc_call **out_call) {
@ -291,10 +314,8 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
sizeof(grpc_call) + channel_stack->call_stack_size);
call->arena = arena;
*out_call = call;
gpr_mu_init(&call->child_list_mu);
call->channel = args->channel;
call->cq = args->cq;
call->parent = args->parent_call;
call->start_time = gpr_now(GPR_CLOCK_MONOTONIC);
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
@ -326,11 +347,17 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
gpr_convert_clock_type(args->send_deadline, GPR_CLOCK_MONOTONIC);
if (args->parent_call != NULL) {
child_call *cc = call->child_call =
gpr_arena_alloc(arena, sizeof(child_call));
call->child_call->parent = args->parent_call;
GRPC_CALL_INTERNAL_REF(args->parent_call, "child");
GPR_ASSERT(call->is_client);
GPR_ASSERT(!args->parent_call->is_client);
gpr_mu_lock(&args->parent_call->child_list_mu);
parent_call *pc = get_or_create_parent_call(args->parent_call);
gpr_mu_lock(&pc->child_list_mu);
if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) {
send_deadline = gpr_time_min(
@ -364,17 +391,17 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
}
}
if (args->parent_call->first_child == NULL) {
args->parent_call->first_child = call;
call->sibling_next = call->sibling_prev = call;
if (pc->first_child == NULL) {
pc->first_child = call;
cc->sibling_next = cc->sibling_prev = call;
} else {
call->sibling_next = args->parent_call->first_child;
call->sibling_prev = args->parent_call->first_child->sibling_prev;
call->sibling_next->sibling_prev = call->sibling_prev->sibling_next =
call;
cc->sibling_next = pc->first_child;
cc->sibling_prev = pc->first_child->child_call->sibling_prev;
cc->sibling_next->child_call->sibling_prev =
cc->sibling_prev->child_call->sibling_next = call;
}
gpr_mu_unlock(&args->parent_call->child_list_mu);
gpr_mu_unlock(&pc->child_list_mu);
}
call->send_deadline = send_deadline;
@ -469,7 +496,10 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
if (c->receiving_stream != NULL) {
grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
}
gpr_mu_destroy(&c->child_list_mu);
parent_call *pc = get_parent_call(c);
if (pc != NULL) {
gpr_mu_destroy(&pc->child_list_mu);
}
for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
GRPC_MDELEM_UNREF(exec_ctx, c->send_extra_metadata[ii].md);
}
@ -499,31 +529,31 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
}
void grpc_call_destroy(grpc_call *c) {
int cancel;
grpc_call *parent = c->parent;
child_call *cc = c->child_call;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GPR_TIMER_BEGIN("grpc_call_destroy", 0);
GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
if (parent) {
gpr_mu_lock(&parent->child_list_mu);
if (c == parent->first_child) {
parent->first_child = c->sibling_next;
if (c == parent->first_child) {
parent->first_child = NULL;
if (cc) {
parent_call *pc = get_parent_call(cc->parent);
gpr_mu_lock(&pc->child_list_mu);
if (c == pc->first_child) {
pc->first_child = cc->sibling_next;
if (c == pc->first_child) {
pc->first_child = NULL;
}
}
c->sibling_prev->sibling_next = c->sibling_next;
c->sibling_next->sibling_prev = c->sibling_prev;
gpr_mu_unlock(&parent->child_list_mu);
GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
cc->sibling_prev->child_call->sibling_next = cc->sibling_next;
cc->sibling_next->child_call->sibling_prev = cc->sibling_prev;
gpr_mu_unlock(&pc->child_list_mu);
GRPC_CALL_INTERNAL_UNREF(&exec_ctx, cc->parent, "child");
}
GPR_ASSERT(!c->destroy_called);
c->destroy_called = 1;
cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) &&
!gpr_atm_acq_load(&c->received_final_op_atm);
bool cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) != 0 &&
gpr_atm_acq_load(&c->received_final_op_atm) == 0;
if (cancel) {
cancel_with_error(&exec_ctx, c, STATUS_FROM_API_OVERRIDE,
GRPC_ERROR_CANCELLED);
@ -1034,7 +1064,11 @@ static batch_control *allocate_batch_control(grpc_call *call,
const grpc_op *ops,
size_t num_ops) {
int slot = batch_slot_for_op(ops[0].op);
batch_control *bctl = &call->active_batches[slot];
batch_control **pslot = &call->active_batches[slot];
if (*pslot == NULL) {
*pslot = gpr_arena_alloc(call->arena, sizeof(batch_control));
}
batch_control *bctl = *pslot;
if (bctl->call != NULL) {
return NULL;
}
@ -1075,7 +1109,6 @@ static grpc_error *consolidate_batch_errors(batch_control *bctl) {
static void post_batch_completion(grpc_exec_ctx *exec_ctx,
batch_control *bctl) {
grpc_call *child_call;
grpc_call *next_child_call;
grpc_call *call = bctl->call;
grpc_error *error = consolidate_batch_errors(bctl);
@ -1100,21 +1133,25 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
/* propagate cancellation to any interested children */
gpr_atm_rel_store(&call->received_final_op_atm, 1);
gpr_mu_lock(&call->child_list_mu);
child_call = call->first_child;
if (child_call != NULL) {
do {
next_child_call = child_call->sibling_next;
if (child_call->cancellation_is_inherited) {
GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
cancel_with_error(exec_ctx, child_call, STATUS_FROM_API_OVERRIDE,
GRPC_ERROR_CANCELLED);
GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
}
child_call = next_child_call;
} while (child_call != call->first_child);
parent_call *pc = get_parent_call(call);
if (pc != NULL) {
grpc_call *child;
gpr_mu_lock(&pc->child_list_mu);
child = pc->first_child;
if (child != NULL) {
do {
next_child_call = child->child_call->sibling_next;
if (child->cancellation_is_inherited) {
GRPC_CALL_INTERNAL_REF(child, "propagate_cancel");
cancel_with_error(exec_ctx, child, STATUS_FROM_API_OVERRIDE,
GRPC_ERROR_CANCELLED);
GRPC_CALL_INTERNAL_UNREF(exec_ctx, child, "propagate_cancel");
}
child = next_child_call;
} while (child != pc->first_child);
}
gpr_mu_unlock(&pc->child_list_mu);
}
gpr_mu_unlock(&call->child_list_mu);
if (call->is_client) {
get_final_status(call, set_status_value_directly,

@ -345,7 +345,6 @@ static void dump_pending_tags(grpc_completion_queue *cc) {}
grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_timespec deadline, void *reserved) {
grpc_event ret;
grpc_pollset_worker *worker = NULL;
gpr_timespec now;
GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
@ -426,8 +425,8 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_mu_lock(cc->mu);
continue;
} else {
grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc),
&worker, now, iteration_deadline);
grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), NULL,
now, iteration_deadline);
if (err != GRPC_ERROR_NONE) {
gpr_mu_unlock(cc->mu);
const char *msg = grpc_error_string(err);

@ -111,6 +111,8 @@ grpc_byte_buffer* CoreCodegen::grpc_raw_byte_buffer_create(grpc_slice* slice,
return ::grpc_raw_byte_buffer_create(slice, nslices);
}
grpc_slice CoreCodegen::grpc_empty_slice() { return ::grpc_empty_slice(); }
grpc_slice CoreCodegen::grpc_slice_malloc(size_t length) {
return ::grpc_slice_malloc(length);
}

@ -1,5 +1,5 @@
{
"sdk": {
"version": "1.0.0-preview2-003121"
"version": "1.0.0-preview2-003131"
}
}

@ -45,6 +45,7 @@
namespace grpc {
namespace node {
using Nan::Callback;
using Nan::MaybeLocal;
using v8::Function;
@ -62,7 +63,11 @@ grpc_byte_buffer *BufferToByteBuffer(Local<Value> buffer) {
}
namespace {
void delete_buffer(char *data, void *hint) { delete[] data; }
void delete_buffer(char *data, void *hint) {
grpc_slice *slice = static_cast<grpc_slice *>(hint);
grpc_slice_unref(*slice);
delete slice;
}
}
Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
@ -75,31 +80,15 @@ Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
Nan::ThrowError("Error initializing byte buffer reader.");
return scope.Escape(Nan::Undefined());
}
grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
size_t length = GRPC_SLICE_LENGTH(slice);
char *result = new char[length];
memcpy(result, GRPC_SLICE_START_PTR(slice), length);
grpc_slice_unref(slice);
return scope.Escape(MakeFastBuffer(
Nan::NewBuffer(result, length, delete_buffer, NULL).ToLocalChecked()));
grpc_slice *slice = new grpc_slice;
*slice = grpc_byte_buffer_reader_readall(&reader);
grpc_byte_buffer_reader_destroy(&reader);
char *result = reinterpret_cast<char *>(GRPC_SLICE_START_PTR(*slice));
size_t length = GRPC_SLICE_LENGTH(*slice);
Local<Value> buf =
Nan::NewBuffer(result, length, delete_buffer, slice).ToLocalChecked();
return scope.Escape(buf);
}
Local<Value> MakeFastBuffer(Local<Value> slowBuffer) {
Nan::EscapableHandleScope scope;
Local<Object> globalObj = Nan::GetCurrentContext()->Global();
MaybeLocal<Value> constructorValue = Nan::Get(
globalObj, Nan::New("Buffer").ToLocalChecked());
Local<Function> bufferConstructor = Local<Function>::Cast(
constructorValue.ToLocalChecked());
const int argc = 3;
Local<Value> consArgs[argc] = {
slowBuffer,
Nan::New<Number>(::node::Buffer::Length(slowBuffer)),
Nan::New<Number>(0)
};
MaybeLocal<Object> fastBuffer = Nan::NewInstance(bufferConstructor,
argc, consArgs);
return scope.Escape(fastBuffer.ToLocalChecked());
}
} // namespace node
} // namespace grpc

@ -50,10 +50,6 @@ grpc_byte_buffer *BufferToByteBuffer(v8::Local<v8::Value> buffer);
/* Convert a grpc_byte_buffer to a Node.js Buffer */
v8::Local<v8::Value> ByteBufferToBuffer(grpc_byte_buffer *buffer);
/* Convert a ::node::Buffer to a fast Buffer, as defined in the Node
Buffer documentation */
v8::Local<v8::Value> MakeFastBuffer(v8::Local<v8::Value> slowBuffer);
} // namespace node
} // namespace grpc

@ -37,7 +37,6 @@
#include <grpc/support/alloc.h>
#include "slice.h"
#include "byte_buffer.h"
namespace grpc {
namespace node {
@ -93,9 +92,9 @@ Local<Value> CreateBufferFromSlice(const grpc_slice slice) {
Nan::EscapableHandleScope scope;
grpc_slice *slice_ptr = new grpc_slice;
*slice_ptr = grpc_slice_ref(slice);
return scope.Escape(MakeFastBuffer(Nan::NewBuffer(
return scope.Escape(Nan::NewBuffer(
const_cast<char *>(reinterpret_cast<const char *>(GRPC_SLICE_START_PTR(*slice_ptr))),
GRPC_SLICE_LENGTH(*slice_ptr), SliceFreeCallback, slice_ptr).ToLocalChecked()));
GRPC_SLICE_LENGTH(*slice_ptr), SliceFreeCallback, slice_ptr).ToLocalChecked());
}
} // namespace node

@ -52,42 +52,89 @@ var Metadata = require('./src/metadata.js');
var grpc = require('./src/grpc_extension');
var protobuf_js_5_common = require('./src/protobuf_js_5_common');
var protobuf_js_6_common = require('./src/protobuf_js_6_common');
grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii'));
/**
* Load a gRPC object from an existing ProtoBuf.Reflect object.
* @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
* @param {Object=} options Options to apply to the loaded object
* Load a ProtoBuf.js object as a gRPC object. The options object can provide
* the following options:
* - binaryAsBase64: deserialize bytes values as base64 strings instead of
* Buffers. Defaults to false
* - longsAsStrings: deserialize long values as strings instead of objects.
* Defaults to true
* - enumsAsStrings: deserialize enum values as strings instead of numbers.
* Defaults to true
* - deprecatedArgumentOrder: Use the beta method argument order for client
* methods, with optional arguments after the callback. Defaults to false.
* This option is only a temporary stopgap measure to smooth an API breakage.
* It is deprecated, and new code should not use it.
* - protobufjsVersion: Available values are 5, 6, and 'detect'. 5 and 6
* respectively indicate that an object from the corresponding version of
* ProtoBuf.js is provided in the value argument. If the option is 'detect',
* gRPC will guess what the version is based on the structure of the value.
* Defaults to 'detect'.
* @param {Object} value The ProtoBuf.js reflection object to load
* @param {Object=} options Options to apply to the loaded file
* @return {Object<string, *>} The resulting gRPC object
*/
exports.loadObject = function loadObject(value, options) {
var result = {};
if (value.className === 'Namespace') {
_.each(value.children, function(child) {
result[child.name] = loadObject(child, options);
});
return result;
} else if (value.className === 'Service') {
return client.makeProtobufClientConstructor(value, options);
} else if (value.className === 'Message' || value.className === 'Enum') {
return value.build();
options = _.defaults(options, common.defaultGrpcOptions);
options = _.defaults(options, {'protobufjsVersion': 'detect'});
var protobufjsVersion;
if (options.protobufjsVersion === 'detect') {
if (protobuf_js_6_common.isProbablyProtobufJs6(value)) {
protobufjsVersion = 6;
} else if (protobuf_js_5_common.isProbablyProtobufJs5(value)) {
protobufjsVersion = 5;
} else {
var error_message = 'Could not detect ProtoBuf.js version. Please ' +
'specify the version number with the "protobufjs_version" option';
throw new Error(error_message);
}
} else {
return value;
protobufjsVersion = options.protobufjsVersion;
}
switch (protobufjsVersion) {
case 6: return protobuf_js_6_common.loadObject(value, options);
case 5:
var deprecation_message = 'Calling grpc.loadObject with an object ' +
'generated by ProtoBuf.js 5 is deprecated. Please upgrade to ' +
'ProtoBuf.js 6.';
common.log(grpc.logVerbosity.INFO, deprecation_message);
return protobuf_js_5_common.loadObject(value, options);
default:
throw new Error('Unrecognized protobufjsVersion', protobufjsVersion);
}
};
var loadObject = exports.loadObject;
function applyProtoRoot(filename, root) {
if (_.isString(filename)) {
return filename;
}
filename.root = path.resolve(filename.root) + '/';
root.resolvePath = function(originPath, importPath, alreadyNormalized) {
return ProtoBuf.util.path.resolve(filename.root,
importPath,
alreadyNormalized);
};
return filename.file;
}
/**
* Load a gRPC object from a .proto file. The options object can provide the
* following options:
* - convertFieldsToCamelCase: Loads this file with that option on protobuf.js
* set as specified. See
* https://github.com/dcodeIO/protobuf.js/wiki/Advanced-options for details
* - convertFieldsToCamelCase: Load this file with field names in camel case
* instead of their original case
* - binaryAsBase64: deserialize bytes values as base64 strings instead of
* Buffers. Defaults to false
* - longsAsStrings: deserialize long values as strings instead of objects.
* Defaults to true
* - enumsAsStrings: deserialize enum values as strings instead of numbers.
* Defaults to true
* - deprecatedArgumentOrder: Use the beta method argument order for client
* methods, with optional arguments after the callback. Defaults to false.
* This option is only a temporary stopgap measure to smooth an API breakage.
@ -99,29 +146,17 @@ var loadObject = exports.loadObject;
* @return {Object<string, *>} The resulting gRPC object
*/
exports.load = function load(filename, format, options) {
if (!format) {
format = 'proto';
}
var convertFieldsToCamelCaseOriginal = ProtoBuf.convertFieldsToCamelCase;
if(options && options.hasOwnProperty('convertFieldsToCamelCase')) {
ProtoBuf.convertFieldsToCamelCase = options.convertFieldsToCamelCase;
}
var builder;
try {
switch(format) {
case 'proto':
builder = ProtoBuf.loadProtoFile(filename);
break;
case 'json':
builder = ProtoBuf.loadJsonFile(filename);
break;
default:
throw new Error('Unrecognized format "' + format + '"');
}
} finally {
ProtoBuf.convertFieldsToCamelCase = convertFieldsToCamelCaseOriginal;
}
return loadObject(builder.ns, options);
/* Note: format is currently unused, because the API for loading a proto
file or a JSON file is identical in Protobuf.js 6. In the future, there is
still the possibility of adding other formats that would be loaded
differently */
options = _.defaults(options, common.defaultGrpcOptions);
options.protobufjs_version = 6;
var root = new ProtoBuf.Root();
var parse_options = {keepCase: !options.convertFieldsToCamelCase};
return loadObject(root.loadSync(applyProtoRoot(filename, root),
parse_options),
options);
};
var log_template = _.template(

@ -228,7 +228,7 @@ function getServer(port, tls) {
server_creds = grpc.ServerCredentials.createInsecure();
}
var server = new grpc.Server(options);
server.addProtoService(testProto.TestService.service, {
server.addService(testProto.TestService.service, {
emptyCall: handleEmpty,
unaryCall: handleUnary,
streamingOutputCall: handleStreamingOutput,

@ -88,6 +88,13 @@ function streamingCall(call) {
});
}
function makeUnaryGenericCall(response_size) {
var response = zeroBuffer(response_size);
return function unaryGenericCall(call, callback) {
callback(null, response);
};
}
function makeStreamingGenericCall(response_size) {
var response = zeroBuffer(response_size);
return function streamingGenericCall(call) {
@ -129,10 +136,11 @@ function BenchmarkServer(host, port, tls, generic, response_size) {
this.port = server.bind(host + ':' + port, server_creds);
if (generic) {
server.addService(genericService, {
unaryCall: makeUnaryGenericCall(response_size),
streamingCall: makeStreamingGenericCall(response_size)
});
} else {
server.addProtoService(serviceProto.BenchmarkService.service, {
server.addService(serviceProto.BenchmarkService.service, {
unaryCall: unaryCall,
streamingCall: streamingCall
});

@ -34,8 +34,17 @@
var _ = require('lodash');
module.exports = {
'unaryCall' : {
path: '/grpc.testing.BenchmarkService/UnaryCall',
requestStream: false,
responseStream: false,
requestSerialize: _.identity,
requestDeserialize: _.identity,
responseSerialize: _.identity,
responseDeserialize: _.identity
},
'streamingCall' : {
path: '/grpc.testing/BenchmarkService',
path: '/grpc.testing.BenchmarkService/StreamingCall',
requestStream: true,
responseStream: true,
requestSerialize: _.identity,

@ -44,8 +44,8 @@ var serviceProto = grpc.load({
function runServer(port, benchmark_impl) {
var server_creds = grpc.ServerCredentials.createInsecure();
var server = new grpc.Server();
server.addProtoService(serviceProto.WorkerService.service,
new WorkerServiceImpl(benchmark_impl, server));
server.addService(serviceProto.WorkerService.service,
new WorkerServiceImpl(benchmark_impl, server));
var address = '0.0.0.0:' + port;
server.bind(address, server_creds);
server.start();

@ -89,6 +89,7 @@ module.exports = function WorkerServiceImpl(benchmark_impl, server) {
default:
call.emit('error', new Error('Unsupported PayloadConfig type' +
setup.payload_config.payload));
return;
}
switch (setup.load_params.load) {
case 'closed_loop':
@ -103,6 +104,7 @@ module.exports = function WorkerServiceImpl(benchmark_impl, server) {
default:
call.emit('error', new Error('Unsupported LoadParams type' +
setup.load_params.load));
return;
}
stats = client.mark();
call.write({
@ -137,8 +139,27 @@ module.exports = function WorkerServiceImpl(benchmark_impl, server) {
switch (request.argtype) {
case 'setup':
console.log('ServerConfig %j', request.setup);
var setup = request.setup;
var resp_size, generic;
if (setup.payload_config) {
switch (setup.payload_config.payload) {
case 'bytebuf_params':
resp_size = setup.payload_config.bytebuf_params.resp_size;
generic = true;
break;
case 'simple_params':
resp_size = setup.payload_config.simple_params.resp_size;
generic = false;
break;
default:
call.emit('error', new Error('Unsupported PayloadConfig type' +
setup.payload_config.payload));
return;
}
}
server = new BenchmarkServer('[::]', request.setup.port,
request.setup.security_params);
request.setup.security_params,
generic, resp_size);
server.on('started', function() {
stats = server.mark();
call.write({

@ -780,6 +780,8 @@ exports.makeClientConstructor = function(methods, serviceName,
_.assign(Client.prototype[name], attrs);
});
Client.service = methods;
return Client;
};
@ -822,26 +824,6 @@ exports.waitForClientReady = function(client, deadline, callback) {
checkState();
};
/**
* Creates a constructor for clients for the given service
* @param {ProtoBuf.Reflect.Service} service The service to generate a client
* for
* @param {Object=} options Options to apply to the client
* @return {function(string, Object)} New client constructor
*/
exports.makeProtobufClientConstructor = function(service, options) {
var method_attrs = common.getProtobufServiceAttrs(service, options);
if (!options) {
options = {deprecatedArgumentOrder: false};
}
var Client = exports.makeClientConstructor(
method_attrs, common.fullyQualifiedName(service),
options);
Client.service = service;
Client.service.grpc_options = options;
return Client;
};
/**
* Map of status code names to status codes
*/

@ -41,74 +41,6 @@
var _ = require('lodash');
/**
* Get a function that deserializes a specific type of protobuf.
* @param {function()} cls The constructor of the message type to deserialize
* @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
* instead of Buffers. Defaults to false
* @param {bool=} longsAsStrings Deserialize long values as strings instead of
* objects. Defaults to true
* @return {function(Buffer):cls} The deserialization function
*/
exports.deserializeCls = function deserializeCls(cls, binaryAsBase64,
longsAsStrings) {
if (binaryAsBase64 === undefined || binaryAsBase64 === null) {
binaryAsBase64 = false;
}
if (longsAsStrings === undefined || longsAsStrings === null) {
longsAsStrings = true;
}
/**
* Deserialize a buffer to a message object
* @param {Buffer} arg_buf The buffer to deserialize
* @return {cls} The resulting object
*/
return function deserialize(arg_buf) {
// Convert to a native object with binary fields as Buffers (first argument)
// and longs as strings (second argument)
return cls.decode(arg_buf).toRaw(binaryAsBase64, longsAsStrings);
};
};
var deserializeCls = exports.deserializeCls;
/**
* Get a function that serializes objects to a buffer by protobuf class.
* @param {function()} Cls The constructor of the message type to serialize
* @return {function(Cls):Buffer} The serialization function
*/
exports.serializeCls = function serializeCls(Cls) {
/**
* Serialize an object to a Buffer
* @param {Object} arg The object to serialize
* @return {Buffer} The serialized object
*/
return function serialize(arg) {
return new Buffer(new Cls(arg).encode().toBuffer());
};
};
var serializeCls = exports.serializeCls;
/**
* Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
* @param {ProtoBuf.Reflect.Namespace} value The value to get the name of
* @return {string} The fully qualified name of the value
*/
exports.fullyQualifiedName = function fullyQualifiedName(value) {
if (value === null || value === undefined) {
return '';
}
var name = value.name;
var parent_name = fullyQualifiedName(value.parent);
if (parent_name !== '') {
name = parent_name + '.' + name;
}
return name;
};
var fullyQualifiedName = exports.fullyQualifiedName;
/**
* Wrap a function to pass null-like values through without calling it. If no
* function is given, just uses the identity;
@ -127,44 +59,6 @@ exports.wrapIgnoreNull = function wrapIgnoreNull(func) {
};
};
/**
* Return a map from method names to method attributes for the service.
* @param {ProtoBuf.Reflect.Service} service The service to get attributes for
* @param {Object=} options Options to apply to these attributes
* @return {Object} The attributes map
*/
exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
options) {
var prefix = '/' + fullyQualifiedName(service) + '/';
var binaryAsBase64, longsAsStrings;
if (options) {
binaryAsBase64 = options.binaryAsBase64;
longsAsStrings = options.longsAsStrings;
}
/* This slightly awkward construction is used to make sure we only use
lodash@3.10.1-compatible functions. A previous version used
_.fromPairs, which would be cleaner, but was introduced in lodash
version 4 */
return _.zipObject(_.map(service.children, function(method) {
return _.camelCase(method.name);
}), _.map(service.children, function(method) {
return {
originalName: method.name,
path: prefix + method.name,
requestStream: method.requestStream,
responseStream: method.responseStream,
requestType: method.resolvedRequestType,
responseType: method.resolvedResponseType,
requestSerialize: serializeCls(method.resolvedRequestType.build()),
requestDeserialize: deserializeCls(method.resolvedRequestType.build(),
binaryAsBase64, longsAsStrings),
responseSerialize: serializeCls(method.resolvedResponseType.build()),
responseDeserialize: deserializeCls(method.resolvedResponseType.build(),
binaryAsBase64, longsAsStrings)
};
}));
};
/**
* The logger object for the gRPC module. Defaults to console.
*/
@ -185,3 +79,14 @@ exports.log = function log(severity, message) {
exports.logger.error(message);
}
};
/**
* Default options for loading proto files into gRPC
*/
exports.defaultGrpcOptions = {
convertFieldsToCamelCase: false,
binaryAsBase64: false,
longsAsStrings: true,
enumsAsStrings: true,
deprecatedArgumentOrder: false
};

@ -0,0 +1,181 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
'use strict';
var _ = require('lodash');
var client = require('./client');
/**
* Get a function that deserializes a specific type of protobuf.
* @param {function()} cls The constructor of the message type to deserialize
* @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
* instead of Buffers. Defaults to false
* @param {bool=} longsAsStrings Deserialize long values as strings instead of
* objects. Defaults to true
* @return {function(Buffer):cls} The deserialization function
*/
exports.deserializeCls = function deserializeCls(cls, binaryAsBase64,
longsAsStrings) {
/**
* Deserialize a buffer to a message object
* @param {Buffer} arg_buf The buffer to deserialize
* @return {cls} The resulting object
*/
return function deserialize(arg_buf) {
// Convert to a native object with binary fields as Buffers (first argument)
// and longs as strings (second argument)
return cls.decode(arg_buf).toRaw(binaryAsBase64, longsAsStrings);
};
};
var deserializeCls = exports.deserializeCls;
/**
* Get a function that serializes objects to a buffer by protobuf class.
* @param {function()} Cls The constructor of the message type to serialize
* @return {function(Cls):Buffer} The serialization function
*/
exports.serializeCls = function serializeCls(Cls) {
/**
* Serialize an object to a Buffer
* @param {Object} arg The object to serialize
* @return {Buffer} The serialized object
*/
return function serialize(arg) {
return new Buffer(new Cls(arg).encode().toBuffer());
};
};
var serializeCls = exports.serializeCls;
/**
* Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
* @param {ProtoBuf.Reflect.Namespace} value The value to get the name of
* @return {string} The fully qualified name of the value
*/
exports.fullyQualifiedName = function fullyQualifiedName(value) {
if (value === null || value === undefined) {
return '';
}
var name = value.name;
var parent_name = fullyQualifiedName(value.parent);
if (parent_name !== '') {
name = parent_name + '.' + name;
}
return name;
};
var fullyQualifiedName = exports.fullyQualifiedName;
/**
* Return a map from method names to method attributes for the service.
* @param {ProtoBuf.Reflect.Service} service The service to get attributes for
* @param {Object=} options Options to apply to these attributes
* @return {Object} The attributes map
*/
exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
options) {
var prefix = '/' + fullyQualifiedName(service) + '/';
var binaryAsBase64, longsAsStrings;
if (options) {
binaryAsBase64 = options.binaryAsBase64;
longsAsStrings = options.longsAsStrings;
}
/* This slightly awkward construction is used to make sure we only use
lodash@3.10.1-compatible functions. A previous version used
_.fromPairs, which would be cleaner, but was introduced in lodash
version 4 */
return _.zipObject(_.map(service.children, function(method) {
return _.camelCase(method.name);
}), _.map(service.children, function(method) {
return {
originalName: method.name,
path: prefix + method.name,
requestStream: method.requestStream,
responseStream: method.responseStream,
requestType: method.resolvedRequestType,
responseType: method.resolvedResponseType,
requestSerialize: serializeCls(method.resolvedRequestType.build()),
requestDeserialize: deserializeCls(method.resolvedRequestType.build(),
binaryAsBase64, longsAsStrings),
responseSerialize: serializeCls(method.resolvedResponseType.build()),
responseDeserialize: deserializeCls(method.resolvedResponseType.build(),
binaryAsBase64, longsAsStrings)
};
}));
};
var getProtobufServiceAttrs = exports.getProtobufServiceAttrs;
/**
* Load a gRPC object from an existing ProtoBuf.Reflect object.
* @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
* @param {Object=} options Options to apply to the loaded object
* @return {Object<string, *>} The resulting gRPC object
*/
exports.loadObject = function loadObject(value, options) {
var result = {};
if (!value) {
return value;
}
if (value.hasOwnProperty('ns')) {
return loadObject(value.ns, options);
}
if (value.className === 'Namespace') {
_.each(value.children, function(child) {
result[child.name] = loadObject(child, options);
});
return result;
} else if (value.className === 'Service') {
return client.makeClientConstructor(getProtobufServiceAttrs(value, options),
options);
} else if (value.className === 'Message' || value.className === 'Enum') {
return value.build();
} else {
return value;
}
};
/**
* The primary purpose of this method is to distinguish between reflection
* objects from different versions of ProtoBuf.js. This is just a heuristic,
* checking for properties that are (currently) specific to this version of
* ProtoBuf.js
* @param {Object} obj The object to check
* @return {boolean} Whether the object appears to be a Protobuf.js 5
* ReflectionObject
*/
exports.isProbablyProtobufJs5 = function isProbablyProtobufJs5(obj) {
return _.isArray(obj.children) && (typeof obj.build === 'function');
};

@ -0,0 +1,170 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
'use strict';
var _ = require('lodash');
var client = require('./client');
/**
* Get a function that deserializes a specific type of protobuf.
* @param {function()} cls The constructor of the message type to deserialize
* @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
* instead of Buffers. Defaults to false
* @param {bool=} longsAsStrings Deserialize long values as strings instead of
* objects. Defaults to true
* @return {function(Buffer):cls} The deserialization function
*/
exports.deserializeCls = function deserializeCls(cls, options) {
var conversion_options = {
defaults: true,
bytes: options.binaryAsBase64 ? String : Buffer,
longs: options.longsAsStrings ? String : null,
enums: options.enumsAsStrings ? String : null,
oneofs: true
};
/**
* Deserialize a buffer to a message object
* @param {Buffer} arg_buf The buffer to deserialize
* @return {cls} The resulting object
*/
return function deserialize(arg_buf) {
return cls.decode(arg_buf).toObject(conversion_options);
};
};
var deserializeCls = exports.deserializeCls;
/**
* Get a function that serializes objects to a buffer by protobuf class.
* @param {function()} Cls The constructor of the message type to serialize
* @return {function(Cls):Buffer} The serialization function
*/
exports.serializeCls = function serializeCls(cls) {
/**
* Serialize an object to a Buffer
* @param {Object} arg The object to serialize
* @return {Buffer} The serialized object
*/
return function serialize(arg) {
var message = cls.fromObject(arg);
return cls.encode(message).finish();
};
};
var serializeCls = exports.serializeCls;
/**
* Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
* @param {ProtoBuf.ReflectionObject} value The value to get the name of
* @return {string} The fully qualified name of the value
*/
exports.fullyQualifiedName = function fullyQualifiedName(value) {
if (value === null || value === undefined) {
return '';
}
var name = value.name;
var parent_fqn = fullyQualifiedName(value.parent);
if (parent_fqn !== '') {
name = parent_fqn + '.' + name;
}
return name;
};
var fullyQualifiedName = exports.fullyQualifiedName;
/**
* Return a map from method names to method attributes for the service.
* @param {ProtoBuf.Service} service The service to get attributes for
* @param {Object=} options Options to apply to these attributes
* @return {Object} The attributes map
*/
exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
options) {
var prefix = '/' + fullyQualifiedName(service) + '/';
service.resolveAll();
return _.zipObject(_.map(service.methods, function(method) {
return _.camelCase(method.name);
}), _.map(service.methods, function(method) {
return {
originalName: method.name,
path: prefix + method.name,
requestStream: !!method.requestStream,
responseStream: !!method.responseStream,
requestType: method.resolvedRequestType,
responseType: method.resolvedResponseType,
requestSerialize: serializeCls(method.resolvedRequestType),
requestDeserialize: deserializeCls(method.resolvedRequestType, options),
responseSerialize: serializeCls(method.resolvedResponseType),
responseDeserialize: deserializeCls(method.resolvedResponseType, options)
};
}));
};
var getProtobufServiceAttrs = exports.getProtobufServiceAttrs;
exports.loadObject = function loadObject(value, options) {
var result = {};
if (!value) {
return value;
}
if (value.hasOwnProperty('methods')) {
// It's a service object
var service_attrs = getProtobufServiceAttrs(value, options);
return client.makeClientConstructor(service_attrs);
}
if (value.hasOwnProperty('nested')) {
// It's a namespace or root object
_.each(value.nested, function(nested, name) {
result[name] = loadObject(nested, options);
});
return result;
}
// Otherwise, it's not something we need to change
return value;
};
/**
* The primary purpose of this method is to distinguish between reflection
* objects from different versions of ProtoBuf.js. This is just a heuristic,
* checking for properties that are (currently) specific to this version of
* ProtoBuf.js
* @param {Object} obj The object to check
* @return {boolean} Whether the object appears to be a Protobuf.js 6
* ReflectionObject
*/
exports.isProbablyProtobufJs6 = function isProbablyProtobufJs6(obj) {
return (typeof obj.root === 'object') && (typeof obj.resolve === 'function');
};

@ -781,17 +781,31 @@ Server.prototype.addService = function(service, implementation) {
/**
* Add a proto service to the server, with a corresponding implementation
* @deprecated Use grpc.load and Server#addService instead
* @param {Protobuf.Reflect.Service} service The proto service descriptor
* @param {Object<String, function>} implementation Map of method names to
* method implementation for the provided service.
*/
Server.prototype.addProtoService = function(service, implementation) {
var options;
if (service.grpc_options) {
options = service.grpc_options;
var protobuf_js_5_common = require('./protobuf_js_5_common');
var protobuf_js_6_common = require('./protobuf_js_6_common');
common.log(grpc.logVerbosity.INFO,
'Server#addProtoService is deprecated. Use addService instead');
if (protobuf_js_5_common.isProbablyProtobufJs5(service)) {
options = _.defaults(service.grpc_options, common.defaultGrpcOptions);
this.addService(
protobuf_js_5_common.getProtobufServiceAttrs(service, options),
implementation);
} else if (protobuf_js_6_common.isProbablyProtobufJs6(service)) {
options = _.defaults(service.grpc_options, common.defaultGrpcOptions);
this.addService(
protobuf_js_6_common.getProtobufServiceAttrs(service, options),
implementation);
} else {
// We assume that this is a service attributes object
this.addService(service, implementation);
}
this.addService(common.getProtobufServiceAttrs(service, options),
implementation);
};
/**

@ -63,7 +63,7 @@ function getAllGauges(call) {
function MetricsServer(port) {
var server = new grpc.Server();
server.addProtoService(metrics.MetricsService.service, {
server.addService(metrics.MetricsService.service, {
getGauge: _.bind(getGauge, this),
getAllGauges: _.bind(getAllGauges, this)
});

@ -34,17 +34,26 @@
'use strict';
var assert = require('assert');
var _ = require('lodash');
var common = require('../src/common.js');
var common = require('../src/common');
var protobuf_js_6_common = require('../src/protobuf_js_6_common');
var serializeCls = protobuf_js_6_common.serializeCls;
var deserializeCls = protobuf_js_6_common.deserializeCls;
var ProtoBuf = require('protobufjs');
var messages_proto = ProtoBuf.loadProtoFile(
__dirname + '/test_messages.proto').build();
var messages_proto = new ProtoBuf.Root();
messages_proto = messages_proto.loadSync(
__dirname + '/test_messages.proto', {keepCase: true}).resolveAll();
var default_options = common.defaultGrpcOptions;
describe('Proto message long int serialize and deserialize', function() {
var longSerialize = common.serializeCls(messages_proto.LongValues);
var longDeserialize = common.deserializeCls(messages_proto.LongValues);
var longSerialize = serializeCls(messages_proto.LongValues);
var longDeserialize = deserializeCls(messages_proto.LongValues,
default_options);
var pos_value = '314159265358979';
var neg_value = '-27182818284590';
it('should preserve positive int64 values', function() {
@ -88,8 +97,9 @@ describe('Proto message long int serialize and deserialize', function() {
neg_value);
});
it('should deserialize as a number with the right option set', function() {
var longNumDeserialize = common.deserializeCls(messages_proto.LongValues,
false, false);
var num_options = _.defaults({longsAsStrings: false}, default_options);
var longNumDeserialize = deserializeCls(messages_proto.LongValues,
num_options);
var serialized = longSerialize({int_64: pos_value});
assert.strictEqual(typeof longDeserialize(serialized).int_64, 'string');
/* With the longsAsStrings option disabled, long values are represented as
@ -98,11 +108,12 @@ describe('Proto message long int serialize and deserialize', function() {
});
});
describe('Proto message bytes serialize and deserialize', function() {
var sequenceSerialize = common.serializeCls(messages_proto.SequenceValues);
var sequenceDeserialize = common.deserializeCls(
messages_proto.SequenceValues);
var sequenceBase64Deserialize = common.deserializeCls(
messages_proto.SequenceValues, true);
var sequenceSerialize = serializeCls(messages_proto.SequenceValues);
var sequenceDeserialize = deserializeCls(
messages_proto.SequenceValues, default_options);
var b64_options = _.defaults({binaryAsBase64: true}, default_options);
var sequenceBase64Deserialize = deserializeCls(
messages_proto.SequenceValues, b64_options);
var buffer_val = new Buffer([0x69, 0xb7]);
var base64_val = 'abc=';
it('should preserve a buffer', function() {
@ -120,19 +131,73 @@ describe('Proto message bytes serialize and deserialize', function() {
var deserialized = sequenceBase64Deserialize(serialized);
assert.strictEqual(deserialized.bytes_field, base64_val);
});
/* The next two tests are specific tests to verify that issue
* https://github.com/grpc/grpc/issues/5174 has been fixed. They are skipped
* because they will not pass until a protobuf.js release has been published
* with a fix for https://github.com/dcodeIO/protobuf.js/issues/390 */
it.skip('should serialize a repeated field as packed by default', function() {
var expected_serialize = new Buffer([0x12, 0x01, 0x01, 0x0a]);
it('should serialize a repeated field as packed by default', function() {
var expected_serialize = new Buffer([0x12, 0x01, 0x0a]);
var serialized = sequenceSerialize({repeated_field: [10]});
assert.strictEqual(expected_serialize.compare(serialized), 0);
});
it.skip('should deserialize packed or unpacked repeated', function() {
var serialized = new Buffer([0x12, 0x01, 0x01, 0x0a]);
it('should deserialize packed or unpacked repeated', function() {
var expectedDeserialize = {
bytes_field: new Buffer(''),
repeated_field: [10]
};
var packedSerialized = new Buffer([0x12, 0x01, 0x0a]);
var unpackedSerialized = new Buffer([0x10, 0x0a]);
var packedDeserialized;
var unpackedDeserialized;
assert.doesNotThrow(function() {
sequenceDeserialize(serialized);
packedDeserialized = sequenceDeserialize(packedSerialized);
});
assert.doesNotThrow(function() {
unpackedDeserialized = sequenceDeserialize(unpackedSerialized);
});
assert.deepEqual(packedDeserialized, expectedDeserialize);
assert.deepEqual(unpackedDeserialized, expectedDeserialize);
});
});
describe('Proto message oneof serialize and deserialize', function() {
var oneofSerialize = serializeCls(messages_proto.OneOfValues);
var oneofDeserialize = deserializeCls(
messages_proto.OneOfValues, default_options);
it('Should have idempotent round trips', function() {
var test_message = {oneof_choice: 'int_choice', int_choice: 5};
var serialized1 = oneofSerialize(test_message);
var deserialized1 = oneofDeserialize(serialized1);
assert.equal(deserialized1.int_choice, 5);
var serialized2 = oneofSerialize(deserialized1);
var deserialized2 = oneofDeserialize(serialized2);
assert.deepEqual(deserialized1, deserialized2);
});
it('Should emit a property indicating which field was chosen', function() {
var test_message1 = {oneof_choice: 'int_choice', int_choice: 5};
var serialized1 = oneofSerialize(test_message1);
var deserialized1 = oneofDeserialize(serialized1);
assert.equal(deserialized1.oneof_choice, 'int_choice');
var test_message2 = {oneof_choice: 'string_choice', string_choice: 'abc'};
var serialized2 = oneofSerialize(test_message2);
var deserialized2 = oneofDeserialize(serialized2);
assert.equal(deserialized2.oneof_choice, 'string_choice');
});
});
describe('Proto message enum serialize and deserialize', function() {
var enumSerialize = serializeCls(messages_proto.EnumValues);
var enumDeserialize = deserializeCls(
messages_proto.EnumValues, default_options);
var enumIntOptions = _.defaults({enumsAsStrings: false}, default_options);
var enumIntDeserialize = deserializeCls(
messages_proto.EnumValues, enumIntOptions);
it('Should accept both names and numbers', function() {
var nameSerialized = enumSerialize({enum_value: 'ONE'});
var numberSerialized = enumSerialize({enum_value: 1});
assert.strictEqual(messages_proto.TestEnum.ONE, 1);
assert.deepEqual(enumDeserialize(nameSerialized),
enumDeserialize(numberSerialized));
});
it('Should deserialize as a string the enumsAsStrings option', function() {
var serialized = enumSerialize({enum_value: 'TWO'});
var nameDeserialized = enumDeserialize(serialized);
var numberDeserialized = enumIntDeserialize(serialized);
assert.deepEqual(nameDeserialized, {enum_value: 'TWO'});
assert.deepEqual(numberDeserialized, {enum_value: 2});
});
});

@ -228,7 +228,7 @@ describe('client credentials', function() {
before(function() {
var proto = grpc.load(__dirname + '/test_service.proto');
server = new grpc.Server();
server.addProtoService(proto.TestService.service, {
server.addService(proto.TestService.service, {
unary: function(call, cb) {
call.sendMetadata(call.metadata);
cb(null, {});

@ -34,19 +34,22 @@
'use strict';
var assert = require('assert');
var _ = require('lodash');
var surface_client = require('../src/client.js');
var common = require('../src/common');
var ProtoBuf = require('protobufjs');
var grpc = require('..');
var math_proto = ProtoBuf.loadProtoFile(__dirname +
'/../../proto/math/math.proto');
var math_proto = new ProtoBuf.Root();
math_proto = math_proto.loadSync(__dirname +
'/../../proto/math/math.proto', {keepCase: true});
var mathService = math_proto.lookup('math.Math');
var _ = require('lodash');
var mathServiceAttrs = grpc.loadObject(
mathService, common.defaultGrpcOptions).service;
/**
* This is used for testing functions with multiple asynchronous calls that
@ -87,11 +90,6 @@ describe('File loader', function() {
grpc.load(__dirname + '/test_service.json', 'json');
});
});
it('Should fail to load a file with an unknown format', function() {
assert.throws(function() {
grpc.load(__dirname + '/test_service.proto', 'fake_format');
});
});
});
describe('surface Server', function() {
var server;
@ -132,15 +130,40 @@ describe('Server.prototype.addProtoService', function() {
afterEach(function() {
server.forceShutdown();
});
it('Should succeed with a single service', function() {
it('Should succeed with a single proto service', function() {
assert.doesNotThrow(function() {
server.addProtoService(mathService, dummyImpls);
});
});
it('Should succeed with a single service attributes object', function() {
assert.doesNotThrow(function() {
server.addProtoService(mathServiceAttrs, dummyImpls);
});
});
});
describe('Server.prototype.addService', function() {
var server;
var dummyImpls = {
'div': function() {},
'divMany': function() {},
'fib': function() {},
'sum': function() {}
};
beforeEach(function() {
server = new grpc.Server();
});
afterEach(function() {
server.forceShutdown();
});
it('Should succeed with a single service', function() {
assert.doesNotThrow(function() {
server.addService(mathServiceAttrs, dummyImpls);
});
});
it('Should fail with conflicting method names', function() {
server.addProtoService(mathService, dummyImpls);
server.addService(mathServiceAttrs, dummyImpls);
assert.throws(function() {
server.addProtoService(mathService, dummyImpls);
server.addService(mathServiceAttrs, dummyImpls);
});
});
it('Should allow method names as originally written', function() {
@ -172,15 +195,15 @@ describe('Server.prototype.addProtoService', function() {
it('Should fail if the server has been started', function() {
server.start();
assert.throws(function() {
server.addProtoService(mathService, dummyImpls);
server.addService(mathServiceAttrs, dummyImpls);
});
});
describe('Default handlers', function() {
var client;
beforeEach(function() {
server.addProtoService(mathService, {});
server.addService(mathServiceAttrs, {});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(mathService);
var Client = grpc.loadObject(mathService);
client = new Client('localhost:' + port,
grpc.credentials.createInsecure());
server.start();
@ -252,7 +275,7 @@ describe('waitForClientReady', function() {
server = new grpc.Server();
port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure());
server.start();
Client = surface_client.makeProtobufClientConstructor(mathService);
Client = grpc.loadObject(mathService);
});
beforeEach(function() {
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
@ -309,16 +332,18 @@ describe('Echo service', function() {
var server;
var client;
before(function() {
var test_proto = ProtoBuf.loadProtoFile(__dirname + '/echo_service.proto');
var test_proto = new ProtoBuf.Root();
test_proto = test_proto.loadSync(__dirname + '/echo_service.proto',
{keepCase: true});
var echo_service = test_proto.lookup('EchoService');
var Client = grpc.loadObject(echo_service);
server = new grpc.Server();
server.addProtoService(echo_service, {
server.addService(Client.service, {
echo: function(call, callback) {
callback(null, call.request);
}
});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(echo_service);
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
});
@ -432,10 +457,13 @@ describe('Echo metadata', function() {
var server;
var metadata;
before(function() {
var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
var test_proto = new ProtoBuf.Root();
test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
{keepCase: true});
var test_service = test_proto.lookup('TestService');
var Client = grpc.loadObject(test_service);
server = new grpc.Server();
server.addProtoService(test_service, {
server.addService(Client.service, {
unary: function(call, cb) {
call.sendMetadata(call.metadata);
cb(null, {});
@ -460,7 +488,6 @@ describe('Echo metadata', function() {
}
});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(test_service);
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
metadata = new grpc.Metadata();
@ -533,7 +560,9 @@ describe('Client malformed response handling', function() {
var client;
var badArg = new Buffer([0xFF]);
before(function() {
var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
var test_proto = new ProtoBuf.Root();
test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
{keepCase: true});
var test_service = test_proto.lookup('TestService');
var malformed_test_service = {
unary: {
@ -591,7 +620,7 @@ describe('Client malformed response handling', function() {
}
});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(test_service);
var Client = grpc.loadObject(test_service);
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
});
@ -640,7 +669,9 @@ describe('Server serialization failure handling', function() {
var client;
var server;
before(function() {
var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
var test_proto = new ProtoBuf.Root();
test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
{keepCase: true});
var test_service = test_proto.lookup('TestService');
var malformed_test_service = {
unary: {
@ -698,7 +729,7 @@ describe('Server serialization failure handling', function() {
}
});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(test_service);
var Client = grpc.loadObject(test_service);
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
});
@ -747,12 +778,15 @@ describe('Other conditions', function() {
var server;
var port;
before(function() {
var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
var test_proto = new ProtoBuf.Root();
test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
{keepCase: true});
test_service = test_proto.lookup('TestService');
Client = grpc.loadObject(test_service);
server = new grpc.Server();
var trailer_metadata = new grpc.Metadata();
trailer_metadata.add('trailer-present', 'yes');
server.addProtoService(test_service, {
server.addService(Client.service, {
unary: function(call, cb) {
var req = call.request;
if (req.error) {
@ -812,7 +846,6 @@ describe('Other conditions', function() {
}
});
port = server.bind('localhost:0', server_insecure_creds);
Client = surface_client.makeProtobufClientConstructor(test_service);
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
});
@ -1093,17 +1126,19 @@ describe('Call propagation', function() {
var client;
var server;
before(function() {
var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
var test_proto = new ProtoBuf.Root();
test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
{keepCase: true});
test_service = test_proto.lookup('TestService');
server = new grpc.Server();
server.addProtoService(test_service, {
Client = grpc.loadObject(test_service);
server.addService(Client.service, {
unary: function(call) {},
clientStream: function(stream) {},
serverStream: function(stream) {},
bidiStream: function(stream) {}
});
var port = server.bind('localhost:0', server_insecure_creds);
Client = surface_client.makeProtobufClientConstructor(test_service);
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
});
@ -1138,7 +1173,7 @@ describe('Call propagation', function() {
});
call.cancel();
};
proxy.addProtoService(test_service, proxy_impl);
proxy.addService(Client.service, proxy_impl);
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
proxy.start();
var proxy_client = new Client('localhost:' + proxy_port,
@ -1160,7 +1195,7 @@ describe('Call propagation', function() {
});
call.cancel();
};
proxy.addProtoService(test_service, proxy_impl);
proxy.addService(Client.service, proxy_impl);
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
proxy.start();
var proxy_client = new Client('localhost:' + proxy_port,
@ -1180,7 +1215,7 @@ describe('Call propagation', function() {
});
call.cancel();
};
proxy.addProtoService(test_service, proxy_impl);
proxy.addService(Client.service, proxy_impl);
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
proxy.start();
var proxy_client = new Client('localhost:' + proxy_port,
@ -1204,7 +1239,7 @@ describe('Call propagation', function() {
});
call.cancel();
};
proxy.addProtoService(test_service, proxy_impl);
proxy.addService(Client.service, proxy_impl);
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
proxy.start();
var proxy_client = new Client('localhost:' + proxy_port,
@ -1235,7 +1270,7 @@ describe('Call propagation', function() {
}
});
};
proxy.addProtoService(test_service, proxy_impl);
proxy.addService(Client.service, proxy_impl);
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
proxy.start();
var proxy_client = new Client('localhost:' + proxy_port,
@ -1259,7 +1294,7 @@ describe('Call propagation', function() {
done();
});
};
proxy.addProtoService(test_service, proxy_impl);
proxy.addService(Client.service, proxy_impl);
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
proxy.start();
var proxy_client = new Client('localhost:' + proxy_port,
@ -1279,14 +1314,14 @@ describe('Cancelling surface client', function() {
var server;
before(function() {
server = new grpc.Server();
server.addProtoService(mathService, {
server.addService(mathServiceAttrs, {
'div': function(stream) {},
'divMany': function(stream) {},
'fib': function(stream) {},
'sum': function(stream) {}
});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(mathService);
var Client = surface_client.makeClientConstructor(mathServiceAttrs);
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
});

@ -41,3 +41,20 @@ message SequenceValues {
bytes bytes_field = 1;
repeated int32 repeated_field = 2;
}
message OneOfValues {
oneof oneof_choice {
int32 int_choice = 1;
string string_choice = 2;
}
}
enum TestEnum {
ZERO = 0;
ONE = 1;
TWO = 2;
}
message EnumValues {
TestEnum enum_value = 1;
}

@ -68,12 +68,16 @@ xcodebuild \
-destination name="iPhone 6" \
test | xcpretty
echo "TIME: $(date)"
xcodebuild \
-workspace Tests.xcworkspace \
-scheme CronetUnitTests \
-destination name="iPhone 6" \
test | xcpretty
# Temporarily disabled for (possible) flakiness on Jenkins.
# Fix or reenable after confirmation/disconfirmation that it is the source of
# Jenkins problem.
# echo "TIME: $(date)"
# xcodebuild \
# -workspace Tests.xcworkspace \
# -scheme CronetUnitTests \
# -destination name="iPhone 6" \
# test | xcpretty
echo "TIME: $(date)"
xcodebuild \

@ -705,6 +705,10 @@ def _serve(state):
state.rpc_states.remove(rpc_state)
if _stop_serving(state):
return
# We want to force the deletion of the previous event
# ~before~ we poll again; if the event has a reference
# to a shutdown Call object, this can induce spinlock.
event = None
def _stop(state, grace):

@ -0,0 +1,4 @@
include grpc_version.py
include reflection_commands.py
graft grpc_reflection
global-exclude *.pyc

@ -143,12 +143,13 @@ class ReflectionServicer(reflection_pb2.ServerReflectionServicer):
.encode(),))
def enable_server_reflection(service_names, server):
def enable_server_reflection(service_names, server, pool=None):
"""Enables server reflection on a server.
Args:
service_names: Iterable of fully-qualified service names available.
server: grpc.Server to which reflection service will be added.
pool: DescriptorPool object to use (descriptor_pool.Default() if None).
"""
reflection_pb2_grpc.add_ServerReflectionServicer_to_server(
ReflectionServicer(service_names), server)
ReflectionServicer(service_names), server, pool)

@ -36,7 +36,7 @@ require_relative './end2end_common'
def main
STDERR.puts 'start server'
server_runner = ServerRunner.new
server_runner = ServerRunner.new(EchoServerImpl)
server_port = server_runner.run
sleep 1

@ -35,7 +35,7 @@ require_relative './end2end_common'
def main
STDERR.puts 'start server'
server_runner = ServerRunner.new
server_runner = ServerRunner.new(EchoServerImpl)
server_port = server_runner.run
sleep 1

@ -55,13 +55,14 @@ end
# ServerRunner starts an "echo server" that test clients can make calls to
class ServerRunner
def initialize
def initialize(service_impl)
@service_impl = service_impl
end
def run
@srv = GRPC::RpcServer.new
port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
@srv.handle(EchoServerImpl)
@srv.handle(@service_impl)
@thd = Thread.new do
@srv.run

@ -0,0 +1,58 @@
#!/usr/bin/env ruby
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Attempt to reproduce
# https://github.com/GoogleCloudPlatform/google-cloud-ruby/issues/1327
require_relative './end2end_common'
def main
server_port = ''
OptionParser.new do |opts|
opts.on('--client_control_port=P', String) do
STDERR.puts 'client control port not used'
end
opts.on('--server_port=P', String) do |p|
server_port = p
end
end.parse!
thd = Thread.new do
stub = Echo::EchoServer::Stub.new("localhost:#{server_port}",
:this_channel_is_insecure)
stub.echo(Echo::EchoRequest.new(request: 'hello'))
fail 'the clients rpc in this test shouldnt complete. ' \
'expecting SIGINT to happen in the middle of the call'
end
thd.join
end
main

@ -0,0 +1,114 @@
#!/usr/bin/env ruby
# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require_relative './end2end_common'
# Service that sleeps for a long time upon receiving an 'echo request'
# Also, this notifies @call_started_cv once it has received a request.
class SleepingEchoServerImpl < Echo::EchoServer::Service
def initialize(call_started, call_started_mu, call_started_cv)
@call_started = call_started
@call_started_mu = call_started_mu
@call_started_cv = call_started_cv
end
def echo(echo_req, _)
@call_started_mu.synchronize do
@call_started.set_true
@call_started_cv.signal
end
sleep 1000
Echo::EchoReply.new(response: echo_req.request)
end
end
# Mutable boolean
class BoolHolder
attr_reader :val
def init
@val = false
end
def set_true
@val = true
end
end
def main
STDERR.puts 'start server'
call_started = BoolHolder.new
call_started_mu = Mutex.new
call_started_cv = ConditionVariable.new
service_impl = SleepingEchoServerImpl.new(call_started,
call_started_mu,
call_started_cv)
server_runner = ServerRunner.new(service_impl)
server_port = server_runner.run
STDERR.puts 'start client'
_, client_pid = start_client('killed_client_thread_client.rb',
server_port)
call_started_mu.synchronize do
call_started_cv.wait(call_started_mu) until call_started.val
end
# SIGINT the child process now that it's
# in the middle of an RPC (happening on a non-main thread)
Process.kill('SIGINT', client_pid)
STDERR.puts 'sent shutdown'
begin
Timeout.timeout(10) do
Process.wait(client_pid)
end
rescue Timeout::Error
STDERR.puts "timeout wait for client pid #{client_pid}"
Process.kill('SIGKILL', client_pid)
Process.wait(client_pid)
STDERR.puts 'killed client child'
raise 'Timed out waiting for client process. ' \
'It likely hangs when killed while in the middle of an rpc'
end
client_exit_code = $CHILD_STATUS
if client_exit_code.termsig != 2 # SIGINT
fail 'expected client exit from SIGINT ' \
"but got child status: #{client_exit_code}"
end
server_runner.stop
end
main

@ -36,7 +36,7 @@ require_relative './end2end_common'
def main
STDERR.puts 'start server'
server_runner = ServerRunner.new
server_runner = ServerRunner.new(EchoServerImpl)
server_port = server_runner.run
sleep 1

@ -36,7 +36,7 @@ require_relative './end2end_common'
def main
STDERR.puts 'start server'
server_runner = ServerRunner.new
server_runner = ServerRunner.new(EchoServerImpl)
server_port = server_runner.run
sleep 1

@ -784,7 +784,7 @@ static VALUE grpc_run_batch_stack_build_result(run_batch_stack *st) {
Only one operation of each type can be active at once in any given
batch */
static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
run_batch_stack st;
run_batch_stack *st = NULL;
grpc_rb_call *call = NULL;
grpc_event ev;
grpc_call_error err;
@ -792,6 +792,7 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
VALUE rb_write_flag = rb_ivar_get(self, id_write_flag);
unsigned write_flag = 0;
void *tag = (void*)&st;
if (RTYPEDDATA_DATA(self) == NULL) {
rb_raise(grpc_rb_eCallError, "Cannot run batch on closed call");
return Qnil;
@ -806,14 +807,16 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
if (rb_write_flag != Qnil) {
write_flag = NUM2UINT(rb_write_flag);
}
grpc_run_batch_stack_init(&st, write_flag);
grpc_run_batch_stack_fill_ops(&st, ops_hash);
st = gpr_malloc(sizeof(run_batch_stack));
grpc_run_batch_stack_init(st, write_flag);
grpc_run_batch_stack_fill_ops(st, ops_hash);
/* call grpc_call_start_batch, then wait for it to complete using
* pluck_event */
err = grpc_call_start_batch(call->wrapped, st.ops, st.op_num, tag, NULL);
err = grpc_call_start_batch(call->wrapped, st->ops, st->op_num, tag, NULL);
if (err != GRPC_CALL_OK) {
grpc_run_batch_stack_cleanup(&st);
grpc_run_batch_stack_cleanup(st);
gpr_free(st);
rb_raise(grpc_rb_eCallError,
"grpc_call_start_batch failed with %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -826,8 +829,9 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
}
/* Build and return the BatchResult struct result,
if there is an error, it's reflected in the status */
result = grpc_run_batch_stack_build_result(&st);
grpc_run_batch_stack_cleanup(&st);
result = grpc_run_batch_stack_build_result(st);
grpc_run_batch_stack_cleanup(st);
gpr_free(st);
return result;
}

@ -47,9 +47,37 @@
# Some Node installations use the system installation of OpenSSL, and on
# some systems, the system OpenSSL still does not have ALPN support. This
# will let users recompile gRPC to work without ALPN.
'grpc_alpn%': 'true'
'grpc_alpn%': 'true',
# Indicates that the library should be built with gcov.
'grpc_gcov%': 'false'
},
'target_defaults': {
'configurations': {
% for name, args in configs.iteritems():
% if name in ['dbg', 'opt']:
'${{'dbg':'Debug', 'opt': 'Release'}[name]}': {
% for arg, prop in [('CPPFLAGS', 'cflags'), ('DEFINES', 'defines')]:
% if args.get(arg, None) is not None:
'${prop}': [
% for item in args.get(arg).split():
'${item}',
% endfor
],
% endif
% endfor
},
% endif
% endfor
},
% for arg, prop in [('CPPFLAGS', 'cflags'), ('LDFLAGS', 'ldflags')]:
% if defaults['global'].get(arg, None) is not None:
'${prop}': [
% for item in defaults['global'].get(arg).split():
'${item}',
% endfor
],
% endif
% endfor
'include_dirs': [
'.',
'include'
@ -66,6 +94,17 @@
'GRPC_UV'
]
}],
['grpc_gcov=="true"', {
% for arg, prop in [('CPPFLAGS', 'cflags'), ('DEFINES', 'defines'), ('LDFLAGS', 'ldflags')]:
% if configs['gcov'].get(arg, None) is not None:
'${prop}': [
% for item in configs['gcov'].get(arg).split():
'${item}',
% endfor
],
% endif
% endfor
}],
['OS!="win" and runtime=="electron"', {
"defines": [
'OPENSSL_NO_THREADS'
@ -128,26 +167,9 @@
"ws2_32"
]
}, { # OS != "win"
'variables': {
'config': '<!(echo $CONFIG)',
},
'include_dirs': [
'<(node_root_dir)/deps/zlib',
'<(node_root_dir)/deps/cares/include',
],
'conditions': [
['config=="gcov"', {
'cflags': [
'-ftest-coverage',
'-fprofile-arcs',
'-O0'
],
'ldflags': [
'-ftest-coverage',
'-fprofile-arcs'
]
}
]
'<(node_root_dir)/deps/cares/include'
]
}]
]
@ -284,16 +306,10 @@
],
'cflags': [
'-std=c++11',
'-Wall',
'-pthread',
'-g',
'-zdefs',
'-Werror',
'-Wno-error=deprecated-declarations'
],
'ldflags': [
'-g'
],
"conditions": [
['OS=="win" or runtime=="electron"', {
'dependencies': [

@ -26,7 +26,7 @@
s.files += Dir.glob('include/grpc/**/*')
s.test_files = Dir.glob('src/ruby/spec/**/*')
s.bindir = 'src/ruby/bin'
s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
s.require_paths = %w( src/ruby/lib src/ruby/bin src/ruby/pb )
s.platform = Gem::Platform::RUBY
s.add_dependency 'google-protobuf', '~> 3.1'

@ -36,7 +36,7 @@
"lodash": "^4.15.0",
"nan": "^2.0.0",
"node-pre-gyp": "^0.6.0",
"protobufjs": "^5.0.0",
"protobufjs": "^6.7.0",
"cares": "^1.1.5"
},
"devDependencies": {

@ -1,7 +1,7 @@
# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
RUN apt-get update && apt-get install -y curl libunwind8 gettext
# dotnet-dev-1.0.0-preview2-003121
RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=809130
# dotnet-dev-1.0.0-preview2-003131
RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
# dotnet-dev-1.0.1
RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453

@ -117,10 +117,7 @@ void grpc_run_bad_client_test(
grpc_init();
/* Create endpoints */
grpc_resource_quota *resource_quota =
grpc_resource_quota_create("bad_client_test");
sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
/* Create server, completion events */
a.server = grpc_server_create(NULL, NULL);

@ -49,6 +49,8 @@ extern void authority_not_supported(grpc_end2end_test_config config);
extern void authority_not_supported_pre_init(void);
extern void bad_hostname(grpc_end2end_test_config config);
extern void bad_hostname_pre_init(void);
extern void bad_ping(grpc_end2end_test_config config);
extern void bad_ping_pre_init(void);
extern void binary_metadata(grpc_end2end_test_config config);
extern void binary_metadata_pre_init(void);
extern void cancel_after_accept(grpc_end2end_test_config config);
@ -154,6 +156,7 @@ void grpc_end2end_tests_pre_init(void) {
grpc_summon_debugger_macros();
authority_not_supported_pre_init();
bad_hostname_pre_init();
bad_ping_pre_init();
binary_metadata_pre_init();
cancel_after_accept_pre_init();
cancel_after_client_done_pre_init();
@ -214,6 +217,7 @@ void grpc_end2end_tests(int argc, char **argv,
if (argc <= 1) {
authority_not_supported(config);
bad_hostname(config);
bad_ping(config);
binary_metadata(config);
cancel_after_accept(config);
cancel_after_client_done(config);
@ -275,6 +279,10 @@ void grpc_end2end_tests(int argc, char **argv,
bad_hostname(config);
continue;
}
if (0 == strcmp("bad_ping", argv[i])) {
bad_ping(config);
continue;
}
if (0 == strcmp("binary_metadata", argv[i])) {
binary_metadata(config);
continue;

@ -49,6 +49,8 @@ extern void authority_not_supported(grpc_end2end_test_config config);
extern void authority_not_supported_pre_init(void);
extern void bad_hostname(grpc_end2end_test_config config);
extern void bad_hostname_pre_init(void);
extern void bad_ping(grpc_end2end_test_config config);
extern void bad_ping_pre_init(void);
extern void binary_metadata(grpc_end2end_test_config config);
extern void binary_metadata_pre_init(void);
extern void call_creds(grpc_end2end_test_config config);
@ -156,6 +158,7 @@ void grpc_end2end_tests_pre_init(void) {
grpc_summon_debugger_macros();
authority_not_supported_pre_init();
bad_hostname_pre_init();
bad_ping_pre_init();
binary_metadata_pre_init();
call_creds_pre_init();
cancel_after_accept_pre_init();
@ -217,6 +220,7 @@ void grpc_end2end_tests(int argc, char **argv,
if (argc <= 1) {
authority_not_supported(config);
bad_hostname(config);
bad_ping(config);
binary_metadata(config);
call_creds(config);
cancel_after_accept(config);
@ -279,6 +283,10 @@ void grpc_end2end_tests(int argc, char **argv,
bad_hostname(config);
continue;
}
if (0 == strcmp("bad_ping", argv[i])) {
bad_ping(config);
continue;
}
if (0 == strcmp("binary_metadata", argv[i])) {
binary_metadata(config);
continue;

@ -96,9 +96,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
f.fixture_data = sfd;
f.cq = grpc_completion_queue_create(NULL);
grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
*sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
grpc_resource_quota_unref(resource_quota);
*sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
return f;
}

@ -90,9 +90,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
f.fixture_data = sfd;
f.cq = grpc_completion_queue_create(NULL);
grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
*sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
grpc_resource_quota_unref(resource_quota);
*sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
return f;
}

@ -90,9 +90,17 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
f.fixture_data = sfd;
f.cq = grpc_completion_queue_create(NULL);
grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
*sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 1);
grpc_resource_quota_unref(resource_quota);
grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
.type = GRPC_ARG_INTEGER,
.value.integer = 1},
{.key = GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE,
.type = GRPC_ARG_INTEGER,
.value.integer = 1},
{.key = GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE,
.type = GRPC_ARG_INTEGER,
.value.integer = 1}};
grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
*sfd = grpc_iomgr_create_endpoint_pair("fixture", &args);
return f;
}

@ -93,6 +93,7 @@ LOWCPU = 0.1
END2END_TESTS = {
'authority_not_supported': default_test_options,
'bad_hostname': default_test_options,
'bad_ping': connectivity_test_options._replace(proxyable=False),
'binary_metadata': default_test_options,
'resource_quota_server': default_test_options._replace(large_writes=True,
proxyable=False),

@ -85,6 +85,7 @@ def test_options(needs_fullstack=False, needs_dns=False, proxyable=True,
# maps test names to options
END2END_TESTS = {
'bad_hostname': test_options(),
'bad_ping': test_options(),
'binary_metadata': test_options(),
'resource_quota_server': test_options(proxyable=False),
'call_creds': test_options(secure=True),

@ -57,16 +57,18 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
return f;
}
static gpr_timespec n_seconds_time(int n) {
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
@ -102,7 +104,6 @@ static void test_with_authority_header(grpc_end2end_test_config config) {
grpc_slice_from_copied_string("hello world");
grpc_byte_buffer *request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
gpr_timespec deadline = five_seconds_time();
grpc_metadata meta_c[2] = {{grpc_slice_from_static_string("key1"),
grpc_slice_from_static_string("val1"),
0,
@ -124,6 +125,7 @@ static void test_with_authority_header(grpc_end2end_test_config config) {
grpc_slice details;
grpc_slice host = grpc_slice_from_static_string("foo.test.google.fr");
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"), &host,
deadline, NULL);

@ -59,16 +59,18 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
return f;
}
static gpr_timespec n_seconds_time(int n) {
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
@ -99,7 +101,6 @@ static void end_test(grpc_end2end_test_fixture *f) {
static void simple_request_body(grpc_end2end_test_fixture f) {
grpc_call *c;
gpr_timespec deadline = five_seconds_time();
cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_op ops[6];
grpc_op *op;
@ -112,6 +113,7 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
grpc_slice details;
grpc_slice host = grpc_slice_from_static_string("slartibartfast.local");
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"), &host,
deadline, NULL);

@ -0,0 +1,237 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "test/core/end2end/cq_verifier.h"
#define MAX_PING_STRIKES 1
static void *tag(intptr_t t) { return (void *)t; }
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5),
NULL);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture *f) {
if (!f->server) return;
grpc_server_destroy(f->server);
f->server = NULL;
}
static void shutdown_client(grpc_end2end_test_fixture *f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = NULL;
}
static void end_test(grpc_end2end_test_fixture *f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
}
static void test_bad_ping(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL);
cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_arg client_a[] = {{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS,
.value.integer = 0},
{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA,
.value.integer = 20},
{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_HTTP2_BDP_PROBE,
.value.integer = 0}};
grpc_arg server_a[] = {
{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS,
.value.integer = 300000 /* 5 minutes */},
{.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_HTTP2_MAX_PING_STRIKES,
.value.integer = MAX_PING_STRIKES}};
grpc_channel_args client_args = {.num_args = GPR_ARRAY_SIZE(client_a),
.args = client_a};
grpc_channel_args server_args = {.num_args = GPR_ARRAY_SIZE(server_a),
.args = server_a};
config.init_client(&f, &client_args);
config.init_server(&f, &server_args);
grpc_call *c;
grpc_call *s;
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
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_call_details call_details;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
c = grpc_channel_create_call(
f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
NULL);
GPR_ASSERT(c);
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->data.send_initial_metadata.metadata = NULL;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = NULL;
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 = NULL;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
cq_verify(cqv);
// Send too many pings to the server to trigger the punishment:
// The first ping is sent after data frames, it won't trigger a ping strike.
// Each of the following pings will trigger a ping strike, and we need at
// least (MAX_PING_STRIKES + 1) strikes to trigger the punishment. So
// (MAX_PING_STRIKES + 2) pings are needed here.
int i;
for (i = 200; i < 202 + MAX_PING_STRIKES; i++) {
grpc_channel_ping(f.client, f.cq, tag(i), NULL);
CQ_EXPECT_COMPLETION(cqv, tag(i), 1);
cq_verify(cqv);
}
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 = NULL;
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_UNIMPLEMENTED;
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 = NULL;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op->flags = 0;
op->reserved = NULL;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
cq_verify(cqv);
grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
CQ_EXPECT_COMPLETION(cqv, tag(0xdead), 1);
cq_verify(cqv);
grpc_call_destroy(s);
// The connection should be closed immediately after the misbehaved pings,
// the in-progress RPC should fail.
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "Endpoint read failed"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(was_cancelled == 1);
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_destroy(c);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void bad_ping(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION);
test_bad_ping(config);
}
void bad_ping_pre_init(void) {}

@ -57,16 +57,18 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
return f;
}
static gpr_timespec n_seconds_time(int n) {
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
@ -108,7 +110,6 @@ static void test_request_response_with_metadata_and_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_timespec deadline = five_seconds_time();
grpc_metadata meta_c[2] = {
{grpc_slice_from_static_string("key1-bin"),
grpc_slice_from_static_string(
@ -147,6 +148,7 @@ static void test_request_response_with_metadata_and_payload(
grpc_slice details;
int was_cancelled = 2;
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"),

@ -75,16 +75,18 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
return f;
}
static gpr_timespec n_seconds_time(int n) {
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
@ -143,7 +145,6 @@ static void request_response_with_payload_and_call_creds(
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer *response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
gpr_timespec deadline = five_seconds_time();
grpc_end2end_test_fixture f;
cq_verifier *cqv;
grpc_op ops[6];
@ -165,6 +166,7 @@ static void request_response_with_payload_and_call_creds(
f = begin_test(config, test_name, 0);
cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"),
@ -383,7 +385,7 @@ static void test_request_with_server_rejecting_client_creds(
grpc_op *op;
grpc_call *c;
grpc_end2end_test_fixture f;
gpr_timespec deadline = five_seconds_time();
gpr_timespec deadline = five_seconds_from_now();
cq_verifier *cqv;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save