Merge branch 'master' of https://github.com/grpc/grpc into moiz-upb

pull/19433/head
Nicolas "Pixel" Noble 6 years ago
commit d01633944c
  1. 10
      BUILD
  2. 10
      BUILD.gn
  3. 40
      CMakeLists.txt
  4. 40
      Makefile
  5. 10
      build.yaml
  6. 10
      gRPC-C++.podspec
  7. 13
      include/grpcpp/channel_impl.h
  8. 41
      include/grpcpp/generic/generic_stub_impl.h
  9. 28
      include/grpcpp/impl/codegen/async_generic_service.h
  10. 1102
      include/grpcpp/impl/codegen/async_stream.h
  11. 1134
      include/grpcpp/impl/codegen/async_stream_impl.h
  12. 291
      include/grpcpp/impl/codegen/async_unary_call.h
  13. 315
      include/grpcpp/impl/codegen/async_unary_call_impl.h
  14. 19
      include/grpcpp/impl/codegen/byte_buffer.h
  15. 2
      include/grpcpp/impl/codegen/call_op_set.h
  16. 47
      include/grpcpp/impl/codegen/channel_interface.h
  17. 1005
      include/grpcpp/impl/codegen/client_callback.h
  18. 1067
      include/grpcpp/impl/codegen/client_callback_impl.h
  19. 52
      include/grpcpp/impl/codegen/client_context_impl.h
  20. 4
      include/grpcpp/impl/codegen/client_unary_call.h
  21. 17
      include/grpcpp/impl/codegen/completion_queue_impl.h
  22. 1133
      include/grpcpp/impl/codegen/server_callback.h
  23. 1186
      include/grpcpp/impl/codegen/server_callback_impl.h
  24. 54
      include/grpcpp/impl/codegen/server_context_impl.h
  25. 20
      include/grpcpp/impl/codegen/service_type.h
  26. 901
      include/grpcpp/impl/codegen/sync_stream.h
  27. 944
      include/grpcpp/impl/codegen/sync_stream_impl.h
  28. 4
      include/grpcpp/server_builder_impl.h
  29. 24
      include/grpcpp/support/async_stream_impl.h
  30. 24
      include/grpcpp/support/async_unary_call_impl.h
  31. 24
      include/grpcpp/support/client_callback_impl.h
  32. 24
      include/grpcpp/support/server_callback_impl.h
  33. 24
      include/grpcpp/support/sync_stream_impl.h
  34. 121
      src/compiler/cpp_generator.cc
  35. 2
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  36. 11
      src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
  37. 10
      src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
  38. 44
      src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
  39. 4
      src/core/ext/filters/client_channel/resolver_factory.h
  40. 11
      src/core/ext/filters/client_channel/resolver_registry.cc
  41. 3
      src/core/ext/filters/client_channel/resolver_registry.h
  42. 23
      src/core/lib/gprpp/host_port.cc
  43. 8
      src/core/lib/slice/slice_buffer.cc
  44. 30
      src/cpp/client/generic_stub.cc
  45. 4
      src/cpp/server/async_generic_service.cc
  46. 1
      src/cpp/server/health/default_health_check_service.h
  47. 15
      src/cpp/server/server_builder.cc
  48. 11
      src/cpp/server/server_context.cc
  49. 3
      src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj
  50. 25
      src/csharp/Grpc.Core.Api/Metadata.cs
  51. 54
      src/csharp/Grpc.Core.Api/Utils/EncodingExtensions.cs
  52. 3
      src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
  53. 62
      src/csharp/Grpc.Core.Tests/Internal/WellKnownStringsTest.cs
  54. 30
      src/csharp/Grpc.Core.Tests/MetadataTest.cs
  55. 2
      src/csharp/Grpc.Core/Grpc.Core.csproj
  56. 46
      src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
  57. 38
      src/csharp/Grpc.Core/Internal/MarshalUtils.cs
  58. 12
      src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
  59. 6
      src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
  60. 92
      src/csharp/Grpc.Core/Internal/WellKnownStrings.cs
  61. 2
      src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs
  62. 1
      src/csharp/tests.json
  63. 4
      templates/src/csharp/Grpc.Core/Internal/native_methods.include
  64. 2
      test/core/gprpp/host_port_test.cc
  65. 37
      test/cpp/codegen/compiler_test_golden
  66. 350
      test/cpp/end2end/client_lb_end2end_test.cc
  67. 1
      tools/distrib/python/bazel_deps.sh
  68. 10
      tools/doxygen/Doxyfile.c++
  69. 10
      tools/doxygen/Doxyfile.c++.internal
  70. 20
      tools/run_tests/generated/sources_and_headers.json

10
BUILD

@ -269,11 +269,14 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/server_posix.h",
"include/grpcpp/server_posix_impl.h",
"include/grpcpp/support/async_stream.h",
"include/grpcpp/support/async_stream_impl.h",
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/async_unary_call_impl.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
"include/grpcpp/support/channel_arguments_impl.h",
"include/grpcpp/support/client_callback.h",
"include/grpcpp/support/client_callback_impl.h",
"include/grpcpp/support/client_interceptor.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/interceptor.h",
@ -281,6 +284,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
"include/grpcpp/support/server_callback.h",
"include/grpcpp/support/server_callback_impl.h",
"include/grpcpp/support/server_interceptor.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
@ -288,6 +292,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/string_ref.h",
"include/grpcpp/support/stub_options.h",
"include/grpcpp/support/sync_stream.h",
"include/grpcpp/support/sync_stream_impl.h",
"include/grpcpp/support/time.h",
"include/grpcpp/support/validate_service_config.h",
]
@ -2160,7 +2165,9 @@ grpc_cc_library(
"include/grpc++/impl/codegen/time.h",
"include/grpcpp/impl/codegen/async_generic_service.h",
"include/grpcpp/impl/codegen/async_stream.h",
"include/grpcpp/impl/codegen/async_stream_impl.h",
"include/grpcpp/impl/codegen/async_unary_call.h",
"include/grpcpp/impl/codegen/async_unary_call_impl.h",
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
@ -2169,6 +2176,7 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
"include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_callback_impl.h",
"include/grpcpp/impl/codegen/client_context.h",
"include/grpcpp/impl/codegen/client_context_impl.h",
"include/grpcpp/impl/codegen/client_interceptor.h",
@ -2191,6 +2199,7 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/security/auth_context.h",
"include/grpcpp/impl/codegen/serialization_traits.h",
"include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_callback_impl.h",
"include/grpcpp/impl/codegen/server_context.h",
"include/grpcpp/impl/codegen/server_context_impl.h",
"include/grpcpp/impl/codegen/server_interceptor.h",
@ -2202,6 +2211,7 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/string_ref.h",
"include/grpcpp/impl/codegen/stub_options.h",
"include/grpcpp/impl/codegen/sync_stream.h",
"include/grpcpp/impl/codegen/sync_stream_impl.h",
"include/grpcpp/impl/codegen/time.h",
],
deps = [

@ -1048,7 +1048,9 @@ config("grpc_config") {
"include/grpcpp/impl/client_unary_call.h",
"include/grpcpp/impl/codegen/async_generic_service.h",
"include/grpcpp/impl/codegen/async_stream.h",
"include/grpcpp/impl/codegen/async_stream_impl.h",
"include/grpcpp/impl/codegen/async_unary_call.h",
"include/grpcpp/impl/codegen/async_unary_call_impl.h",
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
@ -1057,6 +1059,7 @@ config("grpc_config") {
"include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
"include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_callback_impl.h",
"include/grpcpp/impl/codegen/client_context.h",
"include/grpcpp/impl/codegen/client_context_impl.h",
"include/grpcpp/impl/codegen/client_interceptor.h",
@ -1085,6 +1088,7 @@ config("grpc_config") {
"include/grpcpp/impl/codegen/security/auth_context.h",
"include/grpcpp/impl/codegen/serialization_traits.h",
"include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_callback_impl.h",
"include/grpcpp/impl/codegen/server_context.h",
"include/grpcpp/impl/codegen/server_context_impl.h",
"include/grpcpp/impl/codegen/server_interceptor.h",
@ -1097,6 +1101,7 @@ config("grpc_config") {
"include/grpcpp/impl/codegen/stub_options.h",
"include/grpcpp/impl/codegen/sync.h",
"include/grpcpp/impl/codegen/sync_stream.h",
"include/grpcpp/impl/codegen/sync_stream_impl.h",
"include/grpcpp/impl/codegen/time.h",
"include/grpcpp/impl/grpc_library.h",
"include/grpcpp/impl/method_handler_impl.h",
@ -1126,11 +1131,14 @@ config("grpc_config") {
"include/grpcpp/server_posix.h",
"include/grpcpp/server_posix_impl.h",
"include/grpcpp/support/async_stream.h",
"include/grpcpp/support/async_stream_impl.h",
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/async_unary_call_impl.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
"include/grpcpp/support/channel_arguments_impl.h",
"include/grpcpp/support/client_callback.h",
"include/grpcpp/support/client_callback_impl.h",
"include/grpcpp/support/client_interceptor.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/interceptor.h",
@ -1138,6 +1146,7 @@ config("grpc_config") {
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
"include/grpcpp/support/server_callback.h",
"include/grpcpp/support/server_callback_impl.h",
"include/grpcpp/support/server_interceptor.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
@ -1145,6 +1154,7 @@ config("grpc_config") {
"include/grpcpp/support/string_ref.h",
"include/grpcpp/support/stub_options.h",
"include/grpcpp/support/sync_stream.h",
"include/grpcpp/support/sync_stream_impl.h",
"include/grpcpp/support/time.h",
"include/grpcpp/support/validate_service_config.h",
"src/core/ext/transport/inproc/inproc_transport.h",

@ -3227,11 +3227,14 @@ foreach(_hdr
include/grpcpp/server_posix.h
include/grpcpp/server_posix_impl.h
include/grpcpp/support/async_stream.h
include/grpcpp/support/async_stream_impl.h
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/async_unary_call_impl.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
include/grpcpp/support/channel_arguments_impl.h
include/grpcpp/support/client_callback.h
include/grpcpp/support/client_callback_impl.h
include/grpcpp/support/client_interceptor.h
include/grpcpp/support/config.h
include/grpcpp/support/interceptor.h
@ -3239,6 +3242,7 @@ foreach(_hdr
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
include/grpcpp/support/server_callback.h
include/grpcpp/support/server_callback_impl.h
include/grpcpp/support/server_interceptor.h
include/grpcpp/support/slice.h
include/grpcpp/support/status.h
@ -3246,6 +3250,7 @@ foreach(_hdr
include/grpcpp/support/string_ref.h
include/grpcpp/support/stub_options.h
include/grpcpp/support/sync_stream.h
include/grpcpp/support/sync_stream_impl.h
include/grpcpp/support/time.h
include/grpcpp/support/validate_service_config.h
include/grpc/support/alloc.h
@ -3331,7 +3336,9 @@ foreach(_hdr
include/grpc++/impl/codegen/time.h
include/grpcpp/impl/codegen/async_generic_service.h
include/grpcpp/impl/codegen/async_stream.h
include/grpcpp/impl/codegen/async_stream_impl.h
include/grpcpp/impl/codegen/async_unary_call.h
include/grpcpp/impl/codegen/async_unary_call_impl.h
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
@ -3340,6 +3347,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_callback_impl.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
@ -3362,6 +3370,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_callback_impl.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
@ -3373,6 +3382,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/string_ref.h
include/grpcpp/impl/codegen/stub_options.h
include/grpcpp/impl/codegen/sync_stream.h
include/grpcpp/impl/codegen/sync_stream_impl.h
include/grpcpp/impl/codegen/time.h
include/grpcpp/impl/codegen/sync.h
include/grpc++/impl/codegen/proto_utils.h
@ -3853,11 +3863,14 @@ foreach(_hdr
include/grpcpp/server_posix.h
include/grpcpp/server_posix_impl.h
include/grpcpp/support/async_stream.h
include/grpcpp/support/async_stream_impl.h
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/async_unary_call_impl.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
include/grpcpp/support/channel_arguments_impl.h
include/grpcpp/support/client_callback.h
include/grpcpp/support/client_callback_impl.h
include/grpcpp/support/client_interceptor.h
include/grpcpp/support/config.h
include/grpcpp/support/interceptor.h
@ -3865,6 +3878,7 @@ foreach(_hdr
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
include/grpcpp/support/server_callback.h
include/grpcpp/support/server_callback_impl.h
include/grpcpp/support/server_interceptor.h
include/grpcpp/support/slice.h
include/grpcpp/support/status.h
@ -3872,6 +3886,7 @@ foreach(_hdr
include/grpcpp/support/string_ref.h
include/grpcpp/support/stub_options.h
include/grpcpp/support/sync_stream.h
include/grpcpp/support/sync_stream_impl.h
include/grpcpp/support/time.h
include/grpcpp/support/validate_service_config.h
include/grpc/support/alloc.h
@ -3957,7 +3972,9 @@ foreach(_hdr
include/grpc++/impl/codegen/time.h
include/grpcpp/impl/codegen/async_generic_service.h
include/grpcpp/impl/codegen/async_stream.h
include/grpcpp/impl/codegen/async_stream_impl.h
include/grpcpp/impl/codegen/async_unary_call.h
include/grpcpp/impl/codegen/async_unary_call_impl.h
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
@ -3966,6 +3983,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_callback_impl.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
@ -3988,6 +4006,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_callback_impl.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
@ -3999,6 +4018,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/string_ref.h
include/grpcpp/impl/codegen/stub_options.h
include/grpcpp/impl/codegen/sync_stream.h
include/grpcpp/impl/codegen/sync_stream_impl.h
include/grpcpp/impl/codegen/time.h
include/grpcpp/impl/codegen/sync.h
include/grpc/census.h
@ -4394,7 +4414,9 @@ foreach(_hdr
include/grpc++/impl/codegen/time.h
include/grpcpp/impl/codegen/async_generic_service.h
include/grpcpp/impl/codegen/async_stream.h
include/grpcpp/impl/codegen/async_stream_impl.h
include/grpcpp/impl/codegen/async_unary_call.h
include/grpcpp/impl/codegen/async_unary_call_impl.h
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
@ -4403,6 +4425,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_callback_impl.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
@ -4425,6 +4448,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_callback_impl.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
@ -4436,6 +4460,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/string_ref.h
include/grpcpp/impl/codegen/stub_options.h
include/grpcpp/impl/codegen/sync_stream.h
include/grpcpp/impl/codegen/sync_stream_impl.h
include/grpcpp/impl/codegen/time.h
include/grpc/impl/codegen/byte_buffer.h
include/grpc/impl/codegen/byte_buffer_reader.h
@ -4595,7 +4620,9 @@ foreach(_hdr
include/grpc++/impl/codegen/time.h
include/grpcpp/impl/codegen/async_generic_service.h
include/grpcpp/impl/codegen/async_stream.h
include/grpcpp/impl/codegen/async_stream_impl.h
include/grpcpp/impl/codegen/async_unary_call.h
include/grpcpp/impl/codegen/async_unary_call_impl.h
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
@ -4604,6 +4631,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_callback_impl.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
@ -4626,6 +4654,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_callback_impl.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
@ -4637,6 +4666,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/string_ref.h
include/grpcpp/impl/codegen/stub_options.h
include/grpcpp/impl/codegen/sync_stream.h
include/grpcpp/impl/codegen/sync_stream_impl.h
include/grpcpp/impl/codegen/time.h
include/grpc/impl/codegen/byte_buffer.h
include/grpc/impl/codegen/byte_buffer_reader.h
@ -4853,11 +4883,14 @@ foreach(_hdr
include/grpcpp/server_posix.h
include/grpcpp/server_posix_impl.h
include/grpcpp/support/async_stream.h
include/grpcpp/support/async_stream_impl.h
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/async_unary_call_impl.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
include/grpcpp/support/channel_arguments_impl.h
include/grpcpp/support/client_callback.h
include/grpcpp/support/client_callback_impl.h
include/grpcpp/support/client_interceptor.h
include/grpcpp/support/config.h
include/grpcpp/support/interceptor.h
@ -4865,6 +4898,7 @@ foreach(_hdr
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
include/grpcpp/support/server_callback.h
include/grpcpp/support/server_callback_impl.h
include/grpcpp/support/server_interceptor.h
include/grpcpp/support/slice.h
include/grpcpp/support/status.h
@ -4872,6 +4906,7 @@ foreach(_hdr
include/grpcpp/support/string_ref.h
include/grpcpp/support/stub_options.h
include/grpcpp/support/sync_stream.h
include/grpcpp/support/sync_stream_impl.h
include/grpcpp/support/time.h
include/grpcpp/support/validate_service_config.h
include/grpc/support/alloc.h
@ -4957,7 +4992,9 @@ foreach(_hdr
include/grpc++/impl/codegen/time.h
include/grpcpp/impl/codegen/async_generic_service.h
include/grpcpp/impl/codegen/async_stream.h
include/grpcpp/impl/codegen/async_stream_impl.h
include/grpcpp/impl/codegen/async_unary_call.h
include/grpcpp/impl/codegen/async_unary_call_impl.h
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
@ -4966,6 +5003,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_callback_impl.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
@ -4988,6 +5026,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/security/auth_context.h
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_callback_impl.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
@ -4999,6 +5038,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/string_ref.h
include/grpcpp/impl/codegen/stub_options.h
include/grpcpp/impl/codegen/sync_stream.h
include/grpcpp/impl/codegen/sync_stream_impl.h
include/grpcpp/impl/codegen/time.h
include/grpcpp/impl/codegen/sync.h
)

@ -5597,11 +5597,14 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/server_posix.h \
include/grpcpp/server_posix_impl.h \
include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_stream_impl.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/async_unary_call_impl.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
include/grpcpp/support/channel_arguments_impl.h \
include/grpcpp/support/client_callback.h \
include/grpcpp/support/client_callback_impl.h \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
include/grpcpp/support/interceptor.h \
@ -5609,6 +5612,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
include/grpcpp/support/server_callback.h \
include/grpcpp/support/server_callback_impl.h \
include/grpcpp/support/server_interceptor.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
@ -5616,6 +5620,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/string_ref.h \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/sync_stream_impl.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
include/grpc/support/alloc.h \
@ -5701,7 +5706,9 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/codegen/time.h \
include/grpcpp/impl/codegen/async_generic_service.h \
include/grpcpp/impl/codegen/async_stream.h \
include/grpcpp/impl/codegen/async_stream_impl.h \
include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/async_unary_call_impl.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
@ -5710,6 +5717,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_callback_impl.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
@ -5732,6 +5740,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_callback_impl.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
@ -5743,6 +5752,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/string_ref.h \
include/grpcpp/impl/codegen/stub_options.h \
include/grpcpp/impl/codegen/sync_stream.h \
include/grpcpp/impl/codegen/sync_stream_impl.h \
include/grpcpp/impl/codegen/time.h \
include/grpcpp/impl/codegen/sync.h \
include/grpc++/impl/codegen/proto_utils.h \
@ -6228,11 +6238,14 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/server_posix.h \
include/grpcpp/server_posix_impl.h \
include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_stream_impl.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/async_unary_call_impl.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
include/grpcpp/support/channel_arguments_impl.h \
include/grpcpp/support/client_callback.h \
include/grpcpp/support/client_callback_impl.h \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
include/grpcpp/support/interceptor.h \
@ -6240,6 +6253,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
include/grpcpp/support/server_callback.h \
include/grpcpp/support/server_callback_impl.h \
include/grpcpp/support/server_interceptor.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
@ -6247,6 +6261,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/string_ref.h \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/sync_stream_impl.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
include/grpc/support/alloc.h \
@ -6332,7 +6347,9 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/codegen/time.h \
include/grpcpp/impl/codegen/async_generic_service.h \
include/grpcpp/impl/codegen/async_stream.h \
include/grpcpp/impl/codegen/async_stream_impl.h \
include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/async_unary_call_impl.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
@ -6341,6 +6358,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_callback_impl.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
@ -6363,6 +6381,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_callback_impl.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
@ -6374,6 +6393,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/string_ref.h \
include/grpcpp/impl/codegen/stub_options.h \
include/grpcpp/impl/codegen/sync_stream.h \
include/grpcpp/impl/codegen/sync_stream_impl.h \
include/grpcpp/impl/codegen/time.h \
include/grpcpp/impl/codegen/sync.h \
include/grpc/census.h \
@ -6741,7 +6761,9 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/codegen/time.h \
include/grpcpp/impl/codegen/async_generic_service.h \
include/grpcpp/impl/codegen/async_stream.h \
include/grpcpp/impl/codegen/async_stream_impl.h \
include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/async_unary_call_impl.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
@ -6750,6 +6772,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_callback_impl.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
@ -6772,6 +6795,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_callback_impl.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
@ -6783,6 +6807,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/string_ref.h \
include/grpcpp/impl/codegen/stub_options.h \
include/grpcpp/impl/codegen/sync_stream.h \
include/grpcpp/impl/codegen/sync_stream_impl.h \
include/grpcpp/impl/codegen/time.h \
include/grpc/impl/codegen/byte_buffer.h \
include/grpc/impl/codegen/byte_buffer_reader.h \
@ -6913,7 +6938,9 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/codegen/time.h \
include/grpcpp/impl/codegen/async_generic_service.h \
include/grpcpp/impl/codegen/async_stream.h \
include/grpcpp/impl/codegen/async_stream_impl.h \
include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/async_unary_call_impl.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
@ -6922,6 +6949,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_callback_impl.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
@ -6944,6 +6972,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_callback_impl.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
@ -6955,6 +6984,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/string_ref.h \
include/grpcpp/impl/codegen/stub_options.h \
include/grpcpp/impl/codegen/sync_stream.h \
include/grpcpp/impl/codegen/sync_stream_impl.h \
include/grpcpp/impl/codegen/time.h \
include/grpc/impl/codegen/byte_buffer.h \
include/grpc/impl/codegen/byte_buffer_reader.h \
@ -7177,11 +7207,14 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/server_posix.h \
include/grpcpp/server_posix_impl.h \
include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_stream_impl.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/async_unary_call_impl.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
include/grpcpp/support/channel_arguments_impl.h \
include/grpcpp/support/client_callback.h \
include/grpcpp/support/client_callback_impl.h \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
include/grpcpp/support/interceptor.h \
@ -7189,6 +7222,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
include/grpcpp/support/server_callback.h \
include/grpcpp/support/server_callback_impl.h \
include/grpcpp/support/server_interceptor.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
@ -7196,6 +7230,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/string_ref.h \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/sync_stream_impl.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
include/grpc/support/alloc.h \
@ -7281,7 +7316,9 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/codegen/time.h \
include/grpcpp/impl/codegen/async_generic_service.h \
include/grpcpp/impl/codegen/async_stream.h \
include/grpcpp/impl/codegen/async_stream_impl.h \
include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/async_unary_call_impl.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
@ -7290,6 +7327,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_callback_impl.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
@ -7312,6 +7350,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_callback_impl.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
@ -7323,6 +7362,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/string_ref.h \
include/grpcpp/impl/codegen/stub_options.h \
include/grpcpp/impl/codegen/sync_stream.h \
include/grpcpp/impl/codegen/sync_stream_impl.h \
include/grpcpp/impl/codegen/time.h \
include/grpcpp/impl/codegen/sync.h \

@ -1253,7 +1253,9 @@ filegroups:
- include/grpc++/impl/codegen/time.h
- include/grpcpp/impl/codegen/async_generic_service.h
- include/grpcpp/impl/codegen/async_stream.h
- include/grpcpp/impl/codegen/async_stream_impl.h
- include/grpcpp/impl/codegen/async_unary_call.h
- include/grpcpp/impl/codegen/async_unary_call_impl.h
- include/grpcpp/impl/codegen/byte_buffer.h
- include/grpcpp/impl/codegen/call.h
- include/grpcpp/impl/codegen/call_hook.h
@ -1262,6 +1264,7 @@ filegroups:
- include/grpcpp/impl/codegen/callback_common.h
- include/grpcpp/impl/codegen/channel_interface.h
- include/grpcpp/impl/codegen/client_callback.h
- include/grpcpp/impl/codegen/client_callback_impl.h
- include/grpcpp/impl/codegen/client_context.h
- include/grpcpp/impl/codegen/client_context_impl.h
- include/grpcpp/impl/codegen/client_interceptor.h
@ -1284,6 +1287,7 @@ filegroups:
- include/grpcpp/impl/codegen/security/auth_context.h
- include/grpcpp/impl/codegen/serialization_traits.h
- include/grpcpp/impl/codegen/server_callback.h
- include/grpcpp/impl/codegen/server_callback_impl.h
- include/grpcpp/impl/codegen/server_context.h
- include/grpcpp/impl/codegen/server_context_impl.h
- include/grpcpp/impl/codegen/server_interceptor.h
@ -1295,6 +1299,7 @@ filegroups:
- include/grpcpp/impl/codegen/string_ref.h
- include/grpcpp/impl/codegen/stub_options.h
- include/grpcpp/impl/codegen/sync_stream.h
- include/grpcpp/impl/codegen/sync_stream_impl.h
- include/grpcpp/impl/codegen/time.h
uses:
- grpc_codegen
@ -1413,11 +1418,14 @@ filegroups:
- include/grpcpp/server_posix.h
- include/grpcpp/server_posix_impl.h
- include/grpcpp/support/async_stream.h
- include/grpcpp/support/async_stream_impl.h
- include/grpcpp/support/async_unary_call.h
- include/grpcpp/support/async_unary_call_impl.h
- include/grpcpp/support/byte_buffer.h
- include/grpcpp/support/channel_arguments.h
- include/grpcpp/support/channel_arguments_impl.h
- include/grpcpp/support/client_callback.h
- include/grpcpp/support/client_callback_impl.h
- include/grpcpp/support/client_interceptor.h
- include/grpcpp/support/config.h
- include/grpcpp/support/interceptor.h
@ -1425,6 +1433,7 @@ filegroups:
- include/grpcpp/support/proto_buffer_reader.h
- include/grpcpp/support/proto_buffer_writer.h
- include/grpcpp/support/server_callback.h
- include/grpcpp/support/server_callback_impl.h
- include/grpcpp/support/server_interceptor.h
- include/grpcpp/support/slice.h
- include/grpcpp/support/status.h
@ -1432,6 +1441,7 @@ filegroups:
- include/grpcpp/support/string_ref.h
- include/grpcpp/support/stub_options.h
- include/grpcpp/support/sync_stream.h
- include/grpcpp/support/sync_stream_impl.h
- include/grpcpp/support/time.h
- include/grpcpp/support/validate_service_config.h
headers:

@ -129,11 +129,14 @@ Pod::Spec.new do |s|
'include/grpcpp/server_posix.h',
'include/grpcpp/server_posix_impl.h',
'include/grpcpp/support/async_stream.h',
'include/grpcpp/support/async_stream_impl.h',
'include/grpcpp/support/async_unary_call.h',
'include/grpcpp/support/async_unary_call_impl.h',
'include/grpcpp/support/byte_buffer.h',
'include/grpcpp/support/channel_arguments.h',
'include/grpcpp/support/channel_arguments_impl.h',
'include/grpcpp/support/client_callback.h',
'include/grpcpp/support/client_callback_impl.h',
'include/grpcpp/support/client_interceptor.h',
'include/grpcpp/support/config.h',
'include/grpcpp/support/interceptor.h',
@ -141,6 +144,7 @@ Pod::Spec.new do |s|
'include/grpcpp/support/proto_buffer_reader.h',
'include/grpcpp/support/proto_buffer_writer.h',
'include/grpcpp/support/server_callback.h',
'include/grpcpp/support/server_callback_impl.h',
'include/grpcpp/support/server_interceptor.h',
'include/grpcpp/support/slice.h',
'include/grpcpp/support/status.h',
@ -148,11 +152,14 @@ Pod::Spec.new do |s|
'include/grpcpp/support/string_ref.h',
'include/grpcpp/support/stub_options.h',
'include/grpcpp/support/sync_stream.h',
'include/grpcpp/support/sync_stream_impl.h',
'include/grpcpp/support/time.h',
'include/grpcpp/support/validate_service_config.h',
'include/grpcpp/impl/codegen/async_generic_service.h',
'include/grpcpp/impl/codegen/async_stream.h',
'include/grpcpp/impl/codegen/async_stream_impl.h',
'include/grpcpp/impl/codegen/async_unary_call.h',
'include/grpcpp/impl/codegen/async_unary_call_impl.h',
'include/grpcpp/impl/codegen/byte_buffer.h',
'include/grpcpp/impl/codegen/call.h',
'include/grpcpp/impl/codegen/call_hook.h',
@ -161,6 +168,7 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/callback_common.h',
'include/grpcpp/impl/codegen/channel_interface.h',
'include/grpcpp/impl/codegen/client_callback.h',
'include/grpcpp/impl/codegen/client_callback_impl.h',
'include/grpcpp/impl/codegen/client_context.h',
'include/grpcpp/impl/codegen/client_context_impl.h',
'include/grpcpp/impl/codegen/client_interceptor.h',
@ -183,6 +191,7 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/security/auth_context.h',
'include/grpcpp/impl/codegen/serialization_traits.h',
'include/grpcpp/impl/codegen/server_callback.h',
'include/grpcpp/impl/codegen/server_callback_impl.h',
'include/grpcpp/impl/codegen/server_context.h',
'include/grpcpp/impl/codegen/server_context_impl.h',
'include/grpcpp/impl/codegen/server_interceptor.h',
@ -194,6 +203,7 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/string_ref.h',
'include/grpcpp/impl/codegen/stub_options.h',
'include/grpcpp/impl/codegen/sync_stream.h',
'include/grpcpp/impl/codegen/sync_stream_impl.h',
'include/grpcpp/impl/codegen/time.h',
'include/grpcpp/impl/codegen/sync.h'
end

@ -26,7 +26,7 @@
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/completion_queue_impl.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/sync.h>
@ -86,22 +86,23 @@ class Channel final : public ::grpc::ChannelInterface,
::grpc::internal::Call CreateCall(const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
::grpc::CompletionQueue* cq) override;
::grpc_impl::CompletionQueue* cq) override;
void PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops,
::grpc::internal::Call* call) override;
void* RegisterMethod(const char* method) override;
void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
::grpc::CompletionQueue* cq, void* tag) override;
::grpc_impl::CompletionQueue* cq,
void* tag) override;
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) override;
::grpc::CompletionQueue* CallbackCQ() override;
::grpc_impl::CompletionQueue* CallbackCQ() override;
::grpc::internal::Call CreateCallInternal(
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, ::grpc::CompletionQueue* cq,
::grpc_impl::ClientContext* context, ::grpc_impl::CompletionQueue* cq,
size_t interceptor_pos) override;
const grpc::string host_;
@ -114,7 +115,7 @@ class Channel final : public ::grpc::ChannelInterface,
// with this channel (if any). It is set on the first call to CallbackCQ().
// It is _not owned_ by the channel; ownership belongs with its internal
// shutdown callback tag (invoked when the CQ is fully shutdown).
::grpc::CompletionQueue* callback_cq_ = nullptr;
::grpc_impl::CompletionQueue* callback_cq_ = nullptr;
std::vector<
std::unique_ptr<::grpc::experimental::ClientInterceptorFactoryInterface>>

@ -22,17 +22,20 @@
#include <functional>
#include <grpcpp/client_context.h>
#include <grpcpp/support/async_stream.h>
#include <grpcpp/support/async_unary_call.h>
#include <grpcpp/support/async_stream_impl.h>
#include <grpcpp/support/async_unary_call_impl.h>
#include <grpcpp/support/byte_buffer.h>
#include <grpcpp/support/client_callback.h>
#include <grpcpp/support/client_callback_impl.h>
#include <grpcpp/support/status.h>
#include <functional>
namespace grpc {
typedef ClientAsyncReaderWriter<ByteBuffer, ByteBuffer>
typedef ::grpc_impl::ClientAsyncReaderWriter<ByteBuffer, ByteBuffer>
GenericClientAsyncReaderWriter;
typedef ClientAsyncResponseReader<ByteBuffer> GenericClientAsyncResponseReader;
typedef ::grpc_impl::ClientAsyncResponseReader<ByteBuffer>
GenericClientAsyncResponseReader;
} // namespace grpc
namespace grpc_impl {
class CompletionQueue;
@ -50,15 +53,15 @@ class GenericStub final {
/// succeeded (i.e. the call won't proceed if the return value is nullptr).
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> PrepareCall(
grpc::ClientContext* context, const grpc::string& method,
grpc::CompletionQueue* cq);
CompletionQueue* cq);
/// Setup a unary call to a named method \a method using \a context, and don't
/// start it. Let it be started explicitly with StartCall.
/// The return value only indicates whether or not registration of the call
/// succeeded (i.e. the call won't proceed if the return value is nullptr).
std::unique_ptr<grpc::GenericClientAsyncResponseReader> PrepareUnaryCall(
grpc::ClientContext* context, const grpc::string& method,
const grpc::ByteBuffer& request, grpc::CompletionQueue* cq);
grpc_impl::ClientContext* context, const grpc::string& method,
const grpc::ByteBuffer& request, CompletionQueue* cq);
/// DEPRECATED for multi-threaded use
/// Begin a call to a named method \a method using \a context.
@ -67,8 +70,8 @@ class GenericStub final {
/// The return value only indicates whether or not registration of the call
/// succeeded (i.e. the call won't proceed if the return value is nullptr).
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> Call(
grpc::ClientContext* context, const grpc::string& method,
grpc::CompletionQueue* cq, void* tag);
grpc_impl::ClientContext* context, const grpc::string& method,
CompletionQueue* cq, void* tag);
/// NOTE: class experimental_type is not part of the public API of this class
/// TODO(vjpai): Move these contents to the public API of GenericStub when
@ -79,23 +82,25 @@ class GenericStub final {
/// Setup and start a unary call to a named method \a method using
/// \a context and specifying the \a request and \a response buffers.
void UnaryCall(grpc::ClientContext* context, const grpc::string& method,
const grpc::ByteBuffer* request, grpc::ByteBuffer* response,
void UnaryCall(grpc_impl::ClientContext* context,
const grpc::string& method, const grpc::ByteBuffer* request,
grpc::ByteBuffer* response,
std::function<void(grpc::Status)> on_completion);
/// Setup and start a unary call to a named method \a method using
/// \a context and specifying the \a request and \a response buffers.
void UnaryCall(grpc::ClientContext* context, const grpc::string& method,
const grpc::ByteBuffer* request, grpc::ByteBuffer* response,
grpc::experimental::ClientUnaryReactor* reactor);
void UnaryCall(grpc_impl::ClientContext* context,
const grpc::string& method, const grpc::ByteBuffer* request,
grpc::ByteBuffer* response,
grpc_impl::experimental::ClientUnaryReactor* reactor);
/// Setup a call to a named method \a method using \a context and tied to
/// \a reactor . Like any other bidi streaming RPC, it will not be activated
/// until StartCall is invoked on its reactor.
void PrepareBidiStreamingCall(
grpc::ClientContext* context, const grpc::string& method,
grpc::experimental::ClientBidiReactor<grpc::ByteBuffer,
grpc::ByteBuffer>* reactor);
grpc_impl::ClientContext* context, const grpc::string& method,
grpc_impl::experimental::ClientBidiReactor<grpc::ByteBuffer,
grpc::ByteBuffer>* reactor);
private:
GenericStub* stub_;

@ -19,19 +19,21 @@
#ifndef GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H
#define GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H
#include <grpcpp/impl/codegen/async_stream.h>
#include <grpcpp/impl/codegen/async_stream_impl.h>
#include <grpcpp/impl/codegen/byte_buffer.h>
#include <grpcpp/impl/codegen/server_callback.h>
#include <grpcpp/impl/codegen/server_callback_impl.h>
struct grpc_server;
namespace grpc {
typedef ServerAsyncReaderWriter<ByteBuffer, ByteBuffer>
typedef ::grpc_impl::ServerAsyncReaderWriter<ByteBuffer, ByteBuffer>
GenericServerAsyncReaderWriter;
typedef ServerAsyncResponseWriter<ByteBuffer> GenericServerAsyncResponseWriter;
typedef ServerAsyncReader<ByteBuffer, ByteBuffer> GenericServerAsyncReader;
typedef ServerAsyncWriter<ByteBuffer> GenericServerAsyncWriter;
typedef ::grpc_impl::ServerAsyncResponseWriter<ByteBuffer>
GenericServerAsyncResponseWriter;
typedef ::grpc_impl::ServerAsyncReader<ByteBuffer, ByteBuffer>
GenericServerAsyncReader;
typedef ::grpc_impl::ServerAsyncWriter<ByteBuffer> GenericServerAsyncWriter;
class GenericServerContext final : public ::grpc_impl::ServerContext {
public:
@ -75,8 +77,9 @@ class AsyncGenericService final {
void RequestCall(GenericServerContext* ctx,
GenericServerAsyncReaderWriter* reader_writer,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag);
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag);
private:
friend class grpc_impl::Server;
@ -91,7 +94,8 @@ namespace experimental {
/// GenericServerContext rather than a ServerContext. All other reaction and
/// operation initiation APIs are the same as ServerBidiReactor.
class ServerGenericBidiReactor
: public ServerBidiReactor<ByteBuffer, ByteBuffer> {
: public ::grpc_impl::experimental::ServerBidiReactor<ByteBuffer,
ByteBuffer> {
public:
/// Similar to ServerBidiReactor::OnStarted except for argument type.
///
@ -137,8 +141,10 @@ class CallbackGenericService {
private:
friend class ::grpc_impl::Server;
internal::CallbackBidiHandler<ByteBuffer, ByteBuffer>* Handler() {
return new internal::CallbackBidiHandler<ByteBuffer, ByteBuffer>(
::grpc_impl::internal::CallbackBidiHandler<ByteBuffer, ByteBuffer>*
Handler() {
return new ::grpc_impl::internal::CallbackBidiHandler<ByteBuffer,
ByteBuffer>(
[this] { return CreateReactor(); });
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -19,299 +19,28 @@
#ifndef GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
#define GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
#include <assert.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_context_impl.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/async_unary_call_impl.h>
namespace grpc {
extern CoreCodegenInterface* g_core_codegen_interface;
/// An interface relevant for async client side unary RPCs (which send
/// one request message to a server and receive one response message).
template <class R>
class ClientAsyncResponseReaderInterface {
public:
virtual ~ClientAsyncResponseReaderInterface() {}
/// Start the call that was set up by the constructor, but only if the
/// constructor was invoked through the "Prepare" API which doesn't actually
/// start the call
virtual void StartCall() = 0;
/// Request notification of the reading of initial metadata. Completion
/// will be notified by \a tag on the associated completion queue.
/// This call is optional, but if it is used, it cannot be used concurrently
/// with or after the \a Finish method.
///
/// \param[in] tag Tag identifying this request.
virtual void ReadInitialMetadata(void* tag) = 0;
/// Request to receive the server's response \a msg and final \a status for
/// the call, and to notify \a tag on this call's completion queue when
/// finished.
///
/// This function will return when either:
/// - when the server's response message and status have been received.
/// - when the server has returned a non-OK status (no message expected in
/// this case).
/// - when the call failed for some reason and the library generated a
/// non-OK status.
///
/// \param[in] tag Tag identifying this request.
/// \param[out] status To be updated with the operation status.
/// \param[out] msg To be filled in with the server's response message.
virtual void Finish(R* msg, Status* status, void* tag) = 0;
};
namespace internal {
template <class R>
class ClientAsyncResponseReaderFactory {
public:
/// Start a call and write the request out if \a start is set.
/// \a tag will be notified on \a cq when the call has been started (i.e.
/// intitial metadata sent) and \a request has been written out.
/// If \a start is not set, the actual call must be initiated by StartCall
/// Note that \a context will be used to fill in custom initial metadata
/// used to send to the server when starting the call.
template <class W>
static ClientAsyncResponseReader<R>* Create(
ChannelInterface* channel, ::grpc_impl::CompletionQueue* cq,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, const W& request, bool start) {
::grpc::internal::Call call = channel->CreateCall(method, context, cq);
return new (g_core_codegen_interface->grpc_call_arena_alloc(
call.call(), sizeof(ClientAsyncResponseReader<R>)))
ClientAsyncResponseReader<R>(call, context, request, start);
}
};
} // namespace internal
using ClientAsyncResponseReaderInterface =
grpc_impl::ClientAsyncResponseReaderInterface<R>;
/// Async API for client-side unary RPCs, where the message response
/// received from the server is of type \a R.
template <class R>
class ClientAsyncResponseReader final
: public ClientAsyncResponseReaderInterface<R> {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* ptr, std::size_t size) {
assert(size == sizeof(ClientAsyncResponseReader));
}
// This operator should never be called as the memory should be freed as part
// of the arena destruction. It only exists to provide a matching operator
// delete to the operator new so that some compilers will not complain (see
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
// there are no tests catching the compiler warning.
static void operator delete(void*, void*) { assert(0); }
void StartCall() override {
assert(!started_);
started_ = true;
StartCallInternal();
}
/// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for
/// semantics.
///
/// Side effect:
/// - the \a ClientContext associated with this call is updated with
/// possible initial and trailing metadata sent from the server.
void ReadInitialMetadata(void* tag) override {
assert(started_);
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
single_buf.set_output_tag(tag);
single_buf.RecvInitialMetadata(context_);
call_.PerformOps(&single_buf);
initial_metadata_read_ = true;
}
/// See \a ClientAysncResponseReaderInterface::Finish for semantics.
///
/// Side effect:
/// - the \a ClientContext associated with this call is updated with
/// possible initial and trailing metadata sent from the server.
void Finish(R* msg, Status* status, void* tag) override {
assert(started_);
if (initial_metadata_read_) {
finish_buf.set_output_tag(tag);
finish_buf.RecvMessage(msg);
finish_buf.AllowNoMessage();
finish_buf.ClientRecvStatus(context_, status);
call_.PerformOps(&finish_buf);
} else {
single_buf.set_output_tag(tag);
single_buf.RecvInitialMetadata(context_);
single_buf.RecvMessage(msg);
single_buf.AllowNoMessage();
single_buf.ClientRecvStatus(context_, status);
call_.PerformOps(&single_buf);
}
}
private:
friend class internal::ClientAsyncResponseReaderFactory<R>;
::grpc_impl::ClientContext* const context_;
::grpc::internal::Call call_;
bool started_;
bool initial_metadata_read_ = false;
using ClientAsyncResponseReader = grpc_impl::ClientAsyncResponseReader<R>;
template <class W>
ClientAsyncResponseReader(::grpc::internal::Call call,
::grpc_impl::ClientContext* context,
const W& request, bool start)
: context_(context), call_(call), started_(start) {
// Bind the metadata at time of StartCallInternal but set up the rest here
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(single_buf.SendMessage(request).ok());
single_buf.ClientSendClose();
if (start) StartCallInternal();
}
void StartCallInternal() {
single_buf.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
}
// disable operator new
static void* operator new(std::size_t size);
static void* operator new(std::size_t size, void* p) { return p; }
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose,
::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpRecvMessage<R>,
::grpc::internal::CallOpClientRecvStatus>
single_buf;
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>,
::grpc::internal::CallOpClientRecvStatus>
finish_buf;
};
/// Async server-side API for handling unary calls, where the single
/// response message sent to the client is of type \a W.
template <class W>
class ServerAsyncResponseWriter final
: public internal::ServerAsyncStreamingInterface {
public:
explicit ServerAsyncResponseWriter(::grpc_impl::ServerContext* ctx)
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
/// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
///
/// Side effect:
/// The initial metadata that will be sent to the client from this op will
/// be taken from the \a ServerContext associated with the call.
///
/// \param[in] tag Tag identifying this request.
void SendInitialMetadata(void* tag) override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_buf_.set_output_tag(tag);
meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_buf_);
}
/// Indicate that the stream is to be finished and request notification
/// when the server has sent the appropriate signals to the client to
/// end the call. Should not be used concurrently with other operations.
///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of the call.
/// \param[in] msg Message to be sent to the client.
///
/// Side effect:
/// - also sends initial metadata if not already sent (using the
/// \a ServerContext associated with this call).
///
/// Note: if \a status has a non-OK code, then \a msg will not be sent,
/// and the client will receive only the status with possible trailing
/// metadata.
void Finish(const W& msg, const Status& status, void* tag) {
finish_buf_.set_output_tag(tag);
finish_buf_.set_core_cq_tag(&finish_buf_);
if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// The response is dropped if the status is not OK.
if (status.ok()) {
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_,
finish_buf_.SendMessage(msg));
} else {
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
}
call_.PerformOps(&finish_buf_);
}
using ServerAsyncResponseWriter = ::grpc_impl::ServerAsyncResponseWriter<W>;
/// Indicate that the stream is to be finished with a non-OK status,
/// and request notification for when the server has finished sending the
/// appropriate signals to the client to end the call.
/// Should not be used concurrently with other operations.
///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of the call.
/// - Note: \a status must have a non-OK code.
///
/// Side effect:
/// - also sends initial metadata if not already sent (using the
/// \a ServerContext associated with this call).
void FinishWithError(const Status& status, void* tag) {
GPR_CODEGEN_ASSERT(!status.ok());
finish_buf_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_buf_);
}
namespace internal {
private:
void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
template <class R>
using ClientAsyncResponseReaderFactory =
::grpc_impl::internal::ClientAsyncResponseReaderFactory<R>;
::grpc::internal::Call call_;
::grpc_impl::ServerContext* ctx_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
meta_buf_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpServerSendStatus>
finish_buf_;
};
} // namespace internal
} // namespace grpc
namespace std {
template <class R>
class default_delete<grpc::ClientAsyncResponseReader<R>> {
public:
void operator()(void* p) {}
};
template <class R>
class default_delete<grpc::ClientAsyncResponseReaderInterface<R>> {
public:
void operator()(void* p) {}
};
} // namespace std
#endif // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H

@ -0,0 +1,315 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H
#define GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H
#include <assert.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_context_impl.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
/// An interface relevant for async client side unary RPCs (which send
/// one request message to a server and receive one response message).
template <class R>
class ClientAsyncResponseReaderInterface {
public:
virtual ~ClientAsyncResponseReaderInterface() {}
/// Start the call that was set up by the constructor, but only if the
/// constructor was invoked through the "Prepare" API which doesn't actually
/// start the call
virtual void StartCall() = 0;
/// Request notification of the reading of initial metadata. Completion
/// will be notified by \a tag on the associated completion queue.
/// This call is optional, but if it is used, it cannot be used concurrently
/// with or after the \a Finish method.
///
/// \param[in] tag Tag identifying this request.
virtual void ReadInitialMetadata(void* tag) = 0;
/// Request to receive the server's response \a msg and final \a status for
/// the call, and to notify \a tag on this call's completion queue when
/// finished.
///
/// This function will return when either:
/// - when the server's response message and status have been received.
/// - when the server has returned a non-OK status (no message expected in
/// this case).
/// - when the call failed for some reason and the library generated a
/// non-OK status.
///
/// \param[in] tag Tag identifying this request.
/// \param[out] status To be updated with the operation status.
/// \param[out] msg To be filled in with the server's response message.
virtual void Finish(R* msg, ::grpc::Status* status, void* tag) = 0;
};
namespace internal {
template <class R>
class ClientAsyncResponseReaderFactory {
public:
/// Start a call and write the request out if \a start is set.
/// \a tag will be notified on \a cq when the call has been started (i.e.
/// intitial metadata sent) and \a request has been written out.
/// If \a start is not set, the actual call must be initiated by StartCall
/// Note that \a context will be used to fill in custom initial metadata
/// used to send to the server when starting the call.
template <class W>
static ClientAsyncResponseReader<R>* Create(
::grpc::ChannelInterface* channel, ::grpc_impl::CompletionQueue* cq,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, const W& request, bool start) {
::grpc::internal::Call call = channel->CreateCall(method, context, cq);
return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
call.call(), sizeof(ClientAsyncResponseReader<R>)))
ClientAsyncResponseReader<R>(call, context, request, start);
}
};
} // namespace internal
/// Async API for client-side unary RPCs, where the message response
/// received from the server is of type \a R.
template <class R>
class ClientAsyncResponseReader final
: public ClientAsyncResponseReaderInterface<R> {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* ptr, std::size_t size) {
assert(size == sizeof(ClientAsyncResponseReader));
}
// This operator should never be called as the memory should be freed as part
// of the arena destruction. It only exists to provide a matching operator
// delete to the operator new so that some compilers will not complain (see
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
// there are no tests catching the compiler warning.
static void operator delete(void*, void*) { assert(0); }
void StartCall() override {
assert(!started_);
started_ = true;
StartCallInternal();
}
/// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for
/// semantics.
///
/// Side effect:
/// - the \a ClientContext associated with this call is updated with
/// possible initial and trailing metadata sent from the server.
void ReadInitialMetadata(void* tag) override {
assert(started_);
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
single_buf.set_output_tag(tag);
single_buf.RecvInitialMetadata(context_);
call_.PerformOps(&single_buf);
initial_metadata_read_ = true;
}
/// See \a ClientAysncResponseReaderInterface::Finish for semantics.
///
/// Side effect:
/// - the \a ClientContext associated with this call is updated with
/// possible initial and trailing metadata sent from the server.
void Finish(R* msg, ::grpc::Status* status, void* tag) override {
assert(started_);
if (initial_metadata_read_) {
finish_buf.set_output_tag(tag);
finish_buf.RecvMessage(msg);
finish_buf.AllowNoMessage();
finish_buf.ClientRecvStatus(context_, status);
call_.PerformOps(&finish_buf);
} else {
single_buf.set_output_tag(tag);
single_buf.RecvInitialMetadata(context_);
single_buf.RecvMessage(msg);
single_buf.AllowNoMessage();
single_buf.ClientRecvStatus(context_, status);
call_.PerformOps(&single_buf);
}
}
private:
friend class internal::ClientAsyncResponseReaderFactory<R>;
::grpc_impl::ClientContext* const context_;
::grpc::internal::Call call_;
bool started_;
bool initial_metadata_read_ = false;
template <class W>
ClientAsyncResponseReader(::grpc::internal::Call call,
::grpc_impl::ClientContext* context,
const W& request, bool start)
: context_(context), call_(call), started_(start) {
// Bind the metadata at time of StartCallInternal but set up the rest here
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(single_buf.SendMessage(request).ok());
single_buf.ClientSendClose();
if (start) StartCallInternal();
}
void StartCallInternal() {
single_buf.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
}
// disable operator new
static void* operator new(std::size_t size);
static void* operator new(std::size_t size, void* p) { return p; }
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose,
::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpRecvMessage<R>,
::grpc::internal::CallOpClientRecvStatus>
single_buf;
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>,
::grpc::internal::CallOpClientRecvStatus>
finish_buf;
};
/// Async server-side API for handling unary calls, where the single
/// response message sent to the client is of type \a W.
template <class W>
class ServerAsyncResponseWriter final
: public ::grpc::internal::ServerAsyncStreamingInterface {
public:
explicit ServerAsyncResponseWriter(::grpc_impl::ServerContext* ctx)
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
/// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
///
/// Side effect:
/// The initial metadata that will be sent to the client from this op will
/// be taken from the \a ServerContext associated with the call.
///
/// \param[in] tag Tag identifying this request.
void SendInitialMetadata(void* tag) override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_buf_.set_output_tag(tag);
meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_buf_);
}
/// Indicate that the stream is to be finished and request notification
/// when the server has sent the appropriate signals to the client to
/// end the call. Should not be used concurrently with other operations.
///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of the call.
/// \param[in] msg Message to be sent to the client.
///
/// Side effect:
/// - also sends initial metadata if not already sent (using the
/// \a ServerContext associated with this call).
///
/// Note: if \a status has a non-OK code, then \a msg will not be sent,
/// and the client will receive only the status with possible trailing
/// metadata.
void Finish(const W& msg, const ::grpc::Status& status, void* tag) {
finish_buf_.set_output_tag(tag);
finish_buf_.set_core_cq_tag(&finish_buf_);
if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// The response is dropped if the status is not OK.
if (status.ok()) {
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_,
finish_buf_.SendMessage(msg));
} else {
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
}
call_.PerformOps(&finish_buf_);
}
/// Indicate that the stream is to be finished with a non-OK status,
/// and request notification for when the server has finished sending the
/// appropriate signals to the client to end the call.
/// Should not be used concurrently with other operations.
///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of the call.
/// - Note: \a status must have a non-OK code.
///
/// Side effect:
/// - also sends initial metadata if not already sent (using the
/// \a ServerContext associated with this call).
void FinishWithError(const ::grpc::Status& status, void* tag) {
GPR_CODEGEN_ASSERT(!status.ok());
finish_buf_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_buf_);
}
private:
void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
::grpc::internal::Call call_;
::grpc_impl::ServerContext* ctx_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
meta_buf_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpServerSendStatus>
finish_buf_;
};
} // namespace grpc_impl
namespace std {
template <class R>
class default_delete<::grpc_impl::ClientAsyncResponseReader<R>> {
public:
void operator()(void* p) {}
};
template <class R>
class default_delete<::grpc_impl::ClientAsyncResponseReaderInterface<R>> {
public:
void operator()(void* p) {}
};
} // namespace std
#endif // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H

@ -29,6 +29,17 @@
#include <vector>
namespace grpc_impl {
namespace internal {
template <class RequestType, class ResponseType>
class CallbackUnaryHandler;
template <class RequestType, class ResponseType>
class CallbackServerStreamingHandler;
} // namespace internal
} // namespace grpc_impl
namespace grpc {
class ServerInterface;
@ -45,10 +56,6 @@ template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackUnaryHandler;
template <class RequestType, class ResponseType>
class CallbackServerStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
class ExternalConnectionAcceptorImpl;
@ -176,9 +183,9 @@ class ByteBuffer final {
template <class ServiceType, class RequestType, class ResponseType>
friend class internal::ServerStreamingHandler;
template <class RequestType, class ResponseType>
friend class internal::CallbackUnaryHandler;
friend class ::grpc_impl::internal::CallbackUnaryHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackServerStreamingHandler;
friend class ::grpc_impl::internal::CallbackServerStreamingHandler;
template <StatusCode code>
friend class internal::ErrorMethodHandler;
template <class R>

@ -32,7 +32,7 @@
#include <grpcpp/impl/codegen/call_hook.h>
#include <grpcpp/impl/codegen/call_op_set_interface.h>
#include <grpcpp/impl/codegen/client_context_impl.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/completion_queue_impl.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>

@ -27,24 +27,13 @@
namespace grpc_impl {
class ClientContext;
class CompletionQueue;
} // namespace grpc_impl
namespace grpc {
class ChannelInterface;
template <class R>
class ClientReader;
template <class W>
class ClientWriter;
template <class W, class R>
class ClientReaderWriter;
namespace internal {
class Call;
class CallOpSetInterface;
class RpcMethod;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
class CallbackUnaryCallImpl;
template <class R>
@ -62,7 +51,19 @@ class ClientCallbackReaderFactory;
template <class W>
class ClientCallbackWriterFactory;
class ClientCallbackUnaryFactory;
} // namespace internal
} // namespace grpc_impl
namespace grpc {
class ChannelInterface;
namespace internal {
class Call;
class CallOpSetInterface;
class RpcMethod;
class InterceptedChannel;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
} // namespace internal
/// Codegen interface for \a grpc::Channel.
@ -102,30 +103,30 @@ class ChannelInterface {
private:
template <class R>
friend class ::grpc::ClientReader;
friend class ::grpc_impl::ClientReader;
template <class W>
friend class ::grpc::ClientWriter;
friend class ::grpc_impl::ClientWriter;
template <class W, class R>
friend class ::grpc::ClientReaderWriter;
friend class ::grpc_impl::ClientReaderWriter;
template <class R>
friend class ::grpc::internal::ClientAsyncReaderFactory;
friend class ::grpc_impl::internal::ClientAsyncReaderFactory;
template <class W>
friend class ::grpc::internal::ClientAsyncWriterFactory;
friend class ::grpc_impl::internal::ClientAsyncWriterFactory;
template <class W, class R>
friend class ::grpc::internal::ClientAsyncReaderWriterFactory;
friend class ::grpc_impl::internal::ClientAsyncReaderWriterFactory;
template <class R>
friend class ::grpc::internal::ClientAsyncResponseReaderFactory;
friend class ::grpc_impl::internal::ClientAsyncResponseReaderFactory;
template <class W, class R>
friend class ::grpc::internal::ClientCallbackReaderWriterFactory;
friend class ::grpc_impl::internal::ClientCallbackReaderWriterFactory;
template <class R>
friend class ::grpc::internal::ClientCallbackReaderFactory;
friend class ::grpc_impl::internal::ClientCallbackReaderFactory;
template <class W>
friend class ::grpc::internal::ClientCallbackWriterFactory;
friend class ::grpc::internal::ClientCallbackUnaryFactory;
friend class ::grpc_impl::internal::ClientCallbackWriterFactory;
friend class ::grpc_impl::internal::ClientCallbackUnaryFactory;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::CallbackUnaryCallImpl;
friend class ::grpc_impl::internal::CallbackUnaryCallImpl;
friend class ::grpc::internal::RpcMethod;
friend class ::grpc::internal::InterceptedChannel;
virtual internal::Call CreateCall(const internal::RpcMethod& method,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -63,10 +63,19 @@ class ChannelInterface;
namespace internal {
class RpcMethod;
class CallOpClientRecvStatus;
class CallOpRecvInitialMetadata;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
class CallOpClientRecvStatus;
class CallOpRecvInitialMetadata;
} // namespace internal
namespace testing {
class InteropClientContextInspector;
} // namespace testing
} // namespace grpc
namespace grpc_impl {
namespace internal {
template <class InputMessage, class OutputMessage>
class CallbackUnaryCallImpl;
template <class Request, class Response>
@ -78,6 +87,10 @@ class ClientCallbackWriterImpl;
class ClientCallbackUnaryImpl;
} // namespace internal
class CallCredentials;
class Channel;
class CompletionQueue;
class ServerContext;
template <class R>
class ClientReader;
template <class W>
@ -93,17 +106,6 @@ class ClientAsyncReaderWriter;
template <class R>
class ClientAsyncResponseReader;
namespace testing {
class InteropClientContextInspector;
} // namespace testing
} // namespace grpc
namespace grpc_impl {
class CallCredentials;
class Channel;
class CompletionQueue;
class ServerContext;
/// Options for \a ClientContext::FromServerContext specifying which traits from
/// the \a ServerContext to propagate (copy) from it into a new \a
/// ClientContext.
@ -398,30 +400,30 @@ class ClientContext {
friend class ::grpc::internal::CallOpRecvInitialMetadata;
friend class ::grpc_impl::Channel;
template <class R>
friend class ::grpc::ClientReader;
friend class ::grpc_impl::ClientReader;
template <class W>
friend class ::grpc::ClientWriter;
friend class ::grpc_impl::ClientWriter;
template <class W, class R>
friend class ::grpc::ClientReaderWriter;
friend class ::grpc_impl::ClientReaderWriter;
template <class R>
friend class ::grpc::ClientAsyncReader;
friend class ::grpc_impl::ClientAsyncReader;
template <class W>
friend class ::grpc::ClientAsyncWriter;
friend class ::grpc_impl::ClientAsyncWriter;
template <class W, class R>
friend class ::grpc::ClientAsyncReaderWriter;
friend class ::grpc_impl::ClientAsyncReaderWriter;
template <class R>
friend class ::grpc::ClientAsyncResponseReader;
friend class ::grpc_impl::ClientAsyncResponseReader;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::CallbackUnaryCallImpl;
friend class ::grpc_impl::internal::CallbackUnaryCallImpl;
template <class Request, class Response>
friend class ::grpc::internal::ClientCallbackReaderWriterImpl;
friend class ::grpc_impl::internal::ClientCallbackReaderWriterImpl;
template <class Response>
friend class ::grpc::internal::ClientCallbackReaderImpl;
friend class ::grpc_impl::internal::ClientCallbackReaderImpl;
template <class Request>
friend class ::grpc::internal::ClientCallbackWriterImpl;
friend class ::grpc::internal::ClientCallbackUnaryImpl;
friend class ::grpc_impl::internal::ClientCallbackWriterImpl;
friend class ::grpc_impl::internal::ClientCallbackUnaryImpl;
// Used by friend class CallOpClientRecvStatus
void set_debug_error_string(const grpc::string& debug_error_string) {

@ -49,10 +49,10 @@ class BlockingUnaryCallImpl {
BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method,
grpc_impl::ClientContext* context,
const InputMessage& request, OutputMessage* result) {
CompletionQueue cq(grpc_completion_queue_attributes{
::grpc_impl::CompletionQueue cq(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}); // Pluckable completion queue
Call call(channel->CreateCall(method, context, &cq));
::grpc::internal::Call call(channel->CreateCall(method, context, &cq));
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
CallOpClientSendClose, CallOpClientRecvStatus>

@ -47,9 +47,6 @@ class Channel;
class Server;
class ServerBuilder;
class ServerContext;
} // namespace grpc_impl
namespace grpc {
template <class R>
class ClientReader;
template <class W>
@ -64,6 +61,8 @@ namespace internal {
template <class W, class R>
class ServerReaderWriterBody;
} // namespace internal
} // namespace grpc_impl
namespace grpc {
class ChannelInterface;
class ServerInterface;
@ -255,17 +254,17 @@ class CompletionQueue : private ::grpc::GrpcLibraryCodegen {
// Friend synchronous wrappers so that they can access Pluck(), which is
// a semi-private API geared towards the synchronous implementation.
template <class R>
friend class ::grpc::ClientReader;
friend class ::grpc_impl::ClientReader;
template <class W>
friend class ::grpc::ClientWriter;
friend class ::grpc_impl::ClientWriter;
template <class W, class R>
friend class ::grpc::ClientReaderWriter;
friend class ::grpc_impl::ClientReaderWriter;
template <class R>
friend class ::grpc::ServerReader;
friend class ::grpc_impl::ServerReader;
template <class W>
friend class ::grpc::ServerWriter;
friend class ::grpc_impl::ServerWriter;
template <class W, class R>
friend class ::grpc::internal::ServerReaderWriterBody;
friend class ::grpc_impl::internal::ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -44,10 +44,6 @@ namespace grpc_impl {
class ClientContext;
class CompletionQueue;
class Server;
} // namespace grpc_impl
namespace grpc {
class GenericServerContext;
class ServerInterface;
template <class W, class R>
class ServerAsyncReader;
template <class W>
@ -62,14 +58,6 @@ template <class W>
class ServerWriter;
namespace internal {
template <class W, class R>
class ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler;
template <class RequestType, class ResponseType>
@ -80,12 +68,28 @@ template <class RequestType, class ResponseType>
class CallbackServerStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackBidiHandler;
template <class W, class R>
class ServerReaderWriterBody;
class ServerReactor;
} // namespace internal
} // namespace grpc_impl
namespace grpc {
class GenericServerContext;
class ServerInterface;
namespace internal {
template <class ServiceType, class RequestType, class ResponseType>
class ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
class Call;
class ServerReactor;
} // namespace internal
class ServerInterface;
@ -275,19 +279,19 @@ class ServerContext {
friend class ::grpc::ServerInterface;
friend class ::grpc_impl::Server;
template <class W, class R>
friend class ::grpc::ServerAsyncReader;
friend class ::grpc_impl::ServerAsyncReader;
template <class W>
friend class ::grpc::ServerAsyncWriter;
friend class ::grpc_impl::ServerAsyncWriter;
template <class W>
friend class ::grpc::ServerAsyncResponseWriter;
friend class ::grpc_impl::ServerAsyncResponseWriter;
template <class W, class R>
friend class ::grpc::ServerAsyncReaderWriter;
friend class ::grpc_impl::ServerAsyncReaderWriter;
template <class R>
friend class ::grpc::ServerReader;
friend class ::grpc_impl::ServerReader;
template <class W>
friend class ::grpc::ServerWriter;
friend class ::grpc_impl::ServerWriter;
template <class W, class R>
friend class ::grpc::internal::ServerReaderWriterBody;
friend class ::grpc_impl::internal::ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
@ -297,13 +301,13 @@ class ServerContext {
template <class Streamer, bool WriteNeeded>
friend class ::grpc::internal::TemplatedBidiStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackUnaryHandler;
friend class ::grpc_impl::internal::CallbackUnaryHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackClientStreamingHandler;
friend class ::grpc_impl::internal::CallbackClientStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackServerStreamingHandler;
friend class ::grpc_impl::internal::CallbackServerStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackBidiHandler;
friend class ::grpc_impl::internal::CallbackBidiHandler;
template <::grpc::StatusCode code>
friend class ::grpc::internal::ErrorMethodHandler;
friend class ::grpc_impl::ClientContext;
@ -317,7 +321,7 @@ class ServerContext {
void BeginCompletionOp(::grpc::internal::Call* call,
std::function<void(bool)> callback,
::grpc::internal::ServerReactor* reactor);
::grpc_impl::internal::ServerReactor* reactor);
/// Return the tag queued by BeginCompletionOp()
::grpc::internal::CompletionQueueTag* GetCompletionOpTag();

@ -149,8 +149,9 @@ class Service {
void RequestAsyncUnary(int index, ::grpc_impl::ServerContext* context,
Message* request,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag) {
// Typecast the index to size_t for indexing into a vector
// while preserving the API that existed before a compiler
// warning was first seen (grpc/grpc#11664)
@ -160,8 +161,9 @@ class Service {
}
void RequestAsyncClientStreaming(
int index, ::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
size_t idx = static_cast<size_t>(index);
server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
notification_cq, tag);
@ -169,16 +171,18 @@ class Service {
template <class Message>
void RequestAsyncServerStreaming(
int index, ::grpc_impl::ServerContext* context, Message* request,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
size_t idx = static_cast<size_t>(index);
server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
notification_cq, tag, request);
}
void RequestAsyncBidiStreaming(
int index, ::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
size_t idx = static_cast<size_t>(index);
server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
notification_cq, tag);

@ -19,918 +19,81 @@
#ifndef GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H
#define GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_context_impl.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/sync_stream_impl.h>
namespace grpc {
namespace internal {
/// Common interface for all synchronous client side streaming.
class ClientStreamingInterface {
public:
virtual ~ClientStreamingInterface() {}
/// Block waiting until the stream finishes and a final status of the call is
/// available.
///
/// It is appropriate to call this method when both:
/// * the calling code (client-side) has no more message to send
/// (this can be declared implicitly by calling this method, or
/// explicitly through an earlier call to <i>WritesDone</i> method of the
/// class in use, e.g. \a ClientWriterInterface::WritesDone or
/// \a ClientReaderWriterInterface::WritesDone).
/// * there are no more messages to be received from the server (which can
/// be known implicitly, or explicitly from an earlier call to \a
/// ReaderInterface::Read that returned "false").
///
/// This function will return either:
/// - when all incoming messages have been read and the server has
/// returned status.
/// - when the server has returned a non-OK status.
/// - OR when the call failed for some reason and the library generated a
/// status.
///
/// Return values:
/// - \a Status contains the status code, message and details for the call
/// - the \a ClientContext associated with this call is updated with
/// possible trailing metadata sent from the server.
virtual Status Finish() = 0;
};
typedef ::grpc_impl::internal::ClientStreamingInterface
ClientStreamingInterface;
/// Common interface for all synchronous server side streaming.
class ServerStreamingInterface {
public:
virtual ~ServerStreamingInterface() {}
typedef ::grpc_impl::internal::ServerStreamingInterface
ServerStreamingInterface;
/// Block to send initial metadata to client.
/// This call is optional, but if it is used, it cannot be used concurrently
/// with or after the \a Finish method.
///
/// The initial metadata that will be sent to the client will be
/// taken from the \a ServerContext associated with the call.
virtual void SendInitialMetadata() = 0;
};
/// An interface that yields a sequence of messages of type \a R.
template <class R>
class ReaderInterface {
public:
virtual ~ReaderInterface() {}
/// Get an upper bound on the next message size available for reading on this
/// stream.
virtual bool NextMessageSize(uint32_t* sz) = 0;
/// Block to read a message and parse to \a msg. Returns \a true on success.
/// This is thread-safe with respect to \a Write or \WritesDone methods on
/// the same stream. It should not be called concurrently with another \a
/// Read on the same stream as the order of delivery will not be defined.
///
/// \param[out] msg The read message.
///
/// \return \a false when there will be no more incoming messages, either
/// because the other side has called \a WritesDone() or the stream has failed
/// (or been cancelled).
virtual bool Read(R* msg) = 0;
};
using ReaderInterface = ::grpc_impl::internal::ReaderInterface<R>;
/// An interface that can be fed a sequence of messages of type \a W.
template <class W>
class WriterInterface {
public:
virtual ~WriterInterface() {}
using WriterInterface = ::grpc_impl::internal::WriterInterface<W>;
/// Block to write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
virtual bool Write(const W& msg, WriteOptions options) = 0;
template <class R>
using ClientReaderFactory = ::grpc_impl::internal::ClientReaderFactory<R>;
/// Block to write \a msg to the stream with default write options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
///
/// \return \a true on success, \a false when the stream has been closed.
inline bool Write(const W& msg) { return Write(msg, WriteOptions()); }
template <class W>
using ClientWriterFactory = ::grpc_impl::internal::ClientWriterFactory<W>;
/// Write \a msg and coalesce it with the writing of trailing metadata, using
/// WriteOptions \a options.
///
/// For client, WriteLast is equivalent of performing Write and WritesDone in
/// a single step. \a msg and trailing metadata are coalesced and sent on wire
/// by calling this function. For server, WriteLast buffers the \a msg.
/// The writing of \a msg is held until the service handler returns,
/// where \a msg and trailing metadata are coalesced and sent on wire.
/// Note that WriteLast can only buffer \a msg up to the flow control window
/// size. If \a msg size is larger than the window size, it will be sent on
/// wire without buffering.
///
/// \param[in] msg The message to be written to the stream.
/// \param[in] options The WriteOptions to be used to write this message.
void WriteLast(const W& msg, WriteOptions options) {
Write(msg, options.set_last_message());
}
};
template <class W, class R>
using ClientReaderWriterFactory =
::grpc_impl::internal::ClientReaderWriterFactory<W, R>;
} // namespace internal
/// Client-side interface for streaming reads of message of type \a R.
template <class R>
class ClientReaderInterface : public internal::ClientStreamingInterface,
public internal::ReaderInterface<R> {
public:
/// Block to wait for initial metadata from server. The received metadata
/// can only be accessed after this call returns. Should only be called before
/// the first read. Calling this method is optional, and if it is not called
/// the metadata will be available in ClientContext after the first read.
virtual void WaitForInitialMetadata() = 0;
};
using ClientReaderInterface = ::grpc_impl::ClientReaderInterface<R>;
namespace internal {
template <class R>
class ClientReaderFactory {
public:
template <class W>
static ClientReader<R>* Create(ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
const W& request) {
return new ClientReader<R>(channel, method, context, request);
}
};
} // namespace internal
/// Synchronous (blocking) client-side API for doing server-streaming RPCs,
/// where the stream of messages coming from the server has messages
/// of type \a R.
template <class R>
class ClientReader final : public ClientReaderInterface<R> {
public:
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
/// semantics.
///
// Side effect:
/// Once complete, the initial metadata read from
/// the server will be accessible through the \a ClientContext used to
/// construct this object.
void WaitForInitialMetadata() override {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
ops;
ops.RecvInitialMetadata(context_);
call_.PerformOps(&ops);
cq_.Pluck(&ops); /// status ignored
}
using ClientReader = ::grpc_impl::ClientReader<R>;
bool NextMessageSize(uint32_t* sz) override {
*sz = call_.max_receive_message_size();
return true;
}
/// See the \a ReaderInterface.Read method for semantics.
/// Side effect:
/// This also receives initial metadata from the server, if not
/// already received (if initial metadata is received, it can be then
/// accessed through the \a ClientContext associated with this call).
bool Read(R* msg) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpRecvMessage<R>>
ops;
if (!context_->initial_metadata_received_) {
ops.RecvInitialMetadata(context_);
}
ops.RecvMessage(msg);
call_.PerformOps(&ops);
return cq_.Pluck(&ops) && ops.got_message;
}
/// See the \a ClientStreamingInterface.Finish method for semantics.
///
/// Side effect:
/// The \a ClientContext associated with this call is updated with
/// possible metadata received from the server.
Status Finish() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops;
Status status;
ops.ClientRecvStatus(context_, &status);
call_.PerformOps(&ops);
GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
return status;
}
private:
friend class internal::ClientReaderFactory<R>;
::grpc_impl::ClientContext* context_;
::grpc_impl::CompletionQueue cq_;
::grpc::internal::Call call_;
/// Block to create a stream and write the initial metadata and \a request
/// out. Note that \a context will be used to fill in custom initial
/// metadata used to send to the server when starting the call.
template <class W>
ClientReader(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, const W& request)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(ops.SendMessagePtr(&request).ok());
ops.ClientSendClose();
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
};
/// Client-side interface for streaming writes of message type \a W.
template <class W>
class ClientWriterInterface : public internal::ClientStreamingInterface,
public internal::WriterInterface<W> {
public:
/// Half close writing from the client. (signal that the stream of messages
/// coming from the client is complete).
/// Blocks until currently-pending writes are completed.
/// Thread safe with respect to \a ReaderInterface::Read operations only
///
/// \return Whether the writes were successful.
virtual bool WritesDone() = 0;
};
using ClientWriterInterface = ::grpc_impl::ClientWriterInterface<W>;
namespace internal {
template <class W>
class ClientWriterFactory {
public:
template <class R>
static ClientWriter<W>* Create(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
R* response) {
return new ClientWriter<W>(channel, method, context, response);
}
};
} // namespace internal
/// Synchronous (blocking) client-side API for doing client-streaming RPCs,
/// where the outgoing message stream coming from the client has messages of
/// type \a W.
template <class W>
class ClientWriter : public ClientWriterInterface<W> {
public:
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
/// semantics.
///
// Side effect:
/// Once complete, the initial metadata read from the server will be
/// accessible through the \a ClientContext used to construct this object.
void WaitForInitialMetadata() {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
ops;
ops.RecvInitialMetadata(context_);
call_.PerformOps(&ops);
cq_.Pluck(&ops); // status ignored
}
using ClientWriter = ::grpc_impl::ClientWriter<W>;
/// See the WriterInterface.Write(const W& msg, WriteOptions options) method
/// for semantics.
///
/// Side effect:
/// Also sends initial metadata if not already sent (using the
/// \a ClientContext associated with this call).
using ::grpc::internal::WriterInterface<W>::Write;
bool Write(const W& msg, WriteOptions options) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
if (options.is_last_message()) {
options.set_buffer_hint();
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
if (!ops.SendMessagePtr(&msg, options).ok()) {
return false;
}
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
bool WritesDone() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
ops.ClientSendClose();
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
/// See the ClientStreamingInterface.Finish method for semantics.
/// Side effects:
/// - Also receives initial metadata if not already received.
/// - Attempts to fill in the \a response parameter passed
/// to the constructor of this instance with the response
/// message from the server.
Status Finish() override {
Status status;
if (!context_->initial_metadata_received_) {
finish_ops_.RecvInitialMetadata(context_);
}
finish_ops_.ClientRecvStatus(context_, &status);
call_.PerformOps(&finish_ops_);
GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_));
return status;
}
private:
friend class internal::ClientWriterFactory<W>;
/// Block to create a stream (i.e. send request headers and other initial
/// metadata to the server). Note that \a context will be used to fill
/// in custom initial metadata. \a response will be filled in with the
/// single expected response message from the server upon a successful
/// call to the \a Finish method of this instance.
template <class R>
ClientWriter(ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, R* response)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
finish_ops_.RecvMessage(response);
finish_ops_.AllowNoMessage();
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
}
::grpc_impl::ClientContext* context_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpGenericRecvMessage,
::grpc::internal::CallOpClientRecvStatus>
finish_ops_;
::grpc_impl::CompletionQueue cq_;
::grpc::internal::Call call_;
};
/// Client-side interface for bi-directional streaming with
/// client-to-server stream messages of type \a W and
/// server-to-client stream messages of type \a R.
template <class W, class R>
class ClientReaderWriterInterface : public internal::ClientStreamingInterface,
public internal::WriterInterface<W>,
public internal::ReaderInterface<R> {
public:
/// Block to wait for initial metadata from server. The received metadata
/// can only be accessed after this call returns. Should only be called before
/// the first read. Calling this method is optional, and if it is not called
/// the metadata will be available in ClientContext after the first read.
virtual void WaitForInitialMetadata() = 0;
using ClientReaderWriterInterface =
::grpc_impl::ClientReaderWriterInterface<W, R>;
/// Half close writing from the client. (signal that the stream of messages
/// coming from the clinet is complete).
/// Blocks until currently-pending writes are completed.
/// Thread-safe with respect to \a ReaderInterface::Read
///
/// \return Whether the writes were successful.
virtual bool WritesDone() = 0;
};
namespace internal {
template <class W, class R>
class ClientReaderWriterFactory {
public:
static ClientReaderWriter<W, R>* Create(
::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context) {
return new ClientReaderWriter<W, R>(channel, method, context);
}
};
} // namespace internal
/// Synchronous (blocking) client-side API for bi-directional streaming RPCs,
/// where the outgoing message stream coming from the client has messages of
/// type \a W, and the incoming messages stream coming from the server has
/// messages of type \a R.
template <class W, class R>
class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
public:
/// Block waiting to read initial metadata from the server.
/// This call is optional, but if it is used, it cannot be used concurrently
/// with or after the \a Finish method.
///
/// Once complete, the initial metadata read from the server will be
/// accessible through the \a ClientContext used to construct this object.
void WaitForInitialMetadata() override {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
ops;
ops.RecvInitialMetadata(context_);
call_.PerformOps(&ops);
cq_.Pluck(&ops); // status ignored
}
bool NextMessageSize(uint32_t* sz) override {
*sz = call_.max_receive_message_size();
return true;
}
/// See the \a ReaderInterface.Read method for semantics.
/// Side effect:
/// Also receives initial metadata if not already received (updates the \a
/// ClientContext associated with this call in that case).
bool Read(R* msg) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpRecvMessage<R>>
ops;
if (!context_->initial_metadata_received_) {
ops.RecvInitialMetadata(context_);
}
ops.RecvMessage(msg);
call_.PerformOps(&ops);
return cq_.Pluck(&ops) && ops.got_message;
}
/// See the \a WriterInterface.Write method for semantics.
///
/// Side effect:
/// Also sends initial metadata if not already sent (using the
/// \a ClientContext associated with this call to fill in values).
using ::grpc::internal::WriterInterface<W>::Write;
bool Write(const W& msg, WriteOptions options) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
if (options.is_last_message()) {
options.set_buffer_hint();
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
if (!ops.SendMessagePtr(&msg, options).ok()) {
return false;
}
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
bool WritesDone() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
ops.ClientSendClose();
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
using ClientReaderWriter = ::grpc_impl::ClientReaderWriter<W, R>;
/// See the ClientStreamingInterface.Finish method for semantics.
///
/// Side effect:
/// - the \a ClientContext associated with this call is updated with
/// possible trailing metadata sent from the server.
Status Finish() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpClientRecvStatus>
ops;
if (!context_->initial_metadata_received_) {
ops.RecvInitialMetadata(context_);
}
Status status;
ops.ClientRecvStatus(context_, &status);
call_.PerformOps(&ops);
GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
return status;
}
private:
friend class internal::ClientReaderWriterFactory<W, R>;
::grpc_impl::ClientContext* context_;
::grpc_impl::CompletionQueue cq_;
::grpc::internal::Call call_;
/// Block to create a stream and write the initial metadata and \a request
/// out. Note that \a context will be used to fill in custom initial metadata
/// used to send to the server when starting the call.
ClientReaderWriter(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
}
};
/// Server-side interface for streaming reads of message of type \a R.
template <class R>
class ServerReaderInterface : public internal::ServerStreamingInterface,
public internal::ReaderInterface<R> {};
using ServerReaderInterface = ::grpc_impl::ServerReaderInterface<R>;
/// Synchronous (blocking) server-side API for doing client-streaming RPCs,
/// where the incoming message stream coming from the client has messages of
/// type \a R.
template <class R>
class ServerReader final : public ServerReaderInterface<R> {
public:
/// See the \a ServerStreamingInterface.SendInitialMetadata method
/// for semantics. Note that initial metadata will be affected by the
/// \a ServerContext associated with this call.
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
}
bool NextMessageSize(uint32_t* sz) override {
*sz = call_->max_receive_message_size();
return true;
}
using ServerReader = ::grpc_impl::ServerReader<R>;
bool Read(R* msg) override {
internal::CallOpSet<internal::CallOpRecvMessage<R>> ops;
ops.RecvMessage(msg);
call_->PerformOps(&ops);
return call_->cq()->Pluck(&ops) && ops.got_message;
}
private:
internal::Call* const call_;
::grpc_impl::ServerContext* const ctx_;
template <class ServiceType, class RequestType, class ResponseType>
friend class internal::ClientStreamingHandler;
ServerReader(internal::Call* call, ::grpc_impl::ServerContext* ctx)
: call_(call), ctx_(ctx) {}
};
/// Server-side interface for streaming writes of message of type \a W.
template <class W>
class ServerWriterInterface : public internal::ServerStreamingInterface,
public internal::WriterInterface<W> {};
using ServerWriterInterface = ::grpc_impl::ServerWriterInterface<W>;
/// Synchronous (blocking) server-side API for doing for doing a
/// server-streaming RPCs, where the outgoing message stream coming from the
/// server has messages of type \a W.
template <class W>
class ServerWriter final : public ServerWriterInterface<W> {
public:
/// See the \a ServerStreamingInterface.SendInitialMetadata method
/// for semantics.
/// Note that initial metadata will be affected by the
/// \a ServerContext associated with this call.
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
}
using ServerWriter = ::grpc_impl::ServerWriter<W>;
/// See the \a WriterInterface.Write method for semantics.
///
/// Side effect:
/// Also sends initial metadata if not already sent (using the
/// \a ClientContext associated with this call to fill in values).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, WriteOptions options) override {
if (options.is_last_message()) {
options.set_buffer_hint();
}
if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) {
return false;
}
if (!ctx_->sent_initial_metadata_) {
ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
call_->PerformOps(&ctx_->pending_ops_);
// if this is the last message we defer the pluck until AFTER we start
// the trailing md op. This prevents hangs. See
// https://github.com/grpc/grpc/issues/11546
if (options.is_last_message()) {
ctx_->has_pending_ops_ = true;
return true;
}
ctx_->has_pending_ops_ = false;
return call_->cq()->Pluck(&ctx_->pending_ops_);
}
private:
internal::Call* const call_;
::grpc_impl::ServerContext* const ctx_;
template <class ServiceType, class RequestType, class ResponseType>
friend class internal::ServerStreamingHandler;
ServerWriter(internal::Call* call, ::grpc_impl::ServerContext* ctx)
: call_(call), ctx_(ctx) {}
};
/// Server-side interface for bi-directional streaming.
template <class W, class R>
class ServerReaderWriterInterface : public internal::ServerStreamingInterface,
public internal::WriterInterface<W>,
public internal::ReaderInterface<R> {};
/// Actual implementation of bi-directional streaming
namespace internal {
template <class W, class R>
class ServerReaderWriterBody final {
public:
ServerReaderWriterBody(Call* call, ::grpc_impl::ServerContext* ctx)
: call_(call), ctx_(ctx) {}
void SendInitialMetadata() {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
}
using ServerReaderWriterInterface =
::grpc_impl::ServerReaderWriterInterface<W, R>;
bool NextMessageSize(uint32_t* sz) {
*sz = call_->max_receive_message_size();
return true;
}
bool Read(R* msg) {
CallOpSet<CallOpRecvMessage<R>> ops;
ops.RecvMessage(msg);
call_->PerformOps(&ops);
return call_->cq()->Pluck(&ops) && ops.got_message;
}
bool Write(const W& msg, WriteOptions options) {
if (options.is_last_message()) {
options.set_buffer_hint();
}
if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) {
return false;
}
if (!ctx_->sent_initial_metadata_) {
ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
call_->PerformOps(&ctx_->pending_ops_);
// if this is the last message we defer the pluck until AFTER we start
// the trailing md op. This prevents hangs. See
// https://github.com/grpc/grpc/issues/11546
if (options.is_last_message()) {
ctx_->has_pending_ops_ = true;
return true;
}
ctx_->has_pending_ops_ = false;
return call_->cq()->Pluck(&ctx_->pending_ops_);
}
private:
Call* const call_;
::grpc_impl::ServerContext* const ctx_;
};
} // namespace internal
/// Synchronous (blocking) server-side API for a bidirectional
/// streaming call, where the incoming message stream coming from the client has
/// messages of type \a R, and the outgoing message streaming coming from
/// the server has messages of type \a W.
template <class W, class R>
class ServerReaderWriter final : public ServerReaderWriterInterface<W, R> {
public:
/// See the \a ServerStreamingInterface.SendInitialMetadata method
/// for semantics. Note that initial metadata will be affected by the
/// \a ServerContext associated with this call.
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
bool NextMessageSize(uint32_t* sz) override {
return body_.NextMessageSize(sz);
}
bool Read(R* msg) override { return body_.Read(msg); }
/// See the \a WriterInterface.Write(const W& msg, WriteOptions options)
/// method for semantics.
/// Side effect:
/// Also sends initial metadata if not already sent (using the \a
/// ServerContext associated with this call).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, WriteOptions options) override {
return body_.Write(msg, options);
}
private:
internal::ServerReaderWriterBody<W, R> body_;
friend class internal::TemplatedBidiStreamingHandler<ServerReaderWriter<W, R>,
false>;
ServerReaderWriter(internal::Call* call, ::grpc_impl::ServerContext* ctx)
: body_(call, ctx) {}
};
using ServerReaderWriter = ::grpc_impl::ServerReaderWriter<W, R>;
/// A class to represent a flow-controlled unary call. This is something
/// of a hybrid between conventional unary and streaming. This is invoked
/// through a unary call on the client side, but the server responds to it
/// as though it were a single-ping-pong streaming call. The server can use
/// the \a NextMessageSize method to determine an upper-bound on the size of
/// the message. A key difference relative to streaming: ServerUnaryStreamer
/// must have exactly 1 Read and exactly 1 Write, in that order, to function
/// correctly. Otherwise, the RPC is in error.
template <class RequestType, class ResponseType>
class ServerUnaryStreamer final
: public ServerReaderWriterInterface<ResponseType, RequestType> {
public:
/// Block to send initial metadata to client.
/// Implicit input parameter:
/// - the \a ServerContext associated with this call will be used for
/// sending initial metadata.
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
using ServerUnaryStreamer =
::grpc_impl::ServerUnaryStreamer<RequestType, ResponseType>;
/// Get an upper bound on the request message size from the client.
bool NextMessageSize(uint32_t* sz) override {
return body_.NextMessageSize(sz);
}
/// Read a message of type \a R into \a msg. Completion will be notified by \a
/// tag on the associated completion queue.
/// This is thread-safe with respect to \a Write or \a WritesDone methods. It
/// should not be called concurrently with other streaming APIs
/// on the same stream. It is not meaningful to call it concurrently
/// with another \a ReaderInterface::Read on the same stream since reads on
/// the same stream are delivered in order.
///
/// \param[out] msg Where to eventually store the read message.
/// \param[in] tag The tag identifying the operation.
bool Read(RequestType* request) override {
if (read_done_) {
return false;
}
read_done_ = true;
return body_.Read(request);
}
/// Block to write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
using internal::WriterInterface<ResponseType>::Write;
bool Write(const ResponseType& response, WriteOptions options) override {
if (write_done_ || !read_done_) {
return false;
}
write_done_ = true;
return body_.Write(response, options);
}
private:
internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
bool read_done_;
bool write_done_;
friend class internal::TemplatedBidiStreamingHandler<
ServerUnaryStreamer<RequestType, ResponseType>, true>;
ServerUnaryStreamer(internal::Call* call, ::grpc_impl::ServerContext* ctx)
: body_(call, ctx), read_done_(false), write_done_(false) {}
};
/// A class to represent a flow-controlled server-side streaming call.
/// This is something of a hybrid between server-side and bidi streaming.
/// This is invoked through a server-side streaming call on the client side,
/// but the server responds to it as though it were a bidi streaming call that
/// must first have exactly 1 Read and then any number of Writes.
template <class RequestType, class ResponseType>
class ServerSplitStreamer final
: public ServerReaderWriterInterface<ResponseType, RequestType> {
public:
/// Block to send initial metadata to client.
/// Implicit input parameter:
/// - the \a ServerContext associated with this call will be used for
/// sending initial metadata.
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
/// Get an upper bound on the request message size from the client.
bool NextMessageSize(uint32_t* sz) override {
return body_.NextMessageSize(sz);
}
/// Read a message of type \a R into \a msg. Completion will be notified by \a
/// tag on the associated completion queue.
/// This is thread-safe with respect to \a Write or \a WritesDone methods. It
/// should not be called concurrently with other streaming APIs
/// on the same stream. It is not meaningful to call it concurrently
/// with another \a ReaderInterface::Read on the same stream since reads on
/// the same stream are delivered in order.
///
/// \param[out] msg Where to eventually store the read message.
/// \param[in] tag The tag identifying the operation.
bool Read(RequestType* request) override {
if (read_done_) {
return false;
}
read_done_ = true;
return body_.Read(request);
}
/// Block to write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
using internal::WriterInterface<ResponseType>::Write;
bool Write(const ResponseType& response, WriteOptions options) override {
return read_done_ && body_.Write(response, options);
}
private:
internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
bool read_done_;
friend class internal::TemplatedBidiStreamingHandler<
ServerSplitStreamer<RequestType, ResponseType>, false>;
ServerSplitStreamer(internal::Call* call, ::grpc_impl::ServerContext* ctx)
: body_(call, ctx), read_done_(false) {}
};
using ServerSplitStreamer =
::grpc_impl::ServerSplitStreamer<RequestType, ResponseType>;
} // namespace grpc

@ -0,0 +1,944 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H
#define GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_context_impl.h>
#include <grpcpp/impl/codegen/completion_queue_impl.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
namespace internal {
/// Common interface for all synchronous client side streaming.
class ClientStreamingInterface {
public:
virtual ~ClientStreamingInterface() {}
/// Block waiting until the stream finishes and a final status of the call is
/// available.
///
/// It is appropriate to call this method when both:
/// * the calling code (client-side) has no more message to send
/// (this can be declared implicitly by calling this method, or
/// explicitly through an earlier call to <i>WritesDone</i> method of the
/// class in use, e.g. \a ClientWriterInterface::WritesDone or
/// \a ClientReaderWriterInterface::WritesDone).
/// * there are no more messages to be received from the server (which can
/// be known implicitly, or explicitly from an earlier call to \a
/// ReaderInterface::Read that returned "false").
///
/// This function will return either:
/// - when all incoming messages have been read and the server has
/// returned status.
/// - when the server has returned a non-OK status.
/// - OR when the call failed for some reason and the library generated a
/// status.
///
/// Return values:
/// - \a Status contains the status code, message and details for the call
/// - the \a ClientContext associated with this call is updated with
/// possible trailing metadata sent from the server.
virtual ::grpc::Status Finish() = 0;
};
/// Common interface for all synchronous server side streaming.
class ServerStreamingInterface {
public:
virtual ~ServerStreamingInterface() {}
/// Block to send initial metadata to client.
/// This call is optional, but if it is used, it cannot be used concurrently
/// with or after the \a Finish method.
///
/// The initial metadata that will be sent to the client will be
/// taken from the \a ServerContext associated with the call.
virtual void SendInitialMetadata() = 0;
};
/// An interface that yields a sequence of messages of type \a R.
template <class R>
class ReaderInterface {
public:
virtual ~ReaderInterface() {}
/// Get an upper bound on the next message size available for reading on this
/// stream.
virtual bool NextMessageSize(uint32_t* sz) = 0;
/// Block to read a message and parse to \a msg. Returns \a true on success.
/// This is thread-safe with respect to \a Write or \WritesDone methods on
/// the same stream. It should not be called concurrently with another \a
/// Read on the same stream as the order of delivery will not be defined.
///
/// \param[out] msg The read message.
///
/// \return \a false when there will be no more incoming messages, either
/// because the other side has called \a WritesDone() or the stream has failed
/// (or been cancelled).
virtual bool Read(R* msg) = 0;
};
/// An interface that can be fed a sequence of messages of type \a W.
template <class W>
class WriterInterface {
public:
virtual ~WriterInterface() {}
/// Block to write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
virtual bool Write(const W& msg, ::grpc::WriteOptions options) = 0;
/// Block to write \a msg to the stream with default write options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
///
/// \return \a true on success, \a false when the stream has been closed.
inline bool Write(const W& msg) { return Write(msg, ::grpc::WriteOptions()); }
/// Write \a msg and coalesce it with the writing of trailing metadata, using
/// WriteOptions \a options.
///
/// For client, WriteLast is equivalent of performing Write and WritesDone in
/// a single step. \a msg and trailing metadata are coalesced and sent on wire
/// by calling this function. For server, WriteLast buffers the \a msg.
/// The writing of \a msg is held until the service handler returns,
/// where \a msg and trailing metadata are coalesced and sent on wire.
/// Note that WriteLast can only buffer \a msg up to the flow control window
/// size. If \a msg size is larger than the window size, it will be sent on
/// wire without buffering.
///
/// \param[in] msg The message to be written to the stream.
/// \param[in] options The WriteOptions to be used to write this message.
void WriteLast(const W& msg, ::grpc::WriteOptions options) {
Write(msg, options.set_last_message());
}
};
} // namespace internal
/// Client-side interface for streaming reads of message of type \a R.
template <class R>
class ClientReaderInterface : public internal::ClientStreamingInterface,
public internal::ReaderInterface<R> {
public:
/// Block to wait for initial metadata from server. The received metadata
/// can only be accessed after this call returns. Should only be called before
/// the first read. Calling this method is optional, and if it is not called
/// the metadata will be available in ClientContext after the first read.
virtual void WaitForInitialMetadata() = 0;
};
namespace internal {
template <class R>
class ClientReaderFactory {
public:
template <class W>
static ClientReader<R>* Create(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
const W& request) {
return new ClientReader<R>(channel, method, context, request);
}
};
} // namespace internal
/// Synchronous (blocking) client-side API for doing server-streaming RPCs,
/// where the stream of messages coming from the server has messages
/// of type \a R.
template <class R>
class ClientReader final : public ClientReaderInterface<R> {
public:
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
/// semantics.
///
// Side effect:
/// Once complete, the initial metadata read from
/// the server will be accessible through the \a ClientContext used to
/// construct this object.
void WaitForInitialMetadata() override {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
ops;
ops.RecvInitialMetadata(context_);
call_.PerformOps(&ops);
cq_.Pluck(&ops); /// status ignored
}
bool NextMessageSize(uint32_t* sz) override {
*sz = call_.max_receive_message_size();
return true;
}
/// See the \a ReaderInterface.Read method for semantics.
/// Side effect:
/// This also receives initial metadata from the server, if not
/// already received (if initial metadata is received, it can be then
/// accessed through the \a ClientContext associated with this call).
bool Read(R* msg) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpRecvMessage<R>>
ops;
if (!context_->initial_metadata_received_) {
ops.RecvInitialMetadata(context_);
}
ops.RecvMessage(msg);
call_.PerformOps(&ops);
return cq_.Pluck(&ops) && ops.got_message;
}
/// See the \a ClientStreamingInterface.Finish method for semantics.
///
/// Side effect:
/// The \a ClientContext associated with this call is updated with
/// possible metadata received from the server.
::grpc::Status Finish() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops;
::grpc::Status status;
ops.ClientRecvStatus(context_, &status);
call_.PerformOps(&ops);
GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
return status;
}
private:
friend class internal::ClientReaderFactory<R>;
::grpc_impl::ClientContext* context_;
::grpc_impl::CompletionQueue cq_;
::grpc::internal::Call call_;
/// Block to create a stream and write the initial metadata and \a request
/// out. Note that \a context will be used to fill in custom initial
/// metadata used to send to the server when starting the call.
template <class W>
ClientReader(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, const W& request)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(ops.SendMessagePtr(&request).ok());
ops.ClientSendClose();
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
};
/// Client-side interface for streaming writes of message type \a W.
template <class W>
class ClientWriterInterface : public internal::ClientStreamingInterface,
public internal::WriterInterface<W> {
public:
/// Half close writing from the client. (signal that the stream of messages
/// coming from the client is complete).
/// Blocks until currently-pending writes are completed.
/// Thread safe with respect to \a ReaderInterface::Read operations only
///
/// \return Whether the writes were successful.
virtual bool WritesDone() = 0;
};
namespace internal {
template <class W>
class ClientWriterFactory {
public:
template <class R>
static ClientWriter<W>* Create(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
R* response) {
return new ClientWriter<W>(channel, method, context, response);
}
};
} // namespace internal
/// Synchronous (blocking) client-side API for doing client-streaming RPCs,
/// where the outgoing message stream coming from the client has messages of
/// type \a W.
template <class W>
class ClientWriter : public ClientWriterInterface<W> {
public:
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
/// semantics.
///
// Side effect:
/// Once complete, the initial metadata read from the server will be
/// accessible through the \a ClientContext used to construct this object.
void WaitForInitialMetadata() {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
ops;
ops.RecvInitialMetadata(context_);
call_.PerformOps(&ops);
cq_.Pluck(&ops); // status ignored
}
/// See the WriterInterface.Write(const W& msg, WriteOptions options) method
/// for semantics.
///
/// Side effect:
/// Also sends initial metadata if not already sent (using the
/// \a ClientContext associated with this call).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, ::grpc::WriteOptions options) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
if (options.is_last_message()) {
options.set_buffer_hint();
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
if (!ops.SendMessagePtr(&msg, options).ok()) {
return false;
}
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
bool WritesDone() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
ops.ClientSendClose();
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
/// See the ClientStreamingInterface.Finish method for semantics.
/// Side effects:
/// - Also receives initial metadata if not already received.
/// - Attempts to fill in the \a response parameter passed
/// to the constructor of this instance with the response
/// message from the server.
::grpc::Status Finish() override {
::grpc::Status status;
if (!context_->initial_metadata_received_) {
finish_ops_.RecvInitialMetadata(context_);
}
finish_ops_.ClientRecvStatus(context_, &status);
call_.PerformOps(&finish_ops_);
GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_));
return status;
}
private:
friend class internal::ClientWriterFactory<W>;
/// Block to create a stream (i.e. send request headers and other initial
/// metadata to the server). Note that \a context will be used to fill
/// in custom initial metadata. \a response will be filled in with the
/// single expected response message from the server upon a successful
/// call to the \a Finish method of this instance.
template <class R>
ClientWriter(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, R* response)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
finish_ops_.RecvMessage(response);
finish_ops_.AllowNoMessage();
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
}
::grpc_impl::ClientContext* context_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpGenericRecvMessage,
::grpc::internal::CallOpClientRecvStatus>
finish_ops_;
::grpc_impl::CompletionQueue cq_;
::grpc::internal::Call call_;
};
/// Client-side interface for bi-directional streaming with
/// client-to-server stream messages of type \a W and
/// server-to-client stream messages of type \a R.
template <class W, class R>
class ClientReaderWriterInterface : public internal::ClientStreamingInterface,
public internal::WriterInterface<W>,
public internal::ReaderInterface<R> {
public:
/// Block to wait for initial metadata from server. The received metadata
/// can only be accessed after this call returns. Should only be called before
/// the first read. Calling this method is optional, and if it is not called
/// the metadata will be available in ClientContext after the first read.
virtual void WaitForInitialMetadata() = 0;
/// Half close writing from the client. (signal that the stream of messages
/// coming from the clinet is complete).
/// Blocks until currently-pending writes are completed.
/// Thread-safe with respect to \a ReaderInterface::Read
///
/// \return Whether the writes were successful.
virtual bool WritesDone() = 0;
};
namespace internal {
template <class W, class R>
class ClientReaderWriterFactory {
public:
static ClientReaderWriter<W, R>* Create(
::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context) {
return new ClientReaderWriter<W, R>(channel, method, context);
}
};
} // namespace internal
/// Synchronous (blocking) client-side API for bi-directional streaming RPCs,
/// where the outgoing message stream coming from the client has messages of
/// type \a W, and the incoming messages stream coming from the server has
/// messages of type \a R.
template <class W, class R>
class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
public:
/// Block waiting to read initial metadata from the server.
/// This call is optional, but if it is used, it cannot be used concurrently
/// with or after the \a Finish method.
///
/// Once complete, the initial metadata read from the server will be
/// accessible through the \a ClientContext used to construct this object.
void WaitForInitialMetadata() override {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
ops;
ops.RecvInitialMetadata(context_);
call_.PerformOps(&ops);
cq_.Pluck(&ops); // status ignored
}
bool NextMessageSize(uint32_t* sz) override {
*sz = call_.max_receive_message_size();
return true;
}
/// See the \a ReaderInterface.Read method for semantics.
/// Side effect:
/// Also receives initial metadata if not already received (updates the \a
/// ClientContext associated with this call in that case).
bool Read(R* msg) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpRecvMessage<R>>
ops;
if (!context_->initial_metadata_received_) {
ops.RecvInitialMetadata(context_);
}
ops.RecvMessage(msg);
call_.PerformOps(&ops);
return cq_.Pluck(&ops) && ops.got_message;
}
/// See the \a WriterInterface.Write method for semantics.
///
/// Side effect:
/// Also sends initial metadata if not already sent (using the
/// \a ClientContext associated with this call to fill in values).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, ::grpc::WriteOptions options) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
if (options.is_last_message()) {
options.set_buffer_hint();
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
if (!ops.SendMessagePtr(&msg, options).ok()) {
return false;
}
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
bool WritesDone() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
ops.ClientSendClose();
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
/// See the ClientStreamingInterface.Finish method for semantics.
///
/// Side effect:
/// - the \a ClientContext associated with this call is updated with
/// possible trailing metadata sent from the server.
::grpc::Status Finish() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpClientRecvStatus>
ops;
if (!context_->initial_metadata_received_) {
ops.RecvInitialMetadata(context_);
}
::grpc::Status status;
ops.ClientRecvStatus(context_, &status);
call_.PerformOps(&ops);
GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
return status;
}
private:
friend class internal::ClientReaderWriterFactory<W, R>;
::grpc_impl::ClientContext* context_;
::grpc_impl::CompletionQueue cq_;
::grpc::internal::Call call_;
/// Block to create a stream and write the initial metadata and \a request
/// out. Note that \a context will be used to fill in custom initial metadata
/// used to send to the server when starting the call.
ClientReaderWriter(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
}
};
/// Server-side interface for streaming reads of message of type \a R.
template <class R>
class ServerReaderInterface : public internal::ServerStreamingInterface,
public internal::ReaderInterface<R> {};
/// Synchronous (blocking) server-side API for doing client-streaming RPCs,
/// where the incoming message stream coming from the client has messages of
/// type \a R.
template <class R>
class ServerReader final : public ServerReaderInterface<R> {
public:
/// See the \a ServerStreamingInterface.SendInitialMetadata method
/// for semantics. Note that initial metadata will be affected by the
/// \a ServerContext associated with this call.
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
}
bool NextMessageSize(uint32_t* sz) override {
*sz = call_->max_receive_message_size();
return true;
}
bool Read(R* msg) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>> ops;
ops.RecvMessage(msg);
call_->PerformOps(&ops);
return call_->cq()->Pluck(&ops) && ops.got_message;
}
private:
::grpc::internal::Call* const call_;
ServerContext* const ctx_;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ClientStreamingHandler;
ServerReader(::grpc::internal::Call* call, ::grpc_impl::ServerContext* ctx)
: call_(call), ctx_(ctx) {}
};
/// Server-side interface for streaming writes of message of type \a W.
template <class W>
class ServerWriterInterface : public internal::ServerStreamingInterface,
public internal::WriterInterface<W> {};
/// Synchronous (blocking) server-side API for doing for doing a
/// server-streaming RPCs, where the outgoing message stream coming from the
/// server has messages of type \a W.
template <class W>
class ServerWriter final : public ServerWriterInterface<W> {
public:
/// See the \a ServerStreamingInterface.SendInitialMetadata method
/// for semantics.
/// Note that initial metadata will be affected by the
/// \a ServerContext associated with this call.
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
}
/// See the \a WriterInterface.Write method for semantics.
///
/// Side effect:
/// Also sends initial metadata if not already sent (using the
/// \a ClientContext associated with this call to fill in values).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, ::grpc::WriteOptions options) override {
if (options.is_last_message()) {
options.set_buffer_hint();
}
if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) {
return false;
}
if (!ctx_->sent_initial_metadata_) {
ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
call_->PerformOps(&ctx_->pending_ops_);
// if this is the last message we defer the pluck until AFTER we start
// the trailing md op. This prevents hangs. See
// https://github.com/grpc/grpc/issues/11546
if (options.is_last_message()) {
ctx_->has_pending_ops_ = true;
return true;
}
ctx_->has_pending_ops_ = false;
return call_->cq()->Pluck(&ctx_->pending_ops_);
}
private:
::grpc::internal::Call* const call_;
::grpc_impl::ServerContext* const ctx_;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ServerStreamingHandler;
ServerWriter(::grpc::internal::Call* call, ::grpc_impl::ServerContext* ctx)
: call_(call), ctx_(ctx) {}
};
/// Server-side interface for bi-directional streaming.
template <class W, class R>
class ServerReaderWriterInterface : public internal::ServerStreamingInterface,
public internal::WriterInterface<W>,
public internal::ReaderInterface<R> {};
/// Actual implementation of bi-directional streaming
namespace internal {
template <class W, class R>
class ServerReaderWriterBody final {
public:
ServerReaderWriterBody(grpc::internal::Call* call,
::grpc_impl::ServerContext* ctx)
: call_(call), ctx_(ctx) {}
void SendInitialMetadata() {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
}
bool NextMessageSize(uint32_t* sz) {
*sz = call_->max_receive_message_size();
return true;
}
bool Read(R* msg) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>> ops;
ops.RecvMessage(msg);
call_->PerformOps(&ops);
return call_->cq()->Pluck(&ops) && ops.got_message;
}
bool Write(const W& msg, ::grpc::WriteOptions options) {
if (options.is_last_message()) {
options.set_buffer_hint();
}
if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) {
return false;
}
if (!ctx_->sent_initial_metadata_) {
ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
call_->PerformOps(&ctx_->pending_ops_);
// if this is the last message we defer the pluck until AFTER we start
// the trailing md op. This prevents hangs. See
// https://github.com/grpc/grpc/issues/11546
if (options.is_last_message()) {
ctx_->has_pending_ops_ = true;
return true;
}
ctx_->has_pending_ops_ = false;
return call_->cq()->Pluck(&ctx_->pending_ops_);
}
private:
grpc::internal::Call* const call_;
::grpc_impl::ServerContext* const ctx_;
};
} // namespace internal
/// Synchronous (blocking) server-side API for a bidirectional
/// streaming call, where the incoming message stream coming from the client has
/// messages of type \a R, and the outgoing message streaming coming from
/// the server has messages of type \a W.
template <class W, class R>
class ServerReaderWriter final : public ServerReaderWriterInterface<W, R> {
public:
/// See the \a ServerStreamingInterface.SendInitialMetadata method
/// for semantics. Note that initial metadata will be affected by the
/// \a ServerContext associated with this call.
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
bool NextMessageSize(uint32_t* sz) override {
return body_.NextMessageSize(sz);
}
bool Read(R* msg) override { return body_.Read(msg); }
/// See the \a WriterInterface.Write(const W& msg, WriteOptions options)
/// method for semantics.
/// Side effect:
/// Also sends initial metadata if not already sent (using the \a
/// ServerContext associated with this call).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, ::grpc::WriteOptions options) override {
return body_.Write(msg, options);
}
private:
internal::ServerReaderWriterBody<W, R> body_;
friend class ::grpc::internal::TemplatedBidiStreamingHandler<
ServerReaderWriter<W, R>, false>;
ServerReaderWriter(::grpc::internal::Call* call,
::grpc_impl::ServerContext* ctx)
: body_(call, ctx) {}
};
/// A class to represent a flow-controlled unary call. This is something
/// of a hybrid between conventional unary and streaming. This is invoked
/// through a unary call on the client side, but the server responds to it
/// as though it were a single-ping-pong streaming call. The server can use
/// the \a NextMessageSize method to determine an upper-bound on the size of
/// the message. A key difference relative to streaming: ServerUnaryStreamer
/// must have exactly 1 Read and exactly 1 Write, in that order, to function
/// correctly. Otherwise, the RPC is in error.
template <class RequestType, class ResponseType>
class ServerUnaryStreamer final
: public ServerReaderWriterInterface<ResponseType, RequestType> {
public:
/// Block to send initial metadata to client.
/// Implicit input parameter:
/// - the \a ServerContext associated with this call will be used for
/// sending initial metadata.
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
/// Get an upper bound on the request message size from the client.
bool NextMessageSize(uint32_t* sz) override {
return body_.NextMessageSize(sz);
}
/// Read a message of type \a R into \a msg. Completion will be notified by \a
/// tag on the associated completion queue.
/// This is thread-safe with respect to \a Write or \a WritesDone methods. It
/// should not be called concurrently with other streaming APIs
/// on the same stream. It is not meaningful to call it concurrently
/// with another \a ReaderInterface::Read on the same stream since reads on
/// the same stream are delivered in order.
///
/// \param[out] msg Where to eventually store the read message.
/// \param[in] tag The tag identifying the operation.
bool Read(RequestType* request) override {
if (read_done_) {
return false;
}
read_done_ = true;
return body_.Read(request);
}
/// Block to write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
using internal::WriterInterface<ResponseType>::Write;
bool Write(const ResponseType& response,
::grpc::WriteOptions options) override {
if (write_done_ || !read_done_) {
return false;
}
write_done_ = true;
return body_.Write(response, options);
}
private:
internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
bool read_done_;
bool write_done_;
friend class ::grpc::internal::TemplatedBidiStreamingHandler<
ServerUnaryStreamer<RequestType, ResponseType>, true>;
ServerUnaryStreamer(::grpc::internal::Call* call,
::grpc_impl::ServerContext* ctx)
: body_(call, ctx), read_done_(false), write_done_(false) {}
};
/// A class to represent a flow-controlled server-side streaming call.
/// This is something of a hybrid between server-side and bidi streaming.
/// This is invoked through a server-side streaming call on the client side,
/// but the server responds to it as though it were a bidi streaming call that
/// must first have exactly 1 Read and then any number of Writes.
template <class RequestType, class ResponseType>
class ServerSplitStreamer final
: public ServerReaderWriterInterface<ResponseType, RequestType> {
public:
/// Block to send initial metadata to client.
/// Implicit input parameter:
/// - the \a ServerContext associated with this call will be used for
/// sending initial metadata.
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
/// Get an upper bound on the request message size from the client.
bool NextMessageSize(uint32_t* sz) override {
return body_.NextMessageSize(sz);
}
/// Read a message of type \a R into \a msg. Completion will be notified by \a
/// tag on the associated completion queue.
/// This is thread-safe with respect to \a Write or \a WritesDone methods. It
/// should not be called concurrently with other streaming APIs
/// on the same stream. It is not meaningful to call it concurrently
/// with another \a ReaderInterface::Read on the same stream since reads on
/// the same stream are delivered in order.
///
/// \param[out] msg Where to eventually store the read message.
/// \param[in] tag The tag identifying the operation.
bool Read(RequestType* request) override {
if (read_done_) {
return false;
}
read_done_ = true;
return body_.Read(request);
}
/// Block to write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
using internal::WriterInterface<ResponseType>::Write;
bool Write(const ResponseType& response,
::grpc::WriteOptions options) override {
return read_done_ && body_.Write(response, options);
}
private:
internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
bool read_done_;
friend class ::grpc::internal::TemplatedBidiStreamingHandler<
ServerSplitStreamer<RequestType, ResponseType>, false>;
ServerSplitStreamer(::grpc::internal::Call* call,
::grpc_impl::ServerContext* ctx)
: body_(call, ctx), read_done_(false) {}
};
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H

@ -112,10 +112,6 @@ class ServerBuilder {
///
/// It can be invoked multiple times.
///
/// If port is not provided in the \a addr (e.g., "1.2.3.4:" or "1.2.3.4"),
/// the default port (i.e., https) is used. To request an ephemeral port,
/// \a addr must include 0 as the port number (e.g., "1.2.3.4:0").
///
/// \param addr_uri The address to try to bind to the server in URI form. If
/// the scheme name is omitted, "dns:///" is assumed. To bind to any address,
/// please use IPv6 any, i.e., [::]:<port>, which also accepts IPv4

@ -0,0 +1,24 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SUPPORT_ASYNC_STREAM_IMPL_H
#define GRPCPP_SUPPORT_ASYNC_STREAM_IMPL_H
#include <grpcpp/impl/codegen/async_stream_impl.h>
#endif // GRPCPP_SUPPORT_ASYNC_STREAM_IMPL_H

@ -0,0 +1,24 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SUPPORT_ASYNC_UNARY_CALL_IMPL_H
#define GRPCPP_SUPPORT_ASYNC_UNARY_CALL_IMPL_H
#include <grpcpp/impl/codegen/async_unary_call_impl.h>
#endif // GRPCPP_SUPPORT_ASYNC_UNARY_CALL_IMPL_H

@ -0,0 +1,24 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SUPPORT_CLIENT_CALLBACK_IMPL_H
#define GRPCPP_SUPPORT_CLIENT_CALLBACK_IMPL_H
#include <grpcpp/impl/codegen/client_callback_impl.h>
#endif // GRPCPP_SUPPORT_CLIENT_CALLBACK_IMPL_H

@ -0,0 +1,24 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SUPPORT_SERVER_CALLBACK_IMPL_H
#define GRPCPP_SUPPORT_SERVER_CALLBACK_IMPL_H
#include <grpcpp/impl/codegen/server_callback_impl.h>
#endif // GRPCPP_SUPPORT_SERVER_CALLBACK_IMPL_H

@ -0,0 +1,24 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SUPPORT_SYNC_STREAM_IMPL_H
#define GRPCPP_SUPPORT_SYNC_STREAM_IMPL_H
#include <grpcpp/impl/codegen/sync_stream_impl.h>
#endif // GRPCPP_SUPPORT_SYNC_STREAM_IMPL_H

@ -143,6 +143,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
"grpcpp/impl/codegen/async_unary_call.h",
"grpcpp/impl/codegen/client_callback.h",
"grpcpp/impl/codegen/client_context.h",
"grpcpp/impl/codegen/completion_queue.h",
"grpcpp/impl/codegen/method_handler_impl.h",
"grpcpp/impl/codegen/proto_utils.h",
"grpcpp/impl/codegen/rpc_method.h",
@ -946,11 +947,12 @@ void PrintHeaderServerCallbackMethodsHelper(
" abort();\n"
" return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
"}\n");
printer->Print(*vars,
"virtual ::grpc::experimental::ServerReadReactor< "
"$RealRequest$, $RealResponse$>* $Method$() {\n"
" return new ::grpc::internal::UnimplementedReadReactor<\n"
" $RealRequest$, $RealResponse$>;}\n");
printer->Print(
*vars,
"virtual ::grpc::experimental::ServerReadReactor< "
"$RealRequest$, $RealResponse$>* $Method$() {\n"
" return new ::grpc_impl::internal::UnimplementedReadReactor<\n"
" $RealRequest$, $RealResponse$>;}\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
@ -962,11 +964,12 @@ void PrintHeaderServerCallbackMethodsHelper(
" abort();\n"
" return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
"}\n");
printer->Print(*vars,
"virtual ::grpc::experimental::ServerWriteReactor< "
"$RealRequest$, $RealResponse$>* $Method$() {\n"
" return new ::grpc::internal::UnimplementedWriteReactor<\n"
" $RealRequest$, $RealResponse$>;}\n");
printer->Print(
*vars,
"virtual ::grpc::experimental::ServerWriteReactor< "
"$RealRequest$, $RealResponse$>* $Method$() {\n"
" return new ::grpc_impl::internal::UnimplementedWriteReactor<\n"
" $RealRequest$, $RealResponse$>;}\n");
} else if (method->BidiStreaming()) {
printer->Print(
*vars,
@ -978,11 +981,12 @@ void PrintHeaderServerCallbackMethodsHelper(
" abort();\n"
" return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
"}\n");
printer->Print(*vars,
"virtual ::grpc::experimental::ServerBidiReactor< "
"$RealRequest$, $RealResponse$>* $Method$() {\n"
" return new ::grpc::internal::UnimplementedBidiReactor<\n"
" $RealRequest$, $RealResponse$>;}\n");
printer->Print(
*vars,
"virtual ::grpc::experimental::ServerBidiReactor< "
"$RealRequest$, $RealResponse$>* $Method$() {\n"
" return new ::grpc_impl::internal::UnimplementedBidiReactor<\n"
" $RealRequest$, $RealResponse$>;}\n");
}
}
@ -1010,7 +1014,7 @@ void PrintHeaderServerMethodCallback(
printer->Print(
*vars,
" ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n"
" new ::grpc::internal::CallbackUnaryHandler< "
" new ::grpc_impl::internal::CallbackUnaryHandler< "
"$RealRequest$, $RealResponse$>(\n"
" [this](::grpc::ServerContext* context,\n"
" const $RealRequest$* request,\n"
@ -1024,7 +1028,7 @@ void PrintHeaderServerMethodCallback(
"void SetMessageAllocatorFor_$Method$(\n"
" ::grpc::experimental::MessageAllocator< "
"$RealRequest$, $RealResponse$>* allocator) {\n"
" static_cast<::grpc::internal::CallbackUnaryHandler< "
" static_cast<::grpc_impl::internal::CallbackUnaryHandler< "
"$RealRequest$, $RealResponse$>*>(\n"
" ::grpc::Service::experimental().GetHandler($Idx$))\n"
" ->SetMessageAllocator(allocator);\n");
@ -1032,21 +1036,21 @@ void PrintHeaderServerMethodCallback(
printer->Print(
*vars,
" ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n"
" new ::grpc::internal::CallbackClientStreamingHandler< "
" new ::grpc_impl::internal::CallbackClientStreamingHandler< "
"$RealRequest$, $RealResponse$>(\n"
" [this] { return this->$Method$(); }));\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
" ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n"
" new ::grpc::internal::CallbackServerStreamingHandler< "
" new ::grpc_impl::internal::CallbackServerStreamingHandler< "
"$RealRequest$, $RealResponse$>(\n"
" [this] { return this->$Method$(); }));\n");
} else if (method->BidiStreaming()) {
printer->Print(
*vars,
" ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n"
" new ::grpc::internal::CallbackBidiHandler< "
" new ::grpc_impl::internal::CallbackBidiHandler< "
"$RealRequest$, $RealResponse$>(\n"
" [this] { return this->$Method$(); }));\n");
}
@ -1084,7 +1088,7 @@ void PrintHeaderServerMethodRawCallback(
printer->Print(
*vars,
" ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n"
" new ::grpc::internal::CallbackUnaryHandler< "
" new ::grpc_impl::internal::CallbackUnaryHandler< "
"$RealRequest$, $RealResponse$>(\n"
" [this](::grpc::ServerContext* context,\n"
" const $RealRequest$* request,\n"
@ -1098,21 +1102,21 @@ void PrintHeaderServerMethodRawCallback(
printer->Print(
*vars,
" ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n"
" new ::grpc::internal::CallbackClientStreamingHandler< "
" new ::grpc_impl::internal::CallbackClientStreamingHandler< "
"$RealRequest$, $RealResponse$>(\n"
" [this] { return this->$Method$(); }));\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
" ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n"
" new ::grpc::internal::CallbackServerStreamingHandler< "
" new ::grpc_impl::internal::CallbackServerStreamingHandler< "
"$RealRequest$, $RealResponse$>(\n"
" [this] { return this->$Method$(); }));\n");
} else if (method->BidiStreaming()) {
printer->Print(
*vars,
" ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n"
" new ::grpc::internal::CallbackBidiHandler< "
" new ::grpc_impl::internal::CallbackBidiHandler< "
"$RealRequest$, $RealResponse$>(\n"
" [this] { return this->$Method$(); }));\n");
}
@ -1705,7 +1709,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"const $Request$* request, $Response$* response, "
"std::function<void(::grpc::Status)> f) {\n");
printer->Print(*vars,
" ::grpc::internal::CallbackUnaryCall"
" ::grpc_impl::internal::CallbackUnaryCall"
"(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
"context, request, response, std::move(f));\n}\n\n");
@ -1715,7 +1719,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"const ::grpc::ByteBuffer* request, $Response$* response, "
"std::function<void(::grpc::Status)> f) {\n");
printer->Print(*vars,
" ::grpc::internal::CallbackUnaryCall"
" ::grpc_impl::internal::CallbackUnaryCall"
"(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
"context, request, response, std::move(f));\n}\n\n");
@ -1725,7 +1729,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"const $Request$* request, $Response$* response, "
"::grpc::experimental::ClientUnaryReactor* reactor) {\n");
printer->Print(*vars,
" ::grpc::internal::ClientCallbackUnaryFactory::Create"
" ::grpc_impl::internal::ClientCallbackUnaryFactory::Create"
"(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
"context, request, response, reactor);\n}\n\n");
@ -1735,7 +1739,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"const ::grpc::ByteBuffer* request, $Response$* response, "
"::grpc::experimental::ClientUnaryReactor* reactor) {\n");
printer->Print(*vars,
" ::grpc::internal::ClientCallbackUnaryFactory::Create"
" ::grpc_impl::internal::ClientCallbackUnaryFactory::Create"
"(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
"context, request, response, reactor);\n}\n\n");
@ -1751,7 +1755,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
printer->Print(
*vars,
" return "
"::grpc::internal::ClientAsyncResponseReaderFactory< $Response$>"
"::grpc_impl::internal::ClientAsyncResponseReaderFactory< $Response$>"
"::Create(channel_.get(), cq, "
"rpcmethod_$Method$_, "
"context, request, $AsyncStart$);\n"
@ -1762,13 +1766,13 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"::grpc::ClientWriter< $Request$>* "
"$ns$$Service$::Stub::$Method$Raw("
"::grpc::ClientContext* context, $Response$* response) {\n");
printer->Print(
*vars,
" return ::grpc::internal::ClientWriterFactory< $Request$>::Create("
"channel_.get(), "
"rpcmethod_$Method$_, "
"context, response);\n"
"}\n\n");
printer->Print(*vars,
" return ::grpc_impl::internal::ClientWriterFactory< "
"$Request$>::Create("
"channel_.get(), "
"rpcmethod_$Method$_, "
"context, response);\n"
"}\n\n");
printer->Print(
*vars,
@ -1777,7 +1781,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"$Response$* response, "
"::grpc::experimental::ClientWriteReactor< $Request$>* reactor) {\n");
printer->Print(*vars,
" ::grpc::internal::ClientCallbackWriterFactory< "
" ::grpc_impl::internal::ClientCallbackWriterFactory< "
"$Request$>::Create("
"stub_->channel_.get(), "
"stub_->rpcmethod_$Method$_, "
@ -1796,7 +1800,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
printer->Print(
*vars,
" return ::grpc::internal::ClientAsyncWriterFactory< $Request$>"
" return ::grpc_impl::internal::ClientAsyncWriterFactory< $Request$>"
"::Create(channel_.get(), cq, "
"rpcmethod_$Method$_, "
"context, response, $AsyncStart$$AsyncCreateArgs$);\n"
@ -1808,13 +1812,13 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"::grpc::ClientReader< $Response$>* "
"$ns$$Service$::Stub::$Method$Raw("
"::grpc::ClientContext* context, const $Request$& request) {\n");
printer->Print(
*vars,
" return ::grpc::internal::ClientReaderFactory< $Response$>::Create("
"channel_.get(), "
"rpcmethod_$Method$_, "
"context, request);\n"
"}\n\n");
printer->Print(*vars,
" return ::grpc_impl::internal::ClientReaderFactory< "
"$Response$>::Create("
"channel_.get(), "
"rpcmethod_$Method$_, "
"context, request);\n"
"}\n\n");
printer->Print(
*vars,
@ -1823,7 +1827,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"$Request$* request, "
"::grpc::experimental::ClientReadReactor< $Response$>* reactor) {\n");
printer->Print(*vars,
" ::grpc::internal::ClientCallbackReaderFactory< "
" ::grpc_impl::internal::ClientCallbackReaderFactory< "
"$Response$>::Create("
"stub_->channel_.get(), "
"stub_->rpcmethod_$Method$_, "
@ -1843,7 +1847,8 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
printer->Print(
*vars,
" return ::grpc::internal::ClientAsyncReaderFactory< $Response$>"
" return ::grpc_impl::internal::ClientAsyncReaderFactory< "
"$Response$>"
"::Create(channel_.get(), cq, "
"rpcmethod_$Method$_, "
"context, request, $AsyncStart$$AsyncCreateArgs$);\n"
@ -1855,7 +1860,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"::grpc::ClientReaderWriter< $Request$, $Response$>* "
"$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n");
printer->Print(*vars,
" return ::grpc::internal::ClientReaderWriterFactory< "
" return ::grpc_impl::internal::ClientReaderWriterFactory< "
"$Request$, $Response$>::Create("
"channel_.get(), "
"rpcmethod_$Method$_, "
@ -1868,13 +1873,14 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"ClientContext* context, "
"::grpc::experimental::ClientBidiReactor< $Request$,$Response$>* "
"reactor) {\n");
printer->Print(*vars,
" ::grpc::internal::ClientCallbackReaderWriterFactory< "
"$Request$,$Response$>::Create("
"stub_->channel_.get(), "
"stub_->rpcmethod_$Method$_, "
"context, reactor);\n"
"}\n\n");
printer->Print(
*vars,
" ::grpc_impl::internal::ClientCallbackReaderWriterFactory< "
"$Request$,$Response$>::Create("
"stub_->channel_.get(), "
"stub_->rpcmethod_$Method$_, "
"context, reactor);\n"
"}\n\n");
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
@ -1888,7 +1894,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
printer->Print(*vars,
" return "
"::grpc::internal::ClientAsyncReaderWriterFactory< "
"::grpc_impl::internal::ClientAsyncReaderWriterFactory< "
"$Request$, $Response$>::Create("
"channel_.get(), cq, "
"rpcmethod_$Method$_, "
@ -2279,7 +2285,8 @@ void PrintMockClientMethods(grpc_generator::Printer* printer,
printer->Print(
*vars,
"MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, "
"::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*"
"::grpc::ClientAsyncReaderWriterInterface<$Request$, "
"$Response$>*"
"(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq"
"$AsyncMethodParams$));\n");
}

@ -433,6 +433,8 @@ void AresDnsResolver::StartResolvingLocked() {
class AresDnsResolverFactory : public ResolverFactory {
public:
bool IsValidUri(const grpc_uri* uri) const override { return true; }
OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
return OrphanablePtr<Resolver>(New<AresDnsResolver>(std::move(args)));
}

@ -258,11 +258,16 @@ void NativeDnsResolver::StartResolvingLocked() {
class NativeDnsResolverFactory : public ResolverFactory {
public:
OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
if (GPR_UNLIKELY(0 != strcmp(args.uri->authority, ""))) {
bool IsValidUri(const grpc_uri* uri) const override {
if (GPR_UNLIKELY(0 != strcmp(uri->authority, ""))) {
gpr_log(GPR_ERROR, "authority based dns uri's not supported");
return OrphanablePtr<Resolver>(nullptr);
return false;
}
return true;
}
OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
if (!IsValidUri(args.uri)) return nullptr;
return OrphanablePtr<Resolver>(New<NativeDnsResolver>(std::move(args)));
}

@ -89,9 +89,15 @@ FakeResolver::FakeResolver(ResolverArgs args)
: Resolver(args.combiner, std::move(args.result_handler)) {
GRPC_CLOSURE_INIT(&reresolution_closure_, ReturnReresolutionResult, this,
grpc_combiner_scheduler(combiner()));
channel_args_ = grpc_channel_args_copy(args.args);
FakeResolverResponseGenerator* response_generator =
FakeResolverResponseGenerator::GetFromArgs(args.args);
// Channels sharing the same subchannels may have different resolver response
// generators. If we don't remove this arg, subchannel pool will create new
// subchannels for the same address instead of reusing existing ones because
// of different values of this channel arg.
const char* args_to_remove[] = {GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR};
channel_args_ = grpc_channel_args_copy_and_remove(
args.args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove));
if (response_generator != nullptr) {
response_generator->resolver_ = this;
if (response_generator->has_result_) {
@ -315,6 +321,8 @@ namespace {
class FakeResolverFactory : public ResolverFactory {
public:
bool IsValidUri(const grpc_uri* uri) const override { return true; }
OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
return OrphanablePtr<Resolver>(New<FakeResolver>(std::move(args)));
}

@ -80,24 +80,23 @@ void SockaddrResolver::StartLocked() {
void DoNothing(void* ignored) {}
OrphanablePtr<Resolver> CreateSockaddrResolver(
ResolverArgs args,
bool parse(const grpc_uri* uri, grpc_resolved_address* dst)) {
if (0 != strcmp(args.uri->authority, "")) {
bool ParseUri(const grpc_uri* uri,
bool parse(const grpc_uri* uri, grpc_resolved_address* dst),
ServerAddressList* addresses) {
if (0 != strcmp(uri->authority, "")) {
gpr_log(GPR_ERROR, "authority-based URIs not supported by the %s scheme",
args.uri->scheme);
return nullptr;
uri->scheme);
return false;
}
// Construct addresses.
grpc_slice path_slice =
grpc_slice_new(args.uri->path, strlen(args.uri->path), DoNothing);
grpc_slice_new(uri->path, strlen(uri->path), DoNothing);
grpc_slice_buffer path_parts;
grpc_slice_buffer_init(&path_parts);
grpc_slice_split(path_slice, ",", &path_parts);
ServerAddressList addresses;
bool errors_found = false;
for (size_t i = 0; i < path_parts.count; i++) {
grpc_uri ith_uri = *args.uri;
grpc_uri ith_uri = *uri;
UniquePtr<char> part_str(grpc_slice_to_c_string(path_parts.slices[i]));
ith_uri.path = part_str.get();
grpc_resolved_address addr;
@ -105,13 +104,20 @@ OrphanablePtr<Resolver> CreateSockaddrResolver(
errors_found = true;
break;
}
addresses.emplace_back(addr, nullptr /* args */);
if (addresses != nullptr) {
addresses->emplace_back(addr, nullptr /* args */);
}
}
grpc_slice_buffer_destroy_internal(&path_parts);
grpc_slice_unref_internal(path_slice);
if (errors_found) {
return OrphanablePtr<Resolver>(nullptr);
}
return !errors_found;
}
OrphanablePtr<Resolver> CreateSockaddrResolver(
ResolverArgs args,
bool parse(const grpc_uri* uri, grpc_resolved_address* dst)) {
ServerAddressList addresses;
if (!ParseUri(args.uri, parse, &addresses)) return nullptr;
// Instantiate resolver.
return OrphanablePtr<Resolver>(
New<SockaddrResolver>(std::move(addresses), std::move(args)));
@ -119,6 +125,10 @@ OrphanablePtr<Resolver> CreateSockaddrResolver(
class IPv4ResolverFactory : public ResolverFactory {
public:
bool IsValidUri(const grpc_uri* uri) const override {
return ParseUri(uri, grpc_parse_ipv4, nullptr);
}
OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
return CreateSockaddrResolver(std::move(args), grpc_parse_ipv4);
}
@ -128,6 +138,10 @@ class IPv4ResolverFactory : public ResolverFactory {
class IPv6ResolverFactory : public ResolverFactory {
public:
bool IsValidUri(const grpc_uri* uri) const override {
return ParseUri(uri, grpc_parse_ipv6, nullptr);
}
OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
return CreateSockaddrResolver(std::move(args), grpc_parse_ipv6);
}
@ -138,6 +152,10 @@ class IPv6ResolverFactory : public ResolverFactory {
#ifdef GRPC_HAVE_UNIX_SOCKET
class UnixResolverFactory : public ResolverFactory {
public:
bool IsValidUri(const grpc_uri* uri) const override {
return ParseUri(uri, grpc_parse_unix, nullptr);
}
OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
return CreateSockaddrResolver(std::move(args), grpc_parse_unix);
}

@ -47,6 +47,10 @@ struct ResolverArgs {
class ResolverFactory {
public:
/// Returns a bool indicating whether the input uri is valid to create a
/// resolver.
virtual bool IsValidUri(const grpc_uri* uri) const GRPC_ABSTRACT;
/// Returns a new resolver instance.
virtual OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const
GRPC_ABSTRACT;

@ -132,6 +132,17 @@ ResolverFactory* ResolverRegistry::LookupResolverFactory(const char* scheme) {
return g_state->LookupResolverFactory(scheme);
}
bool ResolverRegistry::IsValidTarget(const char* target) {
grpc_uri* uri = nullptr;
char* canonical_target = nullptr;
ResolverFactory* factory =
g_state->FindResolverFactory(target, &uri, &canonical_target);
bool result = factory == nullptr ? false : factory->IsValidUri(uri);
grpc_uri_destroy(uri);
gpr_free(canonical_target);
return result;
}
OrphanablePtr<Resolver> ResolverRegistry::CreateResolver(
const char* target, const grpc_channel_args* args,
grpc_pollset_set* pollset_set, grpc_combiner* combiner,

@ -50,6 +50,9 @@ class ResolverRegistry {
static void RegisterResolverFactory(UniquePtr<ResolverFactory> factory);
};
/// Checks whether the user input \a target is valid to create a resolver.
static bool IsValidTarget(const char* target);
/// Creates a resolver given \a target.
/// First tries to parse \a target as a URI. If this succeeds, tries
/// to locate a registered resolver factory based on the URI scheme.

@ -44,7 +44,10 @@ int JoinHostPort(UniquePtr<char>* out, const char* host, int port) {
return ret;
}
bool SplitHostPort(StringView name, StringView* host, StringView* port) {
namespace {
bool DoSplitHostPort(StringView name, StringView* host, StringView* port,
bool* has_port) {
*has_port = false;
if (name[0] == '[') {
/* Parse a bracketed host, typically an IPv6 literal. */
const size_t rbracket = name.find(']', 1);
@ -58,6 +61,7 @@ bool SplitHostPort(StringView name, StringView* host, StringView* port) {
} else if (name[rbracket + 1] == ':') {
/* ]:<port?> */
*port = name.substr(rbracket + 2, name.size() - rbracket - 2);
*has_port = true;
} else {
/* ]<invalid> */
return false;
@ -76,6 +80,7 @@ bool SplitHostPort(StringView name, StringView* host, StringView* port) {
/* Exactly 1 colon. Split into host:port. */
*host = name.substr(0, colon);
*port = name.substr(colon + 1, name.size() - colon - 1);
*has_port = true;
} else {
/* 0 or 2+ colons. Bare hostname or IPv6 litearal. */
*host = name;
@ -84,6 +89,12 @@ bool SplitHostPort(StringView name, StringView* host, StringView* port) {
}
return true;
}
} // namespace
bool SplitHostPort(StringView name, StringView* host, StringView* port) {
bool unused;
return DoSplitHostPort(name, host, port, &unused);
}
bool SplitHostPort(StringView name, UniquePtr<char>* host,
UniquePtr<char>* port) {
@ -91,12 +102,14 @@ bool SplitHostPort(StringView name, UniquePtr<char>* host,
GPR_DEBUG_ASSERT(port != nullptr && *port == nullptr);
StringView host_view;
StringView port_view;
const bool ret = SplitHostPort(name, &host_view, &port_view);
bool has_port;
const bool ret = DoSplitHostPort(name, &host_view, &port_view, &has_port);
if (ret) {
// We always set the host, but port is set only when it's non-empty,
// to remain backward compatible with the old split_host_port API.
// We always set the host, but port is set only when DoSplitHostPort find a
// port in the string, to remain backward compatible with the old
// gpr_split_host_port API.
*host = host_view.dup();
if (!port_view.empty()) {
if (has_port) {
*port = port_view.dup();
}
}

@ -262,9 +262,9 @@ void grpc_slice_buffer_move_into(grpc_slice_buffer* src,
src->length = 0;
}
template <bool incref>
static void slice_buffer_move_first_maybe_ref(grpc_slice_buffer* src, size_t n,
grpc_slice_buffer* dst,
bool incref) {
grpc_slice_buffer* dst) {
GPR_ASSERT(src->length >= n);
if (src->length == n) {
grpc_slice_buffer_move_into(src, dst);
@ -304,12 +304,12 @@ static void slice_buffer_move_first_maybe_ref(grpc_slice_buffer* src, size_t n,
void grpc_slice_buffer_move_first(grpc_slice_buffer* src, size_t n,
grpc_slice_buffer* dst) {
slice_buffer_move_first_maybe_ref(src, n, dst, true);
slice_buffer_move_first_maybe_ref<true>(src, n, dst);
}
void grpc_slice_buffer_move_first_no_ref(grpc_slice_buffer* src, size_t n,
grpc_slice_buffer* dst) {
slice_buffer_move_first_maybe_ref(src, n, dst, false);
slice_buffer_move_first_maybe_ref<false>(src, n, dst);
}
void grpc_slice_buffer_move_first_into_buffer(grpc_slice_buffer* src, size_t n,

@ -27,11 +27,10 @@ namespace grpc_impl {
namespace {
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> CallInternal(
grpc::ChannelInterface* channel, grpc::ClientContext* context,
const grpc::string& method, grpc::CompletionQueue* cq, bool start,
void* tag) {
const grpc::string& method, CompletionQueue* cq, bool start, void* tag) {
return std::unique_ptr<grpc::GenericClientAsyncReaderWriter>(
grpc::internal::ClientAsyncReaderWriterFactory<grpc::ByteBuffer,
grpc::ByteBuffer>::
internal::ClientAsyncReaderWriterFactory<grpc::ByteBuffer,
grpc::ByteBuffer>::
Create(channel, cq,
grpc::internal::RpcMethod(
method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
@ -43,14 +42,14 @@ std::unique_ptr<grpc::GenericClientAsyncReaderWriter> CallInternal(
// begin a call to a named method
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> GenericStub::Call(
grpc::ClientContext* context, const grpc::string& method,
grpc::CompletionQueue* cq, void* tag) {
CompletionQueue* cq, void* tag) {
return CallInternal(channel_.get(), context, method, cq, true, tag);
}
// setup a call to a named method
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> GenericStub::PrepareCall(
grpc::ClientContext* context, const grpc::string& method,
grpc::CompletionQueue* cq) {
CompletionQueue* cq) {
return CallInternal(channel_.get(), context, method, cq, false, nullptr);
}
@ -59,21 +58,20 @@ std::unique_ptr<grpc::GenericClientAsyncResponseReader>
GenericStub::PrepareUnaryCall(grpc::ClientContext* context,
const grpc::string& method,
const grpc::ByteBuffer& request,
grpc::CompletionQueue* cq) {
CompletionQueue* cq) {
return std::unique_ptr<grpc::GenericClientAsyncResponseReader>(
grpc::internal::ClientAsyncResponseReaderFactory<
grpc::ByteBuffer>::Create(channel_.get(), cq,
grpc::internal::RpcMethod(
method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, false));
internal::ClientAsyncResponseReaderFactory<grpc::ByteBuffer>::Create(
channel_.get(), cq,
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, false));
}
void GenericStub::experimental_type::UnaryCall(
grpc::ClientContext* context, const grpc::string& method,
const grpc::ByteBuffer* request, grpc::ByteBuffer* response,
std::function<void(grpc::Status)> on_completion) {
grpc::internal::CallbackUnaryCall(
internal::CallbackUnaryCall(
stub_->channel_.get(),
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
@ -82,9 +80,9 @@ void GenericStub::experimental_type::UnaryCall(
void GenericStub::experimental_type::PrepareBidiStreamingCall(
grpc::ClientContext* context, const grpc::string& method,
grpc::experimental::ClientBidiReactor<grpc::ByteBuffer, grpc::ByteBuffer>*
experimental::ClientBidiReactor<grpc::ByteBuffer, grpc::ByteBuffer>*
reactor) {
grpc::internal::ClientCallbackReaderWriterFactory<
internal::ClientCallbackReaderWriterFactory<
grpc::ByteBuffer,
grpc::ByteBuffer>::Create(stub_->channel_.get(),
grpc::internal::RpcMethod(

@ -24,8 +24,8 @@ namespace grpc {
void AsyncGenericService::RequestCall(
GenericServerContext* ctx, GenericServerAsyncReaderWriter* reader_writer,
CompletionQueue* call_cq, ServerCompletionQueue* notification_cq,
void* tag) {
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
server_->RequestAsyncGenericCall(ctx, reader_writer, call_cq, notification_cq,
tag);
}

@ -28,6 +28,7 @@
#include <grpcpp/health_check_service_interface.h>
#include <grpcpp/impl/codegen/async_generic_service.h>
#include <grpcpp/impl/codegen/async_unary_call.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/support/byte_buffer.h>

@ -69,14 +69,14 @@ ServerBuilder::~ServerBuilder() {
}
}
std::unique_ptr<grpc::ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
bool is_frequently_polled) {
grpc::ServerCompletionQueue* cq = new grpc::ServerCompletionQueue(
ServerCompletionQueue* cq = new ServerCompletionQueue(
GRPC_CQ_NEXT,
is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING,
nullptr);
cqs_.push_back(cq);
return std::unique_ptr<grpc::ServerCompletionQueue>(cq);
return std::unique_ptr<ServerCompletionQueue>(cq);
}
ServerBuilder& ServerBuilder::RegisterService(grpc::Service* service) {
@ -266,10 +266,9 @@ std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
// This is different from the completion queues added to the server via
// ServerBuilder's AddCompletionQueue() method (those completion queues
// are in 'cqs_' member variable of ServerBuilder object)
std::shared_ptr<std::vector<std::unique_ptr<grpc::ServerCompletionQueue>>>
sync_server_cqs(
std::make_shared<
std::vector<std::unique_ptr<grpc::ServerCompletionQueue>>>());
std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
sync_server_cqs(std::make_shared<
std::vector<std::unique_ptr<ServerCompletionQueue>>>());
bool has_frequently_polled_cqs = false;
for (auto it = cqs_.begin(); it != cqs_.end(); ++it) {
@ -298,7 +297,7 @@ std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
// Create completion queues to listen to incoming rpc requests
for (int i = 0; i < sync_server_settings_.num_cqs; i++) {
sync_server_cqs->emplace_back(
new grpc::ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr));
new ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr));
}
}

@ -45,8 +45,7 @@ class ServerContext::CompletionOp final
public:
// initial refs: one in the server context, one in the cq
// must ref the call before calling constructor and after deleting this
CompletionOp(::grpc::internal::Call* call,
::grpc::internal::ServerReactor* reactor)
CompletionOp(::grpc::internal::Call* call, internal::ServerReactor* reactor)
: call_(*call),
reactor_(reactor),
has_tag_(false),
@ -152,7 +151,7 @@ class ServerContext::CompletionOp final
}
::grpc::internal::Call call_;
::grpc::internal::ServerReactor* const reactor_;
internal::ServerReactor* const reactor_;
bool has_tag_;
void* tag_;
void* core_cq_tag_;
@ -294,9 +293,9 @@ void ServerContext::Clear() {
}
}
void ServerContext::BeginCompletionOp(
::grpc::internal::Call* call, std::function<void(bool)> callback,
::grpc::internal::ServerReactor* reactor) {
void ServerContext::BeginCompletionOp(::grpc::internal::Call* call,
std::function<void(bool)> callback,
internal::ServerReactor* reactor) {
GPR_ASSERT(!completion_op_);
if (rpc_info_) {
rpc_info_->Ref();

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\Grpc.Core\Common.csproj.include" />
@ -11,6 +11,7 @@
<PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
<PackageTags>gRPC RPC HTTP/2</PackageTags>
<VersionPrefix>$(GrpcCsharpVersion)</VersionPrefix>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>

@ -17,8 +17,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using Grpc.Core.Api.Utils;
using Grpc.Core.Utils;
@ -345,15 +346,31 @@ namespace Grpc.Core
/// Creates a binary value or ascii value metadata entry from data received from the native layer.
/// We trust C core to give us well-formed data, so we don't perform any checks or defensive copying.
/// </summary>
internal static Entry CreateUnsafe(string key, byte[] valueBytes)
internal static Entry CreateUnsafe(string key, IntPtr source, int length)
{
if (HasBinaryHeaderSuffix(key))
{
return new Entry(key, null, valueBytes);
byte[] arr;
if (length == 0)
{
arr = EmptyByteArray;
}
else
{ // create a local copy in a fresh array
arr = new byte[length];
Marshal.Copy(source, arr, 0, length);
}
return new Entry(key, null, arr);
}
else
{
string s = EncodingASCII.GetString(source, length);
return new Entry(key, s, null);
}
return new Entry(key, EncodingASCII.GetString(valueBytes), null);
}
static readonly byte[] EmptyByteArray = new byte[0];
private static string NormalizeKey(string key)
{
GrpcPreconditions.CheckNotNull(key, "key");

@ -0,0 +1,54 @@
#region Copyright notice and license
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
using System;
using System.Runtime.CompilerServices;
using System.Text;
namespace Grpc.Core.Api.Utils
{
internal static class EncodingExtensions
{
#if NET45 // back-fill over a method missing in NET45
/// <summary>
/// Converts <c>byte*</c> pointing to an encoded byte array to a <c>string</c> using the provided <c>Encoding</c>.
/// </summary>
public static unsafe string GetString(this Encoding encoding, byte* source, int byteCount)
{
if (byteCount == 0) return ""; // most callers will have already checked, but: make sure
// allocate a right-sized string and decode into it
int charCount = encoding.GetCharCount(source, byteCount);
string s = new string('\0', charCount);
fixed (char* cPtr = s)
{
encoding.GetChars(source, byteCount, cPtr, charCount);
}
return s;
}
#endif
/// <summary>
/// Converts <c>IntPtr</c> pointing to a encoded byte array to a <c>string</c> using the provided <c>Encoding</c>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe string GetString(this Encoding encoding, IntPtr ptr, int len)
{
return len == 0 ? "" : encoding.GetString((byte*)ptr.ToPointer(), len);
}
}
}

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\Grpc.Core\Common.csproj.include" />
@ -6,6 +6,7 @@
<TargetFrameworks>net45;netcoreapp2.1</TargetFrameworks>
<OutputType>Exe</OutputType>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">

@ -0,0 +1,62 @@
#region Copyright notice and license
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
using System.Text;
using Grpc.Core.Internal;
using NUnit.Framework;
namespace Grpc.Core.Internal.Tests
{
public class WellKnownStringsTest
{
[Test]
[TestCase("", true)]
[TestCase("u", false)]
[TestCase("us", false)]
[TestCase("use", false)]
[TestCase("user", false)]
[TestCase("user-", false)]
[TestCase("user-a", false)]
[TestCase("user-ag", false)]
[TestCase("user-age", false)]
[TestCase("user-agent", true)]
[TestCase("user-agent ", false)]
[TestCase("useragent ", false)]
[TestCase("User-Agent", false)]
[TestCase("sdlkfjlskjfdlkjs;lfdksflsdfkh skjdfh sdkfhskdhf skjfhk sdhjkjh", false)]
// test for endianness snafus (reversed in segments)
[TestCase("ega-resutn", false)]
public unsafe void TestWellKnownStrings(string input, bool expected)
{
// create a copy of the data; no cheating!
byte[] bytes = Encoding.ASCII.GetBytes(input);
fixed(byte* ptr = bytes)
{
string result = WellKnownStrings.TryIdentify(ptr, bytes.Length);
if (expected) Assert.AreEqual(input, result);
else Assert.IsNull(result);
if (expected)
{
// try again, and check we get the same instance
string again = WellKnownStrings.TryIdentify(ptr, bytes.Length);
Assert.AreSame(result, again);
}
}
}
}
}

@ -111,25 +111,31 @@ namespace Grpc.Core.Tests
}
[Test]
public void Entry_CreateUnsafe_Ascii()
public unsafe void Entry_CreateUnsafe_Ascii()
{
var bytes = new byte[] { (byte)'X', (byte)'y' };
var entry = Metadata.Entry.CreateUnsafe("abc", bytes);
Assert.IsFalse(entry.IsBinary);
Assert.AreEqual("abc", entry.Key);
Assert.AreEqual("Xy", entry.Value);
CollectionAssert.AreEqual(bytes, entry.ValueBytes);
fixed (byte* ptr = bytes)
{
var entry = Metadata.Entry.CreateUnsafe("abc", new IntPtr(ptr), bytes.Length);
Assert.IsFalse(entry.IsBinary);
Assert.AreEqual("abc", entry.Key);
Assert.AreEqual("Xy", entry.Value);
CollectionAssert.AreEqual(bytes, entry.ValueBytes);
}
}
[Test]
public void Entry_CreateUnsafe_Binary()
public unsafe void Entry_CreateUnsafe_Binary()
{
var bytes = new byte[] { 1, 2, 3 };
var entry = Metadata.Entry.CreateUnsafe("abc-bin", bytes);
Assert.IsTrue(entry.IsBinary);
Assert.AreEqual("abc-bin", entry.Key);
Assert.Throws(typeof(InvalidOperationException), () => { var v = entry.Value; });
CollectionAssert.AreEqual(bytes, entry.ValueBytes);
fixed (byte* ptr = bytes)
{
var entry = Metadata.Entry.CreateUnsafe("abc-bin", new IntPtr(ptr), bytes.Length);
Assert.IsTrue(entry.IsBinary);
Assert.AreEqual("abc-bin", entry.Key);
Assert.Throws(typeof(InvalidOperationException), () => { var v = entry.Value; });
CollectionAssert.AreEqual(bytes, entry.ValueBytes);
}
}
[Test]

@ -100,6 +100,8 @@
<ItemGroup>
<PackageReference Include="System.Interactive.Async" Version="3.2.0" />
<!-- System.Buffers *may* come in transitively, but: we can *always* use ArrayPool -->
<PackageReference Include="System.Buffers" Version="4.5.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">

@ -21,6 +21,7 @@ using System.Text;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Core.Profiling;
using System.Buffers;
namespace Grpc.Core.Internal
{
@ -134,9 +135,48 @@ namespace Grpc.Core.Internal
{
var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_ISendStatusFromServerCompletionCallback, callback);
var optionalPayloadLength = optionalPayload != null ? new UIntPtr((ulong)optionalPayload.Length) : UIntPtr.Zero;
var statusDetailBytes = MarshalUtils.GetBytesUTF8(status.Detail);
Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, statusDetailBytes, new UIntPtr((ulong)statusDetailBytes.Length), metadataArray, sendEmptyInitialMetadata ? 1 : 0,
optionalPayload, optionalPayloadLength, writeFlags).CheckOk();
const int MaxStackAllocBytes = 256;
int maxBytes = MarshalUtils.GetMaxByteCountUTF8(status.Detail);
if (maxBytes > MaxStackAllocBytes)
{
// pay the extra to get the *actual* size; this could mean that
// it ends up fitting on the stack after all, but even if not
// it will mean that we ask for a *much* smaller buffer
maxBytes = MarshalUtils.GetByteCountUTF8(status.Detail);
}
unsafe
{
if (maxBytes <= MaxStackAllocBytes)
{ // for small status, we can encode on the stack without touching arrays
// note: if init-locals is disabled, it would be more efficient
// to just stackalloc[MaxStackAllocBytes]; but by default, since we
// expect this to be small and it needs to wipe, just use maxBytes
byte* ptr = stackalloc byte[maxBytes];
int statusBytes = MarshalUtils.GetBytesUTF8(status.Detail, ptr, maxBytes);
Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, new IntPtr(ptr), new UIntPtr((ulong)statusBytes), metadataArray, sendEmptyInitialMetadata ? 1 : 0,
optionalPayload, optionalPayloadLength, writeFlags).CheckOk();
}
else
{ // for larger status (rare), rent a buffer from the pool and
// use that for encoding
var statusBuffer = ArrayPool<byte>.Shared.Rent(maxBytes);
try
{
fixed (byte* ptr = statusBuffer)
{
int statusBytes = MarshalUtils.GetBytesUTF8(status.Detail, ptr, maxBytes);
Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, new IntPtr(ptr), new UIntPtr((ulong)statusBytes), metadataArray, sendEmptyInitialMetadata ? 1 : 0,
optionalPayload, optionalPayloadLength, writeFlags).CheckOk();
}
}
finally
{
ArrayPool<byte>.Shared.Return(statusBuffer);
}
}
}
}
}

@ -17,8 +17,9 @@
#endregion
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Text;
using Grpc.Core.Api.Utils;
namespace Grpc.Core.Internal
{
@ -32,34 +33,41 @@ namespace Grpc.Core.Internal
/// <summary>
/// Converts <c>IntPtr</c> pointing to a UTF-8 encoded byte array to <c>string</c>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string PtrToStringUTF8(IntPtr ptr, int len)
{
if (len == 0)
return EncodingUTF8.GetString(ptr, len);
}
/// <summary>
/// UTF-8 encodes the given string into a buffer of sufficient size
/// </summary>
public static unsafe int GetBytesUTF8(string str, byte* destination, int destinationLength)
{
int charCount = str.Length;
if (charCount == 0) return 0;
fixed (char* source = str)
{
return "";
return EncodingUTF8.GetBytes(source, charCount, destination, destinationLength);
}
// TODO(jtattermusch): once Span dependency is added,
// use Span-based API to decode the string without copying the buffer.
var bytes = new byte[len];
Marshal.Copy(ptr, bytes, 0, len);
return EncodingUTF8.GetString(bytes);
}
/// <summary>
/// Returns byte array containing UTF-8 encoding of given string.
/// Returns the maximum number of bytes required to encode a given string.
/// </summary>
public static byte[] GetBytesUTF8(string str)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetMaxByteCountUTF8(string str)
{
return EncodingUTF8.GetBytes(str);
return EncodingUTF8.GetMaxByteCount(str.Length);
}
/// <summary>
/// Get string from a UTF8 encoded byte array.
/// Returns the actual number of bytes required to encode a given string.
/// </summary>
public static string GetStringUTF8(byte[] bytes)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetByteCountUTF8(string str)
{
return EncodingUTF8.GetString(bytes);
return EncodingUTF8.GetByteCount(str);
}
}
}

@ -15,8 +15,7 @@
#endregion
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Profiling;
using System.Text;
namespace Grpc.Core.Internal
{
@ -66,12 +65,13 @@ namespace Grpc.Core.Internal
var index = new UIntPtr(i);
UIntPtr keyLen;
IntPtr keyPtr = Native.grpcsharp_metadata_array_get_key(metadataArray, index, out keyLen);
string key = Marshal.PtrToStringAnsi(keyPtr, (int)keyLen.ToUInt32());
int keyLen32 = checked((int)keyLen.ToUInt32());
string key = WellKnownStrings.TryIdentify(keyPtr, keyLen32)
?? Marshal.PtrToStringAnsi(keyPtr, keyLen32);
UIntPtr valueLen;
IntPtr valuePtr = Native.grpcsharp_metadata_array_get_value(metadataArray, index, out valueLen);
var bytes = new byte[valueLen.ToUInt64()];
Marshal.Copy(valuePtr, bytes, 0, bytes.Length);
metadata.Add(Metadata.Entry.CreateUnsafe(key, bytes));
int len32 = checked((int)valueLen.ToUInt64());
metadata.Add(Metadata.Entry.CreateUnsafe(key, valuePtr, len32));
}
return metadata;
}

@ -469,7 +469,7 @@ namespace Grpc.Core.Internal
public delegate CallError grpcsharp_call_start_duplex_streaming_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_send_message_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, int sendEmptyInitialMetadata);
public delegate CallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call, BatchContextSafeHandle ctx);
public delegate CallError grpcsharp_call_send_status_from_server_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
public delegate CallError grpcsharp_call_send_status_from_server_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, IntPtr statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
public delegate CallError grpcsharp_call_recv_message_delegate(CallSafeHandle call, BatchContextSafeHandle ctx);
public delegate CallError grpcsharp_call_recv_initial_metadata_delegate(CallSafeHandle call, BatchContextSafeHandle ctx);
public delegate CallError grpcsharp_call_start_serverside_delegate(CallSafeHandle call, BatchContextSafeHandle ctx);
@ -637,7 +637,7 @@ namespace Grpc.Core.Internal
public static extern CallError grpcsharp_call_send_close_from_client(CallSafeHandle call, BatchContextSafeHandle ctx);
[DllImport(ImportName)]
public static extern CallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
public static extern CallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, IntPtr statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
[DllImport(ImportName)]
public static extern CallError grpcsharp_call_recv_message(CallSafeHandle call, BatchContextSafeHandle ctx);
@ -933,7 +933,7 @@ namespace Grpc.Core.Internal
public static extern CallError grpcsharp_call_send_close_from_client(CallSafeHandle call, BatchContextSafeHandle ctx);
[DllImport(ImportName)]
public static extern CallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
public static extern CallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, IntPtr statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
[DllImport(ImportName)]
public static extern CallError grpcsharp_call_recv_message(CallSafeHandle call, BatchContextSafeHandle ctx);

@ -0,0 +1,92 @@
#region Copyright notice and license
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
using System;
using System.Runtime.CompilerServices;
namespace Grpc.Core.Internal
{
/// <summary>
/// Utility type for identifying "well-known" strings (i.e. headers/keys etc that
/// we expect to see frequently, and don't want to allocate lots of copies of)
/// </summary>
internal static class WellKnownStrings
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong Coerce64(byte* value)
{
return *(ulong*)value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint Coerce32(byte* value)
{
return *(uint*)value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ushort Coerce16(byte* value)
{
return *(ushort*)value;
}
/// <summary>
/// Test whether the provided byte sequence is recognized as a well-known string; if
/// so, return a shared instance of that string; otherwise, return null
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe string TryIdentify(IntPtr source, int length)
{
return TryIdentify((byte*)source.ToPointer(), length);
}
/// <summary>
/// Test whether the provided byte sequence is recognized as a well-known string; if
/// so, return a shared instance of that string; otherwise, return null
/// </summary>
public static unsafe string TryIdentify(byte* source, int length)
{
// note: the logic here is hard-coded to constants for optimal processing;
// refer to an ASCII/hex converter (and remember to reverse **segments** for little-endian)
if (BitConverter.IsLittleEndian) // this is a JIT intrinsic; branch removal happens on modern runtimes
{
switch (length)
{
case 0: return "";
case 10:
switch(Coerce64(source))
{
case 0x6567612d72657375: return Coerce16(source + 8) == 0x746e ? "user-agent" : null;
}
break;
}
}
else
{
switch (length)
{
case 0: return "";
case 10:
switch (Coerce64(source))
{
case 0x757365722d616765: return Coerce16(source + 8) == 0x6e74 ? "user-agent" : null;
}
break;
}
}
return null;
}
}
}

@ -61,7 +61,7 @@ namespace Grpc.Microbenchmarks
var native = NativeMethods.Get();
// nop the native-call via reflection
NativeMethods.Delegates.grpcsharp_call_send_status_from_server_delegate nop = (CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags) => {
NativeMethods.Delegates.grpcsharp_call_send_status_from_server_delegate nop = (CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, IntPtr statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags) => {
completionRegistry.Extract(ctx.Handle).OnComplete(true); // drain the dictionary as we go
return CallError.OK;
};

@ -14,6 +14,7 @@
"Grpc.Core.Internal.Tests.ReusableSliceBufferTest",
"Grpc.Core.Internal.Tests.SliceTest",
"Grpc.Core.Internal.Tests.TimespecTest",
"Grpc.Core.Internal.Tests.WellKnownStringsTest",
"Grpc.Core.Tests.AppDomainUnloadTest",
"Grpc.Core.Tests.AuthContextTest",
"Grpc.Core.Tests.AuthPropertyTest",

@ -31,7 +31,7 @@ native_method_signatures = [
'CallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags)',
'CallError grpcsharp_call_send_message(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, int sendEmptyInitialMetadata)',
'CallError grpcsharp_call_send_close_from_client(CallSafeHandle call, BatchContextSafeHandle ctx)',
'CallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags)',
'CallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, IntPtr statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags)',
'CallError grpcsharp_call_recv_message(CallSafeHandle call, BatchContextSafeHandle ctx)',
'CallError grpcsharp_call_recv_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx)',
'CallError grpcsharp_call_start_serverside(CallSafeHandle call, BatchContextSafeHandle ctx)',
@ -107,4 +107,4 @@ for signature in native_method_signatures:
native_methods.append({'returntype': match.group(1), 'name': match.group(2), 'params': match.group(3), 'comment': match.group(4)})
return list(native_methods)
%></%def>
%></%def>

@ -71,7 +71,9 @@ static void test_split_host_port() {
split_host_port_expect("", "", nullptr, true);
split_host_port_expect("[a:b]", "a:b", nullptr, true);
split_host_port_expect("1.2.3.4", "1.2.3.4", nullptr, true);
split_host_port_expect("0.0.0.0:", "0.0.0.0", "", true);
split_host_port_expect("a:b:c::", "a:b:c::", nullptr, true);
split_host_port_expect("[a:b:c::]:", "a:b:c::", "", true);
split_host_port_expect("[a:b]:30", "a:b", "30", true);
split_host_port_expect("1.2.3.4:30", "1.2.3.4", "30", true);
split_host_port_expect(":30", "", "30", true);

@ -32,6 +32,7 @@
#include <grpcpp/impl/codegen/async_unary_call.h>
#include <grpcpp/impl/codegen/client_callback.h>
#include <grpcpp/impl/codegen/client_context.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/method_handler_impl.h>
#include <grpcpp/impl/codegen/proto_utils.h>
#include <grpcpp/impl/codegen/rpc_method.h>
@ -336,7 +337,7 @@ class ServiceA final {
public:
ExperimentalWithCallbackMethod_MethodA1() {
::grpc::Service::experimental().MarkMethodCallback(0,
new ::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
[this](::grpc::ServerContext* context,
const ::grpc::testing::Request* request,
::grpc::testing::Response* response,
@ -346,7 +347,7 @@ class ServiceA final {
}
void SetMessageAllocatorFor_MethodA1(
::grpc::experimental::MessageAllocator< ::grpc::testing::Request, ::grpc::testing::Response>* allocator) {
static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>(
static_cast<::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>(
::grpc::Service::experimental().GetHandler(0))
->SetMessageAllocator(allocator);
}
@ -367,7 +368,7 @@ class ServiceA final {
public:
ExperimentalWithCallbackMethod_MethodA2() {
::grpc::Service::experimental().MarkMethodCallback(1,
new ::grpc::internal::CallbackClientStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
new ::grpc_impl::internal::CallbackClientStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
[this] { return this->MethodA2(); }));
}
~ExperimentalWithCallbackMethod_MethodA2() override {
@ -379,7 +380,7 @@ class ServiceA final {
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::experimental::ServerReadReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA2() {
return new ::grpc::internal::UnimplementedReadReactor<
return new ::grpc_impl::internal::UnimplementedReadReactor<
::grpc::testing::Request, ::grpc::testing::Response>;}
};
template <class BaseClass>
@ -389,7 +390,7 @@ class ServiceA final {
public:
ExperimentalWithCallbackMethod_MethodA3() {
::grpc::Service::experimental().MarkMethodCallback(2,
new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
new ::grpc_impl::internal::CallbackServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
[this] { return this->MethodA3(); }));
}
~ExperimentalWithCallbackMethod_MethodA3() override {
@ -401,7 +402,7 @@ class ServiceA final {
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::experimental::ServerWriteReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA3() {
return new ::grpc::internal::UnimplementedWriteReactor<
return new ::grpc_impl::internal::UnimplementedWriteReactor<
::grpc::testing::Request, ::grpc::testing::Response>;}
};
template <class BaseClass>
@ -411,7 +412,7 @@ class ServiceA final {
public:
ExperimentalWithCallbackMethod_MethodA4() {
::grpc::Service::experimental().MarkMethodCallback(3,
new ::grpc::internal::CallbackBidiHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
new ::grpc_impl::internal::CallbackBidiHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
[this] { return this->MethodA4(); }));
}
~ExperimentalWithCallbackMethod_MethodA4() override {
@ -423,7 +424,7 @@ class ServiceA final {
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::experimental::ServerBidiReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4() {
return new ::grpc::internal::UnimplementedBidiReactor<
return new ::grpc_impl::internal::UnimplementedBidiReactor<
::grpc::testing::Request, ::grpc::testing::Response>;}
};
typedef ExperimentalWithCallbackMethod_MethodA1<ExperimentalWithCallbackMethod_MethodA2<ExperimentalWithCallbackMethod_MethodA3<ExperimentalWithCallbackMethod_MethodA4<Service > > > > ExperimentalCallbackService;
@ -582,7 +583,7 @@ class ServiceA final {
public:
ExperimentalWithRawCallbackMethod_MethodA1() {
::grpc::Service::experimental().MarkMethodRawCallback(0,
new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this](::grpc::ServerContext* context,
const ::grpc::ByteBuffer* request,
::grpc::ByteBuffer* response,
@ -607,7 +608,7 @@ class ServiceA final {
public:
ExperimentalWithRawCallbackMethod_MethodA2() {
::grpc::Service::experimental().MarkMethodRawCallback(1,
new ::grpc::internal::CallbackClientStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
new ::grpc_impl::internal::CallbackClientStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this] { return this->MethodA2(); }));
}
~ExperimentalWithRawCallbackMethod_MethodA2() override {
@ -619,7 +620,7 @@ class ServiceA final {
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::experimental::ServerReadReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA2() {
return new ::grpc::internal::UnimplementedReadReactor<
return new ::grpc_impl::internal::UnimplementedReadReactor<
::grpc::ByteBuffer, ::grpc::ByteBuffer>;}
};
template <class BaseClass>
@ -629,7 +630,7 @@ class ServiceA final {
public:
ExperimentalWithRawCallbackMethod_MethodA3() {
::grpc::Service::experimental().MarkMethodRawCallback(2,
new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
new ::grpc_impl::internal::CallbackServerStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this] { return this->MethodA3(); }));
}
~ExperimentalWithRawCallbackMethod_MethodA3() override {
@ -641,7 +642,7 @@ class ServiceA final {
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::experimental::ServerWriteReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA3() {
return new ::grpc::internal::UnimplementedWriteReactor<
return new ::grpc_impl::internal::UnimplementedWriteReactor<
::grpc::ByteBuffer, ::grpc::ByteBuffer>;}
};
template <class BaseClass>
@ -651,7 +652,7 @@ class ServiceA final {
public:
ExperimentalWithRawCallbackMethod_MethodA4() {
::grpc::Service::experimental().MarkMethodRawCallback(3,
new ::grpc::internal::CallbackBidiHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
new ::grpc_impl::internal::CallbackBidiHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this] { return this->MethodA4(); }));
}
~ExperimentalWithRawCallbackMethod_MethodA4() override {
@ -663,7 +664,7 @@ class ServiceA final {
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::experimental::ServerBidiReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA4() {
return new ::grpc::internal::UnimplementedBidiReactor<
return new ::grpc_impl::internal::UnimplementedBidiReactor<
::grpc::ByteBuffer, ::grpc::ByteBuffer>;}
};
template <class BaseClass>
@ -814,7 +815,7 @@ class ServiceB final {
public:
ExperimentalWithCallbackMethod_MethodB1() {
::grpc::Service::experimental().MarkMethodCallback(0,
new ::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(
[this](::grpc::ServerContext* context,
const ::grpc::testing::Request* request,
::grpc::testing::Response* response,
@ -824,7 +825,7 @@ class ServiceB final {
}
void SetMessageAllocatorFor_MethodB1(
::grpc::experimental::MessageAllocator< ::grpc::testing::Request, ::grpc::testing::Response>* allocator) {
static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>(
static_cast<::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>(
::grpc::Service::experimental().GetHandler(0))
->SetMessageAllocator(allocator);
}
@ -883,7 +884,7 @@ class ServiceB final {
public:
ExperimentalWithRawCallbackMethod_MethodB1() {
::grpc::Service::experimental().MarkMethodRawCallback(0,
new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this](::grpc::ServerContext* context,
const ::grpc::ByteBuffer* request,
::grpc::ByteBuffer* response,

@ -133,6 +133,59 @@ class MyTestServiceImpl : public TestServiceImpl {
std::set<grpc::string> clients_;
};
class FakeResolverResponseGeneratorWrapper {
public:
FakeResolverResponseGeneratorWrapper()
: response_generator_(grpc_core::MakeRefCounted<
grpc_core::FakeResolverResponseGenerator>()) {}
FakeResolverResponseGeneratorWrapper(
FakeResolverResponseGeneratorWrapper&& other) {
response_generator_ = std::move(other.response_generator_);
}
void SetNextResolution(const std::vector<int>& ports) {
grpc_core::ExecCtx exec_ctx;
response_generator_->SetResponse(BuildFakeResults(ports));
}
void SetNextResolutionUponError(const std::vector<int>& ports) {
grpc_core::ExecCtx exec_ctx;
response_generator_->SetReresolutionResponse(BuildFakeResults(ports));
}
void SetFailureOnReresolution() {
grpc_core::ExecCtx exec_ctx;
response_generator_->SetFailureOnReresolution();
}
grpc_core::FakeResolverResponseGenerator* Get() const {
return response_generator_.get();
}
private:
static grpc_core::Resolver::Result BuildFakeResults(
const std::vector<int>& ports) {
grpc_core::Resolver::Result result;
for (const int& port : ports) {
char* lb_uri_str;
gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", port);
grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true);
GPR_ASSERT(lb_uri != nullptr);
grpc_resolved_address address;
GPR_ASSERT(grpc_parse_uri(lb_uri, &address));
result.addresses.emplace_back(address.addr, address.len,
nullptr /* args */);
grpc_uri_destroy(lb_uri);
gpr_free(lb_uri_str);
}
return result;
}
grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
response_generator_;
};
class ClientLbEnd2endTest : public ::testing::Test {
protected:
ClientLbEnd2endTest()
@ -147,11 +200,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
}
void SetUp() override {
grpc_init();
response_generator_ =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
}
void SetUp() override { grpc_init(); }
void TearDown() override {
for (size_t i = 0; i < servers_.size(); ++i) {
@ -186,38 +235,6 @@ class ClientLbEnd2endTest : public ::testing::Test {
}
}
grpc_core::Resolver::Result BuildFakeResults(const std::vector<int>& ports) {
grpc_core::Resolver::Result result;
for (const int& port : ports) {
char* lb_uri_str;
gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", port);
grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true);
GPR_ASSERT(lb_uri != nullptr);
grpc_resolved_address address;
GPR_ASSERT(grpc_parse_uri(lb_uri, &address));
result.addresses.emplace_back(address.addr, address.len,
nullptr /* args */);
grpc_uri_destroy(lb_uri);
gpr_free(lb_uri_str);
}
return result;
}
void SetNextResolution(const std::vector<int>& ports) {
grpc_core::ExecCtx exec_ctx;
response_generator_->SetResponse(BuildFakeResults(ports));
}
void SetNextResolutionUponError(const std::vector<int>& ports) {
grpc_core::ExecCtx exec_ctx;
response_generator_->SetReresolutionResponse(BuildFakeResults(ports));
}
void SetFailureOnReresolution() {
grpc_core::ExecCtx exec_ctx;
response_generator_->SetFailureOnReresolution();
}
std::vector<int> GetServersPorts(size_t start_index = 0) {
std::vector<int> ports;
for (size_t i = start_index; i < servers_.size(); ++i) {
@ -226,6 +243,10 @@ class ClientLbEnd2endTest : public ::testing::Test {
return ports;
}
FakeResolverResponseGeneratorWrapper BuildResolverResponseGenerator() {
return FakeResolverResponseGeneratorWrapper();
}
std::unique_ptr<grpc::testing::EchoTestService::Stub> BuildStub(
const std::shared_ptr<Channel>& channel) {
return grpc::testing::EchoTestService::NewStub(channel);
@ -233,12 +254,13 @@ class ClientLbEnd2endTest : public ::testing::Test {
std::shared_ptr<Channel> BuildChannel(
const grpc::string& lb_policy_name,
const FakeResolverResponseGeneratorWrapper& response_generator,
ChannelArguments args = ChannelArguments()) {
if (lb_policy_name.size() > 0) {
args.SetLoadBalancingPolicyName(lb_policy_name);
} // else, default to pick first
args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
response_generator_.get());
response_generator.Get());
return ::grpc::CreateCustomChannel("fake:///", creds_, args);
}
@ -401,8 +423,6 @@ class ClientLbEnd2endTest : public ::testing::Test {
const grpc::string server_host_;
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::vector<std::unique_ptr<ServerData>> servers_;
grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
response_generator_;
const grpc::string kRequestMessage_;
std::shared_ptr<ChannelCredentials> creds_;
};
@ -410,7 +430,8 @@ class ClientLbEnd2endTest : public ::testing::Test {
TEST_F(ClientLbEnd2endTest, ChannelStateConnectingWhenResolving) {
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel("");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("", response_generator);
auto stub = BuildStub(channel);
// Initial state should be IDLE.
EXPECT_EQ(channel->GetState(false /* try_to_connect */), GRPC_CHANNEL_IDLE);
@ -423,7 +444,7 @@ TEST_F(ClientLbEnd2endTest, ChannelStateConnectingWhenResolving) {
EXPECT_EQ(channel->GetState(false /* try_to_connect */),
GRPC_CHANNEL_CONNECTING);
// Return a resolver result, which allows the connection attempt to proceed.
SetNextResolution(GetServersPorts());
response_generator.SetNextResolution(GetServersPorts());
// We should eventually transition into state READY.
EXPECT_TRUE(WaitForChannelReady(channel.get()));
}
@ -432,9 +453,11 @@ TEST_F(ClientLbEnd2endTest, PickFirst) {
// Start servers and send one RPC per server.
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel(""); // test that pick first is the default.
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel(
"", response_generator); // test that pick first is the default.
auto stub = BuildStub(channel);
SetNextResolution(GetServersPorts());
response_generator.SetNextResolution(GetServersPorts());
for (size_t i = 0; i < servers_.size(); ++i) {
CheckRpcSendOk(stub, DEBUG_LOCATION);
}
@ -454,19 +477,22 @@ TEST_F(ClientLbEnd2endTest, PickFirst) {
}
TEST_F(ClientLbEnd2endTest, PickFirstProcessPending) {
StartServers(1); // Single server
auto channel = BuildChannel(""); // test that pick first is the default.
StartServers(1); // Single server
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel(
"", response_generator); // test that pick first is the default.
auto stub = BuildStub(channel);
SetNextResolution({servers_[0]->port_});
response_generator.SetNextResolution({servers_[0]->port_});
WaitForServer(stub, 0, DEBUG_LOCATION);
// Create a new channel and its corresponding PF LB policy, which will pick
// the subchannels in READY state from the previous RPC against the same
// target (even if it happened over a different channel, because subchannels
// are globally reused). Progress should happen without any transition from
// this READY state.
auto second_channel = BuildChannel("");
auto second_response_generator = BuildResolverResponseGenerator();
auto second_channel = BuildChannel("", second_response_generator);
auto second_stub = BuildStub(second_channel);
SetNextResolution({servers_[0]->port_});
second_response_generator.SetNextResolution({servers_[0]->port_});
CheckRpcSendOk(second_stub, DEBUG_LOCATION);
}
@ -479,16 +505,18 @@ TEST_F(ClientLbEnd2endTest, PickFirstSelectsReadyAtStartup) {
grpc_pick_unused_port_or_die()};
CreateServers(2, ports);
StartServer(1);
auto channel1 = BuildChannel("pick_first", args);
auto response_generator1 = BuildResolverResponseGenerator();
auto channel1 = BuildChannel("pick_first", response_generator1, args);
auto stub1 = BuildStub(channel1);
SetNextResolution(ports);
response_generator1.SetNextResolution(ports);
// Wait for second server to be ready.
WaitForServer(stub1, 1, DEBUG_LOCATION);
// Create a second channel with the same addresses. Its PF instance
// should immediately pick the second subchannel, since it's already
// in READY state.
auto channel2 = BuildChannel("pick_first", args);
SetNextResolution(ports);
auto response_generator2 = BuildResolverResponseGenerator();
auto channel2 = BuildChannel("pick_first", response_generator2, args);
response_generator2.SetNextResolution(ports);
// Check that the channel reports READY without waiting for the
// initial backoff.
EXPECT_TRUE(WaitForChannelReady(channel2.get(), 1 /* timeout_seconds */));
@ -500,9 +528,10 @@ TEST_F(ClientLbEnd2endTest, PickFirstBackOffInitialReconnect) {
args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, kInitialBackOffMs);
const std::vector<int> ports = {grpc_pick_unused_port_or_die()};
const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC);
auto channel = BuildChannel("pick_first", args);
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator, args);
auto stub = BuildStub(channel);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
// The channel won't become connected (there's no server).
ASSERT_FALSE(channel->WaitForConnected(
grpc_timeout_milliseconds_to_deadline(kInitialBackOffMs * 2)));
@ -529,9 +558,10 @@ TEST_F(ClientLbEnd2endTest, PickFirstBackOffMinReconnect) {
constexpr int kMinReconnectBackOffMs = 1000;
args.SetInt(GRPC_ARG_MIN_RECONNECT_BACKOFF_MS, kMinReconnectBackOffMs);
const std::vector<int> ports = {grpc_pick_unused_port_or_die()};
auto channel = BuildChannel("pick_first", args);
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator, args);
auto stub = BuildStub(channel);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
// Make connection delay a 10% longer than it's willing to in order to make
// sure we are hitting the codepath that waits for the min reconnect backoff.
gpr_atm_rel_store(&g_connection_delay_ms, kMinReconnectBackOffMs * 1.10);
@ -554,9 +584,10 @@ TEST_F(ClientLbEnd2endTest, PickFirstResetConnectionBackoff) {
constexpr int kInitialBackOffMs = 1000;
args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, kInitialBackOffMs);
const std::vector<int> ports = {grpc_pick_unused_port_or_die()};
auto channel = BuildChannel("pick_first", args);
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator, args);
auto stub = BuildStub(channel);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
// The channel won't become connected (there's no server).
EXPECT_FALSE(
channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10)));
@ -585,9 +616,10 @@ TEST_F(ClientLbEnd2endTest,
constexpr int kInitialBackOffMs = 1000;
args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, kInitialBackOffMs);
const std::vector<int> ports = {grpc_pick_unused_port_or_die()};
auto channel = BuildChannel("pick_first", args);
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator, args);
auto stub = BuildStub(channel);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
// Wait for connect, which should fail ~immediately, because the server
// is not up.
gpr_log(GPR_INFO, "=== INITIAL CONNECTION ATTEMPT");
@ -628,21 +660,22 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdates) {
// Start servers and send one RPC per server.
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel("pick_first");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator);
auto stub = BuildStub(channel);
std::vector<int> ports;
// Perform one RPC against the first server.
ports.emplace_back(servers_[0]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** SET [0] *******");
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_EQ(servers_[0]->service_.request_count(), 1);
// An empty update will result in the channel going into TRANSIENT_FAILURE.
ports.clear();
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** SET none *******");
grpc_connectivity_state channel_state;
do {
@ -654,7 +687,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdates) {
// Next update introduces servers_[1], making the channel recover.
ports.clear();
ports.emplace_back(servers_[1]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** SET [1] *******");
WaitForServer(stub, 1, DEBUG_LOCATION);
EXPECT_EQ(servers_[0]->service_.request_count(), 0);
@ -662,7 +695,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdates) {
// And again for servers_[2]
ports.clear();
ports.emplace_back(servers_[2]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** SET [2] *******");
WaitForServer(stub, 2, DEBUG_LOCATION);
EXPECT_EQ(servers_[0]->service_.request_count(), 0);
@ -676,14 +709,15 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdateSuperset) {
// Start servers and send one RPC per server.
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel("pick_first");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator);
auto stub = BuildStub(channel);
std::vector<int> ports;
// Perform one RPC against the first server.
ports.emplace_back(servers_[0]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** SET [0] *******");
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_EQ(servers_[0]->service_.request_count(), 1);
@ -693,7 +727,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdateSuperset) {
ports.clear();
ports.emplace_back(servers_[1]->port_);
ports.emplace_back(servers_[0]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** SET superset *******");
CheckRpcSendOk(stub, DEBUG_LOCATION);
// We stick to the previously connected server.
@ -710,12 +744,14 @@ TEST_F(ClientLbEnd2endTest, PickFirstGlobalSubchannelPool) {
StartServers(kNumServers);
std::vector<int> ports = GetServersPorts();
// Create two channels that (by default) use the global subchannel pool.
auto channel1 = BuildChannel("pick_first");
auto response_generator1 = BuildResolverResponseGenerator();
auto channel1 = BuildChannel("pick_first", response_generator1);
auto stub1 = BuildStub(channel1);
SetNextResolution(ports);
auto channel2 = BuildChannel("pick_first");
response_generator1.SetNextResolution(ports);
auto response_generator2 = BuildResolverResponseGenerator();
auto channel2 = BuildChannel("pick_first", response_generator2);
auto stub2 = BuildStub(channel2);
SetNextResolution(ports);
response_generator2.SetNextResolution(ports);
WaitForServer(stub1, 0, DEBUG_LOCATION);
// Send one RPC on each channel.
CheckRpcSendOk(stub1, DEBUG_LOCATION);
@ -735,12 +771,14 @@ TEST_F(ClientLbEnd2endTest, PickFirstLocalSubchannelPool) {
// Create two channels that use local subchannel pool.
ChannelArguments args;
args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, 1);
auto channel1 = BuildChannel("pick_first", args);
auto response_generator1 = BuildResolverResponseGenerator();
auto channel1 = BuildChannel("pick_first", response_generator1, args);
auto stub1 = BuildStub(channel1);
SetNextResolution(ports);
auto channel2 = BuildChannel("pick_first", args);
response_generator1.SetNextResolution(ports);
auto response_generator2 = BuildResolverResponseGenerator();
auto channel2 = BuildChannel("pick_first", response_generator2, args);
auto stub2 = BuildStub(channel2);
SetNextResolution(ports);
response_generator2.SetNextResolution(ports);
WaitForServer(stub1, 0, DEBUG_LOCATION);
// Send one RPC on each channel.
CheckRpcSendOk(stub1, DEBUG_LOCATION);
@ -756,13 +794,14 @@ TEST_F(ClientLbEnd2endTest, PickFirstManyUpdates) {
const int kNumUpdates = 1000;
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel("pick_first");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator);
auto stub = BuildStub(channel);
std::vector<int> ports = GetServersPorts();
for (size_t i = 0; i < kNumUpdates; ++i) {
std::shuffle(ports.begin(), ports.end(),
std::mt19937(std::random_device()()));
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
// We should re-enter core at the end of the loop to give the resolution
// setting closure a chance to run.
if ((i + 1) % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
@ -784,16 +823,17 @@ TEST_F(ClientLbEnd2endTest, PickFirstReresolutionNoSelected) {
dead_ports.emplace_back(grpc_pick_unused_port_or_die());
}
}
auto channel = BuildChannel("pick_first");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator);
auto stub = BuildStub(channel);
// The initial resolution only contains dead ports. There won't be any
// selected subchannel. Re-resolution will return the same result.
SetNextResolution(dead_ports);
response_generator.SetNextResolution(dead_ports);
gpr_log(GPR_INFO, "****** INITIAL RESOLUTION SET *******");
for (size_t i = 0; i < 10; ++i) CheckRpcSendFailure(stub);
// Set a re-resolution result that contains reachable ports, so that the
// pick_first LB policy can recover soon.
SetNextResolutionUponError(alive_ports);
response_generator.SetNextResolutionUponError(alive_ports);
gpr_log(GPR_INFO, "****** RE-RESOLUTION SET *******");
WaitForServer(stub, 0, DEBUG_LOCATION, true /* ignore_failure */);
CheckRpcSendOk(stub, DEBUG_LOCATION);
@ -805,9 +845,10 @@ TEST_F(ClientLbEnd2endTest, PickFirstReresolutionNoSelected) {
TEST_F(ClientLbEnd2endTest, PickFirstReconnectWithoutNewResolverResult) {
std::vector<int> ports = {grpc_pick_unused_port_or_die()};
StartServers(1, ports);
auto channel = BuildChannel("pick_first");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator);
auto stub = BuildStub(channel);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** INITIAL CONNECTION *******");
WaitForServer(stub, 0, DEBUG_LOCATION);
gpr_log(GPR_INFO, "****** STOPPING SERVER ******");
@ -824,9 +865,10 @@ TEST_F(ClientLbEnd2endTest,
grpc_pick_unused_port_or_die()};
CreateServers(2, ports);
StartServer(1);
auto channel = BuildChannel("pick_first");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("pick_first", response_generator);
auto stub = BuildStub(channel);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** INITIAL CONNECTION *******");
WaitForServer(stub, 1, DEBUG_LOCATION);
gpr_log(GPR_INFO, "****** STOPPING SERVER ******");
@ -840,9 +882,10 @@ TEST_F(ClientLbEnd2endTest,
TEST_F(ClientLbEnd2endTest, PickFirstCheckStateBeforeStartWatch) {
std::vector<int> ports = {grpc_pick_unused_port_or_die()};
StartServers(1, ports);
auto channel_1 = BuildChannel("pick_first");
auto response_generator = BuildResolverResponseGenerator();
auto channel_1 = BuildChannel("pick_first", response_generator);
auto stub_1 = BuildStub(channel_1);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** RESOLUTION SET FOR CHANNEL 1 *******");
WaitForServer(stub_1, 0, DEBUG_LOCATION);
gpr_log(GPR_INFO, "****** CHANNEL 1 CONNECTED *******");
@ -851,13 +894,10 @@ TEST_F(ClientLbEnd2endTest, PickFirstCheckStateBeforeStartWatch) {
// create a new subchannel and hold a ref to it.
StartServers(1, ports);
gpr_log(GPR_INFO, "****** SERVER RESTARTED *******");
auto channel_2 = BuildChannel("pick_first");
auto response_generator_2 = BuildResolverResponseGenerator();
auto channel_2 = BuildChannel("pick_first", response_generator_2);
auto stub_2 = BuildStub(channel_2);
// TODO(juanlishen): This resolution result will only be visible to channel 2
// since the response generator is only associated with channel 2 now. We
// should change the response generator to be able to deliver updates to
// multiple channels at once.
SetNextResolution(ports);
response_generator_2.SetNextResolution(ports);
gpr_log(GPR_INFO, "****** RESOLUTION SET FOR CHANNEL 2 *******");
WaitForServer(stub_2, 0, DEBUG_LOCATION, true);
gpr_log(GPR_INFO, "****** CHANNEL 2 CONNECTED *******");
@ -883,13 +923,15 @@ TEST_F(ClientLbEnd2endTest, PickFirstIdleOnDisconnect) {
// Start server, send RPC, and make sure channel is READY.
const int kNumServers = 1;
StartServers(kNumServers);
auto channel = BuildChannel(""); // pick_first is the default.
auto response_generator = BuildResolverResponseGenerator();
auto channel =
BuildChannel("", response_generator); // pick_first is the default.
auto stub = BuildStub(channel);
SetNextResolution(GetServersPorts());
response_generator.SetNextResolution(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_READY);
// Stop server. Channel should go into state IDLE.
SetFailureOnReresolution();
response_generator.SetFailureOnReresolution();
servers_[0]->Shutdown();
EXPECT_TRUE(WaitForChannelNotReady(channel.get()));
EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_IDLE);
@ -897,14 +939,16 @@ TEST_F(ClientLbEnd2endTest, PickFirstIdleOnDisconnect) {
}
TEST_F(ClientLbEnd2endTest, PickFirstPendingUpdateAndSelectedSubchannelFails) {
auto channel = BuildChannel(""); // pick_first is the default.
auto response_generator = BuildResolverResponseGenerator();
auto channel =
BuildChannel("", response_generator); // pick_first is the default.
auto stub = BuildStub(channel);
// Create a number of servers, but only start 1 of them.
CreateServers(10);
StartServer(0);
// Initially resolve to first server and make sure it connects.
gpr_log(GPR_INFO, "Phase 1: Connect to first server.");
SetNextResolution({servers_[0]->port_});
response_generator.SetNextResolution({servers_[0]->port_});
CheckRpcSendOk(stub, DEBUG_LOCATION, true /* wait_for_ready */);
EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_READY);
// Send a resolution update with the remaining servers, none of which are
@ -916,7 +960,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstPendingUpdateAndSelectedSubchannelFails) {
gpr_log(GPR_INFO,
"Phase 2: Resolver update pointing to remaining "
"(not started) servers.");
SetNextResolution(GetServersPorts(1 /* start_index */));
response_generator.SetNextResolution(GetServersPorts(1 /* start_index */));
// RPCs will continue to be sent to the first server.
CheckRpcSendOk(stub, DEBUG_LOCATION);
// Now stop the first server, so that the current subchannel list
@ -947,9 +991,11 @@ TEST_F(ClientLbEnd2endTest, PickFirstStaysIdleUponEmptyUpdate) {
// Start server, send RPC, and make sure channel is READY.
const int kNumServers = 1;
StartServers(kNumServers);
auto channel = BuildChannel(""); // pick_first is the default.
auto response_generator = BuildResolverResponseGenerator();
auto channel =
BuildChannel("", response_generator); // pick_first is the default.
auto stub = BuildStub(channel);
SetNextResolution(GetServersPorts());
response_generator.SetNextResolution(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_READY);
// Stop server. Channel should go into state IDLE.
@ -958,13 +1004,13 @@ TEST_F(ClientLbEnd2endTest, PickFirstStaysIdleUponEmptyUpdate) {
EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_IDLE);
// Now send resolver update that includes no addresses. Channel
// should stay in state IDLE.
SetNextResolution({});
response_generator.SetNextResolution({});
EXPECT_FALSE(channel->WaitForStateChange(
GRPC_CHANNEL_IDLE, grpc_timeout_seconds_to_deadline(3)));
// Now bring the backend back up and send a non-empty resolver update,
// and then try to send an RPC. Channel should go back into state READY.
StartServer(0);
SetNextResolution(GetServersPorts());
response_generator.SetNextResolution(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_EQ(channel->GetState(false), GRPC_CHANNEL_READY);
}
@ -973,9 +1019,10 @@ TEST_F(ClientLbEnd2endTest, RoundRobin) {
// Start servers and send one RPC per server.
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel("round_robin");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("round_robin", response_generator);
auto stub = BuildStub(channel);
SetNextResolution(GetServersPorts());
response_generator.SetNextResolution(GetServersPorts());
// Wait until all backends are ready.
do {
CheckRpcSendOk(stub, DEBUG_LOCATION);
@ -999,18 +1046,20 @@ TEST_F(ClientLbEnd2endTest, RoundRobin) {
TEST_F(ClientLbEnd2endTest, RoundRobinProcessPending) {
StartServers(1); // Single server
auto channel = BuildChannel("round_robin");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("round_robin", response_generator);
auto stub = BuildStub(channel);
SetNextResolution({servers_[0]->port_});
response_generator.SetNextResolution({servers_[0]->port_});
WaitForServer(stub, 0, DEBUG_LOCATION);
// Create a new channel and its corresponding RR LB policy, which will pick
// the subchannels in READY state from the previous RPC against the same
// target (even if it happened over a different channel, because subchannels
// are globally reused). Progress should happen without any transition from
// this READY state.
auto second_channel = BuildChannel("round_robin");
auto second_response_generator = BuildResolverResponseGenerator();
auto second_channel = BuildChannel("round_robin", second_response_generator);
auto second_stub = BuildStub(second_channel);
SetNextResolution({servers_[0]->port_});
second_response_generator.SetNextResolution({servers_[0]->port_});
CheckRpcSendOk(second_stub, DEBUG_LOCATION);
}
@ -1018,13 +1067,14 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
// Start servers and send one RPC per server.
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel("round_robin");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("round_robin", response_generator);
auto stub = BuildStub(channel);
std::vector<int> ports;
// Start with a single server.
gpr_log(GPR_INFO, "*** FIRST BACKEND ***");
ports.emplace_back(servers_[0]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
WaitForServer(stub, 0, DEBUG_LOCATION);
// Send RPCs. They should all go servers_[0]
for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION);
@ -1036,7 +1086,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
gpr_log(GPR_INFO, "*** SECOND BACKEND ***");
ports.clear();
ports.emplace_back(servers_[1]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
// Wait until update has been processed, as signaled by the second backend
// receiving a request.
EXPECT_EQ(0, servers_[1]->service_.request_count());
@ -1050,7 +1100,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
gpr_log(GPR_INFO, "*** THIRD BACKEND ***");
ports.clear();
ports.emplace_back(servers_[2]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
WaitForServer(stub, 2, DEBUG_LOCATION);
for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_EQ(0, servers_[0]->service_.request_count());
@ -1063,7 +1113,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
ports.emplace_back(servers_[0]->port_);
ports.emplace_back(servers_[1]->port_);
ports.emplace_back(servers_[2]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
WaitForServer(stub, 0, DEBUG_LOCATION);
WaitForServer(stub, 1, DEBUG_LOCATION);
WaitForServer(stub, 2, DEBUG_LOCATION);
@ -1075,7 +1125,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
// An empty update will result in the channel going into TRANSIENT_FAILURE.
gpr_log(GPR_INFO, "*** NO BACKENDS ***");
ports.clear();
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
grpc_connectivity_state channel_state;
do {
channel_state = channel->GetState(true /* try to connect */);
@ -1086,7 +1136,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
gpr_log(GPR_INFO, "*** BACK TO SECOND BACKEND ***");
ports.clear();
ports.emplace_back(servers_[1]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
WaitForServer(stub, 1, DEBUG_LOCATION);
channel_state = channel->GetState(false /* try to connect */);
ASSERT_EQ(channel_state, GRPC_CHANNEL_READY);
@ -1097,13 +1147,14 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
TEST_F(ClientLbEnd2endTest, RoundRobinUpdateInError) {
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel("round_robin");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("round_robin", response_generator);
auto stub = BuildStub(channel);
std::vector<int> ports;
// Start with a single server.
ports.emplace_back(servers_[0]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
WaitForServer(stub, 0, DEBUG_LOCATION);
// Send RPCs. They should all go to servers_[0]
for (size_t i = 0; i < 10; ++i) SendRpc(stub);
@ -1116,7 +1167,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdateInError) {
servers_[1]->Shutdown();
ports.emplace_back(servers_[1]->port_);
ports.emplace_back(servers_[2]->port_);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
WaitForServer(stub, 0, DEBUG_LOCATION);
WaitForServer(stub, 2, DEBUG_LOCATION);
@ -1130,13 +1181,14 @@ TEST_F(ClientLbEnd2endTest, RoundRobinManyUpdates) {
// Start servers and send one RPC per server.
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel("round_robin");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("round_robin", response_generator);
auto stub = BuildStub(channel);
std::vector<int> ports = GetServersPorts();
for (size_t i = 0; i < 1000; ++i) {
std::shuffle(ports.begin(), ports.end(),
std::mt19937(std::random_device()()));
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
if (i % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
}
// Check LB policy name for the channel.
@ -1162,9 +1214,10 @@ TEST_F(ClientLbEnd2endTest, RoundRobinReresolve) {
second_ports.push_back(grpc_pick_unused_port_or_die());
}
StartServers(kNumServers, first_ports);
auto channel = BuildChannel("round_robin");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("round_robin", response_generator);
auto stub = BuildStub(channel);
SetNextResolution(first_ports);
response_generator.SetNextResolution(first_ports);
// Send a number of RPCs, which succeed.
for (size_t i = 0; i < 100; ++i) {
CheckRpcSendOk(stub, DEBUG_LOCATION);
@ -1188,7 +1241,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinReresolve) {
StartServers(kNumServers, second_ports);
// Don't notify of the update. Wait for the LB policy's re-resolution to
// "pull" the new ports.
SetNextResolutionUponError(second_ports);
response_generator.SetNextResolutionUponError(second_ports);
gpr_log(GPR_INFO, "****** SERVERS RESTARTED *******");
gpr_log(GPR_INFO, "****** SENDING REQUEST TO SUCCEED *******");
// Client request should eventually (but still fairly soon) succeed.
@ -1205,9 +1258,10 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
const int kNumServers = 3;
StartServers(kNumServers);
const auto ports = GetServersPorts();
auto channel = BuildChannel("round_robin");
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("round_robin", response_generator);
auto stub = BuildStub(channel);
SetNextResolution(ports);
response_generator.SetNextResolution(ports);
for (size_t i = 0; i < kNumServers; ++i) {
WaitForServer(stub, i, DEBUG_LOCATION);
}
@ -1251,9 +1305,10 @@ TEST_F(ClientLbEnd2endTest,
args.SetServiceConfigJSON(
"{\"healthCheckConfig\": "
"{\"serviceName\": \"health_check_service_name\"}}");
auto channel = BuildChannel("round_robin", args);
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("round_robin", response_generator, args);
auto stub = BuildStub(channel);
SetNextResolution({servers_[0]->port_});
response_generator.SetNextResolution({servers_[0]->port_});
EXPECT_TRUE(WaitForChannelReady(channel.get()));
CheckRpcSendOk(stub, DEBUG_LOCATION);
}
@ -1267,9 +1322,10 @@ TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthChecking) {
args.SetServiceConfigJSON(
"{\"healthCheckConfig\": "
"{\"serviceName\": \"health_check_service_name\"}}");
auto channel = BuildChannel("round_robin", args);
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("round_robin", response_generator, args);
auto stub = BuildStub(channel);
SetNextResolution(GetServersPorts());
response_generator.SetNextResolution(GetServersPorts());
// Channel should not become READY, because health checks should be failing.
gpr_log(GPR_INFO,
"*** initial state: unknown health check service name for "
@ -1341,15 +1397,17 @@ TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthCheckingInhibitPerChannel) {
args.SetServiceConfigJSON(
"{\"healthCheckConfig\": "
"{\"serviceName\": \"health_check_service_name\"}}");
auto channel1 = BuildChannel("round_robin", args);
auto response_generator1 = BuildResolverResponseGenerator();
auto channel1 = BuildChannel("round_robin", response_generator1, args);
auto stub1 = BuildStub(channel1);
std::vector<int> ports = GetServersPorts();
SetNextResolution(ports);
response_generator1.SetNextResolution(ports);
// Create a channel with health checking enabled but inhibited.
args.SetInt(GRPC_ARG_INHIBIT_HEALTH_CHECKING, 1);
auto channel2 = BuildChannel("round_robin", args);
auto response_generator2 = BuildResolverResponseGenerator();
auto channel2 = BuildChannel("round_robin", response_generator2, args);
auto stub2 = BuildStub(channel2);
SetNextResolution(ports);
response_generator2.SetNextResolution(ports);
// First channel should not become READY, because health checks should be
// failing.
EXPECT_FALSE(WaitForChannelReady(channel1.get(), 1));
@ -1376,19 +1434,21 @@ TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthCheckingServiceNamePerChannel) {
args.SetServiceConfigJSON(
"{\"healthCheckConfig\": "
"{\"serviceName\": \"health_check_service_name\"}}");
auto channel1 = BuildChannel("round_robin", args);
auto response_generator1 = BuildResolverResponseGenerator();
auto channel1 = BuildChannel("round_robin", response_generator1, args);
auto stub1 = BuildStub(channel1);
std::vector<int> ports = GetServersPorts();
SetNextResolution(ports);
response_generator1.SetNextResolution(ports);
// Create a channel with health-checking enabled with a different
// service name.
ChannelArguments args2;
args2.SetServiceConfigJSON(
"{\"healthCheckConfig\": "
"{\"serviceName\": \"health_check_service_name2\"}}");
auto channel2 = BuildChannel("round_robin", args2);
auto response_generator2 = BuildResolverResponseGenerator();
auto channel2 = BuildChannel("round_robin", response_generator2, args2);
auto stub2 = BuildStub(channel2);
SetNextResolution(ports);
response_generator2.SetNextResolution(ports);
// Allow health checks from channel 2 to succeed.
servers_[0]->SetServingStatus("health_check_service_name2", true);
// First channel should not become READY, because health checks should be
@ -1438,9 +1498,11 @@ TEST_F(ClientLbInterceptTrailingMetadataTest, InterceptsRetriesDisabled) {
const int kNumServers = 1;
const int kNumRpcs = 10;
StartServers(kNumServers);
auto channel = BuildChannel("intercept_trailing_metadata_lb");
auto response_generator = BuildResolverResponseGenerator();
auto channel =
BuildChannel("intercept_trailing_metadata_lb", response_generator);
auto stub = BuildStub(channel);
SetNextResolution(GetServersPorts());
response_generator.SetNextResolution(GetServersPorts());
for (size_t i = 0; i < kNumRpcs; ++i) {
CheckRpcSendOk(stub, DEBUG_LOCATION);
}
@ -1470,9 +1532,11 @@ TEST_F(ClientLbInterceptTrailingMetadataTest, InterceptsRetriesEnabled) {
" }\n"
" } ]\n"
"}");
auto channel = BuildChannel("intercept_trailing_metadata_lb", args);
auto response_generator = BuildResolverResponseGenerator();
auto channel =
BuildChannel("intercept_trailing_metadata_lb", response_generator, args);
auto stub = BuildStub(channel);
SetNextResolution(GetServersPorts());
response_generator.SetNextResolution(GetServersPorts());
for (size_t i = 0; i < kNumRpcs; ++i) {
CheckRpcSendOk(stub, DEBUG_LOCATION);
}

@ -26,6 +26,7 @@ else
docker build -t bazel_local_img tools/dockerfile/test/sanity
docker run -v "$(realpath .):/src/grpc/:ro" \
-w /src/grpc/third_party/protobuf \
--rm=true \
bazel_local_img \
bazel query 'deps('$1')'
fi

@ -947,7 +947,9 @@ include/grpcpp/impl/channel_argument_option.h \
include/grpcpp/impl/client_unary_call.h \
include/grpcpp/impl/codegen/async_generic_service.h \
include/grpcpp/impl/codegen/async_stream.h \
include/grpcpp/impl/codegen/async_stream_impl.h \
include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/async_unary_call_impl.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
@ -956,6 +958,7 @@ include/grpcpp/impl/codegen/call_op_set_interface.h \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_callback_impl.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
@ -983,6 +986,7 @@ include/grpcpp/impl/codegen/rpc_service_method.h \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_callback_impl.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
@ -995,6 +999,7 @@ include/grpcpp/impl/codegen/string_ref.h \
include/grpcpp/impl/codegen/stub_options.h \
include/grpcpp/impl/codegen/sync.h \
include/grpcpp/impl/codegen/sync_stream.h \
include/grpcpp/impl/codegen/sync_stream_impl.h \
include/grpcpp/impl/codegen/time.h \
include/grpcpp/impl/grpc_library.h \
include/grpcpp/impl/method_handler_impl.h \
@ -1024,11 +1029,14 @@ include/grpcpp/server_impl.h \
include/grpcpp/server_posix.h \
include/grpcpp/server_posix_impl.h \
include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_stream_impl.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/async_unary_call_impl.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
include/grpcpp/support/channel_arguments_impl.h \
include/grpcpp/support/client_callback.h \
include/grpcpp/support/client_callback_impl.h \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
include/grpcpp/support/interceptor.h \
@ -1036,6 +1044,7 @@ include/grpcpp/support/message_allocator.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
include/grpcpp/support/server_callback.h \
include/grpcpp/support/server_callback_impl.h \
include/grpcpp/support/server_interceptor.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
@ -1043,6 +1052,7 @@ include/grpcpp/support/status_code_enum.h \
include/grpcpp/support/string_ref.h \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/sync_stream_impl.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h

@ -948,7 +948,9 @@ include/grpcpp/impl/channel_argument_option.h \
include/grpcpp/impl/client_unary_call.h \
include/grpcpp/impl/codegen/async_generic_service.h \
include/grpcpp/impl/codegen/async_stream.h \
include/grpcpp/impl/codegen/async_stream_impl.h \
include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/async_unary_call_impl.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
@ -957,6 +959,7 @@ include/grpcpp/impl/codegen/call_op_set_interface.h \
include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_callback_impl.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
@ -985,6 +988,7 @@ include/grpcpp/impl/codegen/rpc_service_method.h \
include/grpcpp/impl/codegen/security/auth_context.h \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_callback_impl.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
@ -997,6 +1001,7 @@ include/grpcpp/impl/codegen/string_ref.h \
include/grpcpp/impl/codegen/stub_options.h \
include/grpcpp/impl/codegen/sync.h \
include/grpcpp/impl/codegen/sync_stream.h \
include/grpcpp/impl/codegen/sync_stream_impl.h \
include/grpcpp/impl/codegen/time.h \
include/grpcpp/impl/grpc_library.h \
include/grpcpp/impl/method_handler_impl.h \
@ -1026,11 +1031,14 @@ include/grpcpp/server_impl.h \
include/grpcpp/server_posix.h \
include/grpcpp/server_posix_impl.h \
include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_stream_impl.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/async_unary_call_impl.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
include/grpcpp/support/channel_arguments_impl.h \
include/grpcpp/support/client_callback.h \
include/grpcpp/support/client_callback_impl.h \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
include/grpcpp/support/interceptor.h \
@ -1038,6 +1046,7 @@ include/grpcpp/support/message_allocator.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
include/grpcpp/support/server_callback.h \
include/grpcpp/support/server_callback_impl.h \
include/grpcpp/support/server_interceptor.h \
include/grpcpp/support/slice.h \
include/grpcpp/support/status.h \
@ -1045,6 +1054,7 @@ include/grpcpp/support/status_code_enum.h \
include/grpcpp/support/string_ref.h \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/sync_stream_impl.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
src/core/ext/filters/client_channel/health/health.pb.c \

@ -10209,7 +10209,9 @@
"include/grpc++/impl/codegen/time.h",
"include/grpcpp/impl/codegen/async_generic_service.h",
"include/grpcpp/impl/codegen/async_stream.h",
"include/grpcpp/impl/codegen/async_stream_impl.h",
"include/grpcpp/impl/codegen/async_unary_call.h",
"include/grpcpp/impl/codegen/async_unary_call_impl.h",
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
@ -10218,6 +10220,7 @@
"include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
"include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_callback_impl.h",
"include/grpcpp/impl/codegen/client_context.h",
"include/grpcpp/impl/codegen/client_context_impl.h",
"include/grpcpp/impl/codegen/client_interceptor.h",
@ -10240,6 +10243,7 @@
"include/grpcpp/impl/codegen/security/auth_context.h",
"include/grpcpp/impl/codegen/serialization_traits.h",
"include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_callback_impl.h",
"include/grpcpp/impl/codegen/server_context.h",
"include/grpcpp/impl/codegen/server_context_impl.h",
"include/grpcpp/impl/codegen/server_interceptor.h",
@ -10251,6 +10255,7 @@
"include/grpcpp/impl/codegen/string_ref.h",
"include/grpcpp/impl/codegen/stub_options.h",
"include/grpcpp/impl/codegen/sync_stream.h",
"include/grpcpp/impl/codegen/sync_stream_impl.h",
"include/grpcpp/impl/codegen/time.h"
],
"is_filegroup": true,
@ -10289,7 +10294,9 @@
"include/grpc++/impl/codegen/time.h",
"include/grpcpp/impl/codegen/async_generic_service.h",
"include/grpcpp/impl/codegen/async_stream.h",
"include/grpcpp/impl/codegen/async_stream_impl.h",
"include/grpcpp/impl/codegen/async_unary_call.h",
"include/grpcpp/impl/codegen/async_unary_call_impl.h",
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
@ -10298,6 +10305,7 @@
"include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
"include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_callback_impl.h",
"include/grpcpp/impl/codegen/client_context.h",
"include/grpcpp/impl/codegen/client_context_impl.h",
"include/grpcpp/impl/codegen/client_interceptor.h",
@ -10320,6 +10328,7 @@
"include/grpcpp/impl/codegen/security/auth_context.h",
"include/grpcpp/impl/codegen/serialization_traits.h",
"include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_callback_impl.h",
"include/grpcpp/impl/codegen/server_context.h",
"include/grpcpp/impl/codegen/server_context_impl.h",
"include/grpcpp/impl/codegen/server_interceptor.h",
@ -10331,6 +10340,7 @@
"include/grpcpp/impl/codegen/string_ref.h",
"include/grpcpp/impl/codegen/stub_options.h",
"include/grpcpp/impl/codegen/sync_stream.h",
"include/grpcpp/impl/codegen/sync_stream_impl.h",
"include/grpcpp/impl/codegen/time.h"
],
"third_party": false,
@ -10480,11 +10490,14 @@
"include/grpcpp/server_posix.h",
"include/grpcpp/server_posix_impl.h",
"include/grpcpp/support/async_stream.h",
"include/grpcpp/support/async_stream_impl.h",
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/async_unary_call_impl.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
"include/grpcpp/support/channel_arguments_impl.h",
"include/grpcpp/support/client_callback.h",
"include/grpcpp/support/client_callback_impl.h",
"include/grpcpp/support/client_interceptor.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/interceptor.h",
@ -10492,6 +10505,7 @@
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
"include/grpcpp/support/server_callback.h",
"include/grpcpp/support/server_callback_impl.h",
"include/grpcpp/support/server_interceptor.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
@ -10499,6 +10513,7 @@
"include/grpcpp/support/string_ref.h",
"include/grpcpp/support/stub_options.h",
"include/grpcpp/support/sync_stream.h",
"include/grpcpp/support/sync_stream_impl.h",
"include/grpcpp/support/time.h",
"include/grpcpp/support/validate_service_config.h",
"src/cpp/client/create_channel_internal.h",
@ -10608,11 +10623,14 @@
"include/grpcpp/server_posix.h",
"include/grpcpp/server_posix_impl.h",
"include/grpcpp/support/async_stream.h",
"include/grpcpp/support/async_stream_impl.h",
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/async_unary_call_impl.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
"include/grpcpp/support/channel_arguments_impl.h",
"include/grpcpp/support/client_callback.h",
"include/grpcpp/support/client_callback_impl.h",
"include/grpcpp/support/client_interceptor.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/interceptor.h",
@ -10620,6 +10638,7 @@
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
"include/grpcpp/support/server_callback.h",
"include/grpcpp/support/server_callback_impl.h",
"include/grpcpp/support/server_interceptor.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
@ -10627,6 +10646,7 @@
"include/grpcpp/support/string_ref.h",
"include/grpcpp/support/stub_options.h",
"include/grpcpp/support/sync_stream.h",
"include/grpcpp/support/sync_stream_impl.h",
"include/grpcpp/support/time.h",
"include/grpcpp/support/validate_service_config.h",
"src/cpp/client/channel_cc.cc",

Loading…
Cancel
Save