aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Yuchen Zeng <zyc@google.com>2016-05-06 15:50:15 -0700
committerGravatar Yuchen Zeng <zyc@google.com>2016-05-06 15:50:15 -0700
commit26a1785cfc5a2118b5fbb4c2e7e89edd6a241a61 (patch)
tree851f2b92ccd86254bbb0d973462932a1d555fab6
parent7d099a5c907d9ab164416ea875ae07a3074adedb (diff)
parentc916c1ce17fe273dff881e1c87e17ad991c2078a (diff)
Resolve conflicts
-rw-r--r--BUILD85
-rw-r--r--Makefile13
-rw-r--r--binding.gyp3
-rw-r--r--build.yaml62
-rw-r--r--composer.json2
-rw-r--r--config.m45
-rw-r--r--doc/fail_fast.md15
-rw-r--r--examples/cpp/helloworld/Makefile7
-rw-r--r--examples/cpp/helloworld/greeter_async_client.cc8
-rw-r--r--examples/cpp/helloworld/greeter_async_client2.cc153
-rw-r--r--examples/node/greeter_client.js22
-rw-r--r--examples/node/greeter_server.js12
-rw-r--r--examples/node/helloworld_grpc_pb.js39
-rw-r--r--examples/node/helloworld_pb.js332
-rw-r--r--examples/node/package.json1
-rw-r--r--examples/python/helloworld/helloworld_pb2.py73
-rw-r--r--examples/python/route_guide/route_guide_pb2.py189
-rw-r--r--gRPC.podspec77
-rw-r--r--grpc.def1
-rwxr-xr-xgrpc.gemspec41
-rw-r--r--include/grpc++/impl/codegen/call.h7
-rw-r--r--include/grpc++/impl/codegen/core_codegen_interface.h32
-rw-r--r--include/grpc++/impl/codegen/proto_utils.h161
-rw-r--r--include/grpc/byte_buffer_reader.h21
-rw-r--r--include/grpc/grpc_cronet.h51
-rw-r--r--include/grpc/impl/codegen/byte_buffer_reader.h57
-rw-r--r--include/grpc/impl/codegen/grpc_types.h4
-rw-r--r--package.json2
-rw-r--r--package.xml49
-rw-r--r--setup.py2
-rw-r--r--src/compiler/python_generator.cc47
-rw-r--r--src/core/ext/client_config/resolver_registry.c8
-rw-r--r--src/core/ext/client_config/subchannel.c2
-rw-r--r--src/core/ext/lb_policy/round_robin/round_robin.c6
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c20
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.c6
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.c4
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h11
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c21
-rw-r--r--src/core/ext/transport/cronet/client/secure/cronet_channel_create.c69
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_api_dummy.c85
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_transport.c640
-rw-r--r--src/core/lib/channel/channel_args.h4
-rw-r--r--src/core/lib/iomgr/tcp_client_windows.c29
-rw-r--r--src/core/lib/surface/version.c2
-rw-r--r--src/cpp/common/core_codegen.cc204
-rw-r--r--src/cpp/common/core_codegen.h26
-rw-r--r--src/csharp/Grpc.Core.Tests/ClientServerTest.cs63
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj2
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs191
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs548
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs184
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs18
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs61
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallServer.cs58
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs7
-rw-r--r--src/csharp/Grpc.Core/Internal/ClientResponseStream.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/INativeCall.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMethods.cs18
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCallHandler.cs79
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerRequestStream.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerResponseStream.cs7
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs4
-rw-r--r--src/csharp/build_packages.bat2
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c30
-rw-r--r--src/csharp/tests.json1
-rwxr-xr-xsrc/node/tools/bin/protoc.js4
-rwxr-xr-xsrc/node/tools/bin/protoc_plugin.js6
-rw-r--r--src/node/tools/package.json2
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.m54
-rw-r--r--src/objective-c/tests/InteropTests.m6
-rw-r--r--src/proto/grpc/testing/echo.proto4
-rw-r--r--src/python/grpcio/README.rst1
-rw-r--r--src/python/grpcio/grpc/__init__.py3
-rw-r--r--src/python/grpcio/grpc/_cython/imports.generated.c2
-rw-r--r--src/python/grpcio/grpc/_cython/imports.generated.h4
-rw-r--r--src/python/grpcio/grpc/beta/implementations.py9
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py3
-rw-r--r--src/python/grpcio/grpc_version.py2
-rw-r--r--src/python/grpcio/tests/stress/__init__.py28
-rw-r--r--src/python/grpcio/tests/stress/client.py132
-rw-r--r--src/python/grpcio/tests/stress/metrics_server.py60
-rw-r--r--src/python/grpcio/tests/stress/test_runner.py73
-rw-r--r--src/ruby/.rubocop.yml4
-rw-r--r--src/ruby/ext/grpc/extconf.rb32
-rw-r--r--src/ruby/ext/grpc/rb_byte_buffer.c3
-rw-r--r--src/ruby/ext/grpc/rb_call.c3
-rw-r--r--src/ruby/ext/grpc/rb_call_credentials.c6
-rw-r--r--src/ruby/ext/grpc/rb_channel.c3
-rw-r--r--src/ruby/ext/grpc/rb_channel_args.c3
-rw-r--r--src/ruby/ext/grpc/rb_channel_credentials.c5
-rw-r--r--src/ruby/ext/grpc/rb_completion_queue.c2
-rw-r--r--src/ruby/ext/grpc/rb_event_thread.c2
-rw-r--r--src/ruby/ext/grpc/rb_grpc.c2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h4
-rw-r--r--src/ruby/ext/grpc/rb_server.c3
-rw-r--r--src/ruby/ext/grpc/rb_server_credentials.c3
-rw-r--r--src/ruby/lib/grpc/generic/rpc_server.rb17
-rw-r--r--src/ruby/lib/grpc/version.rb2
-rw-r--r--src/ruby/tools/README.md12
-rwxr-xr-xsrc/ruby/tools/bin/protoc.rb41
-rwxr-xr-xsrc/ruby/tools/bin/protoc_grpc_ruby_plugin.rb41
-rw-r--r--src/ruby/tools/grpc-tools.gemspec22
-rw-r--r--src/ruby/tools/os_check.rb45
-rw-r--r--src/ruby/tools/version.rb34
-rw-r--r--templates/src/ruby/tools/version.rb.template36
-rw-r--r--templates/tools/distrib/python/grpcio_tools/grpc_version.py.template34
-rw-r--r--templates/tools/dockerfile/node_deps.include4
-rw-r--r--templates/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile.template41
-rw-r--r--templates/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile.template41
-rw-r--r--templates/tools/dockerfile/test/sanity/Dockerfile.template12
-rw-r--r--test/core/end2end/fixtures/h2_census.c2
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/03a72675e1969f836094f1ecfec2a7b34418e306bin0 -> 286 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/0416afd6875d9ba55f1e5f86a6456a5445d5e576bin0 -> 651 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/08c42ef29eff83052c5887855f2fa3e07ebe470cbin0 -> 650 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/1ba889ea1543297824e99e641e6ca8b91f45732ebin0 -> 650 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/3b09bf453c6f93983c24c4d5481e55d66213f93abin0 -> 650 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/49cb33cbb60f041e8e99dd718993acd2c3354416bin0 -> 357 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/59743fe120be6ae1aed1c02230ee1bb460f621eebin0 -> 628 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/a5ccb8f124d8ddb5350b90bc0d6b96db280cb7c9bin0 -> 651 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/a7fac1265a384fe9e45a9ee3d708b79c4e80505ebin0 -> 286 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/aaf049720c707d4e14e47e7eb31d6a2dda60e66abin0 -> 651 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/c4e4c7572e005e18d56eac407033da058737a5abbin0 -> 651 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/crash-dae0f07934a527989f23f06e630710ff6ca8c809bin0 -> 104 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/e96ad9c17795e52edc810a08d4fc61fe8790002abin0 -> 651 bytes
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer_corpus/fa202a5f51cd49f8ea5af60c5f403f797c01c504bin0 -> 651 bytes
-rw-r--r--test/core/surface/public_headers_must_be_c89.c2
-rw-r--r--test/core/util/test_config.c2
-rw-r--r--test/cpp/end2end/async_end2end_test.cc338
-rw-r--r--test/cpp/qps/driver.cc3
-rw-r--r--test/distrib/csharp/DistribTest/DistribTest.csproj6
-rw-r--r--test/distrib/csharp/DistribTest/packages.config3
-rwxr-xr-xtest/distrib/python/run_distrib_test.sh23
-rw-r--r--third_party/objective_c/Cronet/cronet_c_for_grpc.h202
-rwxr-xr-xtools/buildgen/plugins/list_api.py9
-rwxr-xr-xtools/distrib/check_include_guards.py3
-rwxr-xr-xtools/distrib/python/bazel_deps.sh46
-rwxr-xr-xtools/distrib/python/check_grpcio_tools.py45
-rw-r--r--tools/distrib/python/grpcio_tools/.gitignore7
-rw-r--r--tools/distrib/python/grpcio_tools/MANIFEST.in5
-rw-r--r--tools/distrib/python/grpcio_tools/grpc/__init__.py30
-rw-r--r--tools/distrib/python/grpcio_tools/grpc/protoc/__init__.py29
-rw-r--r--tools/distrib/python/grpcio_tools/grpc/protoc/compiler.py38
-rw-r--r--tools/distrib/python/grpcio_tools/grpc/protoc/main.cc54
-rw-r--r--tools/distrib/python/grpcio_tools/grpc/protoc/main.h33
-rw-r--r--tools/distrib/python/grpcio_tools/grpc/protoc/protoc_compiler.pyx39
-rw-r--r--tools/distrib/python/grpcio_tools/grpc_version.py32
-rw-r--r--tools/distrib/python/grpcio_tools/protoc_lib_deps.py32
-rw-r--r--tools/distrib/python/grpcio_tools/setup.py84
-rwxr-xr-xtools/distrib/python/make_grpcio_tools.py140
-rw-r--r--tools/dockerfile/bazel/Dockerfile52
-rw-r--r--tools/dockerfile/grpc_artifact_linux_x64/Dockerfile5
-rw-r--r--tools/dockerfile/grpc_artifact_linux_x86/Dockerfile5
-rw-r--r--tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile43
-rw-r--r--tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile43
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_node/Dockerfile5
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_node/build_interop.sh2
-rw-r--r--tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile101
-rwxr-xr-xtools/dockerfile/stress_test/grpc_interop_stress_csharp/build_interop_stress.sh47
-rw-r--r--tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile5
-rwxr-xr-xtools/dockerfile/stress_test/grpc_interop_stress_node/build_interop_stress.sh2
-rw-r--r--tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile99
-rwxr-xr-xtools/dockerfile/stress_test/grpc_interop_stress_ruby/build_interop_stress.sh48
-rw-r--r--tools/dockerfile/test/multilang_jessie_x64/Dockerfile5
-rw-r--r--tools/dockerfile/test/node_jessie_x64/Dockerfile5
-rw-r--r--tools/dockerfile/test/sanity/Dockerfile9
-rw-r--r--tools/doxygen/Doxyfile.c++3
-rw-r--r--tools/doxygen/Doxyfile.c++.internal3
-rw-r--r--tools/doxygen/Doxyfile.core4
-rw-r--r--tools/doxygen/Doxyfile.core.internal43
-rwxr-xr-xtools/gce/linux_performance_worker_init.sh3
-rwxr-xr-xtools/gcp/stress_test/run_ruby.sh37
-rw-r--r--tools/jenkins/README.md1
-rwxr-xr-xtools/jenkins/run_fuzzer.sh4
-rw-r--r--tools/run_tests/artifact_targets.py64
-rw-r--r--tools/run_tests/build_artifact_python.bat13
-rwxr-xr-xtools/run_tests/build_artifact_python.sh42
-rwxr-xr-xtools/run_tests/build_package_ruby.sh24
-rw-r--r--tools/run_tests/distribtest_targets.py4
-rwxr-xr-xtools/run_tests/dockerize/build_and_run_docker.sh (renamed from tools/jenkins/build_and_run_docker.sh)2
-rwxr-xr-xtools/run_tests/dockerize/build_docker_and_run_tests.sh (renamed from tools/jenkins/build_docker_and_run_tests.sh)2
-rwxr-xr-xtools/run_tests/dockerize/build_interop_image.sh (renamed from tools/jenkins/build_interop_image.sh)2
-rwxr-xr-xtools/run_tests/dockerize/build_interop_stress_image.sh (renamed from tools/jenkins/build_interop_stress_image.sh)2
-rwxr-xr-xtools/run_tests/dockerize/docker_run.sh (renamed from tools/jenkins/docker_run.sh)0
-rwxr-xr-xtools/run_tests/dockerize/docker_run_tests.sh (renamed from tools/jenkins/docker_run_tests.sh)0
-rw-r--r--tools/run_tests/package_targets.py4
-rwxr-xr-xtools/run_tests/performance/run_worker_node.sh2
-rwxr-xr-xtools/run_tests/run_interop_tests.py2
-rwxr-xr-xtools/run_tests/run_stress_tests.py2
-rwxr-xr-xtools/run_tests/run_tests.py16
-rw-r--r--tools/run_tests/sanity/sanity_tests.yaml1
-rw-r--r--tools/run_tests/sources_and_headers.json122
-rw-r--r--tools/run_tests/stress_test/configs/asan.json2
-rw-r--r--tools/run_tests/stress_test/configs/csharp.json90
-rw-r--r--tools/run_tests/stress_test/configs/go.json2
-rw-r--r--tools/run_tests/stress_test/configs/java.json2
-rw-r--r--tools/run_tests/stress_test/configs/node-cxx.json4
-rw-r--r--tools/run_tests/stress_test/configs/node.json2
-rw-r--r--tools/run_tests/stress_test/configs/opt-tsan-asan.json6
-rw-r--r--tools/run_tests/stress_test/configs/opt.json2
-rw-r--r--tools/run_tests/stress_test/configs/ruby.json92
-rw-r--r--tools/run_tests/stress_test/configs/tsan.json2
-rw-r--r--tools/run_tests/tests.json224
-rw-r--r--vsprojects/vcxproj/grpc++/grpc++.vcxproj1
-rw-r--r--vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters3
-rw-r--r--vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj1
-rw-r--r--vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters3
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj44
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj.filters147
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj1
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters3
-rw-r--r--vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj1
-rw-r--r--vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj.filters3
-rw-r--r--vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj1
-rw-r--r--vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj.filters3
216 files changed, 6162 insertions, 1407 deletions
diff --git a/BUILD b/BUILD
index 30f0b5028c..ee9801b6b7 100644
--- a/BUILD
+++ b/BUILD
@@ -285,6 +285,42 @@ cc_library(
"src/core/ext/client_config/subchannel_call_holder.h",
"src/core/ext/client_config/subchannel_index.h",
"src/core/ext/client_config/uri_parser.h",
+ "include/grpc/byte_buffer.h",
+ "include/grpc/grpc.h",
+ "include/grpc/impl/codegen/alloc.h",
+ "include/grpc/impl/codegen/atm.h",
+ "include/grpc/impl/codegen/atm_gcc_atomic.h",
+ "include/grpc/impl/codegen/atm_gcc_sync.h",
+ "include/grpc/impl/codegen/atm_win32.h",
+ "include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/compression_types.h",
+ "include/grpc/impl/codegen/connectivity_state.h",
+ "include/grpc/impl/codegen/grpc_types.h",
+ "include/grpc/impl/codegen/log.h",
+ "include/grpc/impl/codegen/port_platform.h",
+ "include/grpc/impl/codegen/propagation_bits.h",
+ "include/grpc/impl/codegen/slice.h",
+ "include/grpc/impl/codegen/slice_buffer.h",
+ "include/grpc/impl/codegen/status.h",
+ "include/grpc/impl/codegen/sync.h",
+ "include/grpc/impl/codegen/sync_generic.h",
+ "include/grpc/impl/codegen/sync_posix.h",
+ "include/grpc/impl/codegen/sync_win32.h",
+ "include/grpc/impl/codegen/time.h",
+ "include/grpc/status.h",
+ "include/grpc/support/alloc.h",
+ "include/grpc/support/atm.h",
+ "include/grpc/support/host_port.h",
+ "include/grpc/support/log.h",
+ "include/grpc/support/port_platform.h",
+ "include/grpc/support/slice.h",
+ "include/grpc/support/slice_buffer.h",
+ "include/grpc/support/string_util.h",
+ "include/grpc/support/sync.h",
+ "include/grpc/support/time.h",
+ "include/grpc/support/useful.h",
+ "src/core/lib/support/string.h",
+ "third_party/objective_c/Cronet/cronet_c_for_grpc.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.h",
"src/core/ext/census/aggregation.h",
@@ -439,6 +475,9 @@ cc_library(
"src/core/ext/client_config/uri_parser.c",
"src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create.c",
+ "src/core/ext/transport/cronet/client/secure/cronet_channel_create.c",
+ "src/core/ext/transport/cronet/transport/cronet_api_dummy.c",
+ "src/core/ext/transport/cronet/transport/cronet_transport.c",
"src/core/ext/lb_policy/grpclb/load_balancer_api.c",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c",
"src/core/ext/lb_policy/pick_first/pick_first.c",
@@ -463,6 +502,7 @@ cc_library(
"include/grpc/grpc.h",
"include/grpc/status.h",
"include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/byte_buffer_reader.h",
"include/grpc/impl/codegen/compression_types.h",
"include/grpc/impl/codegen/connectivity_state.h",
"include/grpc/impl/codegen/grpc_types.h",
@@ -482,6 +522,7 @@ cc_library(
"include/grpc/impl/codegen/sync_posix.h",
"include/grpc/impl/codegen/sync_win32.h",
"include/grpc/impl/codegen/time.h",
+ "include/grpc/grpc_cronet.h",
"include/grpc/grpc_security.h",
"include/grpc/grpc_security_constants.h",
"include/grpc/census.h",
@@ -774,6 +815,7 @@ cc_library(
"include/grpc/grpc.h",
"include/grpc/status.h",
"include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/byte_buffer_reader.h",
"include/grpc/impl/codegen/compression_types.h",
"include/grpc/impl/codegen/connectivity_state.h",
"include/grpc/impl/codegen/grpc_types.h",
@@ -948,6 +990,7 @@ cc_library(
"include/grpc++/impl/codegen/sync_stream.h",
"include/grpc++/impl/codegen/time.h",
"include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/byte_buffer_reader.h",
"include/grpc/impl/codegen/compression_types.h",
"include/grpc/impl/codegen/connectivity_state.h",
"include/grpc/impl/codegen/grpc_types.h",
@@ -1095,6 +1138,7 @@ cc_library(
"include/grpc++/impl/codegen/sync_stream.h",
"include/grpc++/impl/codegen/time.h",
"include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/byte_buffer_reader.h",
"include/grpc/impl/codegen/compression_types.h",
"include/grpc/impl/codegen/connectivity_state.h",
"include/grpc/impl/codegen/grpc_types.h",
@@ -1460,6 +1504,9 @@ objc_library(
"src/core/ext/client_config/uri_parser.c",
"src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create.c",
+ "src/core/ext/transport/cronet/client/secure/cronet_channel_create.c",
+ "src/core/ext/transport/cronet/transport/cronet_api_dummy.c",
+ "src/core/ext/transport/cronet/transport/cronet_transport.c",
"src/core/ext/lb_policy/grpclb/load_balancer_api.c",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c",
"src/core/ext/lb_policy/pick_first/pick_first.c",
@@ -1484,6 +1531,7 @@ objc_library(
"include/grpc/grpc.h",
"include/grpc/status.h",
"include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/byte_buffer_reader.h",
"include/grpc/impl/codegen/compression_types.h",
"include/grpc/impl/codegen/connectivity_state.h",
"include/grpc/impl/codegen/grpc_types.h",
@@ -1503,6 +1551,7 @@ objc_library(
"include/grpc/impl/codegen/sync_posix.h",
"include/grpc/impl/codegen/sync_win32.h",
"include/grpc/impl/codegen/time.h",
+ "include/grpc/grpc_cronet.h",
"include/grpc/grpc_security.h",
"include/grpc/grpc_security_constants.h",
"include/grpc/census.h",
@@ -1630,6 +1679,42 @@ objc_library(
"src/core/ext/client_config/subchannel_call_holder.h",
"src/core/ext/client_config/subchannel_index.h",
"src/core/ext/client_config/uri_parser.h",
+ "include/grpc/byte_buffer.h",
+ "include/grpc/grpc.h",
+ "include/grpc/impl/codegen/alloc.h",
+ "include/grpc/impl/codegen/atm.h",
+ "include/grpc/impl/codegen/atm_gcc_atomic.h",
+ "include/grpc/impl/codegen/atm_gcc_sync.h",
+ "include/grpc/impl/codegen/atm_win32.h",
+ "include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/compression_types.h",
+ "include/grpc/impl/codegen/connectivity_state.h",
+ "include/grpc/impl/codegen/grpc_types.h",
+ "include/grpc/impl/codegen/log.h",
+ "include/grpc/impl/codegen/port_platform.h",
+ "include/grpc/impl/codegen/propagation_bits.h",
+ "include/grpc/impl/codegen/slice.h",
+ "include/grpc/impl/codegen/slice_buffer.h",
+ "include/grpc/impl/codegen/status.h",
+ "include/grpc/impl/codegen/sync.h",
+ "include/grpc/impl/codegen/sync_generic.h",
+ "include/grpc/impl/codegen/sync_posix.h",
+ "include/grpc/impl/codegen/sync_win32.h",
+ "include/grpc/impl/codegen/time.h",
+ "include/grpc/status.h",
+ "include/grpc/support/alloc.h",
+ "include/grpc/support/atm.h",
+ "include/grpc/support/host_port.h",
+ "include/grpc/support/log.h",
+ "include/grpc/support/port_platform.h",
+ "include/grpc/support/slice.h",
+ "include/grpc/support/slice_buffer.h",
+ "include/grpc/support/string_util.h",
+ "include/grpc/support/sync.h",
+ "include/grpc/support/time.h",
+ "include/grpc/support/useful.h",
+ "src/core/lib/support/string.h",
+ "third_party/objective_c/Cronet/cronet_c_for_grpc.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.h",
"src/core/ext/census/aggregation.h",
diff --git a/Makefile b/Makefile
index 38228259cd..c265380ae2 100644
--- a/Makefile
+++ b/Makefile
@@ -407,7 +407,7 @@ E = @echo
Q = @
endif
-VERSION = 0.14.0-dev
+VERSION = 0.15.0-dev
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -2627,6 +2627,9 @@ LIBGRPC_SRC = \
src/core/ext/client_config/uri_parser.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.c \
+ src/core/ext/transport/cronet/client/secure/cronet_channel_create.c \
+ src/core/ext/transport/cronet/transport/cronet_api_dummy.c \
+ src/core/ext/transport/cronet/transport/cronet_transport.c \
src/core/ext/lb_policy/grpclb/load_balancer_api.c \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c \
third_party/nanopb/pb_common.c \
@@ -2654,6 +2657,7 @@ PUBLIC_HEADERS_C += \
include/grpc/grpc.h \
include/grpc/status.h \
include/grpc/impl/codegen/byte_buffer.h \
+ include/grpc/impl/codegen/byte_buffer_reader.h \
include/grpc/impl/codegen/compression_types.h \
include/grpc/impl/codegen/connectivity_state.h \
include/grpc/impl/codegen/grpc_types.h \
@@ -2673,6 +2677,7 @@ PUBLIC_HEADERS_C += \
include/grpc/impl/codegen/sync_posix.h \
include/grpc/impl/codegen/sync_win32.h \
include/grpc/impl/codegen/time.h \
+ include/grpc/grpc_cronet.h \
include/grpc/grpc_security.h \
include/grpc/grpc_security_constants.h \
include/grpc/census.h \
@@ -2974,6 +2979,7 @@ PUBLIC_HEADERS_C += \
include/grpc/grpc.h \
include/grpc/status.h \
include/grpc/impl/codegen/byte_buffer.h \
+ include/grpc/impl/codegen/byte_buffer_reader.h \
include/grpc/impl/codegen/compression_types.h \
include/grpc/impl/codegen/connectivity_state.h \
include/grpc/impl/codegen/grpc_types.h \
@@ -3262,6 +3268,7 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/codegen/sync_stream.h \
include/grpc++/impl/codegen/time.h \
include/grpc/impl/codegen/byte_buffer.h \
+ include/grpc/impl/codegen/byte_buffer_reader.h \
include/grpc/impl/codegen/compression_types.h \
include/grpc/impl/codegen/connectivity_state.h \
include/grpc/impl/codegen/grpc_types.h \
@@ -3567,6 +3574,7 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/codegen/sync_stream.h \
include/grpc++/impl/codegen/time.h \
include/grpc/impl/codegen/byte_buffer.h \
+ include/grpc/impl/codegen/byte_buffer_reader.h \
include/grpc/impl/codegen/compression_types.h \
include/grpc/impl/codegen/connectivity_state.h \
include/grpc/impl/codegen/grpc_types.h \
@@ -14364,6 +14372,9 @@ ifneq ($(OPENSSL_DEP),)
# otherwise parallel compilation will fail if a source is compiled first.
src/core/ext/transport/chttp2/client/secure/secure_channel_create.c: $(OPENSSL_DEP)
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c: $(OPENSSL_DEP)
+src/core/ext/transport/cronet/client/secure/cronet_channel_create.c: $(OPENSSL_DEP)
+src/core/ext/transport/cronet/transport/cronet_api_dummy.c: $(OPENSSL_DEP)
+src/core/ext/transport/cronet/transport/cronet_transport.c: $(OPENSSL_DEP)
src/core/lib/http/httpcli_security_connector.c: $(OPENSSL_DEP)
src/core/lib/security/b64.c: $(OPENSSL_DEP)
src/core/lib/security/client_auth_filter.c: $(OPENSSL_DEP)
diff --git a/binding.gyp b/binding.gyp
index 4314ab7243..12a745ffb0 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -709,6 +709,9 @@
'src/core/ext/client_config/uri_parser.c',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
+ 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c',
+ 'src/core/ext/transport/cronet/transport/cronet_api_dummy.c',
+ 'src/core/ext/transport/cronet/transport/cronet_transport.c',
'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c',
'third_party/nanopb/pb_common.c',
diff --git a/build.yaml b/build.yaml
index 928efdee03..edfc3cd58f 100644
--- a/build.yaml
+++ b/build.yaml
@@ -7,7 +7,7 @@ settings:
'#3': Use "-preN" suffixes to identify pre-release versions
'#4': Per-language overrides are possible with (eg) ruby_version tag here
'#5': See the expand_version.py for all the quirks here
- version: 0.14.0-dev
+ version: 0.15.0-dev
filegroups:
- name: census
public_headers:
@@ -351,6 +351,7 @@ filegroups:
- name: grpc_codegen
public_headers:
- include/grpc/impl/codegen/byte_buffer.h
+ - include/grpc/impl/codegen/byte_buffer_reader.h
- include/grpc/impl/codegen/compression_types.h
- include/grpc/impl/codegen/connectivity_state.h
- include/grpc/impl/codegen/grpc_types.h
@@ -399,6 +400,7 @@ filegroups:
- grpc_client_config
- name: grpc_secure
public_headers:
+ - include/grpc/grpc_cronet.h
- include/grpc/grpc_security.h
- include/grpc/grpc_security_constants.h
headers:
@@ -546,6 +548,63 @@ filegroups:
- grpc_transport_chttp2
- grpc_base
- grpc_secure
+- name: grpc_transport_cronet_client_secure
+ headers:
+ - include/grpc/byte_buffer.h
+ - include/grpc/grpc.h
+ - include/grpc/impl/codegen/alloc.h
+ - include/grpc/impl/codegen/atm.h
+ - include/grpc/impl/codegen/atm_gcc_atomic.h
+ - include/grpc/impl/codegen/atm_gcc_sync.h
+ - include/grpc/impl/codegen/atm_win32.h
+ - include/grpc/impl/codegen/byte_buffer.h
+ - include/grpc/impl/codegen/compression_types.h
+ - include/grpc/impl/codegen/connectivity_state.h
+ - include/grpc/impl/codegen/grpc_types.h
+ - include/grpc/impl/codegen/log.h
+ - include/grpc/impl/codegen/port_platform.h
+ - include/grpc/impl/codegen/propagation_bits.h
+ - include/grpc/impl/codegen/slice.h
+ - include/grpc/impl/codegen/slice_buffer.h
+ - include/grpc/impl/codegen/status.h
+ - include/grpc/impl/codegen/sync.h
+ - include/grpc/impl/codegen/sync_generic.h
+ - include/grpc/impl/codegen/sync_posix.h
+ - include/grpc/impl/codegen/sync_win32.h
+ - include/grpc/impl/codegen/time.h
+ - include/grpc/status.h
+ - include/grpc/support/alloc.h
+ - include/grpc/support/atm.h
+ - include/grpc/support/host_port.h
+ - include/grpc/support/log.h
+ - include/grpc/support/port_platform.h
+ - include/grpc/support/slice.h
+ - include/grpc/support/slice_buffer.h
+ - include/grpc/support/string_util.h
+ - include/grpc/support/sync.h
+ - include/grpc/support/time.h
+ - include/grpc/support/useful.h
+ - src/core/ext/transport/chttp2/transport/incoming_metadata.h
+ - src/core/lib/channel/channel_stack.h
+ - src/core/lib/channel/context.h
+ - src/core/lib/debug/trace.h
+ - src/core/lib/iomgr/closure.h
+ - src/core/lib/iomgr/exec_ctx.h
+ - src/core/lib/iomgr/pollset.h
+ - src/core/lib/iomgr/pollset_set.h
+ - src/core/lib/support/string.h
+ - src/core/lib/surface/channel.h
+ - src/core/lib/surface/channel_stack_type.h
+ - src/core/lib/transport/byte_stream.h
+ - src/core/lib/transport/metadata.h
+ - src/core/lib/transport/metadata_batch.h
+ - src/core/lib/transport/transport.h
+ - src/core/lib/transport/transport_impl.h
+ - third_party/objective_c/Cronet/cronet_c_for_grpc.h
+ src:
+ - src/core/ext/transport/cronet/client/secure/cronet_channel_create.c
+ - src/core/ext/transport/cronet/transport/cronet_api_dummy.c
+ - src/core/ext/transport/cronet/transport/cronet_transport.c
- name: nanopb
headers:
- third_party/nanopb/pb.h
@@ -735,6 +794,7 @@ libs:
- grpc_transport_chttp2_client_secure
- grpc_transport_chttp2_server_insecure
- grpc_transport_chttp2_client_insecure
+ - grpc_transport_cronet_client_secure
- grpc_lb_policy_grpclb
- grpc_lb_policy_pick_first
- grpc_lb_policy_round_robin
diff --git a/composer.json b/composer.json
index 97b1a5cb49..b77a59e351 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
"name": "grpc/grpc",
"type": "library",
"description": "gRPC library for PHP",
- "version": "0.14.0",
+ "version": "0.15.0",
"keywords": ["rpc"],
"homepage": "http://grpc.io",
"license": "BSD-3-Clause",
diff --git a/config.m4 b/config.m4
index 74f9ad242a..5259e679ba 100644
--- a/config.m4
+++ b/config.m4
@@ -228,6 +228,9 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/client_config/uri_parser.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.c \
+ src/core/ext/transport/cronet/client/secure/cronet_channel_create.c \
+ src/core/ext/transport/cronet/transport/cronet_api_dummy.c \
+ src/core/ext/transport/cronet/transport/cronet_transport.c \
src/core/ext/lb_policy/grpclb/load_balancer_api.c \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c \
third_party/nanopb/pb_common.c \
@@ -566,6 +569,8 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/insecure)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/cronet/client/secure)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/cronet/transport)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/channel)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug)
diff --git a/doc/fail_fast.md b/doc/fail_fast.md
new file mode 100644
index 0000000000..3ed4297194
--- /dev/null
+++ b/doc/fail_fast.md
@@ -0,0 +1,15 @@
+gRPC Fail Fast Semantics
+========================
+
+Fail fast requests allow terminating requests (with status UNAVAILABLE) prior
+to the deadline of the request being met.
+
+gRPC implementations of fail fast can terminate requests whenever a channel is
+in the TRANSIENT_FAILURE or SHUTDOWN states. If the channel is in any other
+state (CONNECTING, READY, or IDLE) the request should not be terminated.
+
+Fail fast SHOULD be the default for gRPC implementations, with an option to
+switch to non fail fast.
+
+The opposite of fail fast is 'ignore connectivity'.
+
diff --git a/examples/cpp/helloworld/Makefile b/examples/cpp/helloworld/Makefile
index 470b83573e..58a82dbb83 100644
--- a/examples/cpp/helloworld/Makefile
+++ b/examples/cpp/helloworld/Makefile
@@ -41,7 +41,7 @@ PROTOS_PATH = ../../protos
vpath %.proto $(PROTOS_PATH)
-all: system-check greeter_client greeter_server greeter_async_client greeter_async_server
+all: system-check greeter_client greeter_server greeter_async_client greeter_async_client2 greeter_async_server
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o
$(CXX) $^ $(LDFLAGS) -o $@
@@ -52,6 +52,9 @@ greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o
greeter_async_client: helloworld.pb.o helloworld.grpc.pb.o greeter_async_client.o
$(CXX) $^ $(LDFLAGS) -o $@
+greeter_async_client2: helloworld.pb.o helloworld.grpc.pb.o greeter_async_client2.o
+ $(CXX) $^ $(LDFLAGS) -o $@
+
greeter_async_server: helloworld.pb.o helloworld.grpc.pb.o greeter_async_server.o
$(CXX) $^ $(LDFLAGS) -o $@
@@ -64,7 +67,7 @@ greeter_async_server: helloworld.pb.o helloworld.grpc.pb.o greeter_async_server.
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
clean:
- rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server greeter_async_client greeter_async_server
+ rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server greeter_async_client greeter_async_client2 greeter_async_server
# The following is to test your system and ensure a smoother experience.
diff --git a/examples/cpp/helloworld/greeter_async_client.cc b/examples/cpp/helloworld/greeter_async_client.cc
index 35014267fe..c1f5eb55f0 100644
--- a/examples/cpp/helloworld/greeter_async_client.cc
+++ b/examples/cpp/helloworld/greeter_async_client.cc
@@ -53,7 +53,7 @@ class GreeterClient {
explicit GreeterClient(std::shared_ptr<Channel> channel)
: stub_(Greeter::NewStub(channel)) {}
- // Assambles the client's payload, sends it and presents the response back
+ // Assembles the client's payload, sends it and presents the response back
// from the server.
std::string SayHello(const std::string& user) {
// Data we are sending to the server.
@@ -74,9 +74,9 @@ class GreeterClient {
// Storage for the status of the RPC upon completion.
Status status;
- // stub_->AsyncSayHello() perform the RPC call, returning an instance we
- // store in "rpc". Because we are using the asynchronous API, we need the
- // hold on to the "rpc" instance in order to get updates on the ongoig RPC.
+ // stub_->AsyncSayHello() performs the RPC call, returning an instance we
+ // store in "rpc". Because we are using the asynchronous API, we need to
+ // hold on to the "rpc" instance in order to get updates on the ongoing RPC.
std::unique_ptr<ClientAsyncResponseReader<HelloReply> > rpc(
stub_->AsyncSayHello(&context, request, &cq));
diff --git a/examples/cpp/helloworld/greeter_async_client2.cc b/examples/cpp/helloworld/greeter_async_client2.cc
new file mode 100644
index 0000000000..0902376074
--- /dev/null
+++ b/examples/cpp/helloworld/greeter_async_client2.cc
@@ -0,0 +1,153 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <grpc++/grpc++.h>
+#include <thread>
+
+#include "helloworld.grpc.pb.h"
+
+using grpc::Channel;
+using grpc::ClientAsyncResponseReader;
+using grpc::ClientContext;
+using grpc::CompletionQueue;
+using grpc::Status;
+using helloworld::HelloRequest;
+using helloworld::HelloReply;
+using helloworld::Greeter;
+
+class GreeterClient {
+ public:
+ explicit GreeterClient(std::shared_ptr<Channel> channel)
+ : stub_(Greeter::NewStub(channel)) {}
+
+ // Assembles the client's payload and sends it to the server.
+ void SayHello(const std::string& user) {
+ // Data we are sending to the server.
+ HelloRequest request;
+ request.set_name(user);
+
+ // Call object to store rpc data
+ AsyncClientCall* call = new AsyncClientCall;
+
+ // stub_->AsyncSayHello() performs the RPC call, returning an instance to
+ // store in "call". Because we are using the asynchronous API, we need to
+ // hold on to the "call" instance in order to get updates on the ongoing RPC.
+ call->response_reader = stub_->AsyncSayHello(&call->context, request, &cq_);
+
+
+ // Request that, upon completion of the RPC, "reply" be updated with the
+ // server's response; "status" with the indication of whether the operation
+ // was successful. Tag the request with the memory address of the call object.
+ call->response_reader->Finish(&call->reply, &call->status, (void*)call);
+
+ }
+
+ // Loop while listening for completed responses.
+ // Prints out the response from the server.
+ void AsyncCompleteRpc() {
+ void* got_tag;
+ bool ok = false;
+
+ // Block until the next result is available in the completion queue "cq".
+ while (cq_.Next(&got_tag, &ok)) {
+ // The tag in this example is the memory location of the call object
+ AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
+
+ // Verify that the request was completed successfully. Note that "ok"
+ // corresponds solely to the request for updates introduced by Finish().
+ GPR_ASSERT(ok);
+
+ if (call->status.ok())
+ std::cout << "Greeter received: " << call->reply.message() << std::endl;
+ else
+ std::cout << "RPC failed" << std::endl;
+
+ // Once we're complete, deallocate the call object.
+ delete call;
+ }
+ }
+
+ private:
+
+ // struct for keeping state and data information
+ struct AsyncClientCall {
+ // Container for the data we expect from the server.
+ HelloReply reply;
+
+ // Context for the client. It could be used to convey extra information to
+ // the server and/or tweak certain RPC behaviors.
+ ClientContext context;
+
+ // Storage for the status of the RPC upon completion.
+ Status status;
+
+
+ std::unique_ptr<ClientAsyncResponseReader<HelloReply>> response_reader;
+ };
+
+ // Out of the passed in Channel comes the stub, stored here, our view of the
+ // server's exposed services.
+ std::unique_ptr<Greeter::Stub> stub_;
+
+ // The producer-consumer queue we use to communicate asynchronously with the
+ // gRPC runtime.
+ CompletionQueue cq_;
+};
+
+int main(int argc, char** argv) {
+
+
+ // Instantiate the client. It requires a channel, out of which the actual RPCs
+ // are created. This channel models a connection to an endpoint (in this case,
+ // localhost at port 50051). We indicate that the channel isn't authenticated
+ // (use of InsecureChannelCredentials()).
+ GreeterClient greeter(grpc::CreateChannel(
+ "localhost:50051", grpc::InsecureChannelCredentials()));
+
+ // Spawn reader thread that loops indefinitely
+ std::thread thread_ = std::thread(&GreeterClient::AsyncCompleteRpc, &greeter);
+
+ for (int i = 0; i < 100; i++) {
+ std::string user("world " + std::to_string(i));
+ greeter.SayHello(user); // The actual RPC call!
+ }
+
+ std::cout << "Press control-c to quit" << std::endl << std::endl;
+ thread_.join(); //blocks forever
+
+ return 0;
+}
diff --git a/examples/node/greeter_client.js b/examples/node/greeter_client.js
index 7125c2fec5..2820acbbb7 100644
--- a/examples/node/greeter_client.js
+++ b/examples/node/greeter_client.js
@@ -31,30 +31,22 @@
*
*/
-var grpc = require('grpc');
+var PROTO_PATH = __dirname + '/../protos/helloworld.proto';
-var hello_messages = require('./helloworld_pb');
-var hello_service = require('./helloworld_grpc_pb');
+var grpc = require('grpc');
+var hello_proto = grpc.load(PROTO_PATH).helloworld;
function main() {
- var client = new hello_service.GreeterClient('localhost:50051',
- grpc.credentials.createInsecure());
+ var client = new hello_proto.Greeter('localhost:50051',
+ grpc.credentials.createInsecure());
var user;
if (process.argv.length >= 3) {
user = process.argv[2];
} else {
user = 'world';
}
-
- var request = new hello_messages.HelloRequest();
- request.setName(user);
-
- client.sayHello(request, function(err, response) {
- if (err) {
- debugger;
- throw err;
- }
- console.log('Greeting:', response.getMessage());
+ client.sayHello({name: user}, function(err, response) {
+ console.log('Greeting:', response.message);
});
}
diff --git a/examples/node/greeter_server.js b/examples/node/greeter_server.js
index a4aebf6d09..e7ad51f600 100644
--- a/examples/node/greeter_server.js
+++ b/examples/node/greeter_server.js
@@ -31,18 +31,16 @@
*
*/
-var grpc = require('grpc');
+var PROTO_PATH = __dirname + '/../protos/helloworld.proto';
-var hello_messages = require('./helloworld_pb');
-var hello_service = require('./helloworld_grpc_pb');
+var grpc = require('grpc');
+var hello_proto = grpc.load(PROTO_PATH).helloworld;
/**
* Implements the SayHello RPC method.
*/
function sayHello(call, callback) {
- var reply = new hello_messages.HelloReply();
- reply.setMessage("Hello " + call.request.getName());
- callback(null, reply);
+ callback(null, {message: 'Hello ' + call.request.name});
}
/**
@@ -51,7 +49,7 @@ function sayHello(call, callback) {
*/
function main() {
var server = new grpc.Server();
- server.addService(hello_service.GreeterService, {sayHello: sayHello});
+ server.addProtoService(hello_proto.Greeter.service, {sayHello: sayHello});
server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
server.start();
}
diff --git a/examples/node/helloworld_grpc_pb.js b/examples/node/helloworld_grpc_pb.js
deleted file mode 100644
index 3d070d7de0..0000000000
--- a/examples/node/helloworld_grpc_pb.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// GENERATED CODE -- DO NOT EDIT!
-
-var grpc = require('grpc');
-var helloworld_pb = require('./helloworld_pb.js');
-
-function serialize_HelloReply(arg) {
- if (!(arg instanceof helloworld_pb.HelloReply)) {
- throw new Error('Expected argument of type HelloReply');
- }
- return new Buffer(arg.serializeBinary());
-}
-function deserialize_HelloReply(buffer_arg) {
- return helloworld_pb.HelloReply.deserializeBinary(new Uint8Array(buffer_arg));
-}
-function serialize_HelloRequest(arg) {
- if (!(arg instanceof helloworld_pb.HelloRequest)) {
- throw new Error('Expected argument of type HelloRequest');
- }
- return new Buffer(arg.serializeBinary());
-}
-function deserialize_HelloRequest(buffer_arg) {
- return helloworld_pb.HelloRequest.deserializeBinary(new Uint8Array(buffer_arg));
-}
-
-var GreeterService = exports.GreeterService = {
- sayHello: {
- path: '/helloworld.Greeter/SayHello',
- requestStream: false,
- responseStream: false,
- requestType: helloworld_pb.HelloRequest,
- responseType: helloworld_pb.HelloReply,
- requestSerialize: serialize_HelloRequest,
- requestDeserialize: deserialize_HelloRequest,
- responseSerialize: serialize_HelloReply,
- responseDeserialize: deserialize_HelloReply,
- },
-};
-
-exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService);
diff --git a/examples/node/helloworld_pb.js b/examples/node/helloworld_pb.js
deleted file mode 100644
index 6405bd90f1..0000000000
--- a/examples/node/helloworld_pb.js
+++ /dev/null
@@ -1,332 +0,0 @@
-/**
- * @fileoverview
- * @enhanceable
- * @public
- */
-// GENERATED CODE -- DO NOT EDIT!
-
-var jspb = require('google-protobuf');
-var goog = jspb;
-var global = Function('return this')();
-
-goog.exportSymbol('proto.helloworld.HelloReply', null, global);
-goog.exportSymbol('proto.helloworld.HelloRequest', null, global);
-
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.helloworld.HelloRequest = function(opt_data) {
- jspb.Message.initialize(this, opt_data, 0, -1, null, null);
-};
-goog.inherits(proto.helloworld.HelloRequest, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
- proto.helloworld.HelloRequest.displayName = 'proto.helloworld.HelloRequest';
-}
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto suitable for use in Soy templates.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
- * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
- * for transitional soy proto support: http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.helloworld.HelloRequest.prototype.toObject = function(opt_includeInstance) {
- return proto.helloworld.HelloRequest.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Whether to include the JSPB
- * instance for transitional soy proto support:
- * http://goto/soy-param-migration
- * @param {!proto.helloworld.HelloRequest} msg The msg instance to transform.
- * @return {!Object}
- */
-proto.helloworld.HelloRequest.toObject = function(includeInstance, msg) {
- var f, obj = {
- name: msg.getName()
- };
-
- if (includeInstance) {
- obj.$jspbMessageInstance = msg
- }
- return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.helloworld.HelloRequest}
- */
-proto.helloworld.HelloRequest.deserializeBinary = function(bytes) {
- var reader = new jspb.BinaryReader(bytes);
- var msg = new proto.helloworld.HelloRequest;
- return proto.helloworld.HelloRequest.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.helloworld.HelloRequest} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.helloworld.HelloRequest}
- */
-proto.helloworld.HelloRequest.deserializeBinaryFromReader = function(msg, reader) {
- while (reader.nextField()) {
- if (reader.isEndGroup()) {
- break;
- }
- var field = reader.getFieldNumber();
- switch (field) {
- case 1:
- var value = /** @type {string} */ (reader.readString());
- msg.setName(value);
- break;
- default:
- reader.skipField();
- break;
- }
- }
- return msg;
-};
-
-
-/**
- * Class method variant: serializes the given message to binary data
- * (in protobuf wire format), writing to the given BinaryWriter.
- * @param {!proto.helloworld.HelloRequest} message
- * @param {!jspb.BinaryWriter} writer
- */
-proto.helloworld.HelloRequest.serializeBinaryToWriter = function(message, writer) {
- message.serializeBinaryToWriter(writer);
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.helloworld.HelloRequest.prototype.serializeBinary = function() {
- var writer = new jspb.BinaryWriter();
- this.serializeBinaryToWriter(writer);
- return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format),
- * writing to the given BinaryWriter.
- * @param {!jspb.BinaryWriter} writer
- */
-proto.helloworld.HelloRequest.prototype.serializeBinaryToWriter = function (writer) {
- var f = undefined;
- f = this.getName();
- if (f.length > 0) {
- writer.writeString(
- 1,
- f
- );
- }
-};
-
-
-/**
- * Creates a deep clone of this proto. No data is shared with the original.
- * @return {!proto.helloworld.HelloRequest} The clone.
- */
-proto.helloworld.HelloRequest.prototype.cloneMessage = function() {
- return /** @type {!proto.helloworld.HelloRequest} */ (jspb.Message.cloneMessage(this));
-};
-
-
-/**
- * optional string name = 1;
- * @return {string}
- */
-proto.helloworld.HelloRequest.prototype.getName = function() {
- return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, ""));
-};
-
-
-/** @param {string} value */
-proto.helloworld.HelloRequest.prototype.setName = function(value) {
- jspb.Message.setField(this, 1, value);
-};
-
-
-
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.helloworld.HelloReply = function(opt_data) {
- jspb.Message.initialize(this, opt_data, 0, -1, null, null);
-};
-goog.inherits(proto.helloworld.HelloReply, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
- proto.helloworld.HelloReply.displayName = 'proto.helloworld.HelloReply';
-}
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto suitable for use in Soy templates.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
- * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
- * for transitional soy proto support: http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.helloworld.HelloReply.prototype.toObject = function(opt_includeInstance) {
- return proto.helloworld.HelloReply.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Whether to include the JSPB
- * instance for transitional soy proto support:
- * http://goto/soy-param-migration
- * @param {!proto.helloworld.HelloReply} msg The msg instance to transform.
- * @return {!Object}
- */
-proto.helloworld.HelloReply.toObject = function(includeInstance, msg) {
- var f, obj = {
- message: msg.getMessage()
- };
-
- if (includeInstance) {
- obj.$jspbMessageInstance = msg
- }
- return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.helloworld.HelloReply}
- */
-proto.helloworld.HelloReply.deserializeBinary = function(bytes) {
- var reader = new jspb.BinaryReader(bytes);
- var msg = new proto.helloworld.HelloReply;
- return proto.helloworld.HelloReply.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.helloworld.HelloReply} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.helloworld.HelloReply}
- */
-proto.helloworld.HelloReply.deserializeBinaryFromReader = function(msg, reader) {
- while (reader.nextField()) {
- if (reader.isEndGroup()) {
- break;
- }
- var field = reader.getFieldNumber();
- switch (field) {
- case 1:
- var value = /** @type {string} */ (reader.readString());
- msg.setMessage(value);
- break;
- default:
- reader.skipField();
- break;
- }
- }
- return msg;
-};
-
-
-/**
- * Class method variant: serializes the given message to binary data
- * (in protobuf wire format), writing to the given BinaryWriter.
- * @param {!proto.helloworld.HelloReply} message
- * @param {!jspb.BinaryWriter} writer
- */
-proto.helloworld.HelloReply.serializeBinaryToWriter = function(message, writer) {
- message.serializeBinaryToWriter(writer);
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.helloworld.HelloReply.prototype.serializeBinary = function() {
- var writer = new jspb.BinaryWriter();
- this.serializeBinaryToWriter(writer);
- return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format),
- * writing to the given BinaryWriter.
- * @param {!jspb.BinaryWriter} writer
- */
-proto.helloworld.HelloReply.prototype.serializeBinaryToWriter = function (writer) {
- var f = undefined;
- f = this.getMessage();
- if (f.length > 0) {
- writer.writeString(
- 1,
- f
- );
- }
-};
-
-
-/**
- * Creates a deep clone of this proto. No data is shared with the original.
- * @return {!proto.helloworld.HelloReply} The clone.
- */
-proto.helloworld.HelloReply.prototype.cloneMessage = function() {
- return /** @type {!proto.helloworld.HelloReply} */ (jspb.Message.cloneMessage(this));
-};
-
-
-/**
- * optional string message = 1;
- * @return {string}
- */
-proto.helloworld.HelloReply.prototype.getMessage = function() {
- return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, ""));
-};
-
-
-/** @param {string} value */
-proto.helloworld.HelloReply.prototype.setMessage = function(value) {
- jspb.Message.setField(this, 1, value);
-};
-
-
-goog.object.extend(exports, proto.helloworld);
diff --git a/examples/node/package.json b/examples/node/package.json
index 49ab74d318..d135df2464 100644
--- a/examples/node/package.json
+++ b/examples/node/package.json
@@ -4,7 +4,6 @@
"dependencies": {
"async": "^1.5.2",
"grpc": "0.13.0",
- "google-protobuf": "*",
"lodash": "^4.6.1",
"minimist": "^1.2.0"
}
diff --git a/examples/python/helloworld/helloworld_pb2.py b/examples/python/helloworld/helloworld_pb2.py
index 1b2674e4c8..1ee80e4034 100644
--- a/examples/python/helloworld/helloworld_pb2.py
+++ b/examples/python/helloworld/helloworld_pb2.py
@@ -1,6 +1,8 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: helloworld.proto
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
@@ -17,7 +19,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
name='helloworld.proto',
package='helloworld',
syntax='proto3',
- serialized_pb=b'\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x18\n\x10io.grpc.examples\xa2\x02\x03HLWb\x06proto3'
+ serialized_pb=_b('\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
@@ -34,7 +36,7 @@ _HELLOREQUEST = _descriptor.Descriptor(
_descriptor.FieldDescriptor(
name='name', full_name='helloworld.HelloRequest.name', index=0,
number=1, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=b"".decode('utf-8'),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
@@ -65,7 +67,7 @@ _HELLOREPLY = _descriptor.Descriptor(
_descriptor.FieldDescriptor(
name='message', full_name='helloworld.HelloReply.message', index=0,
number=1, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=b"".decode('utf-8'),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
@@ -104,69 +106,28 @@ _sym_db.RegisterMessage(HelloReply)
DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), b'\n\020io.grpc.examples\242\002\003HLW')
+DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'))
import abc
+import six
from grpc.beta import implementations as beta_implementations
-from grpc.early_adopter import implementations as early_adopter_implementations
-from grpc.framework.alpha import utilities as alpha_utilities
+from grpc.beta import interfaces as beta_interfaces
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
-class EarlyAdopterGreeterServicer(object):
- """<fill me in later!>"""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
- def SayHello(self, request, context):
- raise NotImplementedError()
-class EarlyAdopterGreeterServer(object):
- """<fill me in later!>"""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
- def start(self):
- raise NotImplementedError()
- @abc.abstractmethod
- def stop(self):
- raise NotImplementedError()
-class EarlyAdopterGreeterStub(object):
- """<fill me in later!>"""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
- def SayHello(self, request):
- raise NotImplementedError()
- SayHello.async = None
-def early_adopter_create_Greeter_server(servicer, port, private_key=None, certificate_chain=None):
- import helloworld_pb2
- import helloworld_pb2
- method_service_descriptions = {
- "SayHello": alpha_utilities.unary_unary_service_description(
- servicer.SayHello,
- helloworld_pb2.HelloRequest.FromString,
- helloworld_pb2.HelloReply.SerializeToString,
- ),
- }
- return early_adopter_implementations.server("helloworld.Greeter", method_service_descriptions, port, private_key=private_key, certificate_chain=certificate_chain)
-def early_adopter_create_Greeter_stub(host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None):
- import helloworld_pb2
- import helloworld_pb2
- method_invocation_descriptions = {
- "SayHello": alpha_utilities.unary_unary_invocation_description(
- helloworld_pb2.HelloRequest.SerializeToString,
- helloworld_pb2.HelloReply.FromString,
- ),
- }
- return early_adopter_implementations.stub("helloworld.Greeter", method_invocation_descriptions, host, port, metadata_transformer=metadata_transformer, secure=secure, root_certificates=root_certificates, private_key=private_key, certificate_chain=certificate_chain, server_host_override=server_host_override)
class BetaGreeterServicer(object):
- """<fill me in later!>"""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
+ """The greeting service definition.
+ """
def SayHello(self, request, context):
- raise NotImplementedError()
+ """Sends a greeting
+ """
+ context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaGreeterStub(object):
- """The interface to which stubs will conform."""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
+ """The greeting service definition.
+ """
def SayHello(self, request, timeout):
+ """Sends a greeting
+ """
raise NotImplementedError()
SayHello.future = None
diff --git a/examples/python/route_guide/route_guide_pb2.py b/examples/python/route_guide/route_guide_pb2.py
index d4d9f8dcd5..81d5d07527 100644
--- a/examples/python/route_guide/route_guide_pb2.py
+++ b/examples/python/route_guide/route_guide_pb2.py
@@ -1,6 +1,8 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: route_guide.proto
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
@@ -17,7 +19,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
name='route_guide.proto',
package='routeguide',
syntax='proto3',
- serialized_pb=b'\n\x11route_guide.proto\x12\nrouteguide\",\n\x05Point\x12\x10\n\x08latitude\x18\x01 \x01(\x05\x12\x11\n\tlongitude\x18\x02 \x01(\x05\"I\n\tRectangle\x12\x1d\n\x02lo\x18\x01 \x01(\x0b\x32\x11.routeguide.Point\x12\x1d\n\x02hi\x18\x02 \x01(\x0b\x32\x11.routeguide.Point\"<\n\x07\x46\x65\x61ture\x12\x0c\n\x04name\x18\x01 \x01(\t\x12#\n\x08location\x18\x02 \x01(\x0b\x32\x11.routeguide.Point\"A\n\tRouteNote\x12#\n\x08location\x18\x01 \x01(\x0b\x32\x11.routeguide.Point\x12\x0f\n\x07message\x18\x02 \x01(\t\"b\n\x0cRouteSummary\x12\x13\n\x0bpoint_count\x18\x01 \x01(\x05\x12\x15\n\rfeature_count\x18\x02 \x01(\x05\x12\x10\n\x08\x64istance\x18\x03 \x01(\x05\x12\x14\n\x0c\x65lapsed_time\x18\x04 \x01(\x05\x32\x85\x02\n\nRouteGuide\x12\x36\n\nGetFeature\x12\x11.routeguide.Point\x1a\x13.routeguide.Feature\"\x00\x12>\n\x0cListFeatures\x12\x15.routeguide.Rectangle\x1a\x13.routeguide.Feature\"\x00\x30\x01\x12>\n\x0bRecordRoute\x12\x11.routeguide.Point\x1a\x18.routeguide.RouteSummary\"\x00(\x01\x12?\n\tRouteChat\x12\x15.routeguide.RouteNote\x1a\x15.routeguide.RouteNote\"\x00(\x01\x30\x01\x42\x0f\n\x07\x65x.grpc\xa2\x02\x03RTGb\x06proto3'
+ serialized_pb=_b('\n\x11route_guide.proto\x12\nrouteguide\",\n\x05Point\x12\x10\n\x08latitude\x18\x01 \x01(\x05\x12\x11\n\tlongitude\x18\x02 \x01(\x05\"I\n\tRectangle\x12\x1d\n\x02lo\x18\x01 \x01(\x0b\x32\x11.routeguide.Point\x12\x1d\n\x02hi\x18\x02 \x01(\x0b\x32\x11.routeguide.Point\"<\n\x07\x46\x65\x61ture\x12\x0c\n\x04name\x18\x01 \x01(\t\x12#\n\x08location\x18\x02 \x01(\x0b\x32\x11.routeguide.Point\"A\n\tRouteNote\x12#\n\x08location\x18\x01 \x01(\x0b\x32\x11.routeguide.Point\x12\x0f\n\x07message\x18\x02 \x01(\t\"b\n\x0cRouteSummary\x12\x13\n\x0bpoint_count\x18\x01 \x01(\x05\x12\x15\n\rfeature_count\x18\x02 \x01(\x05\x12\x10\n\x08\x64istance\x18\x03 \x01(\x05\x12\x14\n\x0c\x65lapsed_time\x18\x04 \x01(\x05\x32\x85\x02\n\nRouteGuide\x12\x36\n\nGetFeature\x12\x11.routeguide.Point\x1a\x13.routeguide.Feature\"\x00\x12>\n\x0cListFeatures\x12\x15.routeguide.Rectangle\x1a\x13.routeguide.Feature\"\x00\x30\x01\x12>\n\x0bRecordRoute\x12\x11.routeguide.Point\x1a\x18.routeguide.RouteSummary\"\x00(\x01\x12?\n\tRouteChat\x12\x15.routeguide.RouteNote\x1a\x15.routeguide.RouteNote\"\x00(\x01\x30\x01\x42\x36\n\x1bio.grpc.examples.routeguideB\x0fRouteGuideProtoP\x01\xa2\x02\x03RTGb\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
@@ -110,7 +112,7 @@ _FEATURE = _descriptor.Descriptor(
_descriptor.FieldDescriptor(
name='name', full_name='routeguide.Feature.name', index=0,
number=1, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=b"".decode('utf-8'),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
@@ -155,7 +157,7 @@ _ROUTENOTE = _descriptor.Descriptor(
_descriptor.FieldDescriptor(
name='message', full_name='routeguide.RouteNote.message', index=1,
number=2, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=b"".decode('utf-8'),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
@@ -274,149 +276,86 @@ _sym_db.RegisterMessage(RouteSummary)
DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), b'\n\007ex.grpc\242\002\003RTG')
+DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.routeguideB\017RouteGuideProtoP\001\242\002\003RTG'))
import abc
+import six
from grpc.beta import implementations as beta_implementations
-from grpc.early_adopter import implementations as early_adopter_implementations
-from grpc.framework.alpha import utilities as alpha_utilities
+from grpc.beta import interfaces as beta_interfaces
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
-class EarlyAdopterRouteGuideServicer(object):
- """<fill me in later!>"""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
- def GetFeature(self, request, context):
- raise NotImplementedError()
- @abc.abstractmethod
- def ListFeatures(self, request, context):
- raise NotImplementedError()
- @abc.abstractmethod
- def RecordRoute(self, request_iterator, context):
- raise NotImplementedError()
- @abc.abstractmethod
- def RouteChat(self, request_iterator, context):
- raise NotImplementedError()
-class EarlyAdopterRouteGuideServer(object):
- """<fill me in later!>"""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
- def start(self):
- raise NotImplementedError()
- @abc.abstractmethod
- def stop(self):
- raise NotImplementedError()
-class EarlyAdopterRouteGuideStub(object):
- """<fill me in later!>"""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
- def GetFeature(self, request):
- raise NotImplementedError()
- GetFeature.async = None
- @abc.abstractmethod
- def ListFeatures(self, request):
- raise NotImplementedError()
- ListFeatures.async = None
- @abc.abstractmethod
- def RecordRoute(self, request_iterator):
- raise NotImplementedError()
- RecordRoute.async = None
- @abc.abstractmethod
- def RouteChat(self, request_iterator):
- raise NotImplementedError()
- RouteChat.async = None
-def early_adopter_create_RouteGuide_server(servicer, port, private_key=None, certificate_chain=None):
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- method_service_descriptions = {
- "GetFeature": alpha_utilities.unary_unary_service_description(
- servicer.GetFeature,
- route_guide_pb2.Point.FromString,
- route_guide_pb2.Feature.SerializeToString,
- ),
- "ListFeatures": alpha_utilities.unary_stream_service_description(
- servicer.ListFeatures,
- route_guide_pb2.Rectangle.FromString,
- route_guide_pb2.Feature.SerializeToString,
- ),
- "RecordRoute": alpha_utilities.stream_unary_service_description(
- servicer.RecordRoute,
- route_guide_pb2.Point.FromString,
- route_guide_pb2.RouteSummary.SerializeToString,
- ),
- "RouteChat": alpha_utilities.stream_stream_service_description(
- servicer.RouteChat,
- route_guide_pb2.RouteNote.FromString,
- route_guide_pb2.RouteNote.SerializeToString,
- ),
- }
- return early_adopter_implementations.server("routeguide.RouteGuide", method_service_descriptions, port, private_key=private_key, certificate_chain=certificate_chain)
-def early_adopter_create_RouteGuide_stub(host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None):
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- import route_guide_pb2
- method_invocation_descriptions = {
- "GetFeature": alpha_utilities.unary_unary_invocation_description(
- route_guide_pb2.Point.SerializeToString,
- route_guide_pb2.Feature.FromString,
- ),
- "ListFeatures": alpha_utilities.unary_stream_invocation_description(
- route_guide_pb2.Rectangle.SerializeToString,
- route_guide_pb2.Feature.FromString,
- ),
- "RecordRoute": alpha_utilities.stream_unary_invocation_description(
- route_guide_pb2.Point.SerializeToString,
- route_guide_pb2.RouteSummary.FromString,
- ),
- "RouteChat": alpha_utilities.stream_stream_invocation_description(
- route_guide_pb2.RouteNote.SerializeToString,
- route_guide_pb2.RouteNote.FromString,
- ),
- }
- return early_adopter_implementations.stub("routeguide.RouteGuide", method_invocation_descriptions, host, port, metadata_transformer=metadata_transformer, secure=secure, root_certificates=root_certificates, private_key=private_key, certificate_chain=certificate_chain, server_host_override=server_host_override)
class BetaRouteGuideServicer(object):
- """<fill me in later!>"""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
+ """Interface exported by the server.
+ """
def GetFeature(self, request, context):
- raise NotImplementedError()
- @abc.abstractmethod
+ """A simple RPC.
+
+ Obtains the feature at a given position.
+
+ A feature with an empty name is returned if there's no feature at the given
+ position.
+ """
+ context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def ListFeatures(self, request, context):
- raise NotImplementedError()
- @abc.abstractmethod
+ """A server-to-client streaming RPC.
+
+ Obtains the Features available within the given Rectangle. Results are
+ streamed rather than returned at once (e.g. in a response message with a
+ repeated field), as the rectangle may cover a large area and contain a
+ huge number of features.
+ """
+ context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def RecordRoute(self, request_iterator, context):
- raise NotImplementedError()
- @abc.abstractmethod
+ """A client-to-server streaming RPC.
+
+ Accepts a stream of Points on a route being traversed, returning a
+ RouteSummary when traversal is completed.
+ """
+ context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def RouteChat(self, request_iterator, context):
- raise NotImplementedError()
+ """A Bidirectional streaming RPC.
+
+ Accepts a stream of RouteNotes sent while a route is being traversed,
+ while receiving other RouteNotes (e.g. from other users).
+ """
+ context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaRouteGuideStub(object):
- """The interface to which stubs will conform."""
- __metaclass__ = abc.ABCMeta
- @abc.abstractmethod
+ """Interface exported by the server.
+ """
def GetFeature(self, request, timeout):
+ """A simple RPC.
+
+ Obtains the feature at a given position.
+
+ A feature with an empty name is returned if there's no feature at the given
+ position.
+ """
raise NotImplementedError()
GetFeature.future = None
- @abc.abstractmethod
def ListFeatures(self, request, timeout):
+ """A server-to-client streaming RPC.
+
+ Obtains the Features available within the given Rectangle. Results are
+ streamed rather than returned at once (e.g. in a response message with a
+ repeated field), as the rectangle may cover a large area and contain a
+ huge number of features.
+ """
raise NotImplementedError()
- @abc.abstractmethod
def RecordRoute(self, request_iterator, timeout):
+ """A client-to-server streaming RPC.
+
+ Accepts a stream of Points on a route being traversed, returning a
+ RouteSummary when traversal is completed.
+ """
raise NotImplementedError()
RecordRoute.future = None
- @abc.abstractmethod
def RouteChat(self, request_iterator, timeout):
+ """A Bidirectional streaming RPC.
+
+ Accepts a stream of RouteNotes sent while a route is being traversed,
+ while receiving other RouteNotes (e.g. from other users).
+ """
raise NotImplementedError()
def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
diff --git a/gRPC.podspec b/gRPC.podspec
index 77d35bd2c7..018306ca64 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -287,6 +287,42 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/subchannel_call_holder.h',
'src/core/ext/client_config/subchannel_index.h',
'src/core/ext/client_config/uri_parser.h',
+ 'include/grpc/byte_buffer.h',
+ 'include/grpc/grpc.h',
+ 'include/grpc/impl/codegen/alloc.h',
+ 'include/grpc/impl/codegen/atm.h',
+ 'include/grpc/impl/codegen/atm_gcc_atomic.h',
+ 'include/grpc/impl/codegen/atm_gcc_sync.h',
+ 'include/grpc/impl/codegen/atm_win32.h',
+ 'include/grpc/impl/codegen/byte_buffer.h',
+ 'include/grpc/impl/codegen/compression_types.h',
+ 'include/grpc/impl/codegen/connectivity_state.h',
+ 'include/grpc/impl/codegen/grpc_types.h',
+ 'include/grpc/impl/codegen/log.h',
+ 'include/grpc/impl/codegen/port_platform.h',
+ 'include/grpc/impl/codegen/propagation_bits.h',
+ 'include/grpc/impl/codegen/slice.h',
+ 'include/grpc/impl/codegen/slice_buffer.h',
+ 'include/grpc/impl/codegen/status.h',
+ 'include/grpc/impl/codegen/sync.h',
+ 'include/grpc/impl/codegen/sync_generic.h',
+ 'include/grpc/impl/codegen/sync_posix.h',
+ 'include/grpc/impl/codegen/sync_win32.h',
+ 'include/grpc/impl/codegen/time.h',
+ 'include/grpc/status.h',
+ 'include/grpc/support/alloc.h',
+ 'include/grpc/support/atm.h',
+ 'include/grpc/support/host_port.h',
+ 'include/grpc/support/log.h',
+ 'include/grpc/support/port_platform.h',
+ 'include/grpc/support/slice.h',
+ 'include/grpc/support/slice_buffer.h',
+ 'include/grpc/support/string_util.h',
+ 'include/grpc/support/sync.h',
+ 'include/grpc/support/time.h',
+ 'include/grpc/support/useful.h',
+ 'src/core/lib/support/string.h',
+ 'third_party/objective_c/Cronet/cronet_c_for_grpc.h',
'src/core/ext/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.h',
'third_party/nanopb/pb.h',
@@ -305,6 +341,7 @@ Pod::Spec.new do |s|
'include/grpc/grpc.h',
'include/grpc/status.h',
'include/grpc/impl/codegen/byte_buffer.h',
+ 'include/grpc/impl/codegen/byte_buffer_reader.h',
'include/grpc/impl/codegen/compression_types.h',
'include/grpc/impl/codegen/connectivity_state.h',
'include/grpc/impl/codegen/grpc_types.h',
@@ -324,6 +361,7 @@ Pod::Spec.new do |s|
'include/grpc/impl/codegen/sync_posix.h',
'include/grpc/impl/codegen/sync_win32.h',
'include/grpc/impl/codegen/time.h',
+ 'include/grpc/grpc_cronet.h',
'include/grpc/grpc_security.h',
'include/grpc/grpc_security_constants.h',
'include/grpc/census.h',
@@ -473,6 +511,9 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/uri_parser.c',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
+ 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c',
+ 'src/core/ext/transport/cronet/transport/cronet_api_dummy.c',
+ 'src/core/ext/transport/cronet/transport/cronet_transport.c',
'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c',
'third_party/nanopb/pb_common.c',
@@ -629,6 +670,42 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/subchannel_call_holder.h',
'src/core/ext/client_config/subchannel_index.h',
'src/core/ext/client_config/uri_parser.h',
+ 'include/grpc/byte_buffer.h',
+ 'include/grpc/grpc.h',
+ 'include/grpc/impl/codegen/alloc.h',
+ 'include/grpc/impl/codegen/atm.h',
+ 'include/grpc/impl/codegen/atm_gcc_atomic.h',
+ 'include/grpc/impl/codegen/atm_gcc_sync.h',
+ 'include/grpc/impl/codegen/atm_win32.h',
+ 'include/grpc/impl/codegen/byte_buffer.h',
+ 'include/grpc/impl/codegen/compression_types.h',
+ 'include/grpc/impl/codegen/connectivity_state.h',
+ 'include/grpc/impl/codegen/grpc_types.h',
+ 'include/grpc/impl/codegen/log.h',
+ 'include/grpc/impl/codegen/port_platform.h',
+ 'include/grpc/impl/codegen/propagation_bits.h',
+ 'include/grpc/impl/codegen/slice.h',
+ 'include/grpc/impl/codegen/slice_buffer.h',
+ 'include/grpc/impl/codegen/status.h',
+ 'include/grpc/impl/codegen/sync.h',
+ 'include/grpc/impl/codegen/sync_generic.h',
+ 'include/grpc/impl/codegen/sync_posix.h',
+ 'include/grpc/impl/codegen/sync_win32.h',
+ 'include/grpc/impl/codegen/time.h',
+ 'include/grpc/status.h',
+ 'include/grpc/support/alloc.h',
+ 'include/grpc/support/atm.h',
+ 'include/grpc/support/host_port.h',
+ 'include/grpc/support/log.h',
+ 'include/grpc/support/port_platform.h',
+ 'include/grpc/support/slice.h',
+ 'include/grpc/support/slice_buffer.h',
+ 'include/grpc/support/string_util.h',
+ 'include/grpc/support/sync.h',
+ 'include/grpc/support/time.h',
+ 'include/grpc/support/useful.h',
+ 'src/core/lib/support/string.h',
+ 'third_party/objective_c/Cronet/cronet_c_for_grpc.h',
'src/core/ext/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.h',
'third_party/nanopb/pb.h',
diff --git a/grpc.def b/grpc.def
index 61948ed1b8..09a94a6cd0 100644
--- a/grpc.def
+++ b/grpc.def
@@ -87,6 +87,7 @@ EXPORTS
grpc_header_nonbin_value_is_legal
grpc_is_binary_header
grpc_call_error_to_string
+ grpc_cronet_secure_channel_create
grpc_auth_property_iterator_next
grpc_auth_context_property_iterator
grpc_auth_context_peer_identity
diff --git a/grpc.gemspec b/grpc.gemspec
index e68cd81da7..ace28715dc 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -149,6 +149,7 @@ Gem::Specification.new do |s|
s.files += %w( include/grpc/grpc.h )
s.files += %w( include/grpc/status.h )
s.files += %w( include/grpc/impl/codegen/byte_buffer.h )
+ s.files += %w( include/grpc/impl/codegen/byte_buffer_reader.h )
s.files += %w( include/grpc/impl/codegen/compression_types.h )
s.files += %w( include/grpc/impl/codegen/connectivity_state.h )
s.files += %w( include/grpc/impl/codegen/grpc_types.h )
@@ -168,6 +169,7 @@ Gem::Specification.new do |s|
s.files += %w( include/grpc/impl/codegen/sync_posix.h )
s.files += %w( include/grpc/impl/codegen/sync_win32.h )
s.files += %w( include/grpc/impl/codegen/time.h )
+ s.files += %w( include/grpc/grpc_cronet.h )
s.files += %w( include/grpc/grpc_security.h )
s.files += %w( include/grpc/grpc_security_constants.h )
s.files += %w( include/grpc/census.h )
@@ -295,6 +297,42 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_config/subchannel_call_holder.h )
s.files += %w( src/core/ext/client_config/subchannel_index.h )
s.files += %w( src/core/ext/client_config/uri_parser.h )
+ s.files += %w( include/grpc/byte_buffer.h )
+ s.files += %w( include/grpc/grpc.h )
+ s.files += %w( include/grpc/impl/codegen/alloc.h )
+ s.files += %w( include/grpc/impl/codegen/atm.h )
+ s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h )
+ s.files += %w( include/grpc/impl/codegen/atm_gcc_sync.h )
+ s.files += %w( include/grpc/impl/codegen/atm_win32.h )
+ s.files += %w( include/grpc/impl/codegen/byte_buffer.h )
+ s.files += %w( include/grpc/impl/codegen/compression_types.h )
+ s.files += %w( include/grpc/impl/codegen/connectivity_state.h )
+ s.files += %w( include/grpc/impl/codegen/grpc_types.h )
+ s.files += %w( include/grpc/impl/codegen/log.h )
+ s.files += %w( include/grpc/impl/codegen/port_platform.h )
+ s.files += %w( include/grpc/impl/codegen/propagation_bits.h )
+ s.files += %w( include/grpc/impl/codegen/slice.h )
+ s.files += %w( include/grpc/impl/codegen/slice_buffer.h )
+ s.files += %w( include/grpc/impl/codegen/status.h )
+ s.files += %w( include/grpc/impl/codegen/sync.h )
+ s.files += %w( include/grpc/impl/codegen/sync_generic.h )
+ s.files += %w( include/grpc/impl/codegen/sync_posix.h )
+ s.files += %w( include/grpc/impl/codegen/sync_win32.h )
+ s.files += %w( include/grpc/impl/codegen/time.h )
+ s.files += %w( include/grpc/status.h )
+ s.files += %w( include/grpc/support/alloc.h )
+ s.files += %w( include/grpc/support/atm.h )
+ s.files += %w( include/grpc/support/host_port.h )
+ s.files += %w( include/grpc/support/log.h )
+ s.files += %w( include/grpc/support/port_platform.h )
+ s.files += %w( include/grpc/support/slice.h )
+ s.files += %w( include/grpc/support/slice_buffer.h )
+ s.files += %w( include/grpc/support/string_util.h )
+ s.files += %w( include/grpc/support/sync.h )
+ s.files += %w( include/grpc/support/time.h )
+ s.files += %w( include/grpc/support/useful.h )
+ s.files += %w( src/core/lib/support/string.h )
+ s.files += %w( third_party/objective_c/Cronet/cronet_c_for_grpc.h )
s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.h )
s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.h )
s.files += %w( third_party/nanopb/pb.h )
@@ -453,6 +491,9 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_config/uri_parser.c )
s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2.c )
s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.c )
+ s.files += %w( src/core/ext/transport/cronet/client/secure/cronet_channel_create.c )
+ s.files += %w( src/core/ext/transport/cronet/transport/cronet_api_dummy.c )
+ s.files += %w( src/core/ext/transport/cronet/transport/cronet_transport.c )
s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.c )
s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c )
s.files += %w( third_party/nanopb/pb_common.c )
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index aea1a6acec..d081b7d9c5 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -281,10 +281,9 @@ class CallOpRecvMessage {
if (message_ == nullptr) return;
if (recv_buf_) {
if (*status) {
- got_message = true;
- *status = SerializationTraits<R>::Deserialize(recv_buf_, message_,
- max_message_size)
- .ok();
+ got_message = *status = SerializationTraits<R>::Deserialize(
+ recv_buf_, message_, max_message_size)
+ .ok();
} else {
got_message = false;
g_core_codegen_interface->grpc_byte_buffer_destroy(recv_buf_);
diff --git a/include/grpc++/impl/codegen/core_codegen_interface.h b/include/grpc++/impl/codegen/core_codegen_interface.h
index 16424bab35..aa9013c4ce 100644
--- a/include/grpc++/impl/codegen/core_codegen_interface.h
+++ b/include/grpc++/impl/codegen/core_codegen_interface.h
@@ -49,18 +49,6 @@ namespace grpc {
/// \warning This interface should be considered internal and private.
class CoreCodegenInterface {
public:
- // Serialize the msg into a buffer created inside the function. The caller
- // should destroy the returned buffer when done with it. If serialization
- // fails,
- // false is returned and buffer is left unchanged.
- virtual Status SerializeProto(const grpc::protobuf::Message& msg,
- grpc_byte_buffer** buffer) = 0;
-
- // The caller keeps ownership of buffer and msg.
- virtual Status DeserializeProto(grpc_byte_buffer* buffer,
- grpc::protobuf::Message* msg,
- int max_message_size) = 0;
-
/// Upon a failed assertion, log the error.
virtual void assert_fail(const char* failed_assertion) = 0;
@@ -76,9 +64,29 @@ class CoreCodegenInterface {
virtual void gpr_free(void* p) = 0;
virtual void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) = 0;
+
+ virtual void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
+ grpc_byte_buffer* buffer) = 0;
+ virtual void grpc_byte_buffer_reader_destroy(
+ grpc_byte_buffer_reader* reader) = 0;
+ virtual int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
+ gpr_slice* slice) = 0;
+
+ virtual grpc_byte_buffer* grpc_raw_byte_buffer_create(gpr_slice* slice,
+ size_t nslices) = 0;
+
+ virtual gpr_slice gpr_slice_malloc(size_t length) = 0;
+ virtual void gpr_slice_unref(gpr_slice slice) = 0;
+ virtual gpr_slice gpr_slice_split_tail(gpr_slice* s, size_t split) = 0;
+ virtual void gpr_slice_buffer_add(gpr_slice_buffer* sb, gpr_slice slice) = 0;
+ virtual void gpr_slice_buffer_pop(gpr_slice_buffer* sb) = 0;
+
virtual void grpc_metadata_array_init(grpc_metadata_array* array) = 0;
virtual void grpc_metadata_array_destroy(grpc_metadata_array* array) = 0;
+ virtual const Status& ok() = 0;
+ virtual const Status& cancelled() = 0;
+
virtual gpr_timespec gpr_inf_future(gpr_clock_type type) = 0;
};
diff --git a/include/grpc++/impl/codegen/proto_utils.h b/include/grpc++/impl/codegen/proto_utils.h
index 2aaa3c3b30..d044ddc642 100644
--- a/include/grpc++/impl/codegen/proto_utils.h
+++ b/include/grpc++/impl/codegen/proto_utils.h
@@ -41,26 +41,179 @@
#include <grpc++/impl/codegen/serialization_traits.h>
#include <grpc++/impl/codegen/status.h>
#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/byte_buffer_reader.h>
#include <grpc/impl/codegen/log.h>
+#include <grpc/impl/codegen/slice.h>
namespace grpc {
extern CoreCodegenInterface* g_core_codegen_interface;
+namespace {
+
+const int kGrpcBufferWriterMaxBufferLength = 8192;
+
+class GrpcBufferWriter GRPC_FINAL
+ : public ::grpc::protobuf::io::ZeroCopyOutputStream {
+ public:
+ explicit GrpcBufferWriter(grpc_byte_buffer** bp, int block_size)
+ : block_size_(block_size), byte_count_(0), have_backup_(false) {
+ *bp = g_core_codegen_interface->grpc_raw_byte_buffer_create(NULL, 0);
+ slice_buffer_ = &(*bp)->data.raw.slice_buffer;
+ }
+
+ ~GrpcBufferWriter() GRPC_OVERRIDE {
+ if (have_backup_) {
+ g_core_codegen_interface->gpr_slice_unref(backup_slice_);
+ }
+ }
+
+ bool Next(void** data, int* size) GRPC_OVERRIDE {
+ if (have_backup_) {
+ slice_ = backup_slice_;
+ have_backup_ = false;
+ } else {
+ slice_ = g_core_codegen_interface->gpr_slice_malloc(block_size_);
+ }
+ *data = GPR_SLICE_START_PTR(slice_);
+ // On win x64, int is only 32bit
+ GPR_CODEGEN_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
+ byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
+ g_core_codegen_interface->gpr_slice_buffer_add(slice_buffer_, slice_);
+ return true;
+ }
+
+ void BackUp(int count) GRPC_OVERRIDE {
+ g_core_codegen_interface->gpr_slice_buffer_pop(slice_buffer_);
+ if (count == block_size_) {
+ backup_slice_ = slice_;
+ } else {
+ backup_slice_ = g_core_codegen_interface->gpr_slice_split_tail(
+ &slice_, GPR_SLICE_LENGTH(slice_) - count);
+ g_core_codegen_interface->gpr_slice_buffer_add(slice_buffer_, slice_);
+ }
+ have_backup_ = true;
+ byte_count_ -= count;
+ }
+
+ grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE { return byte_count_; }
+
+ private:
+ const int block_size_;
+ int64_t byte_count_;
+ gpr_slice_buffer* slice_buffer_;
+ bool have_backup_;
+ gpr_slice backup_slice_;
+ gpr_slice slice_;
+};
+
+class GrpcBufferReader GRPC_FINAL
+ : public ::grpc::protobuf::io::ZeroCopyInputStream {
+ public:
+ explicit GrpcBufferReader(grpc_byte_buffer* buffer)
+ : byte_count_(0), backup_count_(0) {
+ g_core_codegen_interface->grpc_byte_buffer_reader_init(&reader_, buffer);
+ }
+ ~GrpcBufferReader() GRPC_OVERRIDE {
+ g_core_codegen_interface->grpc_byte_buffer_reader_destroy(&reader_);
+ }
+
+ bool Next(const void** data, int* size) GRPC_OVERRIDE {
+ if (backup_count_ > 0) {
+ *data = GPR_SLICE_START_PTR(slice_) + GPR_SLICE_LENGTH(slice_) -
+ backup_count_;
+ GPR_CODEGEN_ASSERT(backup_count_ <= INT_MAX);
+ *size = (int)backup_count_;
+ backup_count_ = 0;
+ return true;
+ }
+ if (!g_core_codegen_interface->grpc_byte_buffer_reader_next(&reader_,
+ &slice_)) {
+ return false;
+ }
+ g_core_codegen_interface->gpr_slice_unref(slice_);
+ *data = GPR_SLICE_START_PTR(slice_);
+ // On win x64, int is only 32bit
+ GPR_CODEGEN_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
+ byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
+ return true;
+ }
+
+ void BackUp(int count) GRPC_OVERRIDE { backup_count_ = count; }
+
+ bool Skip(int count) GRPC_OVERRIDE {
+ const void* data;
+ int size;
+ while (Next(&data, &size)) {
+ if (size >= count) {
+ BackUp(size - count);
+ return true;
+ }
+ // size < count;
+ count -= size;
+ }
+ // error or we have too large count;
+ return false;
+ }
+
+ grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE {
+ return byte_count_ - backup_count_;
+ }
+
+ private:
+ int64_t byte_count_;
+ int64_t backup_count_;
+ grpc_byte_buffer_reader reader_;
+ gpr_slice slice_;
+};
+} // namespace
+
template <class T>
class SerializationTraits<T, typename std::enable_if<std::is_base_of<
grpc::protobuf::Message, T>::value>::type> {
public:
static Status Serialize(const grpc::protobuf::Message& msg,
- grpc_byte_buffer** buffer, bool* own_buffer) {
+ grpc_byte_buffer** bp, bool* own_buffer) {
*own_buffer = true;
- return g_core_codegen_interface->SerializeProto(msg, buffer);
+ int byte_size = msg.ByteSize();
+ if (byte_size <= kGrpcBufferWriterMaxBufferLength) {
+ gpr_slice slice = g_core_codegen_interface->gpr_slice_malloc(byte_size);
+ GPR_CODEGEN_ASSERT(
+ GPR_SLICE_END_PTR(slice) ==
+ msg.SerializeWithCachedSizesToArray(GPR_SLICE_START_PTR(slice)));
+ *bp = g_core_codegen_interface->grpc_raw_byte_buffer_create(&slice, 1);
+ g_core_codegen_interface->gpr_slice_unref(slice);
+ return g_core_codegen_interface->ok();
+ } else {
+ GrpcBufferWriter writer(bp, kGrpcBufferWriterMaxBufferLength);
+ return msg.SerializeToZeroCopyStream(&writer)
+ ? g_core_codegen_interface->ok()
+ : Status(StatusCode::INTERNAL, "Failed to serialize message");
+ }
}
+
static Status Deserialize(grpc_byte_buffer* buffer,
grpc::protobuf::Message* msg,
int max_message_size) {
- return g_core_codegen_interface->DeserializeProto(buffer, msg,
- max_message_size);
+ if (buffer == nullptr) {
+ return Status(StatusCode::INTERNAL, "No payload");
+ }
+ Status result = g_core_codegen_interface->ok();
+ {
+ GrpcBufferReader reader(buffer);
+ ::grpc::protobuf::io::CodedInputStream decoder(&reader);
+ if (max_message_size > 0) {
+ decoder.SetTotalBytesLimit(max_message_size, max_message_size);
+ }
+ if (!msg->ParseFromCodedStream(&decoder)) {
+ result = Status(StatusCode::INTERNAL, msg->InitializationErrorString());
+ }
+ if (!decoder.ConsumedEntireMessage()) {
+ result = Status(StatusCode::INTERNAL, "Did not read entire message");
+ }
+ }
+ g_core_codegen_interface->grpc_byte_buffer_destroy(buffer);
+ return result;
}
};
diff --git a/include/grpc/byte_buffer_reader.h b/include/grpc/byte_buffer_reader.h
index 9a1c6178ab..e95bf2f80d 100644
--- a/include/grpc/byte_buffer_reader.h
+++ b/include/grpc/byte_buffer_reader.h
@@ -34,25 +34,6 @@
#ifndef GRPC_BYTE_BUFFER_READER_H
#define GRPC_BYTE_BUFFER_READER_H
-#include <grpc/byte_buffer.h>
-#include <grpc/grpc.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct grpc_byte_buffer_reader {
- grpc_byte_buffer *buffer_in;
- grpc_byte_buffer *buffer_out;
- /* Different current objects correspond to different types of byte buffers */
- union {
- /* Index into a slice buffer's array of slices */
- unsigned index;
- } current;
-};
-
-#ifdef __cplusplus
-}
-#endif
+#include <grpc/impl/codegen/byte_buffer_reader.h>
#endif /* GRPC_BYTE_BUFFER_READER_H */
diff --git a/include/grpc/grpc_cronet.h b/include/grpc/grpc_cronet.h
new file mode 100644
index 0000000000..295e0f55e8
--- /dev/null
+++ b/include/grpc/grpc_cronet.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_GRPC_CRONET_H
+#define GRPC_GRPC_CRONET_H
+
+#include <grpc/grpc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRPCAPI grpc_channel *grpc_cronet_secure_channel_create(
+ void *engine, const char *target, const grpc_channel_args *args,
+ void *reserved);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_GRPC_CRONET_H */
diff --git a/include/grpc/impl/codegen/byte_buffer_reader.h b/include/grpc/impl/codegen/byte_buffer_reader.h
new file mode 100644
index 0000000000..10c382924e
--- /dev/null
+++ b/include/grpc/impl/codegen/byte_buffer_reader.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_BYTE_BUFFER_READER_H
+#define GRPC_IMPL_CODEGEN_BYTE_BUFFER_READER_H
+
+#include <grpc/impl/codegen/byte_buffer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct grpc_byte_buffer_reader {
+ grpc_byte_buffer *buffer_in;
+ grpc_byte_buffer *buffer_out;
+ /* Different current objects correspond to different types of byte buffers */
+ union {
+ /* Index into a slice buffer's array of slices */
+ unsigned index;
+ } current;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_BYTE_BUFFER_READER_H */
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 4c7373006b..7b20cc14d4 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -307,7 +307,9 @@ typedef enum {
GRPC_OP_RECV_STATUS_ON_CLIENT,
/** Receive close on the server: one and only one must be made on the
server.
- This op completes after the close has been received by the server. */
+ This op completes after the close has been received by the server.
+ This operation always succeeds, meaning ops paired with this operation
+ will also appear to succeed, even though they may not have. */
GRPC_OP_RECV_CLOSE_ON_SERVER
} grpc_op_type;
diff --git a/package.json b/package.json
index 5ed7f363d3..54a44ca551 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc",
- "version": "0.14.0-dev",
+ "version": "0.15.0-dev",
"author": "Google Inc.",
"description": "gRPC Library for Node",
"homepage": "http://www.grpc.io/",
diff --git a/package.xml b/package.xml
index ffb1c56ed6..152d5d6190 100644
--- a/package.xml
+++ b/package.xml
@@ -13,8 +13,8 @@
<date>2016-04-19</date>
<time>16:06:07</time>
<version>
- <release>0.14.0</release>
- <api>0.14.0</api>
+ <release>0.15.0</release>
+ <api>0.15.0</api>
</version>
<stability>
<release>beta</release>
@@ -156,6 +156,7 @@
<file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
<file baseinstalldir="/" name="include/grpc/status.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer_reader.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/compression_types.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/connectivity_state.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/grpc_types.h" role="src" />
@@ -175,6 +176,7 @@
<file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/sync_win32.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/time.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/grpc_cronet.h" role="src" />
<file baseinstalldir="/" name="include/grpc/grpc_security.h" role="src" />
<file baseinstalldir="/" name="include/grpc/grpc_security_constants.h" role="src" />
<file baseinstalldir="/" name="include/grpc/census.h" role="src" />
@@ -302,6 +304,42 @@
<file baseinstalldir="/" name="src/core/ext/client_config/subchannel_call_holder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/subchannel_index.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/uri_parser.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/byte_buffer.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/alloc.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/atm.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_atomic.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_sync.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_win32.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/compression_types.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/connectivity_state.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/grpc_types.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/log.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/port_platform.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/propagation_bits.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/slice.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/slice_buffer.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/status.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/sync.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_generic.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_win32.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/impl/codegen/time.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/status.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/alloc.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/atm.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/host_port.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/log.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/port_platform.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/slice.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/slice_buffer.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/string_util.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/sync.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/time.h" role="src" />
+ <file baseinstalldir="/" name="include/grpc/support/useful.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/support/string.h" role="src" />
+ <file baseinstalldir="/" name="third_party/objective_c/Cronet/cronet_c_for_grpc.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.h" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb.h" role="src" />
@@ -460,6 +498,9 @@
<file baseinstalldir="/" name="src/core/ext/client_config/uri_parser.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.c" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/transport/cronet/client/secure/cronet_channel_create.c" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/transport/cronet/transport/cronet_api_dummy.c" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/transport/cronet/transport/cronet_transport.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb_common.c" role="src" />
@@ -1013,8 +1054,8 @@ Update to wrap gRPC C Core version 0.10.0
</release>
<release>
<version>
- <release>0.14.0</release>
- <api>0.14.0</api>
+ <release>0.15.0</release>
+ <api>0.15.0</api>
</version>
<stability>
<release>beta</release>
diff --git a/setup.py b/setup.py
index cd0d3a1a51..5cd26124f6 100644
--- a/setup.py
+++ b/setup.py
@@ -236,6 +236,8 @@ setup_arguments = {
'ext_modules': CYTHON_EXTENSION_MODULES,
'packages': list(PACKAGES),
'package_dir': PACKAGE_DIRECTORIES,
+ # TODO(atash): Figure out why auditwheel doesn't like namespace packages.
+ #'namespace_packages': ['grpc'],
'package_data': PACKAGE_DATA,
'install_requires': INSTALL_REQUIRES,
'setup_requires': SETUP_REQUIRES,
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 59137e1c92..8e76e6dce6 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -182,18 +182,40 @@ bool GetModuleAndMessagePath(const Descriptor* type,
return true;
}
+// Get all comments (leading, leading_detached, trailing) and print them as a
+// docstring. Any leading space of a line will be removed, but the line wrapping
+// will not be changed.
+template <typename DescriptorType>
+static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
+ std::vector<grpc::string> comments;
+ grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED,
+ &comments);
+ grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING,
+ &comments);
+ grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING,
+ &comments);
+ if (comments.empty()) {
+ return;
+ }
+ printer->Print("\"\"\"");
+ for (auto it = comments.begin(); it != comments.end(); ++it) {
+ size_t start_pos = it->find_first_not_of(' ');
+ if (start_pos != grpc::string::npos) {
+ printer->Print(it->c_str() + start_pos);
+ }
+ printer->Print("\n");
+ }
+ printer->Print("\"\"\"\n");
+}
+
bool PrintBetaServicer(const ServiceDescriptor* service,
Printer* out) {
- grpc::string doc = "<fill me in later!>";
- map<grpc::string, grpc::string> dict = ListToDict({
- "Service", service->name(),
- "Documentation", doc,
- });
out->Print("\n");
- out->Print(dict, "class Beta$Service$Servicer(object):\n");
+ out->Print("class Beta$Service$Servicer(object):\n", "Service",
+ service->name());
{
IndentScope raii_class_indent(out);
- out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
+ PrintAllComments(service, out);
for (int i = 0; i < service->method_count(); ++i) {
auto meth = service->method(i);
grpc::string arg_name = meth->client_streaming() ?
@@ -202,6 +224,7 @@ bool PrintBetaServicer(const ServiceDescriptor* service,
"Method", meth->name(), "ArgName", arg_name);
{
IndentScope raii_method_indent(out);
+ PrintAllComments(meth, out);
out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n");
}
}
@@ -211,16 +234,11 @@ bool PrintBetaServicer(const ServiceDescriptor* service,
bool PrintBetaStub(const ServiceDescriptor* service,
Printer* out) {
- grpc::string doc = "The interface to which stubs will conform.";
- map<grpc::string, grpc::string> dict = ListToDict({
- "Service", service->name(),
- "Documentation", doc,
- });
out->Print("\n");
- out->Print(dict, "class Beta$Service$Stub(object):\n");
+ out->Print("class Beta$Service$Stub(object):\n", "Service", service->name());
{
IndentScope raii_class_indent(out);
- out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
+ PrintAllComments(service, out);
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor* meth = service->method(i);
grpc::string arg_name = meth->client_streaming() ?
@@ -229,6 +247,7 @@ bool PrintBetaStub(const ServiceDescriptor* service,
out->Print(methdict, "def $Method$(self, $ArgName$, timeout):\n");
{
IndentScope raii_method_indent(out);
+ PrintAllComments(meth, out);
out->Print("raise NotImplementedError()\n");
}
if (!meth->server_streaming()) {
diff --git a/src/core/ext/client_config/resolver_registry.c b/src/core/ext/client_config/resolver_registry.c
index 07f29bcb27..e7a4abd568 100644
--- a/src/core/ext/client_config/resolver_registry.c
+++ b/src/core/ext/client_config/resolver_registry.c
@@ -47,7 +47,6 @@ static int g_number_of_resolvers = 0;
static char *g_default_resolver_prefix;
void grpc_resolver_registry_init(const char *default_resolver_prefix) {
- g_number_of_resolvers = 0;
g_default_resolver_prefix = gpr_strdup(default_resolver_prefix);
}
@@ -57,6 +56,13 @@ void grpc_resolver_registry_shutdown(void) {
grpc_resolver_factory_unref(g_all_of_the_resolvers[i]);
}
gpr_free(g_default_resolver_prefix);
+ // FIXME(ctiller): this should live in grpc_resolver_registry_init,
+ // however that would have the client_config plugin call this AFTER we start
+ // registering resolvers from third party plugins, and so they'd never show
+ // up.
+ // We likely need some kind of dependency system for plugins.... what form
+ // that takes is TBD.
+ g_number_of_resolvers = 0;
}
void grpc_register_resolver_type(grpc_resolver_factory *factory) {
diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c
index 3a5af9f53d..bd45d3825c 100644
--- a/src/core/ext/client_config/subchannel.c
+++ b/src/core/ext/client_config/subchannel.c
@@ -268,7 +268,7 @@ static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
if (con != NULL) {
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection");
- gpr_atm_no_barrier_store(&c->connected_subchannel, 0xdeadbeef);
+ gpr_atm_no_barrier_store(&c->connected_subchannel, (gpr_atm)0xdeadbeef);
}
gpr_mu_unlock(&c->mu);
}
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c
index 3f6051b892..dcdc0c6285 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -306,8 +306,10 @@ static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
size_t i;
p->started_picking = 1;
- gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p,
- p->num_subchannels);
+ if (grpc_lb_round_robin_trace) {
+ gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p,
+ p->num_subchannels);
+ }
for (i = 0; i < p->num_subchannels; i++) {
subchannel_data *sd = p->subchannels[i];
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index fcf2abfe66..53633227ac 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -629,9 +629,10 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
check_read_ops(exec_ctx, &t->global);
gpr_mu_lock(&t->executor.mu);
- if (t->executor.pending_actions != NULL) {
- hdr = t->executor.pending_actions;
- t->executor.pending_actions = NULL;
+ if (t->executor.pending_actions_head != NULL) {
+ hdr = t->executor.pending_actions_head;
+ t->executor.pending_actions_head = t->executor.pending_actions_tail =
+ NULL;
gpr_mu_unlock(&t->executor.mu);
while (hdr != NULL) {
hdr->action(exec_ctx, t, hdr->stream, hdr->arg);
@@ -686,8 +687,14 @@ void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
gpr_free(hdr);
continue;
}
- hdr->next = t->executor.pending_actions;
- t->executor.pending_actions = hdr;
+ hdr->next = NULL;
+ if (t->executor.pending_actions_head != NULL) {
+ t->executor.pending_actions_tail =
+ t->executor.pending_actions_tail->next = hdr;
+ } else {
+ t->executor.pending_actions_tail = t->executor.pending_actions_head =
+ hdr;
+ }
REF_TRANSPORT(t, "pending_action");
gpr_mu_unlock(&t->executor.mu);
}
@@ -776,7 +783,8 @@ void grpc_chttp2_add_incoming_goaway(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
uint32_t goaway_error, gpr_slice goaway_text) {
char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
- gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg);
+ GRPC_CHTTP2_IF_TRACING(
+ gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
gpr_free(msg);
gpr_slice_unref(goaway_text);
transport_global->seen_goaway = 1;
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index 555027c866..ebeee37f0d 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -63,6 +63,8 @@
/* don't consider adding anything bigger than this to the hpack table */
#define MAX_DECODER_SPACE_USAGE 512
+extern int grpc_http_trace;
+
typedef struct {
int is_first_frame;
/* number of bytes in 'output' when we started the frame - used to calculate
@@ -532,7 +534,9 @@ void grpc_chttp2_hpack_compressor_set_max_table_size(
}
}
c->advertise_table_size_change = 1;
- gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
+ if (grpc_http_trace) {
+ gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
+ }
}
void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.c b/src/core/ext/transport/chttp2/transport/hpack_table.c
index 4d64506de2..295f31c44f 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.c
@@ -253,7 +253,9 @@ void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
if (tbl->max_bytes == max_bytes) {
return;
}
- gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
+ if (grpc_http_trace) {
+ gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
+ }
while (tbl->mem_used > max_bytes) {
evict1(tbl);
}
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 7a8084641d..8c4fa2d34a 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -236,9 +236,6 @@ struct grpc_chttp2_transport_parsing {
/** was a goaway frame received? */
uint8_t goaway_received;
- /** the last sent max_table_size setting */
- uint32_t last_sent_max_table_size;
-
/** initial window change */
int64_t initial_window_update;
@@ -272,6 +269,9 @@ struct grpc_chttp2_transport_parsing {
uint32_t incoming_frame_size;
uint32_t incoming_stream_id;
+ /* current max frame size */
+ uint32_t max_frame_size;
+
/* active parser */
void *parser_data;
grpc_chttp2_stream_parsing *incoming_stream;
@@ -282,6 +282,8 @@ struct grpc_chttp2_transport_parsing {
/* received settings */
uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS];
+ /* last settings that were sent */
+ uint32_t last_sent_settings[GRPC_CHTTP2_NUM_SETTINGS];
/* goaway data */
grpc_status_code goaway_error;
@@ -321,7 +323,8 @@ struct grpc_chttp2_transport {
/** is a thread currently parsing */
bool parsing_active;
- grpc_chttp2_executor_action_header *pending_actions;
+ grpc_chttp2_executor_action_header *pending_actions_head;
+ grpc_chttp2_executor_action_header *pending_actions_tail;
} executor;
/** is the transport destroying itself? */
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index e827a43f7a..2995066e51 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -79,9 +79,12 @@ void grpc_chttp2_prepare_to_read(
GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0);
transport_parsing->next_stream_id = transport_global->next_stream_id;
- transport_parsing->last_sent_max_table_size =
- transport_global->settings[GRPC_SENT_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE];
+ memcpy(transport_parsing->last_sent_settings,
+ transport_global->settings[GRPC_SENT_SETTINGS],
+ sizeof(transport_parsing->last_sent_settings));
+ transport_parsing->max_frame_size =
+ transport_global->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE];
/* update the parsing view of incoming window */
while (grpc_chttp2_list_pop_unannounced_incoming_window_available(
@@ -388,6 +391,12 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
return 1;
}
goto dts_fh_0; /* loop */
+ } else if (transport_parsing->incoming_frame_size >
+ transport_parsing->max_frame_size) {
+ gpr_log(GPR_DEBUG, "Frame size %d is larger than max frame size %d",
+ transport_parsing->incoming_frame_size,
+ transport_parsing->max_frame_size);
+ return 0;
}
if (++cur == end) {
return 1;
@@ -840,7 +849,11 @@ static int init_settings_frame_parser(
transport_parsing->settings_ack_received = 1;
grpc_chttp2_hptbl_set_max_bytes(
&transport_parsing->hpack_parser.table,
- transport_parsing->last_sent_max_table_size);
+ transport_parsing
+ ->last_sent_settings[GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+ transport_parsing->max_frame_size =
+ transport_parsing
+ ->last_sent_settings[GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE];
}
transport_parsing->parser = grpc_chttp2_settings_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.settings;
diff --git a/src/core/ext/transport/cronet/client/secure/cronet_channel_create.c b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.c
new file mode 100644
index 0000000000..df1acddcc0
--- /dev/null
+++ b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.c
@@ -0,0 +1,69 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/transport_impl.h"
+
+// Cronet transport object
+typedef struct cronet_transport {
+ grpc_transport base; // must be first element in this structure
+ void *engine;
+ char *host;
+} cronet_transport;
+
+extern grpc_transport_vtable grpc_cronet_vtable;
+
+GRPCAPI grpc_channel *grpc_cronet_secure_channel_create(
+ void *engine, const char *target, const grpc_channel_args *args,
+ void *reserved) {
+ cronet_transport *ct = gpr_malloc(sizeof(cronet_transport));
+ ct->base.vtable = &grpc_cronet_vtable;
+ ct->engine = engine;
+ ct->host = gpr_malloc(strlen(target) + 1);
+ strcpy(ct->host, target);
+ gpr_log(GPR_DEBUG,
+ "grpc_create_cronet_transport: cronet_engine = %p, target=%s", engine,
+ ct->host);
+
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ return grpc_channel_create(&exec_ctx, target, args,
+ GRPC_CLIENT_DIRECT_CHANNEL, (grpc_transport *)ct);
+}
diff --git a/src/core/ext/transport/cronet/transport/cronet_api_dummy.c b/src/core/ext/transport/cronet/transport/cronet_api_dummy.c
new file mode 100644
index 0000000000..687026c9fd
--- /dev/null
+++ b/src/core/ext/transport/cronet/transport/cronet_api_dummy.c
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/* This file has empty implementation of all the functions exposed by the cronet
+library, so we can build it in all environments */
+
+#include <stdbool.h>
+
+#include <grpc/support/log.h>
+
+#include "third_party/objective_c/Cronet/cronet_c_for_grpc.h"
+
+#ifdef GRPC_COMPILE_WITH_CRONET
+/* link with the real CRONET library in the build system */
+#else
+/* Dummy implementation of cronet API just to test for build-ability */
+cronet_bidirectional_stream* cronet_bidirectional_stream_create(
+ cronet_engine* engine, void* annotation,
+ cronet_bidirectional_stream_callback* callback) {
+ GPR_ASSERT(0);
+ return NULL;
+}
+
+int cronet_bidirectional_stream_destroy(cronet_bidirectional_stream* stream) {
+ GPR_ASSERT(0);
+ return 0;
+}
+
+int cronet_bidirectional_stream_start(
+ cronet_bidirectional_stream* stream, const char* url, int priority,
+ const char* method, const cronet_bidirectional_stream_header_array* headers,
+ bool end_of_stream) {
+ GPR_ASSERT(0);
+ return 0;
+}
+
+int cronet_bidirectional_stream_read(cronet_bidirectional_stream* stream,
+ char* buffer, int capacity) {
+ GPR_ASSERT(0);
+ return 0;
+}
+
+int cronet_bidirectional_stream_write(cronet_bidirectional_stream* stream,
+ const char* buffer, int count,
+ bool end_of_stream) {
+ GPR_ASSERT(0);
+ return 0;
+}
+
+int cronet_bidirectional_stream_cancel(cronet_bidirectional_stream* stream) {
+ GPR_ASSERT(0);
+ return 0;
+}
+
+#endif /* GRPC_COMPILE_WITH_CRONET */
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
new file mode 100644
index 0000000000..5bb085195c
--- /dev/null
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -0,0 +1,640 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <string.h>
+
+#include <grpc/impl/codegen/port_platform.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/metadata_batch.h"
+#include "src/core/lib/transport/transport_impl.h"
+#include "third_party/objective_c/Cronet/cronet_c_for_grpc.h"
+
+#define GRPC_HEADER_SIZE_IN_BYTES 5
+
+// Global flag that gets set with GRPC_TRACE env variable
+int grpc_cronet_trace = 1;
+
+// Cronet transport object
+struct grpc_cronet_transport {
+ grpc_transport base; /* must be first element in this structure */
+ cronet_engine *engine;
+ char *host;
+};
+
+typedef struct grpc_cronet_transport grpc_cronet_transport;
+
+enum send_state {
+ CRONET_SEND_IDLE = 0,
+ CRONET_REQ_STARTED,
+ CRONET_SEND_HEADER,
+ CRONET_WRITE,
+ CRONET_WRITE_COMPLETED,
+};
+
+enum recv_state {
+ CRONET_RECV_IDLE = 0,
+ CRONET_RECV_READ_LENGTH,
+ CRONET_RECV_READ_DATA,
+ CRONET_RECV_CLOSED,
+};
+
+static const char *recv_state_name[] = {
+ "CRONET_RECV_IDLE", "CRONET_RECV_READ_LENGTH", "CRONET_RECV_READ_DATA,",
+ "CRONET_RECV_CLOSED"};
+
+// Enum that identifies calling function.
+enum e_caller {
+ PERFORM_STREAM_OP,
+ ON_READ_COMPLETE,
+ ON_RESPONSE_HEADERS_RECEIVED,
+ ON_RESPONSE_TRAILERS_RECEIVED
+};
+
+enum callback_id {
+ CB_SEND_INITIAL_METADATA = 0,
+ CB_SEND_MESSAGE,
+ CB_SEND_TRAILING_METADATA,
+ CB_RECV_MESSAGE,
+ CB_RECV_INITIAL_METADATA,
+ CB_RECV_TRAILING_METADATA,
+ CB_NUM_CALLBACKS
+};
+
+struct stream_obj {
+ // we store received bytes here as they trickle in.
+ gpr_slice_buffer write_slice_buffer;
+ cronet_bidirectional_stream *cbs;
+ gpr_slice slice;
+ gpr_slice_buffer read_slice_buffer;
+ struct grpc_slice_buffer_stream sbs;
+ char *read_buffer;
+ int remaining_read_bytes;
+ int total_read_bytes;
+
+ char *write_buffer;
+ size_t write_buffer_size;
+
+ // Hold the URL
+ char *url;
+
+ bool response_headers_received;
+ bool read_requested;
+ bool response_trailers_received;
+ bool read_closed;
+
+ // Recv message stuff
+ grpc_byte_buffer **recv_message;
+ // Initial metadata stuff
+ grpc_metadata_batch *recv_initial_metadata;
+ // Trailing metadata stuff
+ grpc_metadata_batch *recv_trailing_metadata;
+ grpc_chttp2_incoming_metadata_buffer imb;
+
+ // This mutex protects receive state machine execution
+ gpr_mu recv_mu;
+ // we can queue up up to 2 callbacks for each OP
+ grpc_closure *callback_list[CB_NUM_CALLBACKS][2];
+
+ // storage for header
+ cronet_bidirectional_stream_header *headers;
+ uint32_t num_headers;
+ cronet_bidirectional_stream_header_array header_array;
+ // state tracking
+ enum recv_state cronet_recv_state;
+ enum send_state cronet_send_state;
+};
+
+typedef struct stream_obj stream_obj;
+
+static void next_send_step(stream_obj *s);
+static void next_recv_step(stream_obj *s, enum e_caller caller);
+
+static void set_pollset_do_nothing(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+ grpc_stream *gs, grpc_pollset *pollset) {}
+
+static void enqueue_callbacks(grpc_closure *callback_list[]) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ if (callback_list[0]) {
+ grpc_exec_ctx_enqueue(&exec_ctx, callback_list[0], true, NULL);
+ callback_list[0] = NULL;
+ }
+ if (callback_list[1]) {
+ grpc_exec_ctx_enqueue(&exec_ctx, callback_list[1], true, NULL);
+ callback_list[1] = NULL;
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void on_canceled(cronet_bidirectional_stream *stream) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "on_canceled %p", stream);
+ }
+}
+
+static void on_failed(cronet_bidirectional_stream *stream, int net_error) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "on_failed %p, error = %d", stream, net_error);
+ }
+}
+
+static void on_succeeded(cronet_bidirectional_stream *stream) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "on_succeeded %p", stream);
+ }
+}
+
+static void on_response_trailers_received(
+ cronet_bidirectional_stream *stream,
+ const cronet_bidirectional_stream_header_array *trailers) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "R: on_response_trailers_received");
+ }
+ stream_obj *s = (stream_obj *)stream->annotation;
+
+ memset(&s->imb, 0, sizeof(s->imb));
+ grpc_chttp2_incoming_metadata_buffer_init(&s->imb);
+ unsigned int i = 0;
+ for (i = 0; i < trailers->count; i++) {
+ grpc_chttp2_incoming_metadata_buffer_add(
+ &s->imb, grpc_mdelem_from_metadata_strings(
+ grpc_mdstr_from_string(trailers->headers[i].key),
+ grpc_mdstr_from_string(trailers->headers[i].value)));
+ }
+ s->response_trailers_received = true;
+ next_recv_step(s, ON_RESPONSE_TRAILERS_RECEIVED);
+}
+
+static void on_write_completed(cronet_bidirectional_stream *stream,
+ const char *data) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "W: on_write_completed");
+ }
+ stream_obj *s = (stream_obj *)stream->annotation;
+ enqueue_callbacks(s->callback_list[CB_SEND_MESSAGE]);
+ s->cronet_send_state = CRONET_WRITE_COMPLETED;
+ next_send_step(s);
+}
+
+static void process_recv_message(stream_obj *s, const uint8_t *recv_data) {
+ gpr_slice read_data_slice = gpr_slice_malloc((uint32_t)s->total_read_bytes);
+ uint8_t *dst_p = GPR_SLICE_START_PTR(read_data_slice);
+ memcpy(dst_p, recv_data, (size_t)s->total_read_bytes);
+ gpr_slice_buffer_add(&s->read_slice_buffer, read_data_slice);
+ grpc_slice_buffer_stream_init(&s->sbs, &s->read_slice_buffer, 0);
+ *s->recv_message = (grpc_byte_buffer *)&s->sbs;
+}
+
+static int parse_grpc_header(const uint8_t *data) {
+ const uint8_t *p = data + 1;
+ int length = 0;
+ length |= ((uint8_t)*p++) << 24;
+ length |= ((uint8_t)*p++) << 16;
+ length |= ((uint8_t)*p++) << 8;
+ length |= ((uint8_t)*p++);
+ return length;
+}
+
+static void on_read_completed(cronet_bidirectional_stream *stream, char *data,
+ int count) {
+ stream_obj *s = (stream_obj *)stream->annotation;
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "R: on_read_completed count=%d, total=%d, remaining=%d",
+ count, s->total_read_bytes, s->remaining_read_bytes);
+ }
+ if (count > 0) {
+ GPR_ASSERT(s->recv_message);
+ s->remaining_read_bytes -= count;
+ next_recv_step(s, ON_READ_COMPLETE);
+ } else {
+ s->read_closed = true;
+ next_recv_step(s, ON_READ_COMPLETE);
+ }
+}
+
+static void on_response_headers_received(
+ cronet_bidirectional_stream *stream,
+ const cronet_bidirectional_stream_header_array *headers,
+ const char *negotiated_protocol) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "R: on_response_headers_received");
+ }
+ stream_obj *s = (stream_obj *)stream->annotation;
+ enqueue_callbacks(s->callback_list[CB_RECV_INITIAL_METADATA]);
+ s->response_headers_received = true;
+ next_recv_step(s, ON_RESPONSE_HEADERS_RECEIVED);
+}
+
+static void on_request_headers_sent(cronet_bidirectional_stream *stream) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "W: on_request_headers_sent");
+ }
+ stream_obj *s = (stream_obj *)stream->annotation;
+ enqueue_callbacks(s->callback_list[CB_SEND_INITIAL_METADATA]);
+ s->cronet_send_state = CRONET_SEND_HEADER;
+ next_send_step(s);
+}
+
+// Callback function pointers (invoked by cronet in response to events)
+static cronet_bidirectional_stream_callback callbacks = {
+ on_request_headers_sent,
+ on_response_headers_received,
+ on_read_completed,
+ on_write_completed,
+ on_response_trailers_received,
+ on_succeeded,
+ on_failed,
+ on_canceled};
+
+static void invoke_closing_callback(stream_obj *s) {
+ grpc_chttp2_incoming_metadata_buffer_publish(&s->imb,
+ s->recv_trailing_metadata);
+ if (s->callback_list[CB_RECV_TRAILING_METADATA]) {
+ enqueue_callbacks(s->callback_list[CB_RECV_TRAILING_METADATA]);
+ }
+}
+
+static void set_recv_state(stream_obj *s, enum recv_state state) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "next_state = %s", recv_state_name[state]);
+ }
+ s->cronet_recv_state = state;
+}
+
+// This is invoked from perform_stream_op, and all on_xxxx callbacks.
+static void next_recv_step(stream_obj *s, enum e_caller caller) {
+ gpr_mu_lock(&s->recv_mu);
+ switch (s->cronet_recv_state) {
+ case CRONET_RECV_IDLE:
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_IDLE");
+ }
+ if (caller == PERFORM_STREAM_OP ||
+ caller == ON_RESPONSE_HEADERS_RECEIVED) {
+ if (s->read_closed && s->response_trailers_received) {
+ invoke_closing_callback(s);
+ set_recv_state(s, CRONET_RECV_CLOSED);
+ } else if (s->response_headers_received == true &&
+ s->read_requested == true) {
+ set_recv_state(s, CRONET_RECV_READ_LENGTH);
+ s->total_read_bytes = s->remaining_read_bytes =
+ GRPC_HEADER_SIZE_IN_BYTES;
+ GPR_ASSERT(s->read_buffer);
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()");
+ }
+ cronet_bidirectional_stream_read(s->cbs, s->read_buffer,
+ s->remaining_read_bytes);
+ }
+ }
+ break;
+ case CRONET_RECV_READ_LENGTH:
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_LENGTH");
+ }
+ if (caller == ON_READ_COMPLETE) {
+ if (s->read_closed) {
+ invoke_closing_callback(s);
+ enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]);
+ set_recv_state(s, CRONET_RECV_CLOSED);
+ } else {
+ GPR_ASSERT(s->remaining_read_bytes == 0);
+ set_recv_state(s, CRONET_RECV_READ_DATA);
+ s->total_read_bytes = s->remaining_read_bytes =
+ parse_grpc_header((const uint8_t *)s->read_buffer);
+ s->read_buffer =
+ gpr_realloc(s->read_buffer, (uint32_t)s->remaining_read_bytes);
+ GPR_ASSERT(s->read_buffer);
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()");
+ }
+ cronet_bidirectional_stream_read(s->cbs, (char *)s->read_buffer,
+ s->remaining_read_bytes);
+ }
+ }
+ break;
+ case CRONET_RECV_READ_DATA:
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_DATA");
+ }
+ if (caller == ON_READ_COMPLETE) {
+ if (s->remaining_read_bytes > 0) {
+ int offset = s->total_read_bytes - s->remaining_read_bytes;
+ GPR_ASSERT(s->read_buffer);
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()");
+ }
+ cronet_bidirectional_stream_read(
+ s->cbs, (char *)s->read_buffer + offset, s->remaining_read_bytes);
+ } else {
+ gpr_slice_buffer_init(&s->read_slice_buffer);
+ uint8_t *p = (uint8_t *)s->read_buffer;
+ process_recv_message(s, p);
+ set_recv_state(s, CRONET_RECV_IDLE);
+ enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]);
+ }
+ }
+ break;
+ case CRONET_RECV_CLOSED:
+ break;
+ default:
+ GPR_ASSERT(0); // Should not reach here
+ break;
+ }
+ gpr_mu_unlock(&s->recv_mu);
+}
+
+// This function takes the data from s->write_slice_buffer and assembles into
+// a contiguous byte stream with 5 byte gRPC header prepended.
+static void create_grpc_frame(stream_obj *s) {
+ gpr_slice slice = gpr_slice_buffer_take_first(&s->write_slice_buffer);
+ uint8_t *raw_data = GPR_SLICE_START_PTR(slice);
+ size_t length = GPR_SLICE_LENGTH(slice);
+ s->write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES;
+ s->write_buffer = gpr_realloc(s->write_buffer, s->write_buffer_size);
+ uint8_t *p = (uint8_t *)s->write_buffer;
+ // Append 5 byte header
+ *p++ = 0;
+ *p++ = (uint8_t)(length >> 24);
+ *p++ = (uint8_t)(length >> 16);
+ *p++ = (uint8_t)(length >> 8);
+ *p++ = (uint8_t)(length);
+ // append actual data
+ memcpy(p, raw_data, length);
+}
+
+static void do_write(stream_obj *s) {
+ gpr_slice_buffer *sb = &s->write_slice_buffer;
+ GPR_ASSERT(sb->count <= 1);
+ if (sb->count > 0) {
+ create_grpc_frame(s);
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write");
+ }
+ cronet_bidirectional_stream_write(s->cbs, s->write_buffer,
+ (int)s->write_buffer_size, false);
+ }
+}
+
+//
+static void next_send_step(stream_obj *s) {
+ switch (s->cronet_send_state) {
+ case CRONET_SEND_IDLE:
+ GPR_ASSERT(
+ s->cbs); // cronet_bidirectional_stream is not initialized yet.
+ s->cronet_send_state = CRONET_REQ_STARTED;
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_start to %s", s->url);
+ }
+ cronet_bidirectional_stream_start(s->cbs, s->url, 0, "POST",
+ &s->header_array, false);
+ // we no longer need the memory that was allocated earlier.
+ gpr_free(s->header_array.headers);
+ break;
+ case CRONET_SEND_HEADER:
+ do_write(s);
+ s->cronet_send_state = CRONET_WRITE;
+ break;
+ case CRONET_WRITE_COMPLETED:
+ do_write(s);
+ break;
+ default:
+ GPR_ASSERT(0);
+ break;
+ }
+}
+
+static void convert_metadata_to_cronet_headers(grpc_linked_mdelem *head,
+ const char *host,
+ stream_obj *s) {
+ grpc_linked_mdelem *curr = head;
+ // Walk the linked list and get number of header fields
+ uint32_t num_headers_available = 0;
+ while (curr != NULL) {
+ curr = curr->next;
+ num_headers_available++;
+ }
+ // Allocate enough memory
+ s->headers = (cronet_bidirectional_stream_header *)gpr_malloc(
+ sizeof(cronet_bidirectional_stream_header) * num_headers_available);
+
+ // Walk the linked list again, this time copying the header fields.
+ // s->num_headers
+ // can be less than num_headers_available, as some headers are not used for
+ // cronet
+ curr = head;
+ s->num_headers = 0;
+ while (s->num_headers < num_headers_available) {
+ grpc_mdelem *mdelem = curr->md;
+ curr = curr->next;
+ const char *key = grpc_mdstr_as_c_string(mdelem->key);
+ const char *value = grpc_mdstr_as_c_string(mdelem->value);
+ if (strcmp(key, ":scheme") == 0 || strcmp(key, ":method") == 0 ||
+ strcmp(key, ":authority") == 0) {
+ // Cronet populates these fields on its own.
+ continue;
+ }
+ if (strcmp(key, ":path") == 0) {
+ // Create URL by appending :path value to the hostname
+ gpr_asprintf(&s->url, "https://%s%s", host, value);
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "extracted URL = %s", s->url);
+ }
+ continue;
+ }
+ s->headers[s->num_headers].key = key;
+ s->headers[s->num_headers].value = value;
+ s->num_headers++;
+ if (curr == NULL) {
+ break;
+ }
+ }
+}
+
+static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+ grpc_stream *gs, grpc_transport_stream_op *op) {
+ grpc_cronet_transport *ct = (grpc_cronet_transport *)gt;
+ GPR_ASSERT(ct->engine);
+ stream_obj *s = (stream_obj *)gs;
+ if (op->recv_trailing_metadata) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG,
+ "perform_stream_op - recv_trailing_metadata: on_complete=%p",
+ op->on_complete);
+ }
+ s->recv_trailing_metadata = op->recv_trailing_metadata;
+ GPR_ASSERT(!s->callback_list[CB_RECV_TRAILING_METADATA][0]);
+ s->callback_list[CB_RECV_TRAILING_METADATA][0] = op->on_complete;
+ }
+ if (op->recv_message) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "perform_stream_op - recv_message: on_complete=%p",
+ op->on_complete);
+ }
+ s->recv_message = (grpc_byte_buffer **)op->recv_message;
+ GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][0]);
+ GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][1]);
+ s->callback_list[CB_RECV_MESSAGE][0] = op->recv_message_ready;
+ s->callback_list[CB_RECV_MESSAGE][1] = op->on_complete;
+ s->read_requested = true;
+ next_recv_step(s, PERFORM_STREAM_OP);
+ }
+ if (op->recv_initial_metadata) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "perform_stream_op - recv_initial_metadata:=%p",
+ op->on_complete);
+ }
+ s->recv_initial_metadata = op->recv_initial_metadata;
+ GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][0]);
+ GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][1]);
+ s->callback_list[CB_RECV_INITIAL_METADATA][0] =
+ op->recv_initial_metadata_ready;
+ s->callback_list[CB_RECV_INITIAL_METADATA][1] = op->on_complete;
+ }
+ if (op->send_initial_metadata) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG,
+ "perform_stream_op - send_initial_metadata: on_complete=%p",
+ op->on_complete);
+ }
+ s->num_headers = 0;
+ convert_metadata_to_cronet_headers(op->send_initial_metadata->list.head,
+ ct->host, s);
+ s->header_array.count = s->num_headers;
+ s->header_array.capacity = s->num_headers;
+ s->header_array.headers = s->headers;
+ GPR_ASSERT(!s->callback_list[CB_SEND_INITIAL_METADATA][0]);
+ s->callback_list[CB_SEND_INITIAL_METADATA][0] = op->on_complete;
+ }
+ if (op->send_message) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "perform_stream_op - send_message: on_complete=%p",
+ op->on_complete);
+ }
+ grpc_byte_stream_next(exec_ctx, op->send_message, &s->slice,
+ op->send_message->length, NULL);
+ // Check that compression flag is not ON. We don't support compression yet.
+ // TODO (makdharma): add compression support
+ GPR_ASSERT(op->send_message->flags == 0);
+ gpr_slice_buffer_add(&s->write_slice_buffer, s->slice);
+ if (s->cbs == NULL) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_create");
+ }
+ s->cbs = cronet_bidirectional_stream_create(ct->engine, s, &callbacks);
+ GPR_ASSERT(s->cbs);
+ s->read_closed = false;
+ s->response_trailers_received = false;
+ s->response_headers_received = false;
+ s->cronet_send_state = CRONET_SEND_IDLE;
+ s->cronet_recv_state = CRONET_RECV_IDLE;
+ }
+ GPR_ASSERT(!s->callback_list[CB_SEND_MESSAGE][0]);
+ s->callback_list[CB_SEND_MESSAGE][0] = op->on_complete;
+ next_send_step(s);
+ }
+ if (op->send_trailing_metadata) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG,
+ "perform_stream_op - send_trailing_metadata: on_complete=%p",
+ op->on_complete);
+ }
+ GPR_ASSERT(!s->callback_list[CB_SEND_TRAILING_METADATA][0]);
+ s->callback_list[CB_SEND_TRAILING_METADATA][0] = op->on_complete;
+ if (s->cbs) {
+ // Send an "empty" write to the far end to signal that we're done.
+ // This will induce the server to send down trailers.
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write");
+ }
+ cronet_bidirectional_stream_write(s->cbs, "abc", 0, true);
+ } else {
+ // We never created a stream. This was probably an empty request.
+ invoke_closing_callback(s);
+ }
+ }
+}
+
+static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+ grpc_stream *gs, grpc_stream_refcount *refcount,
+ const void *server_data) {
+ stream_obj *s = (stream_obj *)gs;
+ memset(s->callback_list, 0, sizeof(s->callback_list));
+ s->cbs = NULL;
+ gpr_mu_init(&s->recv_mu);
+ s->read_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES);
+ s->write_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES);
+ gpr_slice_buffer_init(&s->write_slice_buffer);
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "cronet_transport - init_stream");
+ }
+ return 0;
+}
+
+static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+ grpc_stream *gs, void *and_free_memory) {
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "Destroy stream");
+ }
+ stream_obj *s = (stream_obj *)gs;
+ s->cbs = NULL;
+ gpr_free(s->read_buffer);
+ gpr_free(s->write_buffer);
+ gpr_free(s->url);
+ gpr_mu_destroy(&s->recv_mu);
+ if (and_free_memory) {
+ gpr_free(and_free_memory);
+ }
+}
+
+static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
+ grpc_cronet_transport *ct = (grpc_cronet_transport *)gt;
+ gpr_free(ct->host);
+ if (grpc_cronet_trace) {
+ gpr_log(GPR_DEBUG, "Destroy transport");
+ }
+}
+
+const grpc_transport_vtable grpc_cronet_vtable = {
+ sizeof(stream_obj), "cronet_http", init_stream,
+ set_pollset_do_nothing, perform_stream_op, NULL,
+ destroy_stream, destroy_transport, NULL};
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 0a51780a14..23c7b7b897 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -56,10 +56,6 @@ grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a,
/** Destroy arguments created by \a grpc_channel_args_copy */
void grpc_channel_args_destroy(grpc_channel_args *a);
-/** Reads census_enabled settings from channel args. Returns 1 if census_enabled
- * is specified in channel args, otherwise returns 0. */
-int grpc_channel_args_is_census_enabled(const grpc_channel_args *a);
-
/** Returns the compression algorithm set in \a a. */
grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
const grpc_channel_args *a);
diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c
index 7d78beb15a..66f9ff7a46 100644
--- a/src/core/lib/iomgr/tcp_client_windows.c
+++ b/src/core/lib/iomgr/tcp_client_windows.c
@@ -63,39 +63,45 @@ typedef struct {
grpc_endpoint **endpoint;
} async_connect;
-static void async_connect_unlock_and_cleanup(async_connect *ac) {
+static void async_connect_unlock_and_cleanup(async_connect *ac,
+ grpc_winsocket *socket) {
int done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu);
if (done) {
- if (ac->socket != NULL) grpc_winsocket_destroy(ac->socket);
gpr_mu_destroy(&ac->mu);
gpr_free(ac->addr_name);
gpr_free(ac);
}
+ if (socket != NULL) grpc_winsocket_destroy(socket);
}
static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool occured) {
async_connect *ac = acp;
gpr_mu_lock(&ac->mu);
- /* If the alarm didn't occur, it got cancelled. */
- if (ac->socket != NULL && occured) {
+ if (ac->socket != NULL) {
grpc_winsocket_shutdown(ac->socket);
}
- async_connect_unlock_and_cleanup(ac);
+ async_connect_unlock_and_cleanup(ac, ac->socket);
}
static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) {
async_connect *ac = acp;
SOCKET sock = ac->socket->socket;
grpc_endpoint **ep = ac->endpoint;
+ GPR_ASSERT(*ep == NULL);
grpc_winsocket_callback_info *info = &ac->socket->write_info;
grpc_closure *on_done = ac->on_done;
+ gpr_mu_lock(&ac->mu);
+ grpc_winsocket *socket = ac->socket;
+ ac->socket = NULL;
+ gpr_mu_unlock(&ac->mu);
+
grpc_timer_cancel(exec_ctx, &ac->alarm);
gpr_mu_lock(&ac->mu);
- if (from_iocp) {
+ if (from_iocp && socket != NULL) {
DWORD transfered_bytes = 0;
DWORD flags;
BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
@@ -107,12 +113,12 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) {
ac->addr_name, utf8_message);
gpr_free(utf8_message);
} else {
- *ep = grpc_tcp_create(ac->socket, ac->addr_name);
- ac->socket = NULL;
+ *ep = grpc_tcp_create(socket, ac->addr_name);
+ socket = NULL;
}
}
- async_connect_unlock_and_cleanup(ac);
+ async_connect_unlock_and_cleanup(ac, socket);
/* If the connection was aborted, the callback was already called when
the deadline was met. */
on_done->cb(exec_ctx, on_done->cb_arg, *ep != NULL);
@@ -138,6 +144,7 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
const char *message = NULL;
char *utf8_message;
grpc_winsocket_callback_info *info;
+ int last_error;
*endpoint = NULL;
@@ -208,8 +215,10 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
return;
failure:
- utf8_message = gpr_format_message(WSAGetLastError());
+ last_error = WSAGetLastError();
+ utf8_message = gpr_format_message(last_error);
gpr_log(GPR_ERROR, message, utf8_message);
+ gpr_log(GPR_ERROR, "last error = %d", last_error);
gpr_free(utf8_message);
if (socket != NULL) {
grpc_winsocket_destroy(socket);
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index fe954cbefb..aca76d2bb7 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -36,4 +36,4 @@
#include <grpc/grpc.h>
-const char *grpc_version_string(void) { return "0.14.0-dev"; }
+const char *grpc_version_string(void) { return "0.15.0-dev"; }
diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
index 33a8f755e6..8e8d42eb29 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -48,124 +48,6 @@
#include "src/core/lib/profiling/timers.h"
-namespace {
-
-const int kGrpcBufferWriterMaxBufferLength = 8192;
-
-class GrpcBufferWriter GRPC_FINAL
- : public ::grpc::protobuf::io::ZeroCopyOutputStream {
- public:
- explicit GrpcBufferWriter(grpc_byte_buffer** bp, int block_size)
- : block_size_(block_size), byte_count_(0), have_backup_(false) {
- *bp = grpc_raw_byte_buffer_create(NULL, 0);
- slice_buffer_ = &(*bp)->data.raw.slice_buffer;
- }
-
- ~GrpcBufferWriter() GRPC_OVERRIDE {
- if (have_backup_) {
- gpr_slice_unref(backup_slice_);
- }
- }
-
- bool Next(void** data, int* size) GRPC_OVERRIDE {
- if (have_backup_) {
- slice_ = backup_slice_;
- have_backup_ = false;
- } else {
- slice_ = gpr_slice_malloc(block_size_);
- }
- *data = GPR_SLICE_START_PTR(slice_);
- // On win x64, int is only 32bit
- GPR_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
- byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
- gpr_slice_buffer_add(slice_buffer_, slice_);
- return true;
- }
-
- void BackUp(int count) GRPC_OVERRIDE {
- gpr_slice_buffer_pop(slice_buffer_);
- if (count == block_size_) {
- backup_slice_ = slice_;
- } else {
- backup_slice_ =
- gpr_slice_split_tail(&slice_, GPR_SLICE_LENGTH(slice_) - count);
- gpr_slice_buffer_add(slice_buffer_, slice_);
- }
- have_backup_ = true;
- byte_count_ -= count;
- }
-
- grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE { return byte_count_; }
-
- private:
- const int block_size_;
- int64_t byte_count_;
- gpr_slice_buffer* slice_buffer_;
- bool have_backup_;
- gpr_slice backup_slice_;
- gpr_slice slice_;
-};
-
-class GrpcBufferReader GRPC_FINAL
- : public ::grpc::protobuf::io::ZeroCopyInputStream {
- public:
- explicit GrpcBufferReader(grpc_byte_buffer* buffer)
- : byte_count_(0), backup_count_(0) {
- grpc_byte_buffer_reader_init(&reader_, buffer);
- }
- ~GrpcBufferReader() GRPC_OVERRIDE {
- grpc_byte_buffer_reader_destroy(&reader_);
- }
-
- bool Next(const void** data, int* size) GRPC_OVERRIDE {
- if (backup_count_ > 0) {
- *data = GPR_SLICE_START_PTR(slice_) + GPR_SLICE_LENGTH(slice_) -
- backup_count_;
- GPR_ASSERT(backup_count_ <= INT_MAX);
- *size = (int)backup_count_;
- backup_count_ = 0;
- return true;
- }
- if (!grpc_byte_buffer_reader_next(&reader_, &slice_)) {
- return false;
- }
- gpr_slice_unref(slice_);
- *data = GPR_SLICE_START_PTR(slice_);
- // On win x64, int is only 32bit
- GPR_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
- byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
- return true;
- }
-
- void BackUp(int count) GRPC_OVERRIDE { backup_count_ = count; }
-
- bool Skip(int count) GRPC_OVERRIDE {
- const void* data;
- int size;
- while (Next(&data, &size)) {
- if (size >= count) {
- BackUp(size - count);
- return true;
- }
- // size < count;
- count -= size;
- }
- // error or we have too large count;
- return false;
- }
-
- grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE {
- return byte_count_ - backup_count_;
- }
-
- private:
- int64_t byte_count_;
- int64_t backup_count_;
- grpc_byte_buffer_reader reader_;
- gpr_slice slice_;
-};
-} // namespace
-
namespace grpc {
grpc_completion_queue* CoreCodegen::grpc_completion_queue_create(
@@ -192,6 +74,44 @@ void CoreCodegen::grpc_byte_buffer_destroy(grpc_byte_buffer* bb) {
::grpc_byte_buffer_destroy(bb);
}
+void CoreCodegen::grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
+ grpc_byte_buffer* buffer) {
+ ::grpc_byte_buffer_reader_init(reader, buffer);
+}
+
+void CoreCodegen::grpc_byte_buffer_reader_destroy(
+ grpc_byte_buffer_reader* reader) {
+ ::grpc_byte_buffer_reader_destroy(reader);
+}
+
+int CoreCodegen::grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
+ gpr_slice* slice) {
+ return ::grpc_byte_buffer_reader_next(reader, slice);
+}
+
+grpc_byte_buffer* CoreCodegen::grpc_raw_byte_buffer_create(gpr_slice* slice,
+ size_t nslices) {
+ return ::grpc_raw_byte_buffer_create(slice, nslices);
+}
+
+gpr_slice CoreCodegen::gpr_slice_malloc(size_t length) {
+ return ::gpr_slice_malloc(length);
+}
+
+void CoreCodegen::gpr_slice_unref(gpr_slice slice) { ::gpr_slice_unref(slice); }
+
+gpr_slice CoreCodegen::gpr_slice_split_tail(gpr_slice* s, size_t split) {
+ return ::gpr_slice_split_tail(s, split);
+}
+
+void CoreCodegen::gpr_slice_buffer_add(gpr_slice_buffer* sb, gpr_slice slice) {
+ ::gpr_slice_buffer_add(sb, slice);
+}
+
+void CoreCodegen::gpr_slice_buffer_pop(gpr_slice_buffer* sb) {
+ ::gpr_slice_buffer_pop(sb);
+}
+
void CoreCodegen::grpc_metadata_array_init(grpc_metadata_array* array) {
::grpc_metadata_array_init(array);
}
@@ -200,6 +120,10 @@ void CoreCodegen::grpc_metadata_array_destroy(grpc_metadata_array* array) {
::grpc_metadata_array_destroy(array);
}
+const Status& CoreCodegen::ok() { return grpc::Status::OK; }
+
+const Status& CoreCodegen::cancelled() { return grpc::Status::CANCELLED; }
+
gpr_timespec CoreCodegen::gpr_inf_future(gpr_clock_type type) {
return ::gpr_inf_future(type);
}
@@ -209,48 +133,4 @@ void CoreCodegen::assert_fail(const char* failed_assertion) {
abort();
}
-Status CoreCodegen::SerializeProto(const grpc::protobuf::Message& msg,
- grpc_byte_buffer** bp) {
- GPR_TIMER_SCOPE("SerializeProto", 0);
- int byte_size = msg.ByteSize();
- if (byte_size <= kGrpcBufferWriterMaxBufferLength) {
- gpr_slice slice = gpr_slice_malloc(byte_size);
- GPR_ASSERT(GPR_SLICE_END_PTR(slice) ==
- msg.SerializeWithCachedSizesToArray(GPR_SLICE_START_PTR(slice)));
- *bp = grpc_raw_byte_buffer_create(&slice, 1);
- gpr_slice_unref(slice);
- return Status::OK;
- } else {
- GrpcBufferWriter writer(bp, kGrpcBufferWriterMaxBufferLength);
- return msg.SerializeToZeroCopyStream(&writer)
- ? Status::OK
- : Status(StatusCode::INTERNAL, "Failed to serialize message");
- }
-}
-
-Status CoreCodegen::DeserializeProto(grpc_byte_buffer* buffer,
- grpc::protobuf::Message* msg,
- int max_message_size) {
- GPR_TIMER_SCOPE("DeserializeProto", 0);
- if (buffer == nullptr) {
- return Status(StatusCode::INTERNAL, "No payload");
- }
- Status result = Status::OK;
- {
- GrpcBufferReader reader(buffer);
- ::grpc::protobuf::io::CodedInputStream decoder(&reader);
- if (max_message_size > 0) {
- decoder.SetTotalBytesLimit(max_message_size, max_message_size);
- }
- if (!msg->ParseFromCodedStream(&decoder)) {
- result = Status(StatusCode::INTERNAL, msg->InitializationErrorString());
- }
- if (!decoder.ConsumedEntireMessage()) {
- result = Status(StatusCode::INTERNAL, "Did not read entire message");
- }
- }
- grpc_byte_buffer_destroy(buffer);
- return result;
-}
-
} // namespace grpc
diff --git a/src/cpp/common/core_codegen.h b/src/cpp/common/core_codegen.h
index e15cb4c34a..656b11e7e7 100644
--- a/src/cpp/common/core_codegen.h
+++ b/src/cpp/common/core_codegen.h
@@ -42,13 +42,6 @@ namespace grpc {
/// Implementation of the core codegen interface.
class CoreCodegen : public CoreCodegenInterface {
private:
- Status SerializeProto(const grpc::protobuf::Message& msg,
- grpc_byte_buffer** bp) override;
-
- Status DeserializeProto(grpc_byte_buffer* buffer,
- grpc::protobuf::Message* msg,
- int max_message_size) override;
-
grpc_completion_queue* grpc_completion_queue_create(void* reserved) override;
void grpc_completion_queue_destroy(grpc_completion_queue* cq) override;
grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, void* tag,
@@ -60,11 +53,30 @@ class CoreCodegen : public CoreCodegenInterface {
void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) override;
+ void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
+ grpc_byte_buffer* buffer) override;
+ void grpc_byte_buffer_reader_destroy(
+ grpc_byte_buffer_reader* reader) override;
+ int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
+ gpr_slice* slice) override;
+
+ grpc_byte_buffer* grpc_raw_byte_buffer_create(gpr_slice* slice,
+ size_t nslices) override;
+
+ gpr_slice gpr_slice_malloc(size_t length) override;
+ void gpr_slice_unref(gpr_slice slice) override;
+ gpr_slice gpr_slice_split_tail(gpr_slice* s, size_t split) override;
+ void gpr_slice_buffer_add(gpr_slice_buffer* sb, gpr_slice slice) override;
+ void gpr_slice_buffer_pop(gpr_slice_buffer* sb) override;
+
void grpc_metadata_array_init(grpc_metadata_array* array) override;
void grpc_metadata_array_destroy(grpc_metadata_array* array) override;
gpr_timespec gpr_inf_future(gpr_clock_type type) override;
+ virtual const Status& ok() override;
+ virtual const Status& cancelled() override;
+
void assert_fail(const char* failed_assertion) override;
};
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index 6c13a4fa48..d92addbf54 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -167,6 +167,37 @@ namespace Grpc.Core.Tests
}
[Test]
+ public async Task ServerStreamingCall_EndOfStreamIsIdempotent()
+ {
+ helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
+ {
+ });
+
+ var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
+
+ Assert.IsFalse(await call.ResponseStream.MoveNext());
+ Assert.IsFalse(await call.ResponseStream.MoveNext());
+ }
+
+ [Test]
+ public async Task ServerStreamingCall_ErrorCanBeAwaitedTwice()
+ {
+ helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
+ {
+ context.Status = new Status(StatusCode.InvalidArgument, "");
+ });
+
+ var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
+
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
+ Assert.AreEqual(StatusCode.InvalidArgument, ex.Status.StatusCode);
+
+ // attempting MoveNext again should result in throwing the same exception.
+ var ex2 = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
+ Assert.AreEqual(StatusCode.InvalidArgument, ex2.Status.StatusCode);
+ }
+
+ [Test]
public async Task DuplexStreamingCall()
{
helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
@@ -209,6 +240,38 @@ namespace Grpc.Core.Tests
}
[Test]
+ public async Task ClientStreamingCall_ServerSideReadAfterCancelNotificationReturnsNull()
+ {
+ var handlerStartedBarrier = new TaskCompletionSource<object>();
+ var cancelNotificationReceivedBarrier = new TaskCompletionSource<object>();
+ var successTcs = new TaskCompletionSource<string>();
+
+ helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+ {
+ handlerStartedBarrier.SetResult(null);
+
+ // wait for cancellation to be delivered.
+ context.CancellationToken.Register(() => cancelNotificationReceivedBarrier.SetResult(null));
+ await cancelNotificationReceivedBarrier.Task;
+
+ var moveNextResult = await requestStream.MoveNext();
+ successTcs.SetResult(!moveNextResult ? "SUCCESS" : "FAIL");
+ return "";
+ });
+
+ var cts = new CancellationTokenSource();
+ var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
+
+ await handlerStartedBarrier.Task;
+ cts.Cancel();
+
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseAsync);
+ Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+
+ Assert.AreEqual("SUCCESS", await successTcs.Task);
+ }
+
+ [Test]
public async Task AsyncUnaryCall_EchoMetadata()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 0cd059c232..47131fc454 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -84,6 +84,8 @@
<Compile Include="SanityTest.cs" />
<Compile Include="HalfcloseTest.cs" />
<Compile Include="NUnitMain.cs" />
+ <Compile Include="Internal\FakeNativeCall.cs" />
+ <Compile Include="Internal\AsyncCallServerTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
new file mode 100644
index 0000000000..0e204761f6
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
@@ -0,0 +1,191 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+ /// <summary>
+ /// Uses fake native call to test interaction of <c>AsyncCallServer</c> wrapping code with C core in different situations.
+ /// </summary>
+ public class AsyncCallServerTest
+ {
+ Server server;
+ FakeNativeCall fakeCall;
+ AsyncCallServer<string, string> asyncCallServer;
+
+ [SetUp]
+ public void Init()
+ {
+ var environment = GrpcEnvironment.AddRef();
+
+ // Create a fake server just so we have an instance to refer to.
+ // The server won't actually be used at all.
+ server = new Server()
+ {
+ Ports = { { "localhost", 0, ServerCredentials.Insecure } }
+ };
+ server.Start();
+
+ fakeCall = new FakeNativeCall();
+ asyncCallServer = new AsyncCallServer<string, string>(
+ Marshallers.StringMarshaller.Serializer, Marshallers.StringMarshaller.Deserializer,
+ environment,
+ server);
+ asyncCallServer.InitializeForTesting(fakeCall);
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ server.ShutdownAsync().Wait();
+ GrpcEnvironment.Release();
+ }
+
+ [Test]
+ public void CancelNotificationAfterStartDisposes()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void CancelNotificationAfterStartDisposesAfterPendingReadFinishes()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
+
+ var moveNextTask = requestStream.MoveNext();
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+ fakeCall.ReceivedMessageHandler(true, null);
+ Assert.IsFalse(moveNextTask.Result);
+
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void ReadAfterCancelNotificationCanSucceed()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+
+ // Check that starting a read after cancel notification has been processed is legal.
+ var moveNextTask = requestStream.MoveNext();
+ Assert.IsFalse(moveNextTask.Result);
+
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void ReadCompletionFailureClosesRequestStream()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
+
+ // if a read completion's success==false, the request stream will silently finish
+ // and we rely on C core cancelling the call.
+ var moveNextTask = requestStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(false, null);
+ Assert.IsFalse(moveNextTask.Result);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void WriteAfterCancelNotificationFails()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
+ var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+
+ // TODO(jtattermusch): should we throw a different exception type instead?
+ Assert.Throws(typeof(InvalidOperationException), () => responseStream.WriteAsync("request1"));
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void WriteCompletionFailureThrows()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
+
+ var writeTask = responseStream.WriteAsync("request1");
+ fakeCall.SendCompletionHandler(false);
+ // TODO(jtattermusch): should we throw a different exception type instead?
+ Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await writeTask);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void WriteAndWriteStatusCanRunConcurrently()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
+
+ var writeTask = responseStream.WriteAsync("request1");
+ var writeStatusTask = asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata(), null);
+
+ fakeCall.SendCompletionHandler(true);
+ fakeCall.SendStatusFromServerHandler(true);
+
+ Assert.DoesNotThrowAsync(async () => await writeTask);
+ Assert.DoesNotThrowAsync(async () => await writeStatusTask);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ static void AssertFinished(AsyncCallServer<string, string> asyncCallServer, FakeNativeCall fakeCall, Task finishedTask)
+ {
+ Assert.IsTrue(fakeCall.IsDisposed);
+ Assert.IsTrue(finishedTask.IsCompleted);
+ Assert.DoesNotThrow(() => finishedTask.Wait());
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
index 60530d3250..abe9d4a2e6 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
@@ -32,6 +32,7 @@
#endregion
using System;
+using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
@@ -40,6 +41,9 @@ using NUnit.Framework;
namespace Grpc.Core.Internal.Tests
{
+ /// <summary>
+ /// Uses fake native call to test interaction of <c>AsyncCall</c> wrapping code with C core in different situations.
+ /// </summary>
public class AsyncCallTest
{
Channel channel;
@@ -64,159 +68,421 @@ namespace Grpc.Core.Internal.Tests
}
[Test]
- public void AsyncUnary_CompletionSuccess()
+ public void AsyncUnary_CanBeStartedOnlyOnce()
+ {
+ asyncCall.UnaryCallAsync("request1");
+ Assert.Throws(typeof(InvalidOperationException),
+ () => asyncCall.UnaryCallAsync("abc"));
+ }
+
+ [Test]
+ public void AsyncUnary_StreamingOperationsNotAllowed()
+ {
+ asyncCall.UnaryCallAsync("request1");
+ Assert.ThrowsAsync(typeof(InvalidOperationException),
+ async () => await asyncCall.ReadMessageAsync());
+ Assert.Throws(typeof(InvalidOperationException),
+ () => asyncCall.StartSendMessage("abc", new WriteFlags(), (x,y) => {}));
+ }
+
+ [Test]
+ public void AsyncUnary_Success()
+ {
+ var resultTask = asyncCall.UnaryCallAsync("request1");
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ }
+
+ [Test]
+ public void AsyncUnary_NonSuccessStatusCode()
+ {
+ var resultTask = asyncCall.UnaryCallAsync("request1");
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.InvalidArgument),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.InvalidArgument);
+ }
+
+ [Test]
+ public void AsyncUnary_NullResponsePayload()
+ {
+ var resultTask = asyncCall.UnaryCallAsync("request1");
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ null,
+ new Metadata());
+
+ // failure to deserialize will result in InvalidArgument status.
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Internal);
+ }
+
+ [Test]
+ public void ClientStreaming_StreamingReadNotAllowed()
+ {
+ asyncCall.ClientStreamingCallAsync();
+ Assert.ThrowsAsync(typeof(InvalidOperationException),
+ async () => await asyncCall.ReadMessageAsync());
+ }
+
+ [Test]
+ public void ClientStreaming_NoRequest_Success()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ }
+
+ [Test]
+ public void ClientStreaming_NoRequest_NonSuccessStatusCode()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.InvalidArgument),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.InvalidArgument);
+ }
+
+ [Test]
+ public void ClientStreaming_MoreRequests_Success()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ fakeCall.SendCompletionHandler(true);
+ writeTask.Wait();
+
+ var writeTask2 = requestStream.WriteAsync("request2");
+ fakeCall.SendCompletionHandler(true);
+ writeTask2.Wait();
+
+ var completeTask = requestStream.CompleteAsync();
+ fakeCall.SendCompletionHandler(true);
+ completeTask.Wait();
+
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ }
+
+ [Test]
+ public void ClientStreaming_WriteFailure()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ fakeCall.SendCompletionHandler(false);
+ Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await writeTask);
+
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.Internal),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Internal);
+ }
+
+ [Test]
+ public void ClientStreaming_WriteAfterReceivingStatusFails()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ Assert.Throws(typeof(InvalidOperationException), () => requestStream.WriteAsync("request1"));
+ }
+
+ [Test]
+ public void ClientStreaming_CompleteAfterReceivingStatusSucceeds()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ Assert.DoesNotThrowAsync(async () => await requestStream.CompleteAsync());
+ }
+
+ [Test]
+ public void ClientStreaming_WriteAfterCancellationRequestFails()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ asyncCall.Cancel();
+ Assert.IsTrue(fakeCall.IsCancelled);
+
+ Assert.Throws(typeof(OperationCanceledException), () => requestStream.WriteAsync("request1"));
+
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.Cancelled),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Cancelled);
+ }
+
+ [Test]
+ public void ServerStreaming_StreamingSendNotAllowed()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ Assert.Throws(typeof(InvalidOperationException),
+ () => asyncCall.StartSendMessage("abc", new WriteFlags(), (x,y) => {}));
+ }
+
+ [Test]
+ public void ServerStreaming_NoResponse_Success1()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+ var readTask = responseStream.MoveNext();
+
+ fakeCall.ReceivedResponseHeadersHandler(true, new Metadata());
+ Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count);
+
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+ }
+
+ [Test]
+ public void ServerStreaming_NoResponse_Success2()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+ var readTask = responseStream.MoveNext();
+
+ // try alternative order of completions
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+ fakeCall.ReceivedMessageHandler(true, null);
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+ }
+
+ [Test]
+ public void ServerStreaming_NoResponse_ReadFailure()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+ var readTask = responseStream.MoveNext();
+
+ fakeCall.ReceivedMessageHandler(false, null); // after a failed read, we rely on C core to deliver appropriate status code.
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Internal));
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Internal);
+ }
+
+ [Test]
+ public void ServerStreaming_MoreResponses_Success()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var readTask1 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+ Assert.IsTrue(readTask1.Result);
+ Assert.AreEqual("response1", responseStream.Current);
+
+ var readTask2 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+ Assert.IsTrue(readTask2.Result);
+ Assert.AreEqual("response1", responseStream.Current);
+
+ var readTask3 = responseStream.MoveNext();
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+ fakeCall.ReceivedMessageHandler(true, null);
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask3);
+ }
+
+ [Test]
+ public void DuplexStreaming_NoRequestNoResponse_Success()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var writeTask1 = requestStream.CompleteAsync();
+ fakeCall.SendCompletionHandler(true);
+ Assert.DoesNotThrowAsync(async () => await writeTask1);
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+ }
+
+ [Test]
+ public void DuplexStreaming_WriteAfterReceivingStatusFails()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+
+ Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await requestStream.WriteAsync("request1"));
+ }
+
+ [Test]
+ public void DuplexStreaming_CompleteAfterReceivingStatusFails()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+
+ Assert.DoesNotThrowAsync(async () => await requestStream.CompleteAsync());
+ }
+
+ [Test]
+ public void DuplexStreaming_WriteAfterCancellationRequestFails()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ asyncCall.Cancel();
+ Assert.IsTrue(fakeCall.IsCancelled);
+ Assert.Throws(typeof(OperationCanceledException), () => requestStream.WriteAsync("request1"));
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Cancelled);
+ }
+
+ [Test]
+ public void DuplexStreaming_ReadAfterCancellationRequestCanSucceed()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ asyncCall.Cancel();
+ Assert.IsTrue(fakeCall.IsCancelled);
+
+ var readTask1 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+ Assert.IsTrue(readTask1.Result);
+ Assert.AreEqual("response1", responseStream.Current);
+
+ var readTask2 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
+ }
+
+ [Test]
+ public void DuplexStreaming_ReadStartedBeforeCancellationRequestCanSucceed()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var readTask1 = responseStream.MoveNext(); // initiate the read before cancel request
+ asyncCall.Cancel();
+ Assert.IsTrue(fakeCall.IsCancelled);
+
+ fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+ Assert.IsTrue(readTask1.Result);
+ Assert.AreEqual("response1", responseStream.Current);
+
+ var readTask2 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
+ }
+
+ ClientSideStatus CreateClientSideStatus(StatusCode statusCode)
+ {
+ return new ClientSideStatus(new Status(statusCode, ""), new Metadata());
+ }
+
+ byte[] CreateResponsePayload()
+ {
+ return Marshallers.StringMarshaller.Serializer("response1");
+ }
+
+ static void AssertUnaryResponseSuccess(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<string> resultTask)
{
- var resultTask = asyncCall.UnaryCallAsync("abc");
- fakeCall.UnaryResponseClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()), new byte[] { 1, 2, 3 }, new Metadata());
Assert.IsTrue(resultTask.IsCompleted);
Assert.IsTrue(fakeCall.IsDisposed);
+
Assert.AreEqual(Status.DefaultSuccess, asyncCall.GetStatus());
+ Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count);
+ Assert.AreEqual(0, asyncCall.GetTrailers().Count);
+ Assert.AreEqual("response1", resultTask.Result);
}
- [Test]
- public void AsyncUnary_CompletionFailure()
+ static void AssertStreamingResponseSuccess(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<bool> moveNextTask)
{
- var resultTask = asyncCall.UnaryCallAsync("abc");
- fakeCall.UnaryResponseClientHandler(false, new ClientSideStatus(new Status(StatusCode.Internal, ""), null), new byte[] { 1, 2, 3 }, new Metadata());
+ Assert.IsTrue(moveNextTask.IsCompleted);
+ Assert.IsTrue(fakeCall.IsDisposed);
+ Assert.IsFalse(moveNextTask.Result);
+ Assert.AreEqual(Status.DefaultSuccess, asyncCall.GetStatus());
+ Assert.AreEqual(0, asyncCall.GetTrailers().Count);
+ }
+
+ static void AssertUnaryResponseError(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<string> resultTask, StatusCode expectedStatusCode)
+ {
Assert.IsTrue(resultTask.IsCompleted);
Assert.IsTrue(fakeCall.IsDisposed);
- Assert.AreEqual(StatusCode.Internal, asyncCall.GetStatus().StatusCode);
- Assert.IsNull(asyncCall.GetTrailers());
+ Assert.AreEqual(expectedStatusCode, asyncCall.GetStatus().StatusCode);
var ex = Assert.ThrowsAsync<RpcException>(async () => await resultTask);
- Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
- }
-
- internal class FakeNativeCall : INativeCall
- {
- public UnaryResponseClientHandler UnaryResponseClientHandler
- {
- get;
- set;
- }
-
- public ReceivedStatusOnClientHandler ReceivedStatusOnClientHandler
- {
- get;
- set;
- }
-
- public ReceivedMessageHandler ReceivedMessageHandler
- {
- get;
- set;
- }
-
- public ReceivedResponseHeadersHandler ReceivedResponseHeadersHandler
- {
- get;
- set;
- }
-
- public SendCompletionHandler SendCompletionHandler
- {
- get;
- set;
- }
-
- public ReceivedCloseOnServerHandler ReceivedCloseOnServerHandler
- {
- get;
- set;
- }
-
- public bool IsCancelled
- {
- get;
- set;
- }
-
- public bool IsDisposed
- {
- get;
- set;
- }
-
- public void Cancel()
- {
- IsCancelled = true;
- }
-
- public void CancelWithStatus(Status status)
- {
- IsCancelled = true;
- }
-
- public string GetPeer()
- {
- return "PEER";
- }
-
- public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
- {
- UnaryResponseClientHandler = callback;
- }
-
- public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
- {
- throw new NotImplementedException();
- }
-
- public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray)
- {
- UnaryResponseClientHandler = callback;
- }
-
- public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
- {
- ReceivedStatusOnClientHandler = callback;
- }
-
- public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray)
- {
- ReceivedStatusOnClientHandler = callback;
- }
-
- public void StartReceiveMessage(ReceivedMessageHandler callback)
- {
- ReceivedMessageHandler = callback;
- }
-
- public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback)
- {
- ReceivedResponseHeadersHandler = callback;
- }
-
- public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray)
- {
- SendCompletionHandler = callback;
- }
-
- public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
- {
- SendCompletionHandler = callback;
- }
-
- public void StartSendCloseFromClient(SendCompletionHandler callback)
- {
- SendCompletionHandler = callback;
- }
-
- public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata)
- {
- SendCompletionHandler = callback;
- }
-
- public void StartServerSide(ReceivedCloseOnServerHandler callback)
- {
- ReceivedCloseOnServerHandler = callback;
- }
-
- public void Dispose()
- {
- IsDisposed = true;
- }
+ Assert.AreEqual(expectedStatusCode, ex.Status.StatusCode);
+ Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count);
+ Assert.AreEqual(0, asyncCall.GetTrailers().Count);
+ }
+
+ static void AssertStreamingResponseError(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<bool> moveNextTask, StatusCode expectedStatusCode)
+ {
+ Assert.IsTrue(moveNextTask.IsCompleted);
+ Assert.IsTrue(fakeCall.IsDisposed);
+
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await moveNextTask);
+ Assert.AreEqual(expectedStatusCode, ex.Status.StatusCode);
+ Assert.AreEqual(expectedStatusCode, asyncCall.GetStatus().StatusCode);
+ Assert.AreEqual(0, asyncCall.GetTrailers().Count);
}
}
}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
new file mode 100644
index 0000000000..909112a47c
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
@@ -0,0 +1,184 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+ /// <summary>
+ /// For testing purposes.
+ /// </summary>
+ internal class FakeNativeCall : INativeCall
+ {
+ public UnaryResponseClientHandler UnaryResponseClientHandler
+ {
+ get;
+ set;
+ }
+
+ public ReceivedStatusOnClientHandler ReceivedStatusOnClientHandler
+ {
+ get;
+ set;
+ }
+
+ public ReceivedMessageHandler ReceivedMessageHandler
+ {
+ get;
+ set;
+ }
+
+ public ReceivedResponseHeadersHandler ReceivedResponseHeadersHandler
+ {
+ get;
+ set;
+ }
+
+ public SendCompletionHandler SendCompletionHandler
+ {
+ get;
+ set;
+ }
+
+ public SendCompletionHandler SendStatusFromServerHandler
+ {
+ get;
+ set;
+ }
+
+ public ReceivedCloseOnServerHandler ReceivedCloseOnServerHandler
+ {
+ get;
+ set;
+ }
+
+ public bool IsCancelled
+ {
+ get;
+ set;
+ }
+
+ public bool IsDisposed
+ {
+ get;
+ set;
+ }
+
+ public void Cancel()
+ {
+ IsCancelled = true;
+ }
+
+ public void CancelWithStatus(Status status)
+ {
+ IsCancelled = true;
+ }
+
+ public string GetPeer()
+ {
+ return "PEER";
+ }
+
+ public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ {
+ UnaryResponseClientHandler = callback;
+ }
+
+ public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray)
+ {
+ UnaryResponseClientHandler = callback;
+ }
+
+ public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ {
+ ReceivedStatusOnClientHandler = callback;
+ }
+
+ public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray)
+ {
+ ReceivedStatusOnClientHandler = callback;
+ }
+
+ public void StartReceiveMessage(ReceivedMessageHandler callback)
+ {
+ ReceivedMessageHandler = callback;
+ }
+
+ public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback)
+ {
+ ReceivedResponseHeadersHandler = callback;
+ }
+
+ public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray)
+ {
+ SendCompletionHandler = callback;
+ }
+
+ public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
+ {
+ SendCompletionHandler = callback;
+ }
+
+ public void StartSendCloseFromClient(SendCompletionHandler callback)
+ {
+ SendCompletionHandler = callback;
+ }
+
+ public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+ byte[] optionalPayload, WriteFlags writeFlags)
+ {
+ SendStatusFromServerHandler = callback;
+ }
+
+ public void StartServerSide(ReceivedCloseOnServerHandler callback)
+ {
+ ReceivedCloseOnServerHandler = callback;
+ }
+
+ public void Dispose()
+ {
+ IsDisposed = true;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 016e1b8587..f522174bd0 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -241,11 +241,10 @@ namespace Grpc.Core.Internal
/// <summary>
/// Receives a streaming response. Only one pending read action is allowed at any given time.
- /// completionDelegate is called when the operation finishes.
/// </summary>
- public void StartReadMessage(AsyncCompletionDelegate<TResponse> completionDelegate)
+ public Task<TResponse> ReadMessageAsync()
{
- StartReadMessageInternal(completionDelegate);
+ return ReadMessageInternalAsync();
}
/// <summary>
@@ -409,10 +408,13 @@ namespace Grpc.Core.Internal
/// </summary>
private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders)
{
+ // NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT,
+ // success will be always set to true.
+
using (Profilers.ForCurrentThread().NewScope("AsyncCall.HandleUnaryResponse"))
{
TResponse msg = default(TResponse);
- var deserializeException = success ? TryDeserialize(receivedMessage, out msg) : null;
+ var deserializeException = TryDeserialize(receivedMessage, out msg);
lock (myLock)
{
@@ -425,14 +427,13 @@ namespace Grpc.Core.Internal
finishedStatus = receivedStatus;
ReleaseResourcesIfPossible();
-
}
responseHeadersTcs.SetResult(responseHeaders);
var status = receivedStatus.Status;
- if (!success || status.StatusCode != StatusCode.OK)
+ if (status.StatusCode != StatusCode.OK)
{
unaryResponseTcs.SetException(new RpcException(status));
return;
@@ -447,6 +448,9 @@ namespace Grpc.Core.Internal
/// </summary>
private void HandleFinished(bool success, ClientSideStatus receivedStatus)
{
+ // NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT,
+ // success will be always set to true.
+
lock (myLock)
{
finished = true;
@@ -457,7 +461,7 @@ namespace Grpc.Core.Internal
var status = receivedStatus.Status;
- if (!success || status.StatusCode != StatusCode.OK)
+ if (status.StatusCode != StatusCode.OK)
{
streamingCallFinishedTcs.SetException(new RpcException(status));
return;
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index ccd047f469..42234dcac2 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -68,7 +68,8 @@ namespace Grpc.Core.Internal
protected bool cancelRequested;
protected AsyncCompletionDelegate<object> sendCompletionDelegate; // Completion of a pending send or sendclose if not null.
- protected AsyncCompletionDelegate<TRead> readCompletionDelegate; // Completion of a pending send or sendclose if not null.
+ protected TaskCompletionSource<TRead> streamingReadTcs; // Completion of a pending streaming read if not null.
+ protected TaskCompletionSource<object> sendStatusFromServerTcs;
protected bool readingDone; // True if last read (i.e. read with null payload) was already received.
protected bool halfcloseRequested; // True if send close have been initiated.
@@ -150,15 +151,25 @@ namespace Grpc.Core.Internal
/// Initiates reading a message. Only one read operation can be active at a time.
/// completionDelegate is invoked upon completion.
/// </summary>
- protected void StartReadMessageInternal(AsyncCompletionDelegate<TRead> completionDelegate)
+ protected Task<TRead> ReadMessageInternalAsync()
{
lock (myLock)
{
- GrpcPreconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null");
- CheckReadingAllowed();
+ GrpcPreconditions.CheckState(started);
+ if (readingDone)
+ {
+ // the last read that returns null or throws an exception is idempotent
+ // and maintain its state.
+ GrpcPreconditions.CheckState(streamingReadTcs != null, "Call does not support streaming reads.");
+ return streamingReadTcs.Task;
+ }
+
+ GrpcPreconditions.CheckState(streamingReadTcs == null, "Only one read can be pending at a time");
+ GrpcPreconditions.CheckState(!disposed);
call.StartReceiveMessage(HandleReadFinished);
- readCompletionDelegate = completionDelegate;
+ streamingReadTcs = new TaskCompletionSource<TRead>();
+ return streamingReadTcs.Task;
}
}
@@ -213,15 +224,6 @@ namespace Grpc.Core.Internal
GrpcPreconditions.CheckState(sendCompletionDelegate == null, "Only one write can be pending at a time");
}
- protected virtual void CheckReadingAllowed()
- {
- GrpcPreconditions.CheckState(started);
- GrpcPreconditions.CheckState(!disposed);
-
- GrpcPreconditions.CheckState(!readingDone, "Stream has already been closed.");
- GrpcPreconditions.CheckState(readCompletionDelegate == null, "Only one read can be pending at a time");
- }
-
protected void CheckNotCancelled()
{
if (cancelRequested)
@@ -322,22 +324,18 @@ namespace Grpc.Core.Internal
/// </summary>
protected void HandleSendStatusFromServerFinished(bool success)
{
- AsyncCompletionDelegate<object> origCompletionDelegate = null;
lock (myLock)
{
- origCompletionDelegate = sendCompletionDelegate;
- sendCompletionDelegate = null;
-
ReleaseResourcesIfPossible();
}
if (!success)
{
- FireCompletion(origCompletionDelegate, null, new InvalidOperationException("Error sending status from server."));
+ sendStatusFromServerTcs.SetException(new InvalidOperationException("Error sending status from server."));
}
else
{
- FireCompletion(origCompletionDelegate, null, null);
+ sendStatusFromServerTcs.SetResult(null);
}
}
@@ -346,15 +344,17 @@ namespace Grpc.Core.Internal
/// </summary>
protected void HandleReadFinished(bool success, byte[] receivedMessage)
{
+ // if success == false, received message will be null. It that case we will
+ // treat this completion as the last read an rely on C core to handle the failed
+ // read (e.g. deliver approriate statusCode on the clientside).
+
TRead msg = default(TRead);
var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null;
- AsyncCompletionDelegate<TRead> origCompletionDelegate = null;
+ TaskCompletionSource<TRead> origTcs = null;
lock (myLock)
{
- origCompletionDelegate = readCompletionDelegate;
- readCompletionDelegate = null;
-
+ origTcs = streamingReadTcs;
if (receivedMessage == null)
{
// This was the last read.
@@ -364,20 +364,25 @@ namespace Grpc.Core.Internal
if (deserializeException != null && IsClient)
{
readingDone = true;
+
+ // TODO(jtattermusch): it might be too late to set the status
CancelWithStatus(DeserializeResponseFailureStatus);
}
+ if (!readingDone)
+ {
+ streamingReadTcs = null;
+ }
+
ReleaseResourcesIfPossible();
}
- // TODO: handle the case when success==false
-
if (deserializeException != null && !IsClient)
{
- FireCompletion(origCompletionDelegate, default(TRead), new IOException("Failed to deserialize request message.", deserializeException));
+ origTcs.SetException(new IOException("Failed to deserialize request message.", deserializeException));
return;
}
- FireCompletion(origCompletionDelegate, msg, null);
+ origTcs.SetResult(msg);
}
}
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index bea2b3660c..b1566b44a7 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -65,6 +65,15 @@ namespace Grpc.Core.Internal
}
/// <summary>
+ /// Only for testing purposes.
+ /// </summary>
+ public void InitializeForTesting(INativeCall call)
+ {
+ server.AddCallReference(this);
+ InitializeInternal(call);
+ }
+
+ /// <summary>
/// Starts a server side call.
/// </summary>
public Task ServerSideCallAsync()
@@ -91,11 +100,10 @@ namespace Grpc.Core.Internal
/// <summary>
/// Receives a streaming request. Only one pending read action is allowed at any given time.
- /// completionDelegate is called when the operation finishes.
/// </summary>
- public void StartReadMessage(AsyncCompletionDelegate<TRequest> completionDelegate)
+ public Task<TRequest> ReadMessageAsync()
{
- StartReadMessageInternal(completionDelegate);
+ return ReadMessageInternalAsync();
}
/// <summary>
@@ -128,24 +136,33 @@ namespace Grpc.Core.Internal
}
/// <summary>
- /// Sends call result status, also indicating server is done with streaming responses.
- /// Only one pending send action is allowed at any given time.
- /// completionDelegate is called when the operation finishes.
+ /// Sends call result status, indicating we are done with writes.
+ /// Sending a status different from StatusCode.OK will also implicitly cancel the call.
/// </summary>
- public void StartSendStatusFromServer(Status status, Metadata trailers, AsyncCompletionDelegate<object> completionDelegate)
+ public Task SendStatusFromServerAsync(Status status, Metadata trailers, Tuple<TResponse, WriteFlags> optionalWrite)
{
+ byte[] payload = optionalWrite != null ? UnsafeSerialize(optionalWrite.Item1) : null;
+ var writeFlags = optionalWrite != null ? optionalWrite.Item2 : default(WriteFlags);
+
lock (myLock)
{
- GrpcPreconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null");
- CheckSendingAllowed(allowFinished: false);
+ GrpcPreconditions.CheckState(started);
+ GrpcPreconditions.CheckState(!disposed);
+ GrpcPreconditions.CheckState(!halfcloseRequested, "Can only send status from server once.");
using (var metadataArray = MetadataArraySafeHandle.Create(trailers))
{
- call.StartSendStatusFromServer(HandleSendStatusFromServerFinished, status, metadataArray, !initialMetadataSent);
+ call.StartSendStatusFromServer(HandleSendStatusFromServerFinished, status, metadataArray, !initialMetadataSent,
+ payload, writeFlags);
}
halfcloseRequested = true;
- readingDone = true;
- sendCompletionDelegate = completionDelegate;
+ initialMetadataSent = true;
+ sendStatusFromServerTcs = new TaskCompletionSource<object>();
+ if (optionalWrite != null)
+ {
+ streamingWritesCounter++;
+ }
+ return sendStatusFromServerTcs.Task;
}
}
@@ -174,12 +191,6 @@ namespace Grpc.Core.Internal
get { return false; }
}
- protected override void CheckReadingAllowed()
- {
- base.CheckReadingAllowed();
- GrpcPreconditions.CheckArgument(!cancelRequested);
- }
-
protected override void OnAfterReleaseResources()
{
server.RemoveCallReference(this);
@@ -190,12 +201,21 @@ namespace Grpc.Core.Internal
/// </summary>
private void HandleFinishedServerside(bool success, bool cancelled)
{
+ // NOTE: because this event is a result of batch containing GRPC_OP_RECV_CLOSE_ON_SERVER,
+ // success will be always set to true.
lock (myLock)
{
finished = true;
+ if (streamingReadTcs == null)
+ {
+ // if there's no pending read, readingDone=true will dispose now.
+ // if there is a pending read, we will dispose once that read finishes.
+ readingDone = true;
+ streamingReadTcs = new TaskCompletionSource<TRequest>();
+ streamingReadTcs.SetResult(default(TRequest));
+ }
ReleaseResourcesIfPossible();
}
- // TODO(jtattermusch): handle error
if (cancelled)
{
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 500653ba5d..244b97d4a4 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -135,13 +135,16 @@ namespace Grpc.Core.Internal
}
}
- public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata)
+ public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+ byte[] optionalPayload, WriteFlags writeFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
+ var optionalPayloadLength = optionalPayload != null ? new UIntPtr((ulong)optionalPayload.Length) : UIntPtr.Zero;
completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
- Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, sendEmptyInitialMetadata).CheckOk();
+ Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, sendEmptyInitialMetadata,
+ optionalPayload, optionalPayloadLength, writeFlags).CheckOk();
}
}
diff --git a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
index d6e34a0f04..ad9423ff58 100644
--- a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
@@ -68,9 +68,7 @@ namespace Grpc.Core.Internal
{
throw new InvalidOperationException("Cancellation of individual reads is not supported.");
}
- var taskSource = new AsyncCompletionTaskSource<TResponse>();
- call.StartReadMessage(taskSource.CompletionDelegate);
- var result = await taskSource.Task.ConfigureAwait(false);
+ var result = await call.ReadMessageAsync().ConfigureAwait(false);
this.current = result;
if (result == null)
diff --git a/src/csharp/Grpc.Core/Internal/INativeCall.cs b/src/csharp/Grpc.Core/Internal/INativeCall.cs
index cbef599139..cd3719cb50 100644
--- a/src/csharp/Grpc.Core/Internal/INativeCall.cs
+++ b/src/csharp/Grpc.Core/Internal/INativeCall.cs
@@ -78,7 +78,7 @@ namespace Grpc.Core.Internal
void StartSendCloseFromClient(SendCompletionHandler callback);
- void StartSendStatusFromServer(SendCompletionHandler callback, Grpc.Core.Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata);
+ void StartSendStatusFromServer(SendCompletionHandler callback, Grpc.Core.Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, Grpc.Core.WriteFlags writeFlags);
void StartServerSide(ReceivedCloseOnServerHandler callback);
}
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
index 9ee0ba3bc0..c277c73ef0 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
@@ -421,20 +421,21 @@ namespace Grpc.Core.Internal
public delegate GRPCCallError grpcsharp_call_cancel_delegate(CallSafeHandle call);
public delegate GRPCCallError grpcsharp_call_cancel_with_status_delegate(CallSafeHandle call, StatusCode status, string description);
public delegate GRPCCallError grpcsharp_call_start_unary_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
public delegate GRPCCallError grpcsharp_call_start_client_streaming_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
public delegate GRPCCallError grpcsharp_call_start_server_streaming_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len,
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen,
MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
public delegate GRPCCallError grpcsharp_call_start_duplex_streaming_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
public delegate GRPCCallError grpcsharp_call_send_message_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
public delegate GRPCCallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx);
public delegate GRPCCallError grpcsharp_call_send_status_from_server_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata);
+ BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+ byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
public delegate GRPCCallError grpcsharp_call_recv_message_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx);
public delegate GRPCCallError grpcsharp_call_recv_initial_metadata_delegate(CallSafeHandle call,
@@ -593,7 +594,7 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
public static extern GRPCCallError grpcsharp_call_start_unary(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
[DllImport("grpc_csharp_ext.dll")]
public static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call,
@@ -601,7 +602,7 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
public static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len,
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen,
MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
[DllImport("grpc_csharp_ext.dll")]
@@ -610,7 +611,7 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
public static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
[DllImport("grpc_csharp_ext.dll")]
public static extern GRPCCallError grpcsharp_call_send_close_from_client(CallSafeHandle call,
@@ -618,7 +619,8 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
public static extern GRPCCallError grpcsharp_call_send_status_from_server(CallSafeHandle call,
- BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata);
+ BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+ byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
[DllImport("grpc_csharp_ext.dll")]
public static extern GRPCCallError grpcsharp_call_recv_message(CallSafeHandle call,
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index 1f83e51548..85b7a4b01e 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -75,29 +75,32 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
+ Tuple<TResponse,WriteFlags> responseTuple = null;
var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken);
try
{
GrpcPreconditions.CheckArgument(await requestStream.MoveNext().ConfigureAwait(false));
var request = requestStream.Current;
- // TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated.
- GrpcPreconditions.CheckArgument(!await requestStream.MoveNext().ConfigureAwait(false));
- var result = await handler(request, context).ConfigureAwait(false);
+ var response = await handler(request, context).ConfigureAwait(false);
status = context.Status;
- await responseStream.WriteAsync(result).ConfigureAwait(false);
+ responseTuple = Tuple.Create(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured in handler.");
+ if (!(e is RpcException))
+ {
+ Logger.Warning(e, "Exception occured in handler.");
+ }
status = HandlerUtils.StatusFromException(e);
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseTuple).ConfigureAwait(false);
}
- catch (OperationCanceledException)
+ catch (Exception)
{
- // Call has been already cancelled.
+ asyncCall.Cancel();
+ throw;
}
await finishedTask.ConfigureAwait(false);
}
@@ -136,24 +139,26 @@ namespace Grpc.Core.Internal
{
GrpcPreconditions.CheckArgument(await requestStream.MoveNext().ConfigureAwait(false));
var request = requestStream.Current;
- // TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated.
- GrpcPreconditions.CheckArgument(!await requestStream.MoveNext().ConfigureAwait(false));
await handler(request, responseStream, context).ConfigureAwait(false);
status = context.Status;
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured in handler.");
+ if (!(e is RpcException))
+ {
+ Logger.Warning(e, "Exception occured in handler.");
+ }
status = HandlerUtils.StatusFromException(e);
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, null).ConfigureAwait(false);
}
- catch (OperationCanceledException)
+ catch (Exception)
{
- // Call has been already cancelled.
+ asyncCall.Cancel();
+ throw;
}
await finishedTask.ConfigureAwait(false);
}
@@ -187,33 +192,31 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
+ Tuple<TResponse,WriteFlags> responseTuple = null;
var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken);
try
{
- var result = await handler(requestStream, context).ConfigureAwait(false);
+ var response = await handler(requestStream, context).ConfigureAwait(false);
status = context.Status;
- try
- {
- await responseStream.WriteAsync(result).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- status = Status.DefaultCancelled;
- }
+ responseTuple = Tuple.Create(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured in handler.");
+ if (!(e is RpcException))
+ {
+ Logger.Warning(e, "Exception occured in handler.");
+ }
status = HandlerUtils.StatusFromException(e);
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseTuple).ConfigureAwait(false);
}
- catch (OperationCanceledException)
+ catch (Exception)
{
- // Call has been already cancelled.
+ asyncCall.Cancel();
+ throw;
}
await finishedTask.ConfigureAwait(false);
}
@@ -255,16 +258,20 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured in handler.");
+ if (!(e is RpcException))
+ {
+ Logger.Warning(e, "Exception occured in handler.");
+ }
status = HandlerUtils.StatusFromException(e);
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, null).ConfigureAwait(false);
}
- catch (OperationCanceledException)
+ catch (Exception)
{
- // Call has been already cancelled.
+ asyncCall.Cancel();
+ throw;
}
await finishedTask.ConfigureAwait(false);
}
@@ -282,9 +289,7 @@ namespace Grpc.Core.Internal
asyncCall.Initialize(newRpc.Call);
var finishedTask = asyncCall.ServerSideCallAsync();
- var responseStream = new ServerResponseStream<byte[], byte[]>(asyncCall);
-
- await responseStream.WriteStatusAsync(new Status(StatusCode.Unimplemented, ""), Metadata.Empty).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(new Status(StatusCode.Unimplemented, ""), Metadata.Empty, null).ConfigureAwait(false);
await finishedTask.ConfigureAwait(false);
}
}
@@ -300,10 +305,14 @@ namespace Grpc.Core.Internal
return rpcException.Status;
}
- // TODO(jtattermusch): what is the right status code here?
return new Status(StatusCode.Unknown, "Exception was thrown by handler.");
}
+ public static WriteFlags GetWriteFlags(WriteOptions writeOptions)
+ {
+ return writeOptions != null ? writeOptions.Flags : default(WriteFlags);
+ }
+
public static ServerCallContext NewContext<TRequest, TResponse>(ServerRpcNew newRpc, string peer, ServerResponseStream<TRequest, TResponse> serverResponseStream, CancellationToken cancellationToken)
where TRequest : class
where TResponse : class
diff --git a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
index e7be82c318..d76030d1ad 100644
--- a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
@@ -68,9 +68,7 @@ namespace Grpc.Core.Internal
{
throw new InvalidOperationException("Cancellation of individual reads is not supported.");
}
- var taskSource = new AsyncCompletionTaskSource<TRequest>();
- call.StartReadMessage(taskSource.CompletionDelegate);
- var result = await taskSource.Task.ConfigureAwait(false);
+ var result = await call.ReadMessageAsync().ConfigureAwait(false);
this.current = result;
return result != null;
}
diff --git a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs
index 03e39efc02..ecfee0bfdd 100644
--- a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs
@@ -57,13 +57,6 @@ namespace Grpc.Core.Internal
return taskSource.Task;
}
- public Task WriteStatusAsync(Status status, Metadata trailers)
- {
- var taskSource = new AsyncCompletionTaskSource<object>();
- call.StartSendStatusFromServer(status, trailers, taskSource.CompletionDelegate);
- return taskSource.Task;
- }
-
public Task WriteResponseHeadersAsync(Metadata responseHeaders)
{
var taskSource = new AsyncCompletionTaskSource<object>();
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index f7a9cb9c1c..e1609341d9 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -48,11 +48,11 @@ namespace Grpc.Core
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
- public const string CurrentAssemblyFileVersion = "0.14.0.0";
+ public const string CurrentAssemblyFileVersion = "0.15.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "0.14.0-dev";
+ public const string CurrentVersion = "0.15.0-dev";
}
}
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 9a60be26b6..7520b0f81a 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -1,7 +1,7 @@
@rem Builds gRPC NuGet packages
@rem Current package versions
-set VERSION=0.14.0-dev
+set VERSION=0.15.0-dev
set PROTOBUF_VERSION=3.0.0-beta2
@rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index aeef8a79e9..5b8ff9b819 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -715,10 +715,11 @@ grpcsharp_call_send_close_from_client(grpc_call *call,
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
grpc_call *call, grpcsharp_batch_context *ctx, grpc_status_code status_code,
const char *status_details, grpc_metadata_array *trailing_metadata,
- int32_t send_empty_initial_metadata) {
+ int32_t send_empty_initial_metadata, const char* optional_send_buffer,
+ size_t optional_send_buffer_len, uint32_t write_flags) {
/* TODO: don't use magic number */
- grpc_op ops[2];
- size_t nops = send_empty_initial_metadata ? 2 : 1;
+ grpc_op ops[3];
+ size_t nops = 1;
ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
ops[0].data.send_status_from_server.status = status_code;
ops[0].data.send_status_from_server.status_details =
@@ -731,12 +732,23 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
ctx->send_status_from_server.trailing_metadata.metadata;
ops[0].flags = 0;
ops[0].reserved = NULL;
- ops[1].op = GRPC_OP_SEND_INITIAL_METADATA;
- ops[1].data.send_initial_metadata.count = 0;
- ops[1].data.send_initial_metadata.metadata = NULL;
- ops[1].flags = 0;
- ops[1].reserved = NULL;
-
+ if (optional_send_buffer) {
+ ops[nops].op = GRPC_OP_SEND_MESSAGE;
+ ctx->send_message = string_to_byte_buffer(optional_send_buffer,
+ optional_send_buffer_len);
+ ops[nops].data.send_message = ctx->send_message;
+ ops[nops].flags = write_flags;
+ ops[nops].reserved = NULL;
+ nops ++;
+ }
+ if (send_empty_initial_metadata) {
+ ops[nops].op = GRPC_OP_SEND_INITIAL_METADATA;
+ ops[nops].data.send_initial_metadata.count = 0;
+ ops[nops].data.send_initial_metadata.metadata = NULL;
+ ops[nops].flags = 0;
+ ops[nops].reserved = NULL;
+ nops++;
+ }
return grpc_call_start_batch(call, ops, nops, ctx, NULL);
}
diff --git a/src/csharp/tests.json b/src/csharp/tests.json
index f733352a31..f6af3408d5 100644
--- a/src/csharp/tests.json
+++ b/src/csharp/tests.json
@@ -1,5 +1,6 @@
{
"Grpc.Core.Tests": [
+ "Grpc.Core.Internal.Tests.AsyncCallServerTest",
"Grpc.Core.Internal.Tests.AsyncCallTest",
"Grpc.Core.Internal.Tests.ChannelArgsSafeHandleTest",
"Grpc.Core.Internal.Tests.CompletionQueueEventTest",
diff --git a/src/node/tools/bin/protoc.js b/src/node/tools/bin/protoc.js
index 0c6d7ce017..4d50c94b0f 100755
--- a/src/node/tools/bin/protoc.js
+++ b/src/node/tools/bin/protoc.js
@@ -43,7 +43,9 @@
var path = require('path');
var execFile = require('child_process').execFile;
-var protoc = path.resolve(__dirname, 'protoc');
+var exe_ext = process.platform === 'win32' ? '.exe' : '';
+
+var protoc = path.resolve(__dirname, 'protoc' + exe_ext);
execFile(protoc, process.argv.slice(2), function(error, stdout, stderr) {
if (error) {
diff --git a/src/node/tools/bin/protoc_plugin.js b/src/node/tools/bin/protoc_plugin.js
index 0e0bb9406e..281ec0d85e 100755
--- a/src/node/tools/bin/protoc_plugin.js
+++ b/src/node/tools/bin/protoc_plugin.js
@@ -43,9 +43,11 @@
var path = require('path');
var execFile = require('child_process').execFile;
-var protoc = path.resolve(__dirname, 'grpc_node_plugin');
+var exe_ext = process.platform === 'win32' ? '.exe' : '';
-execFile(protoc, process.argv.slice(2), function(error, stdout, stderr) {
+var plugin = path.resolve(__dirname, 'grpc_node_plugin' + exe_ext);
+
+execFile(plugin, process.argv.slice(2), function(error, stdout, stderr) {
if (error) {
throw error;
}
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
index d98ed0b1fc..efdfa81124 100644
--- a/src/node/tools/package.json
+++ b/src/node/tools/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc-tools",
- "version": "0.14.0-dev",
+ "version": "0.15.0-dev",
"author": "Google Inc.",
"description": "Tools for developing with gRPC on Node.js",
"homepage": "http://www.grpc.io/",
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index 1847d6016f..0eb10656dd 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -136,6 +136,10 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
#pragma mark Finish
- (void)finishWithError:(NSError *)errorOrNil {
+ @synchronized(self) {
+ _state = GRXWriterStateFinished;
+ }
+
// If the call isn't retained anywhere else, it can be deallocated now.
_retainSelf = nil;
@@ -342,6 +346,10 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
#pragma mark GRXWriter implementation
- (void)startWithWriteable:(id<GRXWriteable>)writeable {
+ @synchronized(self) {
+ _state = GRXWriterStateStarted;
+ }
+
// Create a retain cycle so that this instance lives until the RPC finishes (or is cancelled).
// This makes RPCs in which the call isn't externally retained possible (as long as it is started
// before being autoreleased).
@@ -375,30 +383,32 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
}
- (void)setState:(GRXWriterState)newState {
- // Manual transitions are only allowed from the started or paused states.
- if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) {
- return;
- }
-
- switch (newState) {
- case GRXWriterStateFinished:
- _state = newState;
- // Per GRXWriter's contract, setting the state to Finished manually
- // means one doesn't wish the writeable to be messaged anymore.
- [_responseWriteable cancelSilently];
- _responseWriteable = nil;
- return;
- case GRXWriterStatePaused:
- _state = newState;
+ @synchronized(self) {
+ // Manual transitions are only allowed from the started or paused states.
+ if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) {
return;
- case GRXWriterStateStarted:
- if (_state == GRXWriterStatePaused) {
+ }
+
+ switch (newState) {
+ case GRXWriterStateFinished:
_state = newState;
- [self startNextRead];
- }
- return;
- case GRXWriterStateNotStarted:
- return;
+ // Per GRXWriter's contract, setting the state to Finished manually
+ // means one doesn't wish the writeable to be messaged anymore.
+ [_responseWriteable cancelSilently];
+ _responseWriteable = nil;
+ return;
+ case GRXWriterStatePaused:
+ _state = newState;
+ return;
+ case GRXWriterStateStarted:
+ if (_state == GRXWriterStatePaused) {
+ _state = newState;
+ [self startNextRead];
+ }
+ return;
+ case GRXWriterStateNotStarted:
+ return;
+ }
}
}
diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m
index 26877b1ae8..4f096b9efa 100644
--- a/src/objective-c/tests/InteropTests.m
+++ b/src/objective-c/tests/InteropTests.m
@@ -272,8 +272,14 @@
XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
[expectation fulfill];
}];
+ XCTAssertEqual(call.state, GRXWriterStateNotStarted);
+
[call start];
+ XCTAssertEqual(call.state, GRXWriterStateStarted);
+
[call cancel];
+ XCTAssertEqual(call.state, GRXWriterStateFinished);
+
[self waitForExpectationsWithTimeout:1 handler:nil];
}
diff --git a/src/proto/grpc/testing/echo.proto b/src/proto/grpc/testing/echo.proto
index 0eef53a92a..c596aabfcc 100644
--- a/src/proto/grpc/testing/echo.proto
+++ b/src/proto/grpc/testing/echo.proto
@@ -45,3 +45,7 @@ service EchoTestService {
service UnimplementedService {
rpc Unimplemented(EchoRequest) returns (EchoResponse);
}
+
+// A service without any rpc defined to test coverage.
+service NoRpcService {
+}
diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst
index cb3f6b87fe..afc4fe6a37 100644
--- a/src/python/grpcio/README.rst
+++ b/src/python/grpcio/README.rst
@@ -48,6 +48,7 @@ package named :code:`python-dev`).
$ export REPO_ROOT=grpc # REPO_ROOT can be any directory of your choice
$ git clone https://github.com/grpc/grpc.git $REPO_ROOT
$ cd $REPO_ROOT
+ $ git submodule update --init
# For the next two commands do `sudo pip install` if you get permission-denied errors
$ pip install -rrequirements.txt
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index 7086519106..b844a14c48 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -27,4 +27,5 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+__import__('pkg_resources').declare_namespace(__name__)
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.c b/src/python/grpcio/grpc/_cython/imports.generated.c
index f0a40dbb35..09551472b5 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.c
+++ b/src/python/grpcio/grpc/_cython/imports.generated.c
@@ -125,6 +125,7 @@ grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
grpc_is_binary_header_type grpc_is_binary_header_import;
grpc_call_error_to_string_type grpc_call_error_to_string_import;
+grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import;
grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@@ -395,6 +396,7 @@ void pygrpc_load_imports(HMODULE library) {
grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
+ grpc_cronet_secure_channel_create_import = (grpc_cronet_secure_channel_create_type) GetProcAddress(library, "grpc_cronet_secure_channel_create");
grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h
index d5e810b7cf..54c8aaad13 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.h
+++ b/src/python/grpcio/grpc/_cython/imports.generated.h
@@ -43,6 +43,7 @@
#include <grpc/census.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
+#include <grpc/grpc_cronet.h>
#include <grpc/grpc_security.h>
#include <grpc/impl/codegen/alloc.h>
#include <grpc/impl/codegen/byte_buffer.h>
@@ -325,6 +326,9 @@ extern grpc_is_binary_header_type grpc_is_binary_header_import;
typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
#define grpc_call_error_to_string grpc_call_error_to_string_import
+typedef grpc_channel *(*grpc_cronet_secure_channel_create_type)(void *engine, const char *target, const grpc_channel_args *args, void *reserved);
+extern grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import;
+#define grpc_cronet_secure_channel_create grpc_cronet_secure_channel_create_import
typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
diff --git a/src/python/grpcio/grpc/beta/implementations.py b/src/python/grpcio/grpc/beta/implementations.py
index 742e94dc65..822f593323 100644
--- a/src/python/grpcio/grpc/beta/implementations.py
+++ b/src/python/grpcio/grpc/beta/implementations.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -188,12 +188,13 @@ def insecure_channel(host, port):
Args:
host: The name of the remote host to which to connect.
port: The port of the remote host to which to connect.
+ If None only the 'host' part will be used.
Returns:
A Channel to the remote host through which RPCs may be conducted.
"""
intermediary_low_channel = _intermediary_low.Channel(
- '%s:%d' % (host, port), None)
+ '%s:%d' % (host, port) if port else host, None)
return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
@@ -203,13 +204,15 @@ def secure_channel(host, port, channel_credentials):
Args:
host: The name of the remote host to which to connect.
port: The port of the remote host to which to connect.
+ If None only the 'host' part will be used.
channel_credentials: A ChannelCredentials.
Returns:
A secure Channel to the remote host through which RPCs may be conducted.
"""
intermediary_low_channel = _intermediary_low.Channel(
- '%s:%d' % (host, port), channel_credentials._low_credentials)
+ '%s:%d' % (host, port) if port else host,
+ channel_credentials._low_credentials)
return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index dab62530aa..5314329c2c 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -222,6 +222,9 @@ CORE_SOURCE_FILES = [
'src/core/ext/client_config/uri_parser.c',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
+ 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c',
+ 'src/core/ext/transport/cronet/transport/cronet_api_dummy.c',
+ 'src/core/ext/transport/cronet/transport/cronet_transport.c',
'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c',
'third_party/nanopb/pb_common.c',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index 873b4e2a91..0c13104d9d 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
-VERSION='0.14.0.dev0'
+VERSION='0.15.0.dev0'
diff --git a/src/python/grpcio/tests/stress/__init__.py b/src/python/grpcio/tests/stress/__init__.py
new file mode 100644
index 0000000000..100a624dc9
--- /dev/null
+++ b/src/python/grpcio/tests/stress/__init__.py
@@ -0,0 +1,28 @@
+# 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.
diff --git a/src/python/grpcio/tests/stress/client.py b/src/python/grpcio/tests/stress/client.py
new file mode 100644
index 0000000000..a733741b73
--- /dev/null
+++ b/src/python/grpcio/tests/stress/client.py
@@ -0,0 +1,132 @@
+# 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.
+
+"""Entry point for running stress tests."""
+
+import argparse
+import Queue
+import threading
+
+from grpc.beta import implementations
+from src.proto.grpc.testing import metrics_pb2
+from src.proto.grpc.testing import test_pb2
+
+from tests.interop import methods
+from tests.qps import histogram
+from tests.stress import metrics_server
+from tests.stress import test_runner
+
+
+def _args():
+ parser = argparse.ArgumentParser(description='gRPC Python stress test client')
+ parser.add_argument(
+ '--server_addresses',
+ help='comma seperated list of hostname:port to run servers on',
+ default='localhost:8080', type=str)
+ parser.add_argument(
+ '--test_cases',
+ help='comma seperated list of testcase:weighting of tests to run',
+ default='large_unary:100',
+ type=str)
+ parser.add_argument(
+ '--test_duration_secs',
+ help='number of seconds to run the stress test',
+ default=-1, type=int)
+ parser.add_argument(
+ '--num_channels_per_server',
+ help='number of channels per server',
+ default=1, type=int)
+ parser.add_argument(
+ '--num_stubs_per_channel',
+ help='number of stubs to create per channel',
+ default=1, type=int)
+ parser.add_argument(
+ '--metrics_port',
+ help='the port to listen for metrics requests on',
+ default=8081, type=int)
+ return parser.parse_args()
+
+
+def _test_case_from_arg(test_case_arg):
+ for test_case in methods.TestCase:
+ if test_case_arg == test_case.value:
+ return test_case
+ else:
+ raise ValueError('No test case {}!'.format(test_case_arg))
+
+
+def _parse_weighted_test_cases(test_case_args):
+ weighted_test_cases = {}
+ for test_case_arg in test_case_args.split(','):
+ name, weight = test_case_arg.split(':', 1)
+ test_case = _test_case_from_arg(name)
+ weighted_test_cases[test_case] = int(weight)
+ return weighted_test_cases
+
+
+def run_test(args):
+ test_cases = _parse_weighted_test_cases(args.test_cases)
+ test_servers = args.server_addresses.split(',')
+ # Propagate any client exceptions with a queue
+ exception_queue = Queue.Queue()
+ stop_event = threading.Event()
+ hist = histogram.Histogram(1, 1)
+ runners = []
+
+ server = metrics_pb2.beta_create_MetricsService_server(
+ metrics_server.MetricsServer(hist))
+ server.add_insecure_port('[::]:{}'.format(args.metrics_port))
+ server.start()
+
+ for test_server in test_servers:
+ host, port = test_server.split(':', 1)
+ for _ in xrange(args.num_channels_per_server):
+ channel = implementations.insecure_channel(host, int(port))
+ for _ in xrange(args.num_stubs_per_channel):
+ stub = test_pb2.beta_create_TestService_stub(channel)
+ runner = test_runner.TestRunner(stub, test_cases, hist,
+ exception_queue, stop_event)
+ runners.append(runner)
+
+ for runner in runners:
+ runner.start()
+ try:
+ raise exception_queue.get(block=True, timeout=args.test_duration_secs)
+ except Queue.Empty:
+ # No exceptions thrown, success
+ pass
+ finally:
+ stop_event.set()
+ for runner in runners:
+ runner.join()
+ runner = None
+ server.stop(0)
+
+if __name__ == '__main__':
+ run_test(_args())
diff --git a/src/python/grpcio/tests/stress/metrics_server.py b/src/python/grpcio/tests/stress/metrics_server.py
new file mode 100644
index 0000000000..b994e4643e
--- /dev/null
+++ b/src/python/grpcio/tests/stress/metrics_server.py
@@ -0,0 +1,60 @@
+# 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.
+
+"""MetricsService for publishing stress test qps data."""
+
+import time
+
+from src.proto.grpc.testing import metrics_pb2
+
+GAUGE_NAME = 'python_overall_qps'
+
+
+class MetricsServer(metrics_pb2.BetaMetricsServiceServicer):
+
+ def __init__(self, histogram):
+ self._start_time = time.time()
+ self._histogram = histogram
+
+ def _get_qps(self):
+ count = self._histogram.get_data().count
+ delta = time.time() - self._start_time
+ self._histogram.reset()
+ self._start_time = time.time()
+ return int(count/delta)
+
+ def GetAllGauges(self, request, context):
+ qps = self._get_qps()
+ return [metrics_pb2.GaugeResponse(name=GAUGE_NAME, long_value=qps)]
+
+ def GetGauge(self, request, context):
+ if request.name != GAUGE_NAME:
+ raise Exception('Gauge {} does not exist'.format(request.name))
+ qps = self._get_qps()
+ return metrics_pb2.GaugeResponse(name=GAUGE_NAME, long_value=qps)
diff --git a/src/python/grpcio/tests/stress/test_runner.py b/src/python/grpcio/tests/stress/test_runner.py
new file mode 100644
index 0000000000..88f13727e3
--- /dev/null
+++ b/src/python/grpcio/tests/stress/test_runner.py
@@ -0,0 +1,73 @@
+# 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.
+
+"""Thread that sends random weighted requests on a TestService stub."""
+
+import random
+import threading
+import time
+import traceback
+
+
+def _weighted_test_case_generator(weighted_cases):
+ weight_sum = sum(weighted_cases.itervalues())
+
+ while True:
+ val = random.uniform(0, weight_sum)
+ partial_sum = 0
+ for case in weighted_cases:
+ partial_sum += weighted_cases[case]
+ if val <= partial_sum:
+ yield case
+ break
+
+
+class TestRunner(threading.Thread):
+
+ def __init__(self, stub, test_cases, hist, exception_queue, stop_event):
+ super(TestRunner, self).__init__()
+ self._exception_queue = exception_queue
+ self._stop_event = stop_event
+ self._stub = stub
+ self._test_cases = _weighted_test_case_generator(test_cases)
+ self._histogram = hist
+
+ def run(self):
+ while not self._stop_event.is_set():
+ try:
+ test_case = next(self._test_cases)
+ start_time = time.time()
+ test_case.test_interoperability(self._stub, None)
+ end_time = time.time()
+ self._histogram.add((end_time - start_time)*1e9)
+ except Exception as e:
+ traceback.print_exc()
+ self._exception_queue.put(
+ Exception("An exception occured during test {}"
+ .format(test_case), e))
diff --git a/src/ruby/.rubocop.yml b/src/ruby/.rubocop.yml
index d13ce42655..34bb477543 100644
--- a/src/ruby/.rubocop.yml
+++ b/src/ruby/.rubocop.yml
@@ -11,10 +11,10 @@ AllCops:
- 'pb/test/**/*'
Metrics/CyclomaticComplexity:
- Max: 8
+ Max: 9
Metrics/PerceivedComplexity:
- Max: 8
+ Max: 9
Metrics/ClassLength:
Max: 250
diff --git a/src/ruby/ext/grpc/extconf.rb b/src/ruby/ext/grpc/extconf.rb
index 82b6d313c8..6d65db8306 100644
--- a/src/ruby/ext/grpc/extconf.rb
+++ b/src/ruby/ext/grpc/extconf.rb
@@ -60,31 +60,25 @@ grpc_root = File.expand_path(File.join(File.dirname(__FILE__), '../../../..'))
grpc_config = ENV['GRPC_CONFIG'] || 'opt'
-if ENV.key?('GRPC_LIB_DIR')
- grpc_lib_dir = File.join(grpc_root, ENV['GRPC_LIB_DIR'])
-else
- grpc_lib_dir = File.join(grpc_root, 'libs', grpc_config)
-end
-
ENV['MACOSX_DEPLOYMENT_TARGET'] = '10.7'
-unless File.exist?(File.join(grpc_lib_dir, 'libgrpc.a')) or windows
- ENV['AR'] = RbConfig::CONFIG['AR'] + ' rcs'
- ENV['CC'] = RbConfig::CONFIG['CC']
- ENV['LD'] = ENV['CC']
+ENV['AR'] = RbConfig::CONFIG['AR'] + ' rcs'
+ENV['CC'] = RbConfig::CONFIG['CC']
+ENV['LD'] = ENV['CC']
- ENV['AR'] = 'libtool -o' if RUBY_PLATFORM =~ /darwin/
+ENV['AR'] = 'libtool -o' if RUBY_PLATFORM =~ /darwin/
- ENV['EMBED_OPENSSL'] = 'true'
- ENV['EMBED_ZLIB'] = 'true'
- ENV['ARCH_FLAGS'] = RbConfig::CONFIG['ARCH_FLAG']
- ENV['ARCH_FLAGS'] = '-arch i386 -arch x86_64' if RUBY_PLATFORM =~ /darwin/
- ENV['CFLAGS'] = '-DGPR_BACKWARDS_COMPATIBILITY_MODE'
+ENV['EMBED_OPENSSL'] = 'true'
+ENV['EMBED_ZLIB'] = 'true'
+ENV['ARCH_FLAGS'] = RbConfig::CONFIG['ARCH_FLAG']
+ENV['ARCH_FLAGS'] = '-arch i386 -arch x86_64' if RUBY_PLATFORM =~ /darwin/
+ENV['CFLAGS'] = '-DGPR_BACKWARDS_COMPATIBILITY_MODE'
- output_dir = File.expand_path(RbConfig::CONFIG['topdir'])
- grpc_lib_dir = File.join(output_dir, 'libs', grpc_config)
- ENV['BUILDDIR'] = output_dir
+output_dir = File.expand_path(RbConfig::CONFIG['topdir'])
+grpc_lib_dir = File.join(output_dir, 'libs', grpc_config)
+ENV['BUILDDIR'] = output_dir
+unless windows
puts 'Building internal gRPC into ' + grpc_lib_dir
system("make -j -C #{grpc_root} #{grpc_lib_dir}/libgrpc.a CONFIG=#{grpc_config}")
exit 1 unless $? == 0
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c
index cba910d832..1172691116 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.c
+++ b/src/ruby/ext/grpc/rb_byte_buffer.c
@@ -32,11 +32,10 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_byte_buffer.h"
-#include <ruby/ruby.h>
-
#include <grpc/grpc.h>
#include <grpc/byte_buffer_reader.h>
#include <grpc/support/slice.h>
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 48c49a21e9..1b06273af9 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -32,11 +32,10 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_call.h"
-#include <ruby/ruby.h>
-
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
diff --git a/src/ruby/ext/grpc/rb_call_credentials.c b/src/ruby/ext/grpc/rb_call_credentials.c
index 38bf1f7710..79ca5b32ce 100644
--- a/src/ruby/ext/grpc/rb_call_credentials.c
+++ b/src/ruby/ext/grpc/rb_call_credentials.c
@@ -32,10 +32,10 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_call_credentials.h"
-#include <ruby/ruby.h>
#include <ruby/thread.h>
#include <grpc/grpc.h>
@@ -86,11 +86,11 @@ static VALUE grpc_rb_call_credentials_callback_rescue(VALUE args,
rb_funcall(exception_object, rb_intern("backtrace"), 0),
rb_intern("join"),
1, rb_str_new2("\n\tfrom "));
- VALUE exception_info = rb_funcall(exception_object, rb_intern("to_s"), 0);
+ VALUE rb_exception_info = rb_funcall(exception_object, rb_intern("to_s"), 0);
const char *exception_classname = rb_obj_classname(exception_object);
(void)args;
gpr_log(GPR_INFO, "Call credentials callback failed: %s: %s\n%s",
- exception_classname, StringValueCStr(exception_info),
+ exception_classname, StringValueCStr(rb_exception_info),
StringValueCStr(backtrace));
rb_hash_aset(result, rb_str_new2("metadata"), Qnil);
/* Currently only gives the exception class name. It should be possible get
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 984afad107..013321ffc8 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -32,11 +32,10 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_channel.h"
-#include <ruby/ruby.h>
-
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c
index 2ffb8f41da..87c0e0a705 100644
--- a/src/ruby/ext/grpc/rb_channel_args.c
+++ b/src/ruby/ext/grpc/rb_channel_args.c
@@ -32,11 +32,10 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_channel_args.h"
-#include <ruby/ruby.h>
-
#include <grpc/grpc.h>
#include "rb_grpc.h"
diff --git a/src/ruby/ext/grpc/rb_channel_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c
index 09bd3093a9..cbb23885aa 100644
--- a/src/ruby/ext/grpc/rb_channel_credentials.c
+++ b/src/ruby/ext/grpc/rb_channel_credentials.c
@@ -31,14 +31,13 @@
*
*/
+#include <ruby/ruby.h>
+
#include <string.h>
-#include <ruby/ruby.h>
#include "rb_grpc_imports.generated.h"
#include "rb_channel_credentials.h"
-#include <ruby/ruby.h>
-
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index 2a2eee190c..4bb615f8be 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -32,10 +32,10 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_completion_queue.h"
-#include <ruby/ruby.h>
#include <ruby/thread.h>
#include <grpc/grpc.h>
diff --git a/src/ruby/ext/grpc/rb_event_thread.c b/src/ruby/ext/grpc/rb_event_thread.c
index 2649a1087f..9e85bbcfbf 100644
--- a/src/ruby/ext/grpc/rb_event_thread.c
+++ b/src/ruby/ext/grpc/rb_event_thread.c
@@ -32,12 +32,12 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_event_thread.h"
#include <stdbool.h>
-#include <ruby/ruby.h>
#include <ruby/thread.h>
#include <grpc/support/alloc.h>
#include <grpc/support/sync.h>
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index acb47b0055..06a07ac646 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -32,11 +32,11 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_grpc.h"
#include <math.h>
-#include <ruby/ruby.h>
#include <ruby/vm.h>
#include <sys/time.h>
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index bc43f9d36b..cebbe8c40f 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -125,6 +125,7 @@ grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
grpc_is_binary_header_type grpc_is_binary_header_import;
grpc_call_error_to_string_type grpc_call_error_to_string_import;
+grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import;
grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@@ -391,6 +392,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
+ grpc_cronet_secure_channel_create_import = (grpc_cronet_secure_channel_create_type) GetProcAddress(library, "grpc_cronet_secure_channel_create");
grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index b67361ca25..d7ea6c574c 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -43,6 +43,7 @@
#include <grpc/census.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
+#include <grpc/grpc_cronet.h>
#include <grpc/grpc_security.h>
#include <grpc/impl/codegen/alloc.h>
#include <grpc/impl/codegen/byte_buffer.h>
@@ -325,6 +326,9 @@ extern grpc_is_binary_header_type grpc_is_binary_header_import;
typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
#define grpc_call_error_to_string grpc_call_error_to_string_import
+typedef grpc_channel *(*grpc_cronet_secure_channel_create_type)(void *engine, const char *target, const grpc_channel_args *args, void *reserved);
+extern grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import;
+#define grpc_cronet_secure_channel_create grpc_cronet_secure_channel_create_import
typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 96e60c6776..2b3acaaf59 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -32,11 +32,10 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_server.h"
-#include <ruby/ruby.h>
-
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include "rb_call.h"
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index b2d7280a30..3b0fb6c910 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -32,11 +32,10 @@
*/
#include <ruby/ruby.h>
+
#include "rb_grpc_imports.generated.h"
#include "rb_server_credentials.h"
-#include <ruby/ruby.h>
-
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 7f3a38a9f4..a0f4071adc 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -332,15 +332,13 @@ module GRPC
# the current thread to terminate it.
def run_till_terminated
GRPC.trap_signals
- stopped = false
t = Thread.new do
run
- stopped = true
end
+ t.abort_on_exception = true
wait_till_running
- loop do
+ until running_state == :stopped
sleep SIGNAL_CHECK_PERIOD
- break if stopped
break unless GRPC.handle_signals
end
stop
@@ -416,7 +414,7 @@ module GRPC
GRPC.logger.warn("NOT AVAILABLE: too many jobs_waiting: #{an_rpc}")
noop = proc { |x| x }
c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline)
- c.send_status(StatusCodes::RESOURCE_EXHAUSTED, '')
+ c.send_status(GRPC::Core::StatusCodes::RESOURCE_EXHAUSTED, '')
nil
end
@@ -427,7 +425,7 @@ module GRPC
GRPC.logger.warn("UNIMPLEMENTED: #{an_rpc}")
noop = proc { |x| x }
c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline)
- c.send_status(StatusCodes::UNIMPLEMENTED, '')
+ c.send_status(GRPC::Core::StatusCodes::UNIMPLEMENTED, '')
nil
end
@@ -443,7 +441,12 @@ module GRPC
unless active_call.nil?
@pool.schedule(active_call) do |ac|
c, mth = ac
- rpc_descs[mth].run_server_method(c, rpc_handlers[mth])
+ begin
+ rpc_descs[mth].run_server_method(c, rpc_handlers[mth])
+ rescue StandardError
+ c.send_status(GRPC::Core::StatusCodes::INTERNAL,
+ 'Server handler failed')
+ end
end
end
rescue Core::CallError, RuntimeError => e
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 67c6a5d5a1..01c8c5ac8f 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
# GRPC contains the General RPC module.
module GRPC
- VERSION = '0.14.0.dev'
+ VERSION = '0.15.0.dev'
end
diff --git a/src/ruby/tools/README.md b/src/ruby/tools/README.md
new file mode 100644
index 0000000000..e43f223c89
--- /dev/null
+++ b/src/ruby/tools/README.md
@@ -0,0 +1,12 @@
+# Ruby gRPC Tools
+
+This package distributes protoc and the Ruby gRPC protoc plugin for Windows, Linux, and Mac.
+
+Before this package is published, the following directories should be filled with the corresponding `protoc` and `grpc_ruby_plugin` executables.
+
+ - `bin/x86-linux`
+ - `bin/x86_64-linux`
+ - `bin/x86-macos`
+ - `bin/x86_64-macos`
+ - `bin/x86-windows`
+ - `bin/x86_64-windows`
diff --git a/src/ruby/tools/bin/protoc.rb b/src/ruby/tools/bin/protoc.rb
new file mode 100755
index 0000000000..3a2a5b8dc9
--- /dev/null
+++ b/src/ruby/tools/bin/protoc.rb
@@ -0,0 +1,41 @@
+#!/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 'rbconfig'
+
+require_relative '../os_check'
+
+protoc_name = 'protoc' + RbConfig::CONFIG['EXEEXT']
+
+protoc_path = File.join(File.dirname(__FILE__),
+ RbConfig::CONFIG['host_cpu'] + '-' + OS.os_name,
+ protoc_name)
+
+exec([ protoc_path, protoc_path ], *ARGV)
diff --git a/src/ruby/tools/bin/protoc_grpc_ruby_plugin.rb b/src/ruby/tools/bin/protoc_grpc_ruby_plugin.rb
new file mode 100755
index 0000000000..4b296dedc7
--- /dev/null
+++ b/src/ruby/tools/bin/protoc_grpc_ruby_plugin.rb
@@ -0,0 +1,41 @@
+#!/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 'rbconfig'
+
+require_relative '../os_check'
+
+plugin_name = 'grpc_ruby_plugin' + RbConfig::CONFIG['EXEEXT']
+
+plugin_path = File.join(File.dirname(__FILE__),
+ RbConfig::CONFIG['host_cpu'] + '-' + OS.os_name,
+ plugin_name)
+
+exec([ plugin_path, plugin_path ], *ARGV)
diff --git a/src/ruby/tools/grpc-tools.gemspec b/src/ruby/tools/grpc-tools.gemspec
new file mode 100644
index 0000000000..af904de4a9
--- /dev/null
+++ b/src/ruby/tools/grpc-tools.gemspec
@@ -0,0 +1,22 @@
+# -*- ruby -*-
+# encoding: utf-8
+require_relative 'version.rb'
+Gem::Specification.new do |s|
+ s.name = 'grpc-tools'
+ s.version = GRPC::Tools::VERSION
+ s.authors = ['grpc Authors']
+ s.email = 'grpc-io@googlegroups.com'
+ s.homepage = 'https://github.com/google/grpc/tree/master/src/ruby/tools'
+ s.summary = 'Development tools for Ruby gRPC'
+ s.description = 'protoc and the Ruby gRPC protoc plugin'
+ s.license = 'BSD-3-Clause'
+
+ s.files = %w( version.rb os_check.rb README.md )
+ s.files += Dir.glob('bin/**/*')
+
+ s.bindir = 'bin'
+
+ s.platform = Gem::Platform::RUBY
+
+ s.executables = %w( protoc.rb protoc_grpc_ruby_plugin.rb )
+end
diff --git a/src/ruby/tools/os_check.rb b/src/ruby/tools/os_check.rb
new file mode 100644
index 0000000000..2677306457
--- /dev/null
+++ b/src/ruby/tools/os_check.rb
@@ -0,0 +1,45 @@
+# 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.
+
+# This is based on http://stackoverflow.com/a/171011/159388 by Aaron Hinni
+
+require 'rbconfig'
+
+module OS
+ def OS.os_name
+ case RbConfig::CONFIG['host_os']
+ when /cygwin|mswin|mingw|bccwin|wince|emx/
+ 'windows'
+ when /darwin/
+ 'macos'
+ else
+ 'linux'
+ end
+ end
+end
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
new file mode 100644
index 0000000000..dca7fd7e72
--- /dev/null
+++ b/src/ruby/tools/version.rb
@@ -0,0 +1,34 @@
+# 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.
+
+module GRPC
+ module Tools
+ VERSION = '0.15.0.dev'
+ end
+end
diff --git a/templates/src/ruby/tools/version.rb.template b/templates/src/ruby/tools/version.rb.template
new file mode 100644
index 0000000000..dbc5f48cf5
--- /dev/null
+++ b/templates/src/ruby/tools/version.rb.template
@@ -0,0 +1,36 @@
+%YAML 1.2
+--- |
+ # 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.
+
+ module GRPC
+ module Tools
+ VERSION = '${settings.ruby_version.ruby()}'
+ end
+ end
diff --git a/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template b/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template
new file mode 100644
index 0000000000..200905d4f3
--- /dev/null
+++ b/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template
@@ -0,0 +1,34 @@
+%YAML 1.2
+--- |
+ # 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.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
+
+ VERSION='${settings.python_version.pep440()}'
diff --git a/templates/tools/dockerfile/node_deps.include b/templates/tools/dockerfile/node_deps.include
index 7d37d67146..7855fbfee3 100644
--- a/templates/tools/dockerfile/node_deps.include
+++ b/templates/tools/dockerfile/node_deps.include
@@ -4,4 +4,8 @@
# Install nvm
RUN touch .profile
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+# Install all versions of node that we want to test
RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm install 4 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm alias default 4" \ No newline at end of file
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile.template
new file mode 100644
index 0000000000..074178252d
--- /dev/null
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile.template
@@ -0,0 +1,41 @@
+%YAML 1.2
+--- |
+ # 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.
+
+ FROM debian:jessie
+
+ <%include file="../../apt_get_basic.include"/>
+ <%include file="../../ccache_setup.include"/>
+ <%include file="../../cxx_deps.include"/>
+ <%include file="../../gcp_api_libraries.include"/>
+ <%include file="../../csharp_deps.include"/>
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile.template
new file mode 100644
index 0000000000..8b933aaa32
--- /dev/null
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile.template
@@ -0,0 +1,41 @@
+%YAML 1.2
+--- |
+ # 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.
+
+ FROM debian:jessie
+
+ <%include file="../../apt_get_basic.include"/>
+ <%include file="../../ccache_setup.include"/>
+ <%include file="../../cxx_deps.include"/>
+ <%include file="../../gcp_api_libraries.include"/>
+ <%include file="../../ruby_deps.include"/>
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/test/sanity/Dockerfile.template b/templates/tools/dockerfile/test/sanity/Dockerfile.template
index 8d6f52db54..8e2140e648 100644
--- a/templates/tools/dockerfile/test/sanity/Dockerfile.template
+++ b/templates/tools/dockerfile/test/sanity/Dockerfile.template
@@ -43,7 +43,17 @@
python-virtualenv ${"\\"}
python-lxml
RUN pip install simplejson mako
-
+
+ #======================================
+ # More sanity test dependencies (bazel)
+ RUN echo "deb http://httpredir.debian.org/debian jessie-backports main" > \
+ /etc/apt/sources.list.d/backports.list
+ RUN apt-get update
+ RUN apt-get -t jessie-backports install -y openjdk-8-jdk
+ RUN git clone https://github.com/bazelbuild/bazel.git /bazel
+ RUN cd /bazel && ./compile.sh
+ RUN ln -s /bazel/output/bazel /bin/
+
#===================
# Docker "inception"
# Note this is quite the ugly hack.
diff --git a/test/core/end2end/fixtures/h2_census.c b/test/core/end2end/fixtures/h2_census.c
index ff2f028f09..e46b39e476 100644
--- a/test/core/end2end/fixtures/h2_census.c
+++ b/test/core/end2end/fixtures/h2_census.c
@@ -111,7 +111,7 @@ void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
/* All test configurations */
static grpc_end2end_test_config configs[] = {
- {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
+ {"chttp2/fullstack+census", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
};
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/03a72675e1969f836094f1ecfec2a7b34418e306 b/test/core/end2end/fuzzers/server_fuzzer_corpus/03a72675e1969f836094f1ecfec2a7b34418e306
new file mode 100644
index 0000000000..503af15fe8
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/03a72675e1969f836094f1ecfec2a7b34418e306
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/0416afd6875d9ba55f1e5f86a6456a5445d5e576 b/test/core/end2end/fuzzers/server_fuzzer_corpus/0416afd6875d9ba55f1e5f86a6456a5445d5e576
new file mode 100644
index 0000000000..30229f98fd
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/0416afd6875d9ba55f1e5f86a6456a5445d5e576
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/08c42ef29eff83052c5887855f2fa3e07ebe470c b/test/core/end2end/fuzzers/server_fuzzer_corpus/08c42ef29eff83052c5887855f2fa3e07ebe470c
new file mode 100644
index 0000000000..828275ee3c
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/08c42ef29eff83052c5887855f2fa3e07ebe470c
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/1ba889ea1543297824e99e641e6ca8b91f45732e b/test/core/end2end/fuzzers/server_fuzzer_corpus/1ba889ea1543297824e99e641e6ca8b91f45732e
new file mode 100644
index 0000000000..6ed060d1e3
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/1ba889ea1543297824e99e641e6ca8b91f45732e
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/3b09bf453c6f93983c24c4d5481e55d66213f93a b/test/core/end2end/fuzzers/server_fuzzer_corpus/3b09bf453c6f93983c24c4d5481e55d66213f93a
new file mode 100644
index 0000000000..1a7a213cd7
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/3b09bf453c6f93983c24c4d5481e55d66213f93a
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/49cb33cbb60f041e8e99dd718993acd2c3354416 b/test/core/end2end/fuzzers/server_fuzzer_corpus/49cb33cbb60f041e8e99dd718993acd2c3354416
new file mode 100644
index 0000000000..7f975251dd
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/49cb33cbb60f041e8e99dd718993acd2c3354416
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/59743fe120be6ae1aed1c02230ee1bb460f621ee b/test/core/end2end/fuzzers/server_fuzzer_corpus/59743fe120be6ae1aed1c02230ee1bb460f621ee
new file mode 100644
index 0000000000..3038fde547
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/59743fe120be6ae1aed1c02230ee1bb460f621ee
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/a5ccb8f124d8ddb5350b90bc0d6b96db280cb7c9 b/test/core/end2end/fuzzers/server_fuzzer_corpus/a5ccb8f124d8ddb5350b90bc0d6b96db280cb7c9
new file mode 100644
index 0000000000..9d39854fc9
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/a5ccb8f124d8ddb5350b90bc0d6b96db280cb7c9
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/a7fac1265a384fe9e45a9ee3d708b79c4e80505e b/test/core/end2end/fuzzers/server_fuzzer_corpus/a7fac1265a384fe9e45a9ee3d708b79c4e80505e
new file mode 100644
index 0000000000..338f61bdce
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/a7fac1265a384fe9e45a9ee3d708b79c4e80505e
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/aaf049720c707d4e14e47e7eb31d6a2dda60e66a b/test/core/end2end/fuzzers/server_fuzzer_corpus/aaf049720c707d4e14e47e7eb31d6a2dda60e66a
new file mode 100644
index 0000000000..dab9c75822
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/aaf049720c707d4e14e47e7eb31d6a2dda60e66a
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/c4e4c7572e005e18d56eac407033da058737a5ab b/test/core/end2end/fuzzers/server_fuzzer_corpus/c4e4c7572e005e18d56eac407033da058737a5ab
new file mode 100644
index 0000000000..070a581b37
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/c4e4c7572e005e18d56eac407033da058737a5ab
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/crash-dae0f07934a527989f23f06e630710ff6ca8c809 b/test/core/end2end/fuzzers/server_fuzzer_corpus/crash-dae0f07934a527989f23f06e630710ff6ca8c809
new file mode 100644
index 0000000000..b6dfd77e67
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/crash-dae0f07934a527989f23f06e630710ff6ca8c809
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/e96ad9c17795e52edc810a08d4fc61fe8790002a b/test/core/end2end/fuzzers/server_fuzzer_corpus/e96ad9c17795e52edc810a08d4fc61fe8790002a
new file mode 100644
index 0000000000..df9241dd0c
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/e96ad9c17795e52edc810a08d4fc61fe8790002a
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/fa202a5f51cd49f8ea5af60c5f403f797c01c504 b/test/core/end2end/fuzzers/server_fuzzer_corpus/fa202a5f51cd49f8ea5af60c5f403f797c01c504
new file mode 100644
index 0000000000..0ba5935164
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/fa202a5f51cd49f8ea5af60c5f403f797c01c504
Binary files differ
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index 0eede6c23b..fd6ff2c26f 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -36,11 +36,13 @@
#include <grpc/census.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
+#include <grpc/grpc_cronet.h>
#include <grpc/grpc_security.h>
#include <grpc/grpc_security_constants.h>
#include <grpc/impl/codegen/alloc.h>
#include <grpc/impl/codegen/atm.h>
#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/byte_buffer_reader.h>
#include <grpc/impl/codegen/compression_types.h>
#include <grpc/impl/codegen/connectivity_state.h>
#include <grpc/impl/codegen/grpc_types.h>
diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c
index 62468a5a61..270d16600d 100644
--- a/test/core/util/test_config.c
+++ b/test/core/util/test_config.c
@@ -210,7 +210,7 @@ static void install_crash_handler() {
#include <stdio.h>
#include <string.h>
-static char g_alt_stack[MINSIGSTKSZ];
+static char g_alt_stack[GPR_MAX(MINSIGSTKSZ, 65536)];
#define MAX_FRAMES 32
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 0de6c74c47..e0649bd694 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -51,6 +51,7 @@
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/string_ref_helper.h"
+#include "test/cpp/util/test_credentials_provider.h"
#ifdef GPR_POSIX_SOCKET
#include "src/core/lib/iomgr/ev_posix.h"
@@ -58,6 +59,7 @@
using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse;
+using grpc::testing::kTlsCredentialsType;
using std::chrono::system_clock;
GPR_TLS_DECL(g_is_async_end2end_test);
@@ -219,20 +221,37 @@ class ServerBuilderSyncPluginDisabler : public ::grpc::ServerBuilderOption {
}
};
-class AsyncEnd2endTest : public ::testing::TestWithParam<bool> {
+class TestScenario {
+ public:
+ TestScenario(bool non_block, const grpc::string& creds_type,
+ const grpc::string& content)
+ : disable_blocking(non_block),
+ credentials_type(creds_type),
+ message_content(content) {}
+ void Log() const {
+ gpr_log(GPR_INFO,
+ "Scenario: disable_blocking %d, credentials %s, message size %d",
+ disable_blocking, credentials_type.c_str(), message_content.size());
+ }
+ bool disable_blocking;
+ const grpc::string credentials_type;
+ const grpc::string message_content;
+};
+
+class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
protected:
- AsyncEnd2endTest() {}
+ AsyncEnd2endTest() { GetParam().Log(); }
void SetUp() GRPC_OVERRIDE {
- poll_overrider_.reset(new PollingOverrider(!GetParam()));
+ poll_overrider_.reset(new PollingOverrider(!GetParam().disable_blocking));
int port = grpc_pick_unused_port_or_die();
server_address_ << "localhost:" << port;
// Setup server
ServerBuilder builder;
- builder.AddListeningPort(server_address_.str(),
- grpc::InsecureServerCredentials());
+ auto server_creds = GetServerCredentials(GetParam().credentials_type);
+ builder.AddListeningPort(server_address_.str(), server_creds);
builder.RegisterService(&service_);
cq_ = builder.AddCompletionQueue();
@@ -258,8 +277,11 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<bool> {
}
void ResetStub() {
+ ChannelArguments args;
+ auto channel_creds =
+ GetChannelCredentials(GetParam().credentials_type, &args);
std::shared_ptr<Channel> channel =
- CreateChannel(server_address_.str(), InsecureChannelCredentials());
+ CreateCustomChannel(server_address_.str(), channel_creds, args);
stub_ = grpc::testing::EchoTestService::NewStub(channel);
}
@@ -275,22 +297,23 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<bool> {
ServerContext srv_ctx;
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
cq_.get(), tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
send_response.set_message(recv_request.message());
response_writer.Finish(send_response, Status::OK, tag(3));
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
-
response_reader->Finish(&recv_response, &recv_status, tag(4));
- Verifier(GetParam()).Expect(4, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(3, true)
+ .Expect(4, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_response.message(), recv_response.message());
EXPECT_TRUE(recv_status.ok());
@@ -330,7 +353,7 @@ TEST_P(AsyncEnd2endTest, AsyncNextRpc) {
ServerContext srv_ctx;
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
@@ -338,23 +361,22 @@ TEST_P(AsyncEnd2endTest, AsyncNextRpc) {
std::chrono::system_clock::now());
std::chrono::system_clock::time_point time_limit(
std::chrono::system_clock::now() + std::chrono::seconds(10));
- Verifier(GetParam()).Verify(cq_.get(), time_now);
- Verifier(GetParam()).Verify(cq_.get(), time_now);
+ Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now);
+ Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now);
service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
cq_.get(), tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get(), time_limit);
+ Verifier(GetParam().disable_blocking)
+ .Expect(2, true)
+ .Verify(cq_.get(), time_limit);
EXPECT_EQ(send_request.message(), recv_request.message());
send_response.set_message(recv_request.message());
response_writer.Finish(send_response, Status::OK, tag(3));
- Verifier(GetParam())
- .Expect(3, true)
- .Verify(cq_.get(), std::chrono::system_clock::time_point::max());
-
response_reader->Finish(&recv_response, &recv_status, tag(4));
- Verifier(GetParam())
+ Verifier(GetParam().disable_blocking)
+ .Expect(3, true)
.Expect(4, true)
.Verify(cq_.get(), std::chrono::system_clock::time_point::max());
@@ -375,41 +397,48 @@ TEST_P(AsyncEnd2endTest, SimpleClientStreaming) {
ServerContext srv_ctx;
ServerAsyncReader<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::unique_ptr<ClientAsyncWriter<EchoRequest>> cli_stream(
stub_->AsyncRequestStream(&cli_ctx, &recv_response, cq_.get(), tag(1)));
service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
tag(2));
- Verifier(GetParam()).Expect(2, true).Expect(1, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(2, true)
+ .Expect(1, true)
+ .Verify(cq_.get());
cli_stream->Write(send_request, tag(3));
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
-
srv_stream.Read(&recv_request, tag(4));
- Verifier(GetParam()).Expect(4, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(3, true)
+ .Expect(4, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
cli_stream->Write(send_request, tag(5));
- Verifier(GetParam()).Expect(5, true).Verify(cq_.get());
-
srv_stream.Read(&recv_request, tag(6));
- Verifier(GetParam()).Expect(6, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(5, true)
+ .Expect(6, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
cli_stream->WritesDone(tag(7));
- Verifier(GetParam()).Expect(7, true).Verify(cq_.get());
-
srv_stream.Read(&recv_request, tag(8));
- Verifier(GetParam()).Expect(8, false).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(7, true)
+ .Expect(8, false)
+ .Verify(cq_.get());
send_response.set_message(recv_request.message());
srv_stream.Finish(send_response, Status::OK, tag(9));
- Verifier(GetParam()).Expect(9, true).Verify(cq_.get());
-
cli_stream->Finish(&recv_status, tag(10));
- Verifier(GetParam()).Expect(10, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(9, true)
+ .Expect(10, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_response.message(), recv_response.message());
EXPECT_TRUE(recv_status.ok());
@@ -428,39 +457,45 @@ TEST_P(AsyncEnd2endTest, SimpleServerStreaming) {
ServerContext srv_ctx;
ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream(
stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1)));
service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
cq_.get(), cq_.get(), tag(2));
- Verifier(GetParam()).Expect(1, true).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(1, true)
+ .Expect(2, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
send_response.set_message(recv_request.message());
srv_stream.Write(send_response, tag(3));
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
-
cli_stream->Read(&recv_response, tag(4));
- Verifier(GetParam()).Expect(4, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(3, true)
+ .Expect(4, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_response.message(), recv_response.message());
srv_stream.Write(send_response, tag(5));
- Verifier(GetParam()).Expect(5, true).Verify(cq_.get());
-
cli_stream->Read(&recv_response, tag(6));
- Verifier(GetParam()).Expect(6, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(5, true)
+ .Expect(6, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_response.message(), recv_response.message());
srv_stream.Finish(Status::OK, tag(7));
- Verifier(GetParam()).Expect(7, true).Verify(cq_.get());
-
cli_stream->Read(&recv_response, tag(8));
- Verifier(GetParam()).Expect(8, false).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(7, true)
+ .Expect(8, false)
+ .Verify(cq_.get());
cli_stream->Finish(&recv_status, tag(9));
- Verifier(GetParam()).Expect(9, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(9, true).Verify(cq_.get());
EXPECT_TRUE(recv_status.ok());
}
@@ -478,41 +513,48 @@ TEST_P(AsyncEnd2endTest, SimpleBidiStreaming) {
ServerContext srv_ctx;
ServerAsyncReaderWriter<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>>
cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1)));
service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
tag(2));
- Verifier(GetParam()).Expect(1, true).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(1, true)
+ .Expect(2, true)
+ .Verify(cq_.get());
cli_stream->Write(send_request, tag(3));
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
-
srv_stream.Read(&recv_request, tag(4));
- Verifier(GetParam()).Expect(4, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(3, true)
+ .Expect(4, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
send_response.set_message(recv_request.message());
srv_stream.Write(send_response, tag(5));
- Verifier(GetParam()).Expect(5, true).Verify(cq_.get());
-
cli_stream->Read(&recv_response, tag(6));
- Verifier(GetParam()).Expect(6, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(5, true)
+ .Expect(6, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_response.message(), recv_response.message());
cli_stream->WritesDone(tag(7));
- Verifier(GetParam()).Expect(7, true).Verify(cq_.get());
-
srv_stream.Read(&recv_request, tag(8));
- Verifier(GetParam()).Expect(8, false).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(7, true)
+ .Expect(8, false)
+ .Verify(cq_.get());
srv_stream.Finish(Status::OK, tag(9));
- Verifier(GetParam()).Expect(9, true).Verify(cq_.get());
-
cli_stream->Finish(&recv_status, tag(10));
- Verifier(GetParam()).Expect(10, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(9, true)
+ .Expect(10, true)
+ .Verify(cq_.get());
EXPECT_TRUE(recv_status.ok());
}
@@ -531,7 +573,7 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) {
ServerContext srv_ctx;
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::pair<grpc::string, grpc::string> meta1("key1", "val1");
std::pair<grpc::string, grpc::string> meta2("key2", "val2");
std::pair<grpc::string, grpc::string> meta3("g.r.d-bin", "xyz");
@@ -544,7 +586,7 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) {
service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
cq_.get(), tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
auto client_initial_metadata = srv_ctx.client_metadata();
EXPECT_EQ(meta1.second,
@@ -557,11 +599,11 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) {
send_response.set_message(recv_request.message());
response_writer.Finish(send_response, Status::OK, tag(3));
-
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
-
response_reader->Finish(&recv_response, &recv_status, tag(4));
- Verifier(GetParam()).Expect(4, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(3, true)
+ .Expect(4, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_response.message(), recv_response.message());
EXPECT_TRUE(recv_status.ok());
@@ -580,7 +622,7 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) {
ServerContext srv_ctx;
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::pair<grpc::string, grpc::string> meta1("key1", "val1");
std::pair<grpc::string, grpc::string> meta2("key2", "val2");
@@ -589,15 +631,15 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) {
service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
cq_.get(), tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
srv_ctx.AddInitialMetadata(meta1.first, meta1.second);
srv_ctx.AddInitialMetadata(meta2.first, meta2.second);
response_writer.SendInitialMetadata(tag(3));
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(3, true).Verify(cq_.get());
response_reader->ReadInitialMetadata(tag(4));
- Verifier(GetParam()).Expect(4, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
auto server_initial_metadata = cli_ctx.GetServerInitialMetadata();
EXPECT_EQ(meta1.second,
ToString(server_initial_metadata.find(meta1.first)->second));
@@ -607,10 +649,11 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) {
send_response.set_message(recv_request.message());
response_writer.Finish(send_response, Status::OK, tag(5));
- Verifier(GetParam()).Expect(5, true).Verify(cq_.get());
-
response_reader->Finish(&recv_response, &recv_status, tag(6));
- Verifier(GetParam()).Expect(6, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(5, true)
+ .Expect(6, true)
+ .Verify(cq_.get());
EXPECT_EQ(send_response.message(), recv_response.message());
EXPECT_TRUE(recv_status.ok());
@@ -629,7 +672,7 @@ TEST_P(AsyncEnd2endTest, ServerTrailingMetadataRpc) {
ServerContext srv_ctx;
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::pair<grpc::string, grpc::string> meta1("key1", "val1");
std::pair<grpc::string, grpc::string> meta2("key2", "val2");
@@ -638,20 +681,22 @@ TEST_P(AsyncEnd2endTest, ServerTrailingMetadataRpc) {
service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
cq_.get(), tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
response_writer.SendInitialMetadata(tag(3));
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(3, true).Verify(cq_.get());
send_response.set_message(recv_request.message());
srv_ctx.AddTrailingMetadata(meta1.first, meta1.second);
srv_ctx.AddTrailingMetadata(meta2.first, meta2.second);
response_writer.Finish(send_response, Status::OK, tag(4));
+ response_reader->Finish(&recv_response, &recv_status, tag(5));
- Verifier(GetParam()).Expect(4, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(4, true)
+ .Expect(5, true)
+ .Verify(cq_.get());
- response_reader->Finish(&recv_response, &recv_status, tag(5));
- Verifier(GetParam()).Expect(5, true).Verify(cq_.get());
EXPECT_EQ(send_response.message(), recv_response.message());
EXPECT_TRUE(recv_status.ok());
auto server_trailing_metadata = cli_ctx.GetServerTrailingMetadata();
@@ -675,7 +720,7 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) {
ServerContext srv_ctx;
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::pair<grpc::string, grpc::string> meta1("key1", "val1");
std::pair<grpc::string, grpc::string> meta2(
"key2-bin",
@@ -699,7 +744,7 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) {
service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
cq_.get(), tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
auto client_initial_metadata = srv_ctx.client_metadata();
EXPECT_EQ(meta1.second,
@@ -711,9 +756,9 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) {
srv_ctx.AddInitialMetadata(meta3.first, meta3.second);
srv_ctx.AddInitialMetadata(meta4.first, meta4.second);
response_writer.SendInitialMetadata(tag(3));
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(3, true).Verify(cq_.get());
response_reader->ReadInitialMetadata(tag(4));
- Verifier(GetParam()).Expect(4, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
auto server_initial_metadata = cli_ctx.GetServerInitialMetadata();
EXPECT_EQ(meta3.second,
ToString(server_initial_metadata.find(meta3.first)->second));
@@ -725,11 +770,13 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) {
srv_ctx.AddTrailingMetadata(meta5.first, meta5.second);
srv_ctx.AddTrailingMetadata(meta6.first, meta6.second);
response_writer.Finish(send_response, Status::OK, tag(5));
+ response_reader->Finish(&recv_response, &recv_status, tag(6));
- Verifier(GetParam()).Expect(5, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(5, true)
+ .Expect(6, true)
+ .Verify(cq_.get());
- response_reader->Finish(&recv_response, &recv_status, tag(6));
- Verifier(GetParam()).Expect(6, true).Verify(cq_.get());
EXPECT_EQ(send_response.message(), recv_response.message());
EXPECT_TRUE(recv_status.ok());
auto server_trailing_metadata = cli_ctx.GetServerTrailingMetadata();
@@ -754,7 +801,7 @@ TEST_P(AsyncEnd2endTest, ServerCheckCancellation) {
ServerContext srv_ctx;
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
@@ -762,15 +809,15 @@ TEST_P(AsyncEnd2endTest, ServerCheckCancellation) {
service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
cq_.get(), tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
cli_ctx.TryCancel();
- Verifier(GetParam()).Expect(5, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(5, true).Verify(cq_.get());
EXPECT_TRUE(srv_ctx.IsCancelled());
response_reader->Finish(&recv_response, &recv_status, tag(4));
- Verifier(GetParam()).Expect(4, false).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(4, false).Verify(cq_.get());
EXPECT_EQ(StatusCode::CANCELLED, recv_status.error_code());
}
@@ -789,7 +836,7 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) {
ServerContext srv_ctx;
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
@@ -797,25 +844,29 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) {
service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
cq_.get(), tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
send_response.set_message(recv_request.message());
response_writer.Finish(send_response, Status::OK, tag(3));
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
- Verifier(GetParam()).Expect(5, true).Verify(cq_.get());
- EXPECT_FALSE(srv_ctx.IsCancelled());
-
response_reader->Finish(&recv_response, &recv_status, tag(4));
- Verifier(GetParam()).Expect(4, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(3, true)
+ .Expect(4, true)
+ .Expect(5, true)
+ .Verify(cq_.get());
+ EXPECT_FALSE(srv_ctx.IsCancelled());
EXPECT_EQ(send_response.message(), recv_response.message());
EXPECT_TRUE(recv_status.ok());
}
TEST_P(AsyncEnd2endTest, UnimplementedRpc) {
+ ChannelArguments args;
+ auto channel_creds =
+ GetChannelCredentials(GetParam().credentials_type, &args);
std::shared_ptr<Channel> channel =
- CreateChannel(server_address_.str(), InsecureChannelCredentials());
+ CreateCustomChannel(server_address_.str(), channel_creds, args);
std::unique_ptr<grpc::testing::UnimplementedService::Stub> stub;
stub = grpc::testing::UnimplementedService::NewStub(channel);
EchoRequest send_request;
@@ -823,12 +874,12 @@ TEST_P(AsyncEnd2endTest, UnimplementedRpc) {
Status recv_status;
ClientContext cli_ctx;
- send_request.set_message("Hello");
+ send_request.set_message(GetParam().message_content);
std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
stub->AsyncUnimplemented(&cli_ctx, send_request, cq_.get()));
response_reader->Finish(&recv_response, &recv_status, tag(4));
- Verifier(GetParam()).Expect(4, false).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(4, false).Verify(cq_.get());
EXPECT_EQ(StatusCode::UNIMPLEMENTED, recv_status.error_code());
EXPECT_EQ("", recv_status.error_message());
@@ -875,23 +926,25 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
// Initiate the 'RequestStream' call on client
std::unique_ptr<ClientAsyncWriter<EchoRequest>> cli_stream(
stub_->AsyncRequestStream(&cli_ctx, &recv_response, cq_.get(), tag(1)));
- Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(1, true).Verify(cq_.get());
// On the server, request to be notified of 'RequestStream' calls
// and receive the 'RequestStream' call just made by the client
srv_ctx.AsyncNotifyWhenDone(tag(11));
service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
// Client sends 3 messages (tags 3, 4 and 5)
for (int tag_idx = 3; tag_idx <= 5; tag_idx++) {
send_request.set_message("Ping " + std::to_string(tag_idx));
cli_stream->Write(send_request, tag(tag_idx));
- Verifier(GetParam()).Expect(tag_idx, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking)
+ .Expect(tag_idx, true)
+ .Verify(cq_.get());
}
cli_stream->WritesDone(tag(6));
- Verifier(GetParam()).Expect(6, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(6, true).Verify(cq_.get());
bool expected_server_cq_result = true;
bool ignore_cq_result = false;
@@ -899,7 +952,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
srv_ctx.TryCancel();
- Verifier(GetParam()).Expect(11, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(11, true).Verify(cq_.get());
EXPECT_TRUE(srv_ctx.IsCancelled());
// Since cancellation is done before server reads any results, we know
@@ -909,7 +962,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
std::thread* server_try_cancel_thd = NULL;
- auto verif = Verifier(GetParam());
+ auto verif = Verifier(GetParam().disable_blocking);
if (server_try_cancel == CANCEL_DURING_PROCESSING) {
server_try_cancel_thd =
@@ -967,13 +1020,13 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
// Server sends the final message and cancelled status (but the RPC is
// already cancelled at this point. So we expect the operation to fail)
srv_stream.Finish(send_response, Status::CANCELLED, tag(9));
- Verifier(GetParam()).Expect(9, false).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(9, false).Verify(cq_.get());
// Client will see the cancellation
cli_stream->Finish(&recv_status, tag(10));
// TODO(sreek): The expectation here should be true. This is a bug (github
// issue #4972)
- Verifier(GetParam()).Expect(10, false).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(10, false).Verify(cq_.get());
EXPECT_FALSE(recv_status.ok());
EXPECT_EQ(::grpc::StatusCode::CANCELLED, recv_status.error_code());
}
@@ -1007,13 +1060,13 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
// Initiate the 'ResponseStream' call on the client
std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream(
stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1)));
- Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(1, true).Verify(cq_.get());
// On the server, request to be notified of 'ResponseStream' calls and
// receive the call just made by the client
srv_ctx.AsyncNotifyWhenDone(tag(11));
service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
cq_.get(), cq_.get(), tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
EXPECT_EQ(send_request.message(), recv_request.message());
bool expected_cq_result = true;
@@ -1022,7 +1075,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
srv_ctx.TryCancel();
- Verifier(GetParam()).Expect(11, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(11, true).Verify(cq_.get());
EXPECT_TRUE(srv_ctx.IsCancelled());
// We know for sure that all cq results will be false from this point
@@ -1032,7 +1085,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
std::thread* server_try_cancel_thd = NULL;
- auto verif = Verifier(GetParam());
+ auto verif = Verifier(GetParam().disable_blocking);
if (server_try_cancel == CANCEL_DURING_PROCESSING) {
server_try_cancel_thd =
@@ -1092,7 +1145,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
// Client attemts to read the three messages from the server
for (int tag_idx = 6; tag_idx <= 8; tag_idx++) {
cli_stream->Read(&recv_response, tag(tag_idx));
- Verifier(GetParam())
+ Verifier(GetParam().disable_blocking)
.Expect(tag_idx, expected_cq_result)
.Verify(cq_.get(), ignore_cq_result);
}
@@ -1103,11 +1156,11 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
// Server finishes the stream (but the RPC is already cancelled)
srv_stream.Finish(Status::CANCELLED, tag(9));
- Verifier(GetParam()).Expect(9, false).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(9, false).Verify(cq_.get());
// Client will see the cancellation
cli_stream->Finish(&recv_status, tag(10));
- Verifier(GetParam()).Expect(10, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(10, true).Verify(cq_.get());
EXPECT_FALSE(recv_status.ok());
EXPECT_EQ(::grpc::StatusCode::CANCELLED, recv_status.error_code());
}
@@ -1142,19 +1195,19 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
// Initiate the call from the client side
std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>>
cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1)));
- Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(1, true).Verify(cq_.get());
// On the server, request to be notified of the 'BidiStream' call and
// receive the call just made by the client
srv_ctx.AsyncNotifyWhenDone(tag(11));
service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
tag(2));
- Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
// Client sends the first and the only message
send_request.set_message("Ping");
cli_stream->Write(send_request, tag(3));
- Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(3, true).Verify(cq_.get());
bool expected_cq_result = true;
bool ignore_cq_result = false;
@@ -1162,7 +1215,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
srv_ctx.TryCancel();
- Verifier(GetParam()).Expect(11, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(11, true).Verify(cq_.get());
EXPECT_TRUE(srv_ctx.IsCancelled());
// We know for sure that all cq results will be false from this point
@@ -1172,7 +1225,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
std::thread* server_try_cancel_thd = NULL;
- auto verif = Verifier(GetParam());
+ auto verif = Verifier(GetParam().disable_blocking);
if (server_try_cancel == CANCEL_DURING_PROCESSING) {
server_try_cancel_thd =
@@ -1272,10 +1325,10 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
// know that cq results are supposed to return false on server.
srv_stream.Finish(Status::CANCELLED, tag(9));
- Verifier(GetParam()).Expect(9, false).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(9, false).Verify(cq_.get());
cli_stream->Finish(&recv_status, tag(10));
- Verifier(GetParam()).Expect(10, true).Verify(cq_.get());
+ Verifier(GetParam().disable_blocking).Expect(10, true).Verify(cq_.get());
EXPECT_FALSE(recv_status.ok());
EXPECT_EQ(grpc::StatusCode::CANCELLED, recv_status.error_code());
}
@@ -1317,11 +1370,48 @@ TEST_P(AsyncEnd2endServerTryCancelTest, ServerBidiStreamingTryCancelAfter) {
TestBidiStreamingServerCancel(CANCEL_AFTER_PROCESSING);
}
+std::vector<TestScenario> CreateTestScenarios(bool test_disable_blocking,
+ bool test_secure,
+ int test_big_limit) {
+ std::vector<TestScenario> scenarios;
+ std::vector<grpc::string> credentials_types;
+ std::vector<grpc::string> messages;
+
+ credentials_types.push_back(kInsecureCredentialsType);
+ auto sec_list = GetSecureCredentialsTypeList();
+ for (auto sec = sec_list.begin(); sec != sec_list.end(); sec++) {
+ credentials_types.push_back(*sec);
+ }
+
+ messages.push_back("Hello");
+ for (int sz = 1; sz < test_big_limit; sz *= 2) {
+ grpc::string big_msg;
+ for (int i = 0; i < sz * 1024; i++) {
+ char c = 'a' + (i % 26);
+ big_msg += c;
+ }
+ messages.push_back(big_msg);
+ }
+
+ for (auto cred = credentials_types.begin(); cred != credentials_types.end();
+ ++cred) {
+ for (auto msg = messages.begin(); msg != messages.end(); msg++) {
+ scenarios.push_back(TestScenario(false, *cred, *msg));
+ if (test_disable_blocking) {
+ scenarios.push_back(TestScenario(true, *cred, *msg));
+ }
+ }
+ }
+ return scenarios;
+}
+
INSTANTIATE_TEST_CASE_P(AsyncEnd2end, AsyncEnd2endTest,
- ::testing::Values(false, true));
+ ::testing::ValuesIn(CreateTestScenarios(true, true,
+ 1024)));
INSTANTIATE_TEST_CASE_P(AsyncEnd2endServerTryCancel,
AsyncEnd2endServerTryCancelTest,
- ::testing::Values(false));
+ ::testing::ValuesIn(CreateTestScenarios(false, false,
+ 0)));
} // namespace
} // namespace testing
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 2583ceb819..04b2b453f9 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -83,6 +83,7 @@ static std::unordered_map<string, std::deque<int>> get_hosts_and_cores(
auto stub = WorkerService::NewStub(
CreateChannel(*it, InsecureChannelCredentials()));
grpc::ClientContext ctx;
+ ctx.set_fail_fast(false);
CoreRequest dummy;
CoreResponse cores;
grpc::Status s = stub->CoreCount(&ctx, dummy, &cores);
@@ -166,6 +167,7 @@ namespace runsc {
static ClientContext* AllocContext(list<ClientContext>* contexts) {
contexts->emplace_back();
auto context = &contexts->back();
+ context->set_fail_fast(false);
return context;
}
@@ -435,6 +437,7 @@ void RunQuit() {
CreateChannel(workers[i], InsecureChannelCredentials()));
Void dummy;
grpc::ClientContext ctx;
+ ctx.set_fail_fast(false);
GPR_ASSERT(stub->QuitWorker(&ctx, dummy, &dummy).ok());
}
}
diff --git a/test/distrib/csharp/DistribTest/DistribTest.csproj b/test/distrib/csharp/DistribTest/DistribTest.csproj
index 7605495f0f..1acb34d1b2 100644
--- a/test/distrib/csharp/DistribTest/DistribTest.csproj
+++ b/test/distrib/csharp/DistribTest/DistribTest.csproj
@@ -113,12 +113,12 @@
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
- <Import Project="..\packages\grpc.native.csharp.__GRPC_NUGET_VERSION__\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets" Condition="Exists('..\packages\grpc.native.csharp.__GRPC_NUGET_VERSION__\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets')" />
+ <Import Project="..\packages\Grpc.Core.__GRPC_NUGET_VERSION__\build\net45\Grpc.Core.targets" Condition="Exists('..\packages\Grpc.Core.__GRPC_NUGET_VERSION__\build\net45\Grpc.Core.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
- <Error Condition="!Exists('..\packages\grpc.native.csharp.__GRPC_NUGET_VERSION__\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.native.csharp.__GRPC_NUGET_VERSION__\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets'))" />
+ <Error Condition="!Exists('..\packages\Grpc.Core.__GRPC_NUGET_VERSION__\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Core.__GRPC_NUGET_VERSION__\build\net45\Grpc.Core.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
</Target>
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
@@ -129,4 +129,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/test/distrib/csharp/DistribTest/packages.config b/test/distrib/csharp/DistribTest/packages.config
index aca09f600c..69630193d0 100644
--- a/test/distrib/csharp/DistribTest/packages.config
+++ b/test/distrib/csharp/DistribTest/packages.config
@@ -6,11 +6,10 @@
<package id="Grpc" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
<package id="Grpc.Auth" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
<package id="Grpc.Core" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
- <package id="grpc.native.csharp" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
-</packages> \ No newline at end of file
+</packages>
diff --git a/test/distrib/python/run_distrib_test.sh b/test/distrib/python/run_distrib_test.sh
index 79893af8e5..6196e540c8 100755
--- a/test/distrib/python/run_distrib_test.sh
+++ b/test/distrib/python/run_distrib_test.sh
@@ -33,8 +33,8 @@ set -ex
cd $(dirname $0)
# Pick up the source dist archive whatever its version is
-SDIST_ARCHIVE=$EXTERNAL_GIT_ROOT/input_artifacts/grpcio-*.tar.gz
-BDIST_DIR="file://$EXTERNAL_GIT_ROOT/input_artifacts"
+BDIST_ARCHIVES=$EXTERNAL_GIT_ROOT/input_artifacts/grpcio-*.whl
+TOOLS_BDIST_ARCHIVES=$EXTERNAL_GIT_ROOT/input_artifacts/grpcio_tools-*.whl
if [ ! -f ${SDIST_ARCHIVE} ]
then
@@ -42,17 +42,22 @@ then
exit 1
fi
-PIP=pip2
-which $PIP || PIP=pip
PYTHON=python2
+PIP=pip2
which $PYTHON || PYTHON=python
+which $PIP || PIP=pip
# TODO(jtattermusch): this shouldn't be required
-$PIP install --upgrade six
+${PIP} install --upgrade six pip
-GRPC_PYTHON_BINARIES_REPOSITORY="${BDIST_DIR}" \
- $PIP install \
- ${SDIST_ARCHIVE}
+# At least one of the bdist packages has to succeed (whichever one matches the
+# test machine, anyway).
+for bdist in ${BDIST_ARCHIVES} ${TOOLS_BDIST_ARCHIVES}; do
+ ($PYTHON -m pip install $bdist) || true
+done
-$PYTHON distribtest.py
+# TODO(jtattermusch): add a .proto file to the distribtest, generate python
+# code from it and then use the generated code from distribtest.py
+$PYTHON -m grpc.protoc.compiler
+$PYTHON distribtest.py
diff --git a/third_party/objective_c/Cronet/cronet_c_for_grpc.h b/third_party/objective_c/Cronet/cronet_c_for_grpc.h
new file mode 100644
index 0000000000..15a511aebd
--- /dev/null
+++ b/third_party/objective_c/Cronet/cronet_c_for_grpc.h
@@ -0,0 +1,202 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CRONET_IOS_CRONET_C_FOR_GRPC_H_
+#define COMPONENTS_CRONET_IOS_CRONET_C_FOR_GRPC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+/* Cronet Engine API. */
+
+/* Opaque object representing Cronet Engine. Created and configured outside
+ * of this API to facilitate sharing with other components */
+typedef struct cronet_engine { void* obj; } cronet_engine;
+
+void cronet_engine_add_quic_hint(cronet_engine* engine,
+ const char* host,
+ int port,
+ int alternate_port);
+
+/* Cronet Bidirectional Stream API */
+
+/* Opaque object representing Cronet Bidirectional Stream. */
+typedef struct cronet_bidirectional_stream {
+ void* obj;
+ void* annotation;
+} cronet_bidirectional_stream;
+
+/* A single request or response header element. */
+typedef struct cronet_bidirectional_stream_header {
+ const char* key;
+ const char* value;
+} cronet_bidirectional_stream_header;
+
+/* Array of request or response headers or trailers. */
+typedef struct cronet_bidirectional_stream_header_array {
+ size_t count;
+ size_t capacity;
+ cronet_bidirectional_stream_header* headers;
+} cronet_bidirectional_stream_header_array;
+
+/* Set of callbacks used to receive callbacks from bidirectional stream. */
+typedef struct cronet_bidirectional_stream_callback {
+ /* Invoked when request headers are sent. Indicates that stream has initiated
+ * the request. Consumer may call cronet_bidirectional_stream_write() to start
+ * writing data.
+ */
+ void (*on_request_headers_sent)(cronet_bidirectional_stream* stream);
+
+ /* Invoked when initial response headers are received.
+ * Consumer must call cronet_bidirectional_stream_read() to start reading.
+ * Consumer may call cronet_bidirectional_stream_write() to start writing or
+ * close the stream. Contents of |headers| is valid for duration of the call.
+ */
+ void (*on_response_headers_received)(
+ cronet_bidirectional_stream* stream,
+ const cronet_bidirectional_stream_header_array* headers,
+ const char* negotiated_protocol);
+
+ /* Invoked when data is read into the buffer passed to
+ * cronet_bidirectional_stream_read(). Only part of the buffer may be
+ * populated. To continue reading, call cronet_bidirectional_stream_read().
+ * It may be invoked after on_response_trailers_received()}, if there was
+ * pending read data before trailers were received.
+ *
+ * If count is 0, it means the remote side has signaled that it will send no
+ * more data; future calls to cronet_bidirectional_stream_read() will result
+ * in the on_data_read() callback or on_succeded() callback if
+ * cronet_bidirectional_stream_write() was invoked with end_of_stream set to
+ * true.
+ */
+ void (*on_read_completed)(cronet_bidirectional_stream* stream,
+ char* data,
+ int count);
+
+ /**
+ * Invoked when all data passed to cronet_bidirectional_stream_write() is
+ * sent.
+ * To continue writing, call cronet_bidirectional_stream_write().
+ */
+ void (*on_write_completed)(cronet_bidirectional_stream* stream,
+ const char* data);
+
+ /* Invoked when trailers are received before closing the stream. Only invoked
+ * when server sends trailers, which it may not. May be invoked while there is
+ * read data remaining in local buffer. Contents of |trailers| is valid for
+ * duration of the call.
+ */
+ void (*on_response_trailers_received)(
+ cronet_bidirectional_stream* stream,
+ const cronet_bidirectional_stream_header_array* trailers);
+
+ /**
+ * Invoked when there is no data to be read or written and the stream is
+ * closed successfully remotely and locally. Once invoked, no further callback
+ * methods will be invoked.
+ */
+ void (*on_succeded)(cronet_bidirectional_stream* stream);
+
+ /**
+ * Invoked if the stream failed for any reason after
+ * cronet_bidirectional_stream_start(). HTTP/2 error codes are
+ * mapped to chrome net error codes. Once invoked, no further callback methods
+ * will be invoked.
+ */
+ void (*on_failed)(cronet_bidirectional_stream* stream, int net_error);
+
+ /**
+ * Invoked if the stream was canceled via
+ * cronet_bidirectional_stream_cancel(). Once invoked, no further callback
+ * methods will be invoked.
+ */
+ void (*on_canceled)(cronet_bidirectional_stream* stream);
+} cronet_bidirectional_stream_callback;
+
+/* Create a new stream object that uses |engine| and |callback|. All stream
+ * tasks are performed asynchronously on the |engine| network thread. |callback|
+ * methods are invoked synchronously on the |engine| network thread, but must
+ * not run tasks on the current thread to prevent blocking networking operations
+ * and causing exceptions during shutdown. The |annotation| is stored in
+ * bidirectional stream for arbitrary use by application.
+ *
+ * Returned |cronet_bidirectional_stream*| is owned by the caller, and must be
+ * destroyed using |cronet_bidirectional_stream_destroy|.
+ *
+ * Both |calback| and |engine| must remain valid until stream is destroyed.
+ */
+cronet_bidirectional_stream* cronet_bidirectional_stream_create(
+ cronet_engine* engine,
+ void* annotation,
+ cronet_bidirectional_stream_callback* callback);
+
+/* TBD: The following methods return int. Should it be a custom type? */
+
+/* Destroy stream object. Destroy could be called from any thread, including
+ * network thread, but is posted, so |stream| is valid until calling task is
+ * complete.
+ */
+int cronet_bidirectional_stream_destroy(cronet_bidirectional_stream* stream);
+
+/* Start the stream by sending request to |url| using |method| and |headers|. If
+ * |end_of_stream| is true, then no data is expected to be written.
+ */
+int cronet_bidirectional_stream_start(
+ cronet_bidirectional_stream* stream,
+ const char* url,
+ int priority,
+ const char* method,
+ const cronet_bidirectional_stream_header_array* headers,
+ bool end_of_stream);
+
+/* Read response data into |buffer| of |capacity| length. Must only be called at
+ * most once in response to each invocation of the
+ * on_response_headers_received() and on_read_completed() methods of the
+ * cronet_bidirectional_stream_callback.
+ * Each call will result in an invocation of one of the callback's
+ * on_read_completed method if data is read, its on_succeeded() method if
+ * the stream is closed, or its on_failed() method if there's an error.
+ */
+int cronet_bidirectional_stream_read(cronet_bidirectional_stream* stream,
+ char* buffer,
+ int capacity);
+
+/* Read response data into |buffer| of |capacity| length. Must only be called at
+ * most once in response to each invocation of the
+ * on_response_headers_received() and on_read_completed() methods of the
+ * cronet_bidirectional_stream_callback.
+ * Each call will result in an invocation of one of the callback's
+ * on_read_completed method if data is read, its on_succeeded() method if
+ * the stream is closed, or its on_failed() method if there's an error.
+ */
+int cronet_bidirectional_stream_write(cronet_bidirectional_stream* stream,
+ const char* buffer,
+ int count,
+ bool end_of_stream);
+
+/* Cancels the stream. Can be called at any time after
+ * cronet_bidirectional_stream_start(). The on_canceled() method of
+ * cronet_bidirectional_stream_callback will be invoked when cancelation
+ * is complete and no further callback methods will be invoked. If the
+ * stream has completed or has not started, calling
+ * cronet_bidirectional_stream_cancel() has no effect and on_canceled() will not
+ * be invoked. At most one callback method may be invoked after
+ * cronet_bidirectional_stream_cancel() has completed.
+ */
+int cronet_bidirectional_stream_cancel(cronet_bidirectional_stream* stream);
+
+/* Returns true if the |stream| was successfully started and is now done
+ * (succeeded, canceled, or failed).
+ * Returns false if the |stream| stream is not yet started or is in progress.
+ */
+bool cronet_bidirectional_stream_is_done(cronet_bidirectional_stream* stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COMPONENTS_CRONET_IOS_CRONET_C_FOR_GRPC_H_
diff --git a/tools/buildgen/plugins/list_api.py b/tools/buildgen/plugins/list_api.py
index ff937a0ab8..1fc4f4123c 100755
--- a/tools/buildgen/plugins/list_api.py
+++ b/tools/buildgen/plugins/list_api.py
@@ -64,12 +64,13 @@ def headers_under(directory):
def mako_plugin(dictionary):
apis = []
+ headers = []
-# for lib in dictionary['libs']:
-# if lib['name'] == 'grpc':
-# apis.extend(list_c_apis(lib['public_headers']))
- apis.extend(list_c_apis(sorted(headers_under('include/grpc'))))
+ for lib in dictionary['libs']:
+ if lib['name'] in ['grpc', 'gpr']:
+ headers.extend(lib['public_headers'])
+ apis.extend(list_c_apis(sorted(set(headers))))
dictionary['c_apis'] = apis
diff --git a/tools/distrib/check_include_guards.py b/tools/distrib/check_include_guards.py
index 897a899e7e..6c160c64b6 100755
--- a/tools/distrib/check_include_guards.py
+++ b/tools/distrib/check_include_guards.py
@@ -31,6 +31,7 @@
import argparse
import os
+import os.path
import re
import sys
import subprocess
@@ -187,6 +188,8 @@ filename_list = []
try:
filename_list = subprocess.check_output(FILE_LIST_COMMAND,
shell=True).splitlines()
+ # Filter out non-existent files (ie, file removed or renamed)
+ filename_list = (f for f in filename_list if os.path.isfile(f))
except subprocess.CalledProcessError:
sys.exit(0)
diff --git a/tools/distrib/python/bazel_deps.sh b/tools/distrib/python/bazel_deps.sh
new file mode 100755
index 0000000000..de3ee07970
--- /dev/null
+++ b/tools/distrib/python/bazel_deps.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# 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.
+
+cd $(dirname $0)/../../../
+
+# First check if bazel is installed on the machine. If it is, then we don't need
+# to invoke the docker bazel.
+if [ "bazel version" ]
+then
+ cd third_party/protobuf
+ bazel query 'deps('$1')'
+else
+ docker build -t bazel `realpath ./tools/dockerfile/bazel/`
+ docker run -v "`realpath .`:/src/grpc/" \
+ -w /src/grpc/third_party/protobuf \
+ bazel \
+ bazel query 'deps('$1')'
+fi
diff --git a/tools/distrib/python/check_grpcio_tools.py b/tools/distrib/python/check_grpcio_tools.py
new file mode 100755
index 0000000000..baf2ff4eff
--- /dev/null
+++ b/tools/distrib/python/check_grpcio_tools.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# 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.
+
+import cStringIO
+
+import make_grpcio_tools as make
+
+OUT_OF_DATE_MESSAGE = """file {} is out of date
+
+Have you called tools/distrib/python/make_grpcio_tools.py since upgrading protobuf?"""
+
+check_protoc_lib_deps_content = make.get_deps(make.BAZEL_DEPS_PROTOC_LIB_QUERY)
+
+with open(make.GRPC_PYTHON_PROTOC_LIB_DEPS, 'r') as protoc_lib_deps_file:
+ if protoc_lib_deps_file.read() != check_protoc_lib_deps_content:
+ print(OUT_OF_DATE_MESSAGE.format(make.GRPC_PYTHON_PROTOC_LIB_DEPS))
+ raise SystemExit(1)
diff --git a/tools/distrib/python/grpcio_tools/.gitignore b/tools/distrib/python/grpcio_tools/.gitignore
new file mode 100644
index 0000000000..979704d970
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/.gitignore
@@ -0,0 +1,7 @@
+build/
+protobuf/
+grpc_plugin/
+grpc_root/
+*.c
+*.cpp
+*.egg-info
diff --git a/tools/distrib/python/grpcio_tools/MANIFEST.in b/tools/distrib/python/grpcio_tools/MANIFEST.in
new file mode 100644
index 0000000000..e6ab312f09
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/MANIFEST.in
@@ -0,0 +1,5 @@
+include protoc_deps.py
+include protoc_lib_deps.py
+graft grpc
+graft grpc_root
+graft third_party
diff --git a/tools/distrib/python/grpcio_tools/grpc/__init__.py b/tools/distrib/python/grpcio_tools/grpc/__init__.py
new file mode 100644
index 0000000000..70ac5edd48
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/grpc/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+__import__('pkg_resources').declare_namespace(__name__)
diff --git a/tools/distrib/python/grpcio_tools/grpc/protoc/__init__.py b/tools/distrib/python/grpcio_tools/grpc/protoc/__init__.py
new file mode 100644
index 0000000000..d5ad73a74a
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/grpc/protoc/__init__.py
@@ -0,0 +1,29 @@
+# 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.
+
diff --git a/tools/distrib/python/grpcio_tools/grpc/protoc/compiler.py b/tools/distrib/python/grpcio_tools/grpc/protoc/compiler.py
new file mode 100644
index 0000000000..caafc544b2
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/grpc/protoc/compiler.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# 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.
+
+import sys
+
+from grpc.protoc import protoc_compiler
+
+
+if __name__ == '__main__':
+ protoc_compiler.run_main(sys.argv)
diff --git a/tools/distrib/python/grpcio_tools/grpc/protoc/main.cc b/tools/distrib/python/grpcio_tools/grpc/protoc/main.cc
new file mode 100644
index 0000000000..c9936a3a6b
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/grpc/protoc/main.cc
@@ -0,0 +1,54 @@
+// 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.
+
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/python/python_generator.h>
+
+#include "src/compiler/python_generator.h"
+
+#include "grpc/protoc/main.h"
+
+int protoc_main(int argc, char* argv[]) {
+ google::protobuf::compiler::CommandLineInterface cli;
+ cli.AllowPlugins("protoc-");
+
+ // Proto2 Python
+ google::protobuf::compiler::python::Generator py_generator;
+ cli.RegisterGenerator("--python_out", &py_generator,
+ "Generate Python source file.");
+
+ // gRPC Python
+ grpc_python_generator::GeneratorConfiguration grpc_py_config;
+ grpc_py_config.beta_package_root = "grpc.beta";
+ grpc_python_generator::PythonGrpcGenerator grpc_py_generator(grpc_py_config);
+ cli.RegisterGenerator("--grpc_python_out", &grpc_py_generator,
+ "Generate Python source file.");
+
+ return cli.Run(argc, argv);
+}
diff --git a/tools/distrib/python/grpcio_tools/grpc/protoc/main.h b/tools/distrib/python/grpcio_tools/grpc/protoc/main.h
new file mode 100644
index 0000000000..ea2860ff02
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/grpc/protoc/main.h
@@ -0,0 +1,33 @@
+// 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.
+
+
+// We declare `protoc_main` here since we want access to it from Cython as an
+// extern but *without* triggering a dllimport declspec when on Windows.
+int protoc_main(int argc, char *argv[]);
diff --git a/tools/distrib/python/grpcio_tools/grpc/protoc/protoc_compiler.pyx b/tools/distrib/python/grpcio_tools/grpc/protoc/protoc_compiler.pyx
new file mode 100644
index 0000000000..af15f3db30
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/grpc/protoc/protoc_compiler.pyx
@@ -0,0 +1,39 @@
+# 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.
+
+from libc cimport stdlib
+
+cdef extern from "grpc/protoc/main.h":
+ int protoc_main(int argc, char *argv[])
+
+def run_main(list args not None):
+ cdef char **argv = <char **>stdlib.malloc(len(args)*sizeof(char *))
+ for i in range(len(args)):
+ argv[i] = args[i]
+ return protoc_main(len(args), argv)
diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
new file mode 100644
index 0000000000..1267d0e45d
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -0,0 +1,32 @@
+# 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.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
+
+VERSION='0.15.0.dev0'
diff --git a/tools/distrib/python/grpcio_tools/protoc_lib_deps.py b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
new file mode 100644
index 0000000000..9f31172170
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
@@ -0,0 +1,32 @@
+
+# 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.
+
+# AUTO-GENERATED BY make_grpcio_tools.py!
+CC_FILES=['google/protobuf/compiler/zip_writer.cc', 'google/protobuf/compiler/subprocess.cc', 'google/protobuf/compiler/ruby/ruby_generator.cc', 'google/protobuf/compiler/python/python_generator.cc', 'google/protobuf/compiler/plugin.pb.cc', 'google/protobuf/compiler/plugin.cc', 'google/protobuf/compiler/objectivec/objectivec_primitive_field.cc', 'google/protobuf/compiler/objectivec/objectivec_oneof.cc', 'google/protobuf/compiler/objectivec/objectivec_message_field.cc', 'google/protobuf/compiler/objectivec/objectivec_message.cc', 'google/protobuf/compiler/objectivec/objectivec_map_field.cc', 'google/protobuf/compiler/objectivec/objectivec_helpers.cc', 'google/protobuf/compiler/objectivec/objectivec_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_file.cc', 'google/protobuf/compiler/objectivec/objectivec_field.cc', 'google/protobuf/compiler/objectivec/objectivec_extension.cc', 'google/protobuf/compiler/objectivec/objectivec_enum_field.cc', 'google/protobuf/compiler/objectivec/objectivec_enum.cc', 'google/protobuf/compiler/js/js_generator.cc', 'google/protobuf/compiler/javanano/javanano_primitive_field.cc', 'google/protobuf/compiler/javanano/javanano_message_field.cc', 'google/protobuf/compiler/javanano/javanano_message.cc', 'google/protobuf/compiler/javanano/javanano_map_field.cc', 'google/protobuf/compiler/javanano/javanano_helpers.cc', 'google/protobuf/compiler/javanano/javanano_generator.cc', 'google/protobuf/compiler/javanano/javanano_file.cc', 'google/protobuf/compiler/javanano/javanano_field.cc', 'google/protobuf/compiler/javanano/javanano_extension.cc', 'google/protobuf/compiler/javanano/javanano_enum_field.cc', 'google/protobuf/compiler/javanano/javanano_enum.cc', 'google/protobuf/compiler/java/java_string_field_lite.cc', 'google/protobuf/compiler/java/java_string_field.cc', 'google/protobuf/compiler/java/java_shared_code_generator.cc', 'google/protobuf/compiler/java/java_service.cc', 'google/protobuf/compiler/java/java_primitive_field_lite.cc', 'google/protobuf/compiler/java/java_primitive_field.cc', 'google/protobuf/compiler/java/java_name_resolver.cc', 'google/protobuf/compiler/java/java_message_lite.cc', 'google/protobuf/compiler/java/java_message_field_lite.cc', 'google/protobuf/compiler/java/java_message_field.cc', 'google/protobuf/compiler/java/java_message_builder_lite.cc', 'google/protobuf/compiler/java/java_message_builder.cc', 'google/protobuf/compiler/java/java_message.cc', 'google/protobuf/compiler/java/java_map_field_lite.cc', 'google/protobuf/compiler/java/java_map_field.cc', 'google/protobuf/compiler/java/java_lazy_message_field_lite.cc', 'google/protobuf/compiler/java/java_lazy_message_field.cc', 'google/protobuf/compiler/java/java_helpers.cc', 'google/protobuf/compiler/java/java_generator_factory.cc', 'google/protobuf/compiler/java/java_generator.cc', 'google/protobuf/compiler/java/java_file.cc', 'google/protobuf/compiler/java/java_field.cc', 'google/protobuf/compiler/java/java_extension.cc', 'google/protobuf/compiler/java/java_enum_lite.cc', 'google/protobuf/compiler/java/java_enum_field_lite.cc', 'google/protobuf/compiler/java/java_enum_field.cc', 'google/protobuf/compiler/java/java_enum.cc', 'google/protobuf/compiler/java/java_doc_comment.cc', 'google/protobuf/compiler/java/java_context.cc', 'google/protobuf/compiler/csharp/csharp_wrapper_field.cc', 'google/protobuf/compiler/csharp/csharp_source_generator_base.cc', 'google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_message_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_reflection_class.cc', 'google/protobuf/compiler/csharp/csharp_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_message_field.cc', 'google/protobuf/compiler/csharp/csharp_message.cc', 'google/protobuf/compiler/csharp/csharp_map_field.cc', 'google/protobuf/compiler/csharp/csharp_helpers.cc', 'google/protobuf/compiler/csharp/csharp_generator.cc', 'google/protobuf/compiler/csharp/csharp_field_base.cc', 'google/protobuf/compiler/csharp/csharp_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_enum.cc', 'google/protobuf/compiler/csharp/csharp_doc_comment.cc', 'google/protobuf/compiler/cpp/cpp_string_field.cc', 'google/protobuf/compiler/cpp/cpp_service.cc', 'google/protobuf/compiler/cpp/cpp_primitive_field.cc', 'google/protobuf/compiler/cpp/cpp_message_field.cc', 'google/protobuf/compiler/cpp/cpp_message.cc', 'google/protobuf/compiler/cpp/cpp_map_field.cc', 'google/protobuf/compiler/cpp/cpp_helpers.cc', 'google/protobuf/compiler/cpp/cpp_generator.cc', 'google/protobuf/compiler/cpp/cpp_file.cc', 'google/protobuf/compiler/cpp/cpp_field.cc', 'google/protobuf/compiler/cpp/cpp_extension.cc', 'google/protobuf/compiler/cpp/cpp_enum_field.cc', 'google/protobuf/compiler/cpp/cpp_enum.cc', 'google/protobuf/compiler/command_line_interface.cc', 'google/protobuf/compiler/code_generator.cc', 'google/protobuf/wrappers.pb.cc', 'google/protobuf/wire_format.cc', 'google/protobuf/util/type_resolver_util.cc', 'google/protobuf/util/time_util.cc', 'google/protobuf/util/message_differencer.cc', 'google/protobuf/util/json_util.cc', 'google/protobuf/util/internal/utility.cc', 'google/protobuf/util/internal/type_info_test_helper.cc', 'google/protobuf/util/internal/type_info.cc', 'google/protobuf/util/internal/protostream_objectwriter.cc', 'google/protobuf/util/internal/protostream_objectsource.cc', 'google/protobuf/util/internal/proto_writer.cc', 'google/protobuf/util/internal/object_writer.cc', 'google/protobuf/util/internal/json_stream_parser.cc', 'google/protobuf/util/internal/json_objectwriter.cc', 'google/protobuf/util/internal/json_escaping.cc', 'google/protobuf/util/internal/field_mask_utility.cc', 'google/protobuf/util/internal/error_listener.cc', 'google/protobuf/util/internal/default_value_objectwriter.cc', 'google/protobuf/util/internal/datapiece.cc', 'google/protobuf/util/field_mask_util.cc', 'google/protobuf/util/field_comparator.cc', 'google/protobuf/unknown_field_set.cc', 'google/protobuf/type.pb.cc', 'google/protobuf/timestamp.pb.cc', 'google/protobuf/text_format.cc', 'google/protobuf/stubs/substitute.cc', 'google/protobuf/stubs/mathlimits.cc', 'google/protobuf/struct.pb.cc', 'google/protobuf/source_context.pb.cc', 'google/protobuf/service.cc', 'google/protobuf/reflection_ops.cc', 'google/protobuf/message.cc', 'google/protobuf/map_field.cc', 'google/protobuf/io/zero_copy_stream_impl.cc', 'google/protobuf/io/tokenizer.cc', 'google/protobuf/io/strtod.cc', 'google/protobuf/io/printer.cc', 'google/protobuf/io/gzip_stream.cc', 'google/protobuf/generated_message_reflection.cc', 'google/protobuf/field_mask.pb.cc', 'google/protobuf/extension_set_heavy.cc', 'google/protobuf/empty.pb.cc', 'google/protobuf/dynamic_message.cc', 'google/protobuf/duration.pb.cc', 'google/protobuf/descriptor_database.cc', 'google/protobuf/descriptor.pb.cc', 'google/protobuf/descriptor.cc', 'google/protobuf/compiler/parser.cc', 'google/protobuf/compiler/importer.cc', 'google/protobuf/api.pb.cc', 'google/protobuf/any.pb.cc', 'google/protobuf/any.cc', 'google/protobuf/wire_format_lite.cc', 'google/protobuf/stubs/time.cc', 'google/protobuf/stubs/strutil.cc', 'google/protobuf/stubs/structurally_valid.cc', 'google/protobuf/stubs/stringprintf.cc', 'google/protobuf/stubs/stringpiece.cc', 'google/protobuf/stubs/statusor.cc', 'google/protobuf/stubs/status.cc', 'google/protobuf/stubs/once.cc', 'google/protobuf/stubs/int128.cc', 'google/protobuf/stubs/common.cc', 'google/protobuf/stubs/bytestream.cc', 'google/protobuf/stubs/atomicops_internals_x86_msvc.cc', 'google/protobuf/stubs/atomicops_internals_x86_gcc.cc', 'google/protobuf/repeated_field.cc', 'google/protobuf/message_lite.cc', 'google/protobuf/io/zero_copy_stream_impl_lite.cc', 'google/protobuf/io/zero_copy_stream.cc', 'google/protobuf/io/coded_stream.cc', 'google/protobuf/generated_message_util.cc', 'google/protobuf/extension_set.cc', 'google/protobuf/arenastring.cc', 'google/protobuf/arena.cc']
diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py
new file mode 100644
index 0000000000..0281c01796
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/setup.py
@@ -0,0 +1,84 @@
+# 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.
+
+from distutils import extension
+import os
+import os.path
+import sys
+
+import setuptools
+from setuptools.command import build_ext
+
+# TODO(atash) add flag to disable Cython use
+
+os.chdir(os.path.dirname(os.path.abspath(__file__)))
+sys.path.insert(0, os.path.abspath('.'))
+
+import protoc_lib_deps
+import grpc_version
+
+def protoc_ext_module():
+ plugin_sources = [
+ 'grpc/protoc/main.cc',
+ 'grpc_root/src/compiler/python_generator.cc'] + [
+ os.path.join('third_party/protobuf/src', cc_file)
+ for cc_file in protoc_lib_deps.CC_FILES]
+ plugin_ext = extension.Extension(
+ name='grpc.protoc.protoc_compiler',
+ sources=['grpc/protoc/protoc_compiler.pyx'] + plugin_sources,
+ include_dirs=[
+ '.',
+ 'grpc_root',
+ 'grpc_root/include',
+ 'third_party/protobuf/src',
+ ],
+ language='c++',
+ define_macros=[('HAVE_PTHREAD', 1)],
+ extra_compile_args=['-lpthread', '-frtti', '-std=c++11'],
+ )
+ return plugin_ext
+
+def maybe_cythonize(exts):
+ from Cython import Build
+ return Build.cythonize(exts)
+
+setuptools.setup(
+ name='grpcio_tools',
+ version=grpc_version.VERSION,
+ license='',
+ ext_modules=maybe_cythonize([
+ protoc_ext_module(),
+ ]),
+ packages=setuptools.find_packages('.'),
+ # TODO(atash): Figure out why auditwheel doesn't like namespace packages.
+ #namespace_packages=['grpc'],
+ install_requires=[
+ 'protobuf>=3.0.0a3',
+ ],
+)
diff --git a/tools/distrib/python/make_grpcio_tools.py b/tools/distrib/python/make_grpcio_tools.py
new file mode 100755
index 0000000000..50fbdbb14c
--- /dev/null
+++ b/tools/distrib/python/make_grpcio_tools.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+
+# 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.
+
+import os
+import os.path
+import shutil
+import subprocess
+import sys
+import traceback
+
+DEPS_FILE_CONTENT="""
+# 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.
+
+# AUTO-GENERATED BY make_grpcio_tools.py!
+CC_FILES={}
+"""
+
+# Bazel query result prefix for expected source files in protobuf.
+PROTOBUF_CC_PREFIX = '//:src/'
+
+GRPC_ROOT = os.path.abspath(
+ os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ '..', '..', '..'))
+
+GRPC_PYTHON_ROOT = os.path.join(GRPC_ROOT, 'tools/distrib/python/grpcio_tools')
+
+GRPC_PROTOBUF = os.path.join(GRPC_ROOT, 'third_party/protobuf/src')
+GRPC_PROTOC_PLUGINS = os.path.join(GRPC_ROOT, 'src/compiler')
+GRPC_PYTHON_PROTOBUF = os.path.join(GRPC_PYTHON_ROOT,
+ 'third_party/protobuf/src')
+GRPC_PYTHON_PROTOC_PLUGINS = os.path.join(GRPC_PYTHON_ROOT,
+ 'grpc_root/src/compiler')
+GRPC_PYTHON_PROTOC_LIB_DEPS = os.path.join(GRPC_PYTHON_ROOT,
+ 'protoc_lib_deps.py')
+
+GRPC_INCLUDE = os.path.join(GRPC_ROOT, 'include')
+GRPC_PYTHON_INCLUDE = os.path.join(GRPC_PYTHON_ROOT, 'grpc_root/include')
+
+BAZEL_DEPS = os.path.join(GRPC_ROOT, 'tools/distrib/python/bazel_deps.sh')
+BAZEL_DEPS_PROTOC_LIB_QUERY = '//:protoc_lib'
+
+
+def get_deps(query):
+ """Write the result of the bazel query `query` against protobuf to
+ `out_file`."""
+ output = subprocess.check_output([BAZEL_DEPS, query])
+ output = output.splitlines()
+ cc_files = [
+ name for name in output
+ if name.endswith('.cc') and name.startswith(PROTOBUF_CC_PREFIX)]
+ cc_files = [cc_file[len(PROTOBUF_CC_PREFIX):] for cc_file in cc_files]
+ deps_file_content = DEPS_FILE_CONTENT.format(cc_files)
+ return deps_file_content
+
+
+def main():
+ os.chdir(GRPC_ROOT)
+
+ for tree in [GRPC_PYTHON_PROTOBUF,
+ GRPC_PYTHON_PROTOC_PLUGINS,
+ GRPC_PYTHON_INCLUDE]:
+ try:
+ shutil.rmtree(tree)
+ except Exception as _:
+ pass
+ shutil.copytree(GRPC_PROTOBUF, GRPC_PYTHON_PROTOBUF)
+ shutil.copytree(GRPC_PROTOC_PLUGINS, GRPC_PYTHON_PROTOC_PLUGINS)
+ shutil.copytree(GRPC_INCLUDE, GRPC_PYTHON_INCLUDE)
+
+ try:
+ protoc_lib_deps_content = get_deps(BAZEL_DEPS_PROTOC_LIB_QUERY)
+ except Exception as error:
+ # We allow this script to succeed even if we couldn't get the dependencies,
+ # as then we can assume that even without a successful bazel run the
+ # dependencies currently in source control are 'good enough'.
+ sys.stderr.write("Got non-fatal error:\n")
+ traceback.print_exc(file=sys.stderr)
+ return
+ # If we successfully got the dependencies, truncate and rewrite the deps file.
+ with open(GRPC_PYTHON_PROTOC_LIB_DEPS, 'w') as deps_file:
+ deps_file.write(protoc_lib_deps_content)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/tools/dockerfile/bazel/Dockerfile b/tools/dockerfile/bazel/Dockerfile
new file mode 100644
index 0000000000..2a80a4d4d5
--- /dev/null
+++ b/tools/dockerfile/bazel/Dockerfile
@@ -0,0 +1,52 @@
+# 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.
+
+FROM ubuntu:wily
+RUN apt-get update
+RUN apt-get -y install software-properties-common python-software-properties
+RUN add-apt-repository ppa:webupd8team/java
+RUN apt-get update
+RUN apt-get -y install \
+ vim \
+ wget \
+ openjdk-8-jdk \
+ pkg-config \
+ zip \
+ g++ \
+ zlib1g-dev \
+ unzip \
+ git
+
+RUN git clone https://github.com/bazelbuild/bazel.git /bazel
+RUN cd /bazel && ./compile.sh
+
+RUN ln -s /bazel/output/bazel /bin/
+
+# ensure the installation has been extracted
+RUN bazel
diff --git a/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
index d048b725c8..4ae4ebdb06 100644
--- a/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
@@ -31,12 +31,15 @@
FROM debian:jessie
+RUN apt-get update && apt-get install debian-keyring && apt-key update
+
# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
+RUN apt-get update && apt-key update && apt-get install -y \
autoconf \
autotools-dev \
build-essential \
bzip2 \
+ clang \
curl \
gcc \
gcc-multilib \
diff --git a/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
index 46bc9f8f52..9c2fd52eee 100644
--- a/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
@@ -31,12 +31,15 @@
FROM 32bit/debian:jessie
+RUN apt-get update && apt-get install debian-keyring && apt-key update
+
# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
+RUN apt-get update && apt-key update && apt-get install -y \
autoconf \
autotools-dev \
build-essential \
bzip2 \
+ clang \
curl \
gcc \
gcc-multilib \
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile
new file mode 100644
index 0000000000..3e31a2b623
--- /dev/null
+++ b/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile
@@ -0,0 +1,43 @@
+# 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.
+
+# Docker file for building gRPC manylinux Python artifacts.
+
+FROM quay.io/pypa/manylinux1_x86_64
+
+# Update the package manager
+RUN yum update -y
+
+###################################
+# Install Python build requirements
+RUN /opt/python/cp27-cp27m/bin/pip install cython
+RUN /opt/python/cp27-cp27mu/bin/pip install cython
+RUN /opt/python/cp34-cp34m/bin/pip install cython
+RUN /opt/python/cp35-cp35m/bin/pip install cython
+
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile
new file mode 100644
index 0000000000..5fe62c28b7
--- /dev/null
+++ b/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile
@@ -0,0 +1,43 @@
+# 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.
+
+# Docker file for building gRPC manylinux Python artifacts.
+
+FROM quay.io/pypa/manylinux1_i686
+
+# Update the package manager
+RUN yum update -y
+
+###################################
+# Install Python build requirements
+RUN /opt/python/cp27-cp27m/bin/pip install cython
+RUN /opt/python/cp27-cp27mu/bin/pip install cython
+RUN /opt/python/cp34-cp34m/bin/pip install cython
+RUN /opt/python/cp35-cp35m/bin/pip install cython
+
diff --git a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
index 64314f8864..2a8d35a5dc 100644
--- a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
@@ -69,8 +69,11 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Install nvm
RUN touch .profile
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+# Install all versions of node that we want to test
RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
-
+RUN /bin/bash -l -c "nvm install 4 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm alias default 4"
# Prepare ccache
RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
index b99fd444ee..976f55d9ab 100755
--- a/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
@@ -38,8 +38,6 @@ git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
-nvm use 0.12
-nvm alias default 0.12 # prevent the need to run 'nvm use' in every shell
# build Node interop client & server
npm install -g node-gyp
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile
new file mode 100644
index 0000000000..823fe948fb
--- /dev/null
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile
@@ -0,0 +1,101 @@
+# 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.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+ autoconf \
+ autotools-dev \
+ build-essential \
+ bzip2 \
+ ccache \
+ curl \
+ gcc \
+ gcc-multilib \
+ git \
+ golang \
+ gyp \
+ lcov \
+ libc6 \
+ libc6-dbg \
+ libc6-dev \
+ libgtest-dev \
+ libtool \
+ make \
+ perl \
+ strace \
+ python-dev \
+ python-setuptools \
+ python-yaml \
+ telnet \
+ unzip \
+ wget \
+ zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+# Google Cloud platform API libraries
+RUN apt-get update && apt-get install -y python-pip && apt-get clean
+RUN pip install --upgrade google-api-python-client
+
+
+#================
+# C# dependencies
+
+# Update to a newer version of mono
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+
+# Install dependencies
+RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
+ mono-devel \
+ ca-certificates-mono \
+ nuget \
+ && apt-get clean
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_csharp/build_interop_stress.sh b/tools/dockerfile/stress_test/grpc_interop_stress_csharp/build_interop_stress.sh
new file mode 100755
index 0000000000..1f4bf893cc
--- /dev/null
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_csharp/build_interop_stress.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# 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.
+#
+# Builds C# interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
+
+# Copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc
+
+# Build C++ metrics client (to query the metrics from csharp stress client)
+make metrics_client -j
+
+# Build C# interop client & server
+tools/run_tests/run_tests.py -l csharp -c dbg --build_only
+
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile
index f70add4e31..4fd7cc29a3 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile
@@ -69,8 +69,11 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Install nvm
RUN touch .profile
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+# Install all versions of node that we want to test
RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
-
+RUN /bin/bash -l -c "nvm install 4 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm alias default 4"
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
RUN pip install --upgrade google-api-python-client
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_node/build_interop_stress.sh b/tools/dockerfile/stress_test/grpc_interop_stress_node/build_interop_stress.sh
index b99fd444ee..976f55d9ab 100755
--- a/tools/dockerfile/stress_test/grpc_interop_stress_node/build_interop_stress.sh
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_node/build_interop_stress.sh
@@ -38,8 +38,6 @@ git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
-nvm use 0.12
-nvm alias default 0.12 # prevent the need to run 'nvm use' in every shell
# build Node interop client & server
npm install -g node-gyp
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile
new file mode 100644
index 0000000000..36b54ddafe
--- /dev/null
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile
@@ -0,0 +1,99 @@
+# 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.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+ autoconf \
+ autotools-dev \
+ build-essential \
+ bzip2 \
+ ccache \
+ curl \
+ gcc \
+ gcc-multilib \
+ git \
+ golang \
+ gyp \
+ lcov \
+ libc6 \
+ libc6-dbg \
+ libc6-dev \
+ libgtest-dev \
+ libtool \
+ make \
+ perl \
+ strace \
+ python-dev \
+ python-setuptools \
+ python-yaml \
+ telnet \
+ unzip \
+ wget \
+ zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+# Google Cloud platform API libraries
+RUN apt-get update && apt-get install -y python-pip && apt-get clean
+RUN pip install --upgrade google-api-python-client
+
+
+#==================
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_ruby/build_interop_stress.sh b/tools/dockerfile/stress_test/grpc_interop_stress_ruby/build_interop_stress.sh
new file mode 100755
index 0000000000..1b7567d87a
--- /dev/null
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_ruby/build_interop_stress.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# 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.
+#
+# Builds Ruby interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
+
+# Copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc
+rvm --default use ruby-2.1
+
+# Build Ruby interop client and server
+(cd src/ruby && gem update bundler && bundle && rake compile)
+
+# Build c++ metrics client to query the metrics from ruby stress client
+make metrics_client -j
+
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
index 71ebf2bf71..5c3f77405e 100644
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -90,8 +90,11 @@ RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev c
# Install nvm
RUN touch .profile
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+# Install all versions of node that we want to test
RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
-
+RUN /bin/bash -l -c "nvm install 4 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm alias default 4"
#=================
# PHP dependencies
diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
index 64314f8864..2a8d35a5dc 100644
--- a/tools/dockerfile/test/node_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -69,8 +69,11 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Install nvm
RUN touch .profile
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+# Install all versions of node that we want to test
RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
-
+RUN /bin/bash -l -c "nvm install 4 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache"
+RUN /bin/bash -l -c "nvm alias default 4"
# Prepare ccache
RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
index 3146a922b7..43b2a0c3d9 100644
--- a/tools/dockerfile/test/sanity/Dockerfile
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -75,6 +75,15 @@ RUN apt-get update && apt-get install -y \
python-lxml
RUN pip install simplejson mako
+#======================================
+# More sanity test dependencies (bazel)
+RUN echo "deb http://httpredir.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list
+RUN apt-get update
+RUN apt-get -t jessie-backports install -y openjdk-8-jdk
+RUN git clone https://github.com/bazelbuild/bazel.git /bazel
+RUN cd /bazel && ./compile.sh
+RUN ln -s /bazel/output/bazel /bin/
+
#===================
# Docker "inception"
# Note this is quite the ugly hack.
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 3fff7bcd50..798d68b018 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 0.14.0-dev
+PROJECT_NUMBER = 0.15.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -835,6 +835,7 @@ include/grpc++/impl/codegen/sync_no_cxx11.h \
include/grpc++/impl/codegen/sync_stream.h \
include/grpc++/impl/codegen/time.h \
include/grpc/impl/codegen/byte_buffer.h \
+include/grpc/impl/codegen/byte_buffer_reader.h \
include/grpc/impl/codegen/compression_types.h \
include/grpc/impl/codegen/connectivity_state.h \
include/grpc/impl/codegen/grpc_types.h \
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 56f51f61cb..ce1d6ac3c1 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 0.14.0-dev
+PROJECT_NUMBER = 0.15.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -835,6 +835,7 @@ include/grpc++/impl/codegen/sync_no_cxx11.h \
include/grpc++/impl/codegen/sync_stream.h \
include/grpc++/impl/codegen/time.h \
include/grpc/impl/codegen/byte_buffer.h \
+include/grpc/impl/codegen/byte_buffer_reader.h \
include/grpc/impl/codegen/compression_types.h \
include/grpc/impl/codegen/connectivity_state.h \
include/grpc/impl/codegen/grpc_types.h \
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index 034d9c6e6f..aabca410da 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 0.14.0-dev
+PROJECT_NUMBER = 0.15.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -766,6 +766,7 @@ include/grpc/compression.h \
include/grpc/grpc.h \
include/grpc/status.h \
include/grpc/impl/codegen/byte_buffer.h \
+include/grpc/impl/codegen/byte_buffer_reader.h \
include/grpc/impl/codegen/compression_types.h \
include/grpc/impl/codegen/connectivity_state.h \
include/grpc/impl/codegen/grpc_types.h \
@@ -785,6 +786,7 @@ include/grpc/impl/codegen/sync_generic.h \
include/grpc/impl/codegen/sync_posix.h \
include/grpc/impl/codegen/sync_win32.h \
include/grpc/impl/codegen/time.h \
+include/grpc/grpc_cronet.h \
include/grpc/grpc_security.h \
include/grpc/grpc_security_constants.h \
include/grpc/census.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 1b1453f7ea..3ffc6174ed 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 0.14.0-dev
+PROJECT_NUMBER = 0.15.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -766,6 +766,7 @@ include/grpc/compression.h \
include/grpc/grpc.h \
include/grpc/status.h \
include/grpc/impl/codegen/byte_buffer.h \
+include/grpc/impl/codegen/byte_buffer_reader.h \
include/grpc/impl/codegen/compression_types.h \
include/grpc/impl/codegen/connectivity_state.h \
include/grpc/impl/codegen/grpc_types.h \
@@ -785,6 +786,7 @@ include/grpc/impl/codegen/sync_generic.h \
include/grpc/impl/codegen/sync_posix.h \
include/grpc/impl/codegen/sync_win32.h \
include/grpc/impl/codegen/time.h \
+include/grpc/grpc_cronet.h \
include/grpc/grpc_security.h \
include/grpc/grpc_security_constants.h \
include/grpc/census.h \
@@ -912,6 +914,42 @@ src/core/ext/client_config/subchannel.h \
src/core/ext/client_config/subchannel_call_holder.h \
src/core/ext/client_config/subchannel_index.h \
src/core/ext/client_config/uri_parser.h \
+include/grpc/byte_buffer.h \
+include/grpc/grpc.h \
+include/grpc/impl/codegen/alloc.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_win32.h \
+include/grpc/impl/codegen/byte_buffer.h \
+include/grpc/impl/codegen/compression_types.h \
+include/grpc/impl/codegen/connectivity_state.h \
+include/grpc/impl/codegen/grpc_types.h \
+include/grpc/impl/codegen/log.h \
+include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/propagation_bits.h \
+include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/slice_buffer.h \
+include/grpc/impl/codegen/status.h \
+include/grpc/impl/codegen/sync.h \
+include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_posix.h \
+include/grpc/impl/codegen/sync_win32.h \
+include/grpc/impl/codegen/time.h \
+include/grpc/status.h \
+include/grpc/support/alloc.h \
+include/grpc/support/atm.h \
+include/grpc/support/host_port.h \
+include/grpc/support/log.h \
+include/grpc/support/port_platform.h \
+include/grpc/support/slice.h \
+include/grpc/support/slice_buffer.h \
+include/grpc/support/string_util.h \
+include/grpc/support/sync.h \
+include/grpc/support/time.h \
+include/grpc/support/useful.h \
+src/core/lib/support/string.h \
+third_party/objective_c/Cronet/cronet_c_for_grpc.h \
src/core/ext/lb_policy/grpclb/load_balancer_api.h \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.h \
third_party/nanopb/pb.h \
@@ -1070,6 +1108,9 @@ src/core/ext/client_config/subchannel_index.c \
src/core/ext/client_config/uri_parser.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.c \
+src/core/ext/transport/cronet/client/secure/cronet_channel_create.c \
+src/core/ext/transport/cronet/transport/cronet_api_dummy.c \
+src/core/ext/transport/cronet/transport/cronet_transport.c \
src/core/ext/lb_policy/grpclb/load_balancer_api.c \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c \
third_party/nanopb/pb_common.c \
diff --git a/tools/gce/linux_performance_worker_init.sh b/tools/gce/linux_performance_worker_init.sh
index 25ac3bcede..df29581e69 100755
--- a/tools/gce/linux_performance_worker_init.sh
+++ b/tools/gce/linux_performance_worker_init.sh
@@ -95,6 +95,9 @@ sudo pip install tox
touch .profile
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
nvm install 0.12 && npm config set cache /tmp/npm-cache
+nvm install 4 && npm config set cache /tmp/npm-cache
+nvm install 5 && npm config set cache /tmp/npm-cache
+nvm alias default 4
# C# dependencies (http://www.mono-project.com/docs/getting-started/install/linux/#debian-ubuntu-and-derivatives)
diff --git a/tools/gcp/stress_test/run_ruby.sh b/tools/gcp/stress_test/run_ruby.sh
new file mode 100755
index 0000000000..80d0567447
--- /dev/null
+++ b/tools/gcp/stress_test/run_ruby.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2015-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.
+
+# This is a wrapper script that was created to help run_server.py and
+# run_client.py to launch 'node js' stress clients and stress servers
+source /etc/profile.d/rvm.sh
+
+set -ex
+
+$@
diff --git a/tools/jenkins/README.md b/tools/jenkins/README.md
new file mode 100644
index 0000000000..8e06b68466
--- /dev/null
+++ b/tools/jenkins/README.md
@@ -0,0 +1 @@
+Scripts invoked by Jenkins (our CI platform) to run gRPC test suites.
diff --git a/tools/jenkins/run_fuzzer.sh b/tools/jenkins/run_fuzzer.sh
index 3f25a93319..cfa7acefab 100755
--- a/tools/jenkins/run_fuzzer.sh
+++ b/tools/jenkins/run_fuzzer.sh
@@ -33,14 +33,14 @@
set -ex
export RUN_COMMAND="tools/fuzzer/build_and_run_fuzzer.sh $1"
-export DOCKER_RUN_SCRIPT=tools/jenkins/docker_run.sh
+export DOCKER_RUN_SCRIPT=tools/run_tests/dockerize/docker_run.sh
export DOCKERFILE_DIR=tools/dockerfile/test/fuzzer
export OUTPUT_DIR=fuzzer_output
runtime=${runtime:-3600}
jobs=${jobs:-3}
-tools/jenkins/build_and_run_docker.sh \
+tools/run_tests/dockerize/build_and_run_docker.sh \
-e RUN_COMMAND="$RUN_COMMAND" \
-e OUTPUT_DIR="$OUTPUT_DIR" \
-e config="$config" \
diff --git a/tools/run_tests/artifact_targets.py b/tools/run_tests/artifact_targets.py
index e61c46d8b5..477bd46888 100644
--- a/tools/run_tests/artifact_targets.py
+++ b/tools/run_tests/artifact_targets.py
@@ -43,10 +43,10 @@ def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
for k,v in environ.iteritems():
docker_args += ['-e', '%s=%s' % (k, v)]
docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
- 'DOCKER_RUN_SCRIPT': 'tools/jenkins/docker_run.sh',
+ 'DOCKER_RUN_SCRIPT': 'tools/run_tests/dockerize/docker_run.sh',
'OUTPUT_DIR': 'artifacts'}
jobspec = jobset.JobSpec(
- cmdline=['tools/jenkins/build_and_run_docker.sh'] + docker_args,
+ cmdline=['tools/run_tests/dockerize/build_and_run_docker.sh'] + docker_args,
environ=docker_env,
shortname='build_artifact.%s' % (name),
timeout_seconds=30*60,
@@ -84,12 +84,16 @@ python_version_arch_map = {
class PythonArtifact:
"""Builds Python artifacts."""
- def __init__(self, platform, arch):
- self.name = 'python_%s_%s' % (platform, arch)
+ def __init__(self, platform, arch, manylinux_build=None):
+ if manylinux_build:
+ self.name = 'python_%s_%s_%s' % (platform, arch, manylinux_build)
+ else:
+ self.name = 'python_%s_%s' % (platform, arch)
self.platform = platform
self.arch = arch
self.labels = ['artifact', 'python', platform, arch]
self.python_version = python_version_arch_map[arch]
+ self.manylinux_build = manylinux_build
def pre_build_jobspecs(self):
return []
@@ -99,14 +103,56 @@ class PythonArtifact:
if self.platform == 'linux':
if self.arch == 'x86':
environ['SETARCH_CMD'] = 'linux32'
+ # Inside the manylinux container, the python installations are located in
+ # special places...
+ environ['PYTHON'] = '/opt/python/{}/bin/python'.format(self.manylinux_build)
+ environ['PIP'] = '/opt/python/{}/bin/pip'.format(self.manylinux_build)
+ # Our docker image has all the prerequisites pip-installed already.
+ environ['SKIP_PIP_INSTALL'] = '1'
+ # Platform autodetection for the manylinux1 image breaks so we set the
+ # defines ourselves.
+ # TODO(atash) get better platform-detection support in core so we don't
+ # need to do this manually...
+ environ['CFLAGS'] = " ".join([
+ '-DGPR_NO_AUTODETECT_PLATFORM',
+ '-DGPR_PLATFORM_STRING=\\"manylinux\\"',
+ '-DGPR_POSIX_CRASH_HANDLER=1',
+ '-DGPR_CPU_LINUX=1',
+ '-DGPR_GCC_ATOMIC=1',
+ '-DGPR_GCC_TLS=1',
+ '-DGPR_LINUX=1',
+ '-DGPR_LINUX_LOG=1',
+ #'-DGPR_LINUX_MULTIPOLL_WITH_EPOLL=1',
+ '-DGPR_POSIX_SOCKET=1',
+ '-DGPR_POSIX_WAKEUP_FD=1',
+ '-DGPR_POSIX_SOCKETADDR=1',
+ #'-DGPR_LINUX_EVENTFD=1',
+ '-DGPR_POSIX_NO_SPECIAL_WAKEUP_FD=1',
+ #'-DGPR_LINUX_SOCKETUTILS=1',
+ '-DGPR_POSIX_SOCKETUTILS=1',
+ '-DGPR_HAVE_UNIX_SOCKET=1',
+ '-DGPR_HAVE_IP_PKTINFO=1',
+ '-DGPR_HAVE_IPV6_RECVPKTINFO=1',
+ '-DGPR_LINUX_ENV=1',
+ '-DGPR_POSIX_FILE=1',
+ '-DGPR_POSIX_TMPFILE=1',
+ '-DGPR_POSIX_STRING=1',
+ '-DGPR_POSIX_SUBPROCESS=1',
+ '-DGPR_POSIX_SYNC=1',
+ '-DGPR_POSIX_TIME=1',
+ '-DGPR_GETPID_IN_UNISTD_H=1',
+ '-DGPR_HAVE_MSG_NOSIGNAL=1',
+ '-DGPR_ARCH_{arch}=1'.format(arch=('32' if self.arch == 'x86' else '64')),
+ ])
return create_docker_jobspec(self.name,
- 'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
+ 'tools/dockerfile/grpc_artifact_python_manylinux_%s' % self.arch,
'tools/run_tests/build_artifact_python.sh',
environ=environ)
elif self.platform == 'windows':
return create_jobspec(self.name,
['tools\\run_tests\\build_artifact_python.bat',
- self.python_version
+ self.python_version,
+ '32' if self.arch == 'x86' else '64'
],
shell=True)
else:
@@ -307,8 +353,10 @@ def targets():
for Cls in (CSharpExtArtifact, NodeExtArtifact, ProtocArtifact)
for platform in ('linux', 'macos', 'windows')
for arch in ('x86', 'x64')] +
- [PythonArtifact('linux', 'x86'),
- PythonArtifact('linux', 'x64'),
+ [PythonArtifact('linux', 'x86', 'cp27-cp27m'),
+ PythonArtifact('linux', 'x86', 'cp27-cp27mu'),
+ PythonArtifact('linux', 'x64', 'cp27-cp27m'),
+ PythonArtifact('linux', 'x64', 'cp27-cp27mu'),
PythonArtifact('macos', 'x64'),
PythonArtifact('windows', 'x86'),
PythonArtifact('windows', 'x64'),
diff --git a/tools/run_tests/build_artifact_python.bat b/tools/run_tests/build_artifact_python.bat
index 023d394549..636ae0d393 100644
--- a/tools/run_tests/build_artifact_python.bat
+++ b/tools/run_tests/build_artifact_python.bat
@@ -52,8 +52,21 @@ set GRPC_PYTHON_BUILD_WITH_CYTHON=1
python setup.py bdist_wheel
+@rem Build gRPC Python tools
+set PATH=C:\msys64\mingw%2\bin;%PATH%
+set CC=C:\msys64\mingw%2\bin\g++.exe
+set CFLAGS=-fno-wrapv
+python tools\distrib\python\make_grpcio_tools.py
+if %2 == 32 (
+ python tools\distrib\python\grpcio_tools\setup.py build_ext -c mingw32
+) else (
+ python tools\distrib\python\grpcio_tools\setup.py build_ext -c mingw32 -DMS_WIN64
+)
+python tools\distrib\python\grpcio_tools\setup.py bdist_wheel
+
mkdir artifacts
xcopy /Y /I /S dist\* artifacts\ || goto :error
+xcopy /Y /I /S tools\distrib\python\grpcio_tools\dist\* artifacts\ || goto :error
goto :EOF
diff --git a/tools/run_tests/build_artifact_python.sh b/tools/run_tests/build_artifact_python.sh
index 1f23f9fade..35c3a48afa 100755
--- a/tools/run_tests/build_artifact_python.sh
+++ b/tools/run_tests/build_artifact_python.sh
@@ -32,36 +32,48 @@ set -ex
cd $(dirname $0)/../..
+export GRPC_PYTHON_USE_CUSTOM_BDIST=0
+export GRPC_PYTHON_BUILD_WITH_CYTHON=1
+export PYTHON=${PYTHON:-python}
+export PIP=${PIP:-pip}
+export AUDITWHEEL=${AUDITWHEEL:-auditwheel}
+
+
if [ "$SKIP_PIP_INSTALL" == "" ]
then
- pip install --upgrade six
+ ${PIP} install --upgrade six
# There's a bug in newer versions of setuptools (see
# https://bitbucket.org/pypa/setuptools/issues/503/pkg_resources_vendorpackagingrequirementsi)
- pip install --upgrade 'setuptools==18'
- pip install -rrequirements.txt
+ ${PIP} pip install --upgrade 'setuptools==18'
+ ${PIP} install -rrequirements.txt
fi
-export GRPC_PYTHON_USE_CUSTOM_BDIST=0
-export GRPC_PYTHON_BUILD_WITH_CYTHON=1
-
# Build the source distribution first because MANIFEST.in cannot override
# exclusion of built shared objects among package resources (for some
# inexplicable reason).
-${SETARCH_CMD} python setup.py \
+${SETARCH_CMD} ${PYTHON} setup.py \
sdist
-# The bdist_wheel_grpc_custom command is finicky about command output ordering
-# and thus ought to be run in a shell command separate of others. Further, it
-# trashes the actual bdist_wheel output, so it should be run first so that
-# bdist_wheel may be run unmolested.
-${SETARCH_CMD} python setup.py \
- build_tagged_ext
-
# Wheel has a bug where directories don't get excluded.
# https://bitbucket.org/pypa/wheel/issues/99/cannot-exclude-directory
-${SETARCH_CMD} python setup.py \
+${SETARCH_CMD} ${PYTHON} setup.py \
bdist_wheel
+# Build gRPC tools package
+${PYTHON} tools/distrib/python/make_grpcio_tools.py
+CFLAGS="$CFLAGS -fno-wrapv" ${SETARCH_CMD} \
+ ${PYTHON} tools/distrib/python/grpcio_tools/setup.py bdist_wheel
+
mkdir -p artifacts
+if command -v ${AUDITWHEEL}
+then
+ for wheel in dist/*.whl; do
+ ${AUDITWHEEL} repair $wheel -w artifacts/
+ done
+ for wheel in tools/distrib/python/grpcio_tools/dist/*.whl; do
+ ${AUDITWHEEL} repair $wheel -w artifacts/
+ done
+fi
cp -r dist/* artifacts
+cp -r tools/distrib/python/grpcio_tools/dist/* artifacts
diff --git a/tools/run_tests/build_package_ruby.sh b/tools/run_tests/build_package_ruby.sh
index 1a5b94348d..e44428bf7e 100755
--- a/tools/run_tests/build_package_ruby.sh
+++ b/tools/run_tests/build_package_ruby.sh
@@ -32,6 +32,8 @@ set -ex
cd $(dirname $0)/../..
+base=$(pwd)
+
mkdir -p artifacts/
# All the ruby packages have been built in the artifact phase already
@@ -41,3 +43,25 @@ cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=ruby,platform={windows,
# TODO: all the artifact builder configurations generate a grpc-VERSION.gem
# source distribution package, and only one of them will end up
# in the artifacts/ directory. They should be all equivalent though.
+
+for arch in {x86,x64}; do
+ case $arch in
+ x64)
+ ruby_arch=x86_64
+ ;;
+ *)
+ ruby_arch=$arch
+ ;;
+ esac
+ for plat in {windows,linux,macos}; do
+ input_dir="$EXTERNAL_GIT_ROOT/architecture=$arch,language=protoc,platform=$plat/artifacts"
+ output_dir="$base/src/ruby/tools/bin/${ruby_arch}-${plat}"
+ mkdir -p $output_dir
+ cp $input_dir/protoc* $output_dir/
+ cp $input_dir/grpc_ruby_plugin* $output_dir/
+ done
+done
+
+cd $base/src/ruby/tools
+gem build grpc-tools.gemspec
+cp ./grpc-tools*.gem $base/artifacts/
diff --git a/tools/run_tests/distribtest_targets.py b/tools/run_tests/distribtest_targets.py
index 34cc1cd710..ae918be21d 100644
--- a/tools/run_tests/distribtest_targets.py
+++ b/tools/run_tests/distribtest_targets.py
@@ -44,9 +44,9 @@ def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
for k,v in environ.iteritems():
docker_args += ['-e', '%s=%s' % (k, v)]
docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
- 'DOCKER_RUN_SCRIPT': 'tools/jenkins/docker_run.sh'}
+ 'DOCKER_RUN_SCRIPT': 'tools/run_tests/dockerize/docker_run.sh'}
jobspec = jobset.JobSpec(
- cmdline=['tools/jenkins/build_and_run_docker.sh'] + docker_args,
+ cmdline=['tools/run_tests/dockerize/build_and_run_docker.sh'] + docker_args,
environ=docker_env,
shortname='distribtest.%s' % (name),
timeout_seconds=30*60,
diff --git a/tools/jenkins/build_and_run_docker.sh b/tools/run_tests/dockerize/build_and_run_docker.sh
index 92dbbc6f38..1ef34b2f96 100755
--- a/tools/jenkins/build_and_run_docker.sh
+++ b/tools/run_tests/dockerize/build_and_run_docker.sh
@@ -33,7 +33,7 @@
set -ex
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
git_root=$(pwd)
cd -
diff --git a/tools/jenkins/build_docker_and_run_tests.sh b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
index 5779e63db9..c2ea6f2c6e 100755
--- a/tools/jenkins/build_docker_and_run_tests.sh
+++ b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
@@ -33,7 +33,7 @@
set -ex
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
git_root=$(pwd)
cd -
diff --git a/tools/jenkins/build_interop_image.sh b/tools/run_tests/dockerize/build_interop_image.sh
index d2ba97c3de..48a216a124 100755
--- a/tools/jenkins/build_interop_image.sh
+++ b/tools/run_tests/dockerize/build_interop_image.sh
@@ -40,7 +40,7 @@ set -x
# BUILD_INTEROP_DOCKER_EXTRA_ARGS - optional args to be passed to the
# docker run command
-cd `dirname $0`/../..
+cd `dirname $0`/../../..
GRPC_ROOT=`pwd`
MOUNT_ARGS="-v $GRPC_ROOT:/var/local/jenkins/grpc:ro"
diff --git a/tools/jenkins/build_interop_stress_image.sh b/tools/run_tests/dockerize/build_interop_stress_image.sh
index 31ffa752ab..4407c8da90 100755
--- a/tools/jenkins/build_interop_stress_image.sh
+++ b/tools/run_tests/dockerize/build_interop_stress_image.sh
@@ -44,7 +44,7 @@ set -x
# BUILD_INTEROP_DOCKER_EXTRA_ARGS - optional args to be passed to the
# docker run command
-cd `dirname $0`/../..
+cd `dirname $0`/../../..
GRPC_ROOT=`pwd`
MOUNT_ARGS="-v $GRPC_ROOT:/var/local/jenkins/grpc:ro"
diff --git a/tools/jenkins/docker_run.sh b/tools/run_tests/dockerize/docker_run.sh
index f04b1cfb55..f04b1cfb55 100755
--- a/tools/jenkins/docker_run.sh
+++ b/tools/run_tests/dockerize/docker_run.sh
diff --git a/tools/jenkins/docker_run_tests.sh b/tools/run_tests/dockerize/docker_run_tests.sh
index 2fc66c21f5..2fc66c21f5 100755
--- a/tools/jenkins/docker_run_tests.sh
+++ b/tools/run_tests/dockerize/docker_run_tests.sh
diff --git a/tools/run_tests/package_targets.py b/tools/run_tests/package_targets.py
index 87bc4865ce..820b539b59 100644
--- a/tools/run_tests/package_targets.py
+++ b/tools/run_tests/package_targets.py
@@ -42,10 +42,10 @@ def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
for k,v in environ.iteritems():
docker_args += ['-e', '%s=%s' % (k, v)]
docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
- 'DOCKER_RUN_SCRIPT': 'tools/jenkins/docker_run.sh',
+ 'DOCKER_RUN_SCRIPT': 'tools/run_tests/dockerize/docker_run.sh',
'OUTPUT_DIR': 'artifacts'}
jobspec = jobset.JobSpec(
- cmdline=['tools/jenkins/build_and_run_docker.sh'] + docker_args,
+ cmdline=['tools/run_tests/dockerize/build_and_run_docker.sh'] + docker_args,
environ=docker_env,
shortname='build_package.%s' % (name),
timeout_seconds=30*60,
diff --git a/tools/run_tests/performance/run_worker_node.sh b/tools/run_tests/performance/run_worker_node.sh
index 46b6ff0177..9a53a311f4 100755
--- a/tools/run_tests/performance/run_worker_node.sh
+++ b/tools/run_tests/performance/run_worker_node.sh
@@ -29,7 +29,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
source ~/.nvm/nvm.sh
-nvm use 0.12
+nvm use 4
set -ex
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 758be9304d..e813473421 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -542,7 +542,7 @@ def build_interop_image_jobspec(language, tag=None):
env['BUILD_INTEROP_DOCKER_EXTRA_ARGS'] = \
'-v %s:/root/.composer/auth.json:ro' % host_file
build_job = jobset.JobSpec(
- cmdline=['tools/jenkins/build_interop_image.sh'],
+ cmdline=['tools/run_tests/dockerize/build_interop_image.sh'],
environ=env,
shortname='build_docker_%s' % (language),
timeout_seconds=30*60)
diff --git a/tools/run_tests/run_stress_tests.py b/tools/run_tests/run_stress_tests.py
index 0ba8f51c58..e42ee24ffb 100755
--- a/tools/run_tests/run_stress_tests.py
+++ b/tools/run_tests/run_stress_tests.py
@@ -195,7 +195,7 @@ def build_interop_stress_image_jobspec(language, tag=None):
tag = 'grpc_interop_stress_%s:%s' % (language.safename, uuid.uuid4())
env = {'INTEROP_IMAGE': tag,
'BASE_NAME': 'grpc_interop_stress_%s' % language.safename}
- build_job = jobset.JobSpec(cmdline=['tools/jenkins/build_interop_stress_image.sh'],
+ build_job = jobset.JobSpec(cmdline=['tools/run_tests/dockerize/build_interop_stress_image.sh'],
environ=env,
shortname='build_docker_%s' % (language),
timeout_seconds=30 * 60)
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index dea481ef90..37291f4d3f 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -272,12 +272,17 @@ class NodeLanguage(object):
def __init__(self):
self.platform = platform_string()
- self.node_version = '0.12'
def configure(self, config, args):
self.config = config
self.args = args
- _check_compiler(self.args.compiler, ['default'])
+ _check_compiler(self.args.compiler, ['default', 'node0.12',
+ 'node4', 'node5'])
+ if self.args.compiler == 'default':
+ self.node_version = '4'
+ else:
+ # Take off the word "node"
+ self.node_version = self.args.compiler[4:]
def test_specs(self):
if self.platform == 'windows':
@@ -802,7 +807,8 @@ argp.add_argument('--compiler',
'gcc4.4', 'gcc4.9', 'gcc5.3',
'clang3.4', 'clang3.6',
'vs2010', 'vs2013', 'vs2015',
- 'python2.7', 'python3.4'],
+ 'python2.7', 'python3.4',
+ 'node0.12', 'node4', 'node5'],
default='default',
help='Selects compiler to use. Allowed values depend on the platform and language.')
argp.add_argument('--build_only',
@@ -906,13 +912,13 @@ if args.use_docker:
env = os.environ.copy()
env['RUN_TESTS_COMMAND'] = run_tests_cmd
env['DOCKERFILE_DIR'] = dockerfile_dir
- env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
+ env['DOCKER_RUN_SCRIPT'] = 'tools/run_tests/dockerize/docker_run_tests.sh'
if args.xml_report:
env['XML_REPORT'] = args.xml_report
if not args.travis:
env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
- subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
+ subprocess.check_call(['tools/run_tests/dockerize/build_docker_and_run_tests.sh'],
shell=True,
env=env)
sys.exit(0)
diff --git a/tools/run_tests/sanity/sanity_tests.yaml b/tools/run_tests/sanity/sanity_tests.yaml
index efc21e6591..c5945c602f 100644
--- a/tools/run_tests/sanity/sanity_tests.yaml
+++ b/tools/run_tests/sanity/sanity_tests.yaml
@@ -10,3 +10,4 @@
- script: tools/distrib/check_trailing_newlines.sh
- script: tools/distrib/check_nanopb_output.sh
- script: tools/distrib/check_include_guards.py
+- script: tools/distrib/python/check_grpcio_tools.py
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index d2931269b2..737d8c5a48 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -4158,7 +4158,8 @@
"grpc_transport_chttp2_client_insecure",
"grpc_transport_chttp2_client_secure",
"grpc_transport_chttp2_server_insecure",
- "grpc_transport_chttp2_server_secure"
+ "grpc_transport_chttp2_server_secure",
+ "grpc_transport_cronet_client_secure"
],
"headers": [],
"language": "c",
@@ -5921,6 +5922,7 @@
],
"headers": [
"include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/byte_buffer_reader.h",
"include/grpc/impl/codegen/compression_types.h",
"include/grpc/impl/codegen/connectivity_state.h",
"include/grpc/impl/codegen/grpc_types.h",
@@ -5931,6 +5933,7 @@
"name": "grpc_codegen",
"src": [
"include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/byte_buffer_reader.h",
"include/grpc/impl/codegen/compression_types.h",
"include/grpc/impl/codegen/connectivity_state.h",
"include/grpc/impl/codegen/grpc_types.h",
@@ -6030,6 +6033,7 @@
"tsi"
],
"headers": [
+ "include/grpc/grpc_cronet.h",
"include/grpc/grpc_security.h",
"include/grpc/grpc_security_constants.h",
"src/core/lib/security/auth_filters.h",
@@ -6045,6 +6049,7 @@
"language": "c",
"name": "grpc_secure",
"src": [
+ "include/grpc/grpc_cronet.h",
"include/grpc/grpc_security.h",
"include/grpc/grpc_security_constants.h",
"src/core/lib/http/httpcli_security_connector.c",
@@ -6283,6 +6288,121 @@
{
"deps": [],
"headers": [
+ "include/grpc/byte_buffer.h",
+ "include/grpc/grpc.h",
+ "include/grpc/impl/codegen/alloc.h",
+ "include/grpc/impl/codegen/atm.h",
+ "include/grpc/impl/codegen/atm_gcc_atomic.h",
+ "include/grpc/impl/codegen/atm_gcc_sync.h",
+ "include/grpc/impl/codegen/atm_win32.h",
+ "include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/compression_types.h",
+ "include/grpc/impl/codegen/connectivity_state.h",
+ "include/grpc/impl/codegen/grpc_types.h",
+ "include/grpc/impl/codegen/log.h",
+ "include/grpc/impl/codegen/port_platform.h",
+ "include/grpc/impl/codegen/propagation_bits.h",
+ "include/grpc/impl/codegen/slice.h",
+ "include/grpc/impl/codegen/slice_buffer.h",
+ "include/grpc/impl/codegen/status.h",
+ "include/grpc/impl/codegen/sync.h",
+ "include/grpc/impl/codegen/sync_generic.h",
+ "include/grpc/impl/codegen/sync_posix.h",
+ "include/grpc/impl/codegen/sync_win32.h",
+ "include/grpc/impl/codegen/time.h",
+ "include/grpc/status.h",
+ "include/grpc/support/alloc.h",
+ "include/grpc/support/atm.h",
+ "include/grpc/support/host_port.h",
+ "include/grpc/support/log.h",
+ "include/grpc/support/port_platform.h",
+ "include/grpc/support/slice.h",
+ "include/grpc/support/slice_buffer.h",
+ "include/grpc/support/string_util.h",
+ "include/grpc/support/sync.h",
+ "include/grpc/support/time.h",
+ "include/grpc/support/useful.h",
+ "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
+ "src/core/lib/channel/channel_stack.h",
+ "src/core/lib/channel/context.h",
+ "src/core/lib/debug/trace.h",
+ "src/core/lib/iomgr/closure.h",
+ "src/core/lib/iomgr/exec_ctx.h",
+ "src/core/lib/iomgr/pollset.h",
+ "src/core/lib/iomgr/pollset_set.h",
+ "src/core/lib/support/string.h",
+ "src/core/lib/surface/channel.h",
+ "src/core/lib/surface/channel_stack_type.h",
+ "src/core/lib/transport/byte_stream.h",
+ "src/core/lib/transport/metadata.h",
+ "src/core/lib/transport/metadata_batch.h",
+ "src/core/lib/transport/transport.h",
+ "src/core/lib/transport/transport_impl.h",
+ "third_party/objective_c/Cronet/cronet_c_for_grpc.h"
+ ],
+ "language": "c",
+ "name": "grpc_transport_cronet_client_secure",
+ "src": [
+ "include/grpc/byte_buffer.h",
+ "include/grpc/grpc.h",
+ "include/grpc/impl/codegen/alloc.h",
+ "include/grpc/impl/codegen/atm.h",
+ "include/grpc/impl/codegen/atm_gcc_atomic.h",
+ "include/grpc/impl/codegen/atm_gcc_sync.h",
+ "include/grpc/impl/codegen/atm_win32.h",
+ "include/grpc/impl/codegen/byte_buffer.h",
+ "include/grpc/impl/codegen/compression_types.h",
+ "include/grpc/impl/codegen/connectivity_state.h",
+ "include/grpc/impl/codegen/grpc_types.h",
+ "include/grpc/impl/codegen/log.h",
+ "include/grpc/impl/codegen/port_platform.h",
+ "include/grpc/impl/codegen/propagation_bits.h",
+ "include/grpc/impl/codegen/slice.h",
+ "include/grpc/impl/codegen/slice_buffer.h",
+ "include/grpc/impl/codegen/status.h",
+ "include/grpc/impl/codegen/sync.h",
+ "include/grpc/impl/codegen/sync_generic.h",
+ "include/grpc/impl/codegen/sync_posix.h",
+ "include/grpc/impl/codegen/sync_win32.h",
+ "include/grpc/impl/codegen/time.h",
+ "include/grpc/status.h",
+ "include/grpc/support/alloc.h",
+ "include/grpc/support/atm.h",
+ "include/grpc/support/host_port.h",
+ "include/grpc/support/log.h",
+ "include/grpc/support/port_platform.h",
+ "include/grpc/support/slice.h",
+ "include/grpc/support/slice_buffer.h",
+ "include/grpc/support/string_util.h",
+ "include/grpc/support/sync.h",
+ "include/grpc/support/time.h",
+ "include/grpc/support/useful.h",
+ "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
+ "src/core/ext/transport/cronet/client/secure/cronet_channel_create.c",
+ "src/core/ext/transport/cronet/transport/cronet_api_dummy.c",
+ "src/core/ext/transport/cronet/transport/cronet_transport.c",
+ "src/core/lib/channel/channel_stack.h",
+ "src/core/lib/channel/context.h",
+ "src/core/lib/debug/trace.h",
+ "src/core/lib/iomgr/closure.h",
+ "src/core/lib/iomgr/exec_ctx.h",
+ "src/core/lib/iomgr/pollset.h",
+ "src/core/lib/iomgr/pollset_set.h",
+ "src/core/lib/support/string.h",
+ "src/core/lib/surface/channel.h",
+ "src/core/lib/surface/channel_stack_type.h",
+ "src/core/lib/transport/byte_stream.h",
+ "src/core/lib/transport/metadata.h",
+ "src/core/lib/transport/metadata_batch.h",
+ "src/core/lib/transport/transport.h",
+ "src/core/lib/transport/transport_impl.h"
+ ],
+ "third_party": false,
+ "type": "filegroup"
+ },
+ {
+ "deps": [],
+ "headers": [
"third_party/nanopb/pb.h",
"third_party/nanopb/pb_common.h",
"third_party/nanopb/pb_decode.h",
diff --git a/tools/run_tests/stress_test/configs/asan.json b/tools/run_tests/stress_test/configs/asan.json
index cb9f55763b..7ae11ccbf1 100644
--- a/tools/run_tests/stress_test/configs/asan.json
+++ b/tools/run_tests/stress_test/configs/asan.json
@@ -1,7 +1,7 @@
{
"dockerImages": {
"grpc_stress_cxx_asan" : {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_cxx",
"buildType": "asan"
}
diff --git a/tools/run_tests/stress_test/configs/csharp.json b/tools/run_tests/stress_test/configs/csharp.json
new file mode 100644
index 0000000000..406949557d
--- /dev/null
+++ b/tools/run_tests/stress_test/configs/csharp.json
@@ -0,0 +1,90 @@
+{
+ "dockerImages": {
+ "grpc_stress_csharp" : {
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
+ "dockerFileDir": "grpc_interop_stress_csharp"
+ }
+ },
+
+ "clientTemplates": {
+ "baseTemplates": {
+ "default": {
+ "wrapperScriptPath": "/var/local/git/grpc/tools/gcp/stress_test/run_client.py",
+ "pollIntervalSecs": 60,
+ "clientArgs": {
+ "num_channels_per_server":5,
+ "num_stubs_per_channel":10,
+ "test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
+ "metrics_port": 8081
+ },
+ "metricsPort": 8081,
+ "metricsArgs": {
+ "metrics_server_address": "localhost:8081",
+ "total_only": "true"
+ }
+ }
+ },
+ "templates": {
+ "csharp_client": {
+ "baseTemplate": "default",
+ "stressClientCmd": [
+ "mono",
+ "/var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.StressClient/bin/Debug/Grpc.IntegrationTesting.StressClient.exe"
+ ],
+ "metricsClientCmd": ["/var/local/git/grpc/bins/opt/metrics_client"]
+ }
+ }
+ },
+
+ "serverTemplates": {
+ "baseTemplates":{
+ "default": {
+ "wrapperScriptPath": "/var/local/git/grpc/tools/gcp/stress_test/run_server.py",
+ "serverPort": 8080,
+ "serverArgs": {
+ "port": 8080
+ }
+ }
+ },
+ "templates": {
+ "csharp_server": {
+ "baseTemplate": "default",
+ "stressServerCmd": [
+ "mono",
+ "/var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Server/bin/Debug/Grpc.IntegrationTesting.Server.exe"
+ ]
+ }
+ }
+ },
+
+ "testMatrix": {
+ "serverPodSpecs": {
+ "stress-server-csharp": {
+ "serverTemplate": "csharp_server",
+ "dockerImage": "grpc_stress_csharp",
+ "numInstances": 1
+ }
+ },
+
+ "clientPodSpecs": {
+ "stress-client-csharp": {
+ "clientTemplate": "csharp_client",
+ "dockerImage": "grpc_stress_csharp",
+ "numInstances": 10,
+ "serverPodSpec": "stress-server-csharp"
+ }
+ }
+ },
+
+ "globalSettings": {
+ "buildDockerImages": true,
+ "pollIntervalSecs": 60,
+ "testDurationSecs": 7200,
+ "kubernetesProxyPort": 8001,
+ "datasetIdNamePrefix": "stress_test_csharp",
+ "summaryTableId": "summary",
+ "qpsTableId": "qps",
+ "podWarmupSecs": 60
+ }
+}
+
diff --git a/tools/run_tests/stress_test/configs/go.json b/tools/run_tests/stress_test/configs/go.json
index 36b465e763..f1b2b523d3 100644
--- a/tools/run_tests/stress_test/configs/go.json
+++ b/tools/run_tests/stress_test/configs/go.json
@@ -1,7 +1,7 @@
{
"dockerImages": {
"grpc_stress_go" : {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_go"
}
},
diff --git a/tools/run_tests/stress_test/configs/java.json b/tools/run_tests/stress_test/configs/java.json
index 275384c066..2ce6c00780 100644
--- a/tools/run_tests/stress_test/configs/java.json
+++ b/tools/run_tests/stress_test/configs/java.json
@@ -1,7 +1,7 @@
{
"dockerImages": {
"grpc_stress_java" : {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_java"
}
},
diff --git a/tools/run_tests/stress_test/configs/node-cxx.json b/tools/run_tests/stress_test/configs/node-cxx.json
index c4245bf9df..094c1236e7 100644
--- a/tools/run_tests/stress_test/configs/node-cxx.json
+++ b/tools/run_tests/stress_test/configs/node-cxx.json
@@ -1,12 +1,12 @@
{
"dockerImages": {
"grpc_stress_cxx_opt" : {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_cxx",
"buildType": "opt"
},
"grpc_stress_node": {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_node"
}
},
diff --git a/tools/run_tests/stress_test/configs/node.json b/tools/run_tests/stress_test/configs/node.json
index 7a48c56a5e..85eb9e0003 100644
--- a/tools/run_tests/stress_test/configs/node.json
+++ b/tools/run_tests/stress_test/configs/node.json
@@ -1,7 +1,7 @@
{
"dockerImages": {
"grpc_stress_node" : {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_node"
}
},
diff --git a/tools/run_tests/stress_test/configs/opt-tsan-asan.json b/tools/run_tests/stress_test/configs/opt-tsan-asan.json
index 936d15169e..fcb3678c02 100644
--- a/tools/run_tests/stress_test/configs/opt-tsan-asan.json
+++ b/tools/run_tests/stress_test/configs/opt-tsan-asan.json
@@ -1,17 +1,17 @@
{
"dockerImages": {
"grpc_stress_cxx_opt" : {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_cxx",
"buildType": "opt"
},
"grpc_stress_cxx_tsan": {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_cxx",
"buildType": "tsan"
},
"grpc_stress_cxx_asan": {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_cxx",
"buildType": "asan"
}
diff --git a/tools/run_tests/stress_test/configs/opt.json b/tools/run_tests/stress_test/configs/opt.json
index f45b824048..5e0e930d45 100644
--- a/tools/run_tests/stress_test/configs/opt.json
+++ b/tools/run_tests/stress_test/configs/opt.json
@@ -1,7 +1,7 @@
{
"dockerImages": {
"grpc_stress_cxx_opt" : {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_cxx",
"buildType": "opt"
}
diff --git a/tools/run_tests/stress_test/configs/ruby.json b/tools/run_tests/stress_test/configs/ruby.json
new file mode 100644
index 0000000000..7e2afcbb69
--- /dev/null
+++ b/tools/run_tests/stress_test/configs/ruby.json
@@ -0,0 +1,92 @@
+{
+ "dockerImages": {
+ "grpc_stress_ruby" : {
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
+ "dockerFileDir": "grpc_interop_stress_ruby"
+ }
+ },
+
+ "clientTemplates": {
+ "baseTemplates": {
+ "default": {
+ "wrapperScriptPath": "/var/local/git/grpc/tools/gcp/stress_test/run_client.py",
+ "pollIntervalSecs": 60,
+ "clientArgs": {
+ "num_channels_per_server":5,
+ "num_stubs_per_channel":10,
+ "test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
+ "metrics_port": 8081
+ },
+ "metricsPort": 8081,
+ "metricsArgs": {
+ "metrics_server_address": "localhost:8081",
+ "total_only": "true"
+ }
+ }
+ },
+ "templates": {
+ "ruby_client": {
+ "baseTemplate": "default",
+ "stressClientCmd": [
+ "/var/local/git/grpc/tools/gcp/stress_test/run_ruby.sh",
+ "ruby",
+ "/var/local/git/grpc/src/ruby/stress/stress_client.rb"
+ ],
+ "metricsClientCmd": ["/var/local/git/grpc/bins/opt/metrics_client"]
+ }
+ }
+ },
+
+ "serverTemplates": {
+ "baseTemplates":{
+ "default": {
+ "wrapperScriptPath": "/var/local/git/grpc/tools/gcp/stress_test/run_server.py",
+ "serverPort": 8080,
+ "serverArgs": {
+ "port": 8080
+ }
+ }
+ },
+ "templates": {
+ "ruby_server": {
+ "baseTemplate": "default",
+ "stressServerCmd": [
+ "/var/local/git/grpc/tools/gcp/stress_test/run_ruby.sh",
+ "ruby",
+ "/var/local/git/grpc/src/ruby/pb/test/server.rb"
+ ]
+ }
+ }
+ },
+
+ "testMatrix": {
+ "serverPodSpecs": {
+ "stress-server-ruby": {
+ "serverTemplate": "ruby_server",
+ "dockerImage": "grpc_stress_ruby",
+ "numInstances": 1
+ }
+ },
+
+ "clientPodSpecs": {
+ "stress-client-ruby": {
+ "clientTemplate": "ruby_client",
+ "dockerImage": "grpc_stress_ruby",
+ "numInstances": 10,
+ "serverPodSpec": "stress-server-ruby"
+ }
+ }
+ },
+
+ "globalSettings": {
+ "buildDockerImages": true,
+ "pollIntervalSecs": 60,
+ "testDurationSecs": 7200,
+ "kubernetesProxyPort": 8001,
+ "datasetIdNamePrefix": "stress_test_ruby",
+ "summaryTableId": "summary",
+ "qpsTableId": "qps",
+ "podWarmupSecs": 60
+ }
+}
+
diff --git a/tools/run_tests/stress_test/configs/tsan.json b/tools/run_tests/stress_test/configs/tsan.json
index 6ef3bdf7ea..abc759c79d 100644
--- a/tools/run_tests/stress_test/configs/tsan.json
+++ b/tools/run_tests/stress_test/configs/tsan.json
@@ -1,7 +1,7 @@
{
"dockerImages": {
"grpc_stress_cxx_tsan" : {
- "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+ "buildScript": "tools/run_tests/dockerize/build_interop_stress_image.sh",
"dockerFileDir": "grpc_interop_stress_cxx",
"buildType": "tsan"
}
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index c7b85de4d2..31e556df88 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -57780,6 +57780,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/03a72675e1969f836094f1ecfec2a7b34418e306"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/03b9be1fa172dff5d1543be079b9c64fa2c9a278"
],
"ci_platforms": [
@@ -57796,6 +57812,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/0416afd6875d9ba55f1e5f86a6456a5445d5e576"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/052c8f28e5884bb48f0d504461272cd3a5893215"
],
"ci_platforms": [
@@ -57940,6 +57972,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/08c42ef29eff83052c5887855f2fa3e07ebe470c"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/09938e3256d06a8e168eb038d8a58b8462f7f697"
],
"ci_platforms": [
@@ -58388,6 +58436,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/1ba889ea1543297824e99e641e6ca8b91f45732e"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/1cf17783de9e662f3720847f2d83d86dcdcab500"
],
"ci_platforms": [
@@ -59172,6 +59236,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/3b09bf453c6f93983c24c4d5481e55d66213f93a"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/3ca5da2f.bin"
],
"ci_platforms": [
@@ -59524,6 +59604,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/49cb33cbb60f041e8e99dd718993acd2c3354416"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/4aa883d0.bin"
],
"ci_platforms": [
@@ -59972,6 +60068,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/59743fe120be6ae1aed1c02230ee1bb460f621ee"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/597fdab5.bin"
],
"ci_platforms": [
@@ -61364,6 +61476,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/a5ccb8f124d8ddb5350b90bc0d6b96db280cb7c9"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/a7e64803.bin"
],
"ci_platforms": [
@@ -61380,6 +61508,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/a7fac1265a384fe9e45a9ee3d708b79c4e80505e"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/a8d229374635fa6f2a75ca1669892e1bc244e719"
],
"ci_platforms": [
@@ -61524,6 +61668,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/aaf049720c707d4e14e47e7eb31d6a2dda60e66a"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/ad810f7f.bin"
],
"ci_platforms": [
@@ -61988,6 +62148,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/c4e4c7572e005e18d56eac407033da058737a5ab"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/c559f565.bin"
],
"ci_platforms": [
@@ -62292,6 +62468,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/crash-dae0f07934a527989f23f06e630710ff6ca8c809"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/crash-e34b0a9a428001cb4094a9ebca76329f578811a4"
],
"ci_platforms": [
@@ -62612,6 +62804,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/e96ad9c17795e52edc810a08d4fc61fe8790002a"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/e9bbe2fe47b7b9c2683e7f17f4a33625c6ffbd8c"
],
"ci_platforms": [
@@ -62932,6 +63140,22 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/server_fuzzer_corpus/fa202a5f51cd49f8ea5af60c5f403f797c01c504"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "server_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/server_fuzzer_corpus/fa36b4280d9e28edd81c5e4d192d1a5c2765e5e4"
],
"ci_platforms": [
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index 729631d28d..65de5e9717 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -333,6 +333,7 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index 6c135b22f3..ce50bd9de8 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -321,6 +321,9 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 9465d2ac42..895e223351 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -333,6 +333,7 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 6cb4a6c89d..ab305fa929 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -306,6 +306,9 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 4eec05a3b1..7f0e5a8339 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -273,6 +273,7 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
@@ -292,6 +293,7 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_cronet.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" />
@@ -421,6 +423,42 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\alloc.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\atm.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\host_port.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\log.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\port_platform.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\slice.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\slice_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\string_util.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\sync.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\time.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\useful.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\string.h" />
+ <ClInclude Include="$(SolutionDir)\..\third_party\objective_c\Cronet\cronet_c_for_grpc.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v0\load_balancer.pb.h" />
<ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
@@ -727,6 +765,12 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\client\secure\cronet_channel_create.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\transport\cronet_api_dummy.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\transport\cronet_transport.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v0\load_balancer.pb.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 17c88c4805..6d1d69a913 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -439,6 +439,15 @@
<ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
<Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\client\secure\cronet_channel_create.c">
+ <Filter>src\core\ext\transport\cronet\client\secure</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\transport\cronet_api_dummy.c">
+ <Filter>src\core\ext\transport\cronet\transport</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\transport\cronet_transport.c">
+ <Filter>src\core\ext\transport\cronet\transport</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
<Filter>src\core\ext\lb_policy\grpclb</Filter>
</ClCompile>
@@ -516,6 +525,9 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
@@ -573,6 +585,9 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_cronet.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h">
<Filter>include\grpc</Filter>
</ClInclude>
@@ -956,6 +971,114 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h">
<Filter>src\core\ext\client_config</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\alloc.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\atm.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\host_port.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\log.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\port_platform.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\slice.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\slice_buffer.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\string_util.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\sync.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\time.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\support\useful.h">
+ <Filter>include\grpc\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\string.h">
+ <Filter>src\core\lib\support</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\third_party\objective_c\Cronet\cronet_c_for_grpc.h">
+ <Filter>third_party\objective_c\Cronet</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h">
<Filter>src\core\ext\lb_policy\grpclb</Filter>
</ClInclude>
@@ -1007,6 +1130,9 @@
<Filter Include="include\grpc\impl\codegen">
<UniqueIdentifier>{def748f5-ed2a-a9bb-40d9-c31d00f0e13b}</UniqueIdentifier>
</Filter>
+ <Filter Include="include\grpc\support">
+ <UniqueIdentifier>{31de82ea-dc6c-73fb-a640-979b8a7b240c}</UniqueIdentifier>
+ </Filter>
<Filter Include="src">
<UniqueIdentifier>{d538af37-07b2-062b-fa2a-d9f882cb2737}</UniqueIdentifier>
</Filter>
@@ -1088,6 +1214,18 @@
<Filter Include="src\core\ext\transport\chttp2\transport">
<UniqueIdentifier>{6f34254e-e69f-c9b4-156d-5024bade5408}</UniqueIdentifier>
</Filter>
+ <Filter Include="src\core\ext\transport\cronet">
+ <UniqueIdentifier>{1e9c85e9-5522-7ef8-0017-7e19990a6194}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\ext\transport\cronet\client">
+ <UniqueIdentifier>{d0530883-75d9-b5f7-d594-26735a70ac7b}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\ext\transport\cronet\client\secure">
+ <UniqueIdentifier>{4fa6fe90-b7a8-5c8f-d629-db1e68d89eed}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\ext\transport\cronet\transport">
+ <UniqueIdentifier>{31518af8-5860-6d0d-ff78-4059fce29ec2}</UniqueIdentifier>
+ </Filter>
<Filter Include="src\core\lib">
<UniqueIdentifier>{5b2ded3f-84a5-f6b4-2060-286c7d1dc945}</UniqueIdentifier>
</Filter>
@@ -1112,6 +1250,9 @@
<Filter Include="src\core\lib\security">
<UniqueIdentifier>{c4661d64-349f-01c1-1ba8-0602f9047595}</UniqueIdentifier>
</Filter>
+ <Filter Include="src\core\lib\support">
+ <UniqueIdentifier>{27f30339-d694-40f5-db07-4b89b9aeea73}</UniqueIdentifier>
+ </Filter>
<Filter Include="src\core\lib\surface">
<UniqueIdentifier>{a21971fb-304f-da08-b1b2-7bd8df8ac373}</UniqueIdentifier>
</Filter>
@@ -1130,6 +1271,12 @@
<Filter Include="third_party\nanopb">
<UniqueIdentifier>{93d6596d-330c-1d27-6f84-3c840e57869e}</UniqueIdentifier>
</Filter>
+ <Filter Include="third_party\objective_c">
+ <UniqueIdentifier>{3a56a516-857e-d2aa-95cc-11685baf4e8c}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="third_party\objective_c\Cronet">
+ <UniqueIdentifier>{a165c6e3-0776-6f40-7351-d7865668e220}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
</Project>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 26050dcf74..0eb6535c6b 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -264,6 +264,7 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index a4acf513bc..f544fe6158 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -456,6 +456,9 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj b/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj
index cd0b40c873..34e939cf84 100644
--- a/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj
+++ b/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj
@@ -191,6 +191,7 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
diff --git a/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj.filters b/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj.filters
index 029b8ef774..d66236580c 100644
--- a/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj.filters
+++ b/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj.filters
@@ -120,6 +120,9 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj b/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj
index 6d138fae1c..890d77df22 100644
--- a/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj
+++ b/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj
@@ -191,6 +191,7 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
diff --git a/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj.filters b/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj.filters
index dc3f0b2d04..4e0ba656fc 100644
--- a/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj.filters
+++ b/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj.filters
@@ -120,6 +120,9 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
<Filter>include\grpc\impl\codegen</Filter>
</ClInclude>